Skip to content

relayburn: install wrapper dispatches Rust burn binary via platform packages#360

Merged
willwashburn merged 3 commits intomainfrom
cli-binary-swap
May 7, 2026
Merged

relayburn: install wrapper dispatches Rust burn binary via platform packages#360
willwashburn merged 3 commits intomainfrom
cli-binary-swap

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

Switches npm i -g relayburn to install the prebuilt Rust burn binary instead of dispatching through the TS @relayburn/cli. Same shape the napi-rs @relayburn/sdk umbrella already uses for @relayburn/sdk-<platform> packages — except we ship native executables instead of .node files.

  • New per-platform packages under packages/relayburn/npm/<short>/: @relayburn/cli-darwin-arm64, @relayburn/cli-darwin-x64, @relayburn/cli-linux-arm64-gnu, @relayburn/cli-linux-x64-gnu. Each carries os / cpu (and libc for linux glibc) filters, version-pinned at 1.10.0 to match the workspace.
  • The umbrella relayburn package drops its @relayburn/cli workspace dep and adds the four platform packages as optionalDependencies. npm's filters install only the matching one; the burn shim require.resolves @relayburn/cli-<platform>/bin/burn and spawnSyncs it with the user's argv. Exit codes propagate; signal exits map to 128 + signo.
  • The dispatcher is forward-compat for Windows (Add Windows targets to napi sdk-node + CLI binary distribution #359) — process.platform === 'win32' already maps to win32-x64 and appends .exe, so Add Windows targets to napi sdk-node + CLI binary distribution #359 only needs to add a matrix leg + optionalDependencies entry.
  • .github/workflows/cli-build.yml builds the four-platform matrix on PR / push (mirroring napi-build.yml): darwin-x64 on macos-15-intel, darwin-arm64 on macos-14, linux-x64-gnu and linux-arm64-gnu on ubuntu-latest with the aarch64 cross-compiler. Each leg strips the binary, stages it under packages/relayburn/npm/<short>/bin/burn, runs a --help smoke test (skipped on aarch64-linux because cross-compile), and uploads it as a build artifact. The publish: job is a stub — full publish.yml integration is the follow-up PR.
  • bin/ under each platform package is gitignored at rest; only package.json + README.md are committed.

Naming

Settled on @relayburn/cli-<platform> to be parallel with @relayburn/sdk-<platform>. No collision with the existing @relayburn/cli (the TS CLI package keeps that name without a platform suffix).

End-to-end manual probe (darwin-arm64)

Built cargo build --release --target aarch64-apple-darwin --bin burn -p relayburn-cli, staged into packages/relayburn/npm/darwin-arm64/bin/burn, npm packed both the platform package and the umbrella, then npm install --global --prefix $TESTDIR of both tarballs into a tmpdir. $TESTDIR/bin/burn --help prints the Rust CLI's help, $TESTDIR/bin/burn summary --help works, $TESTDIR/bin/burn --version prints burn 1.10.0. diff <(installed-burn --help) <(cargo-built-burn --help) produces zero output (identical). No surprises.

Out of scope

Refs #240, forward-compat for #359.

Test plan

  • cli-build matrix passes on all four legs (darwin-arm64, darwin-x64, linux-x64-gnu, linux-arm64-gnu).
  • CI build-and-test + cargo-build-and-test jobs still pass.
  • Smoke test inside cli-build passes for the three native legs (burn --help and burn --version).

…ackages

Mirror the napi-rs `@relayburn/sdk-<platform>` shape: the umbrella
`relayburn` package declares per-platform `@relayburn/cli-<platform>`
packages as `optionalDependencies`, and the `burn` shim in
`packages/relayburn/bin/burn.js` resolves and execs the prebuilt Rust
binary out of whichever one npm installed.

Replaces the prior dispatch through `@relayburn/cli` (TS). Per-platform
packages cover darwin-arm64, darwin-x64, linux-arm64-gnu, linux-x64-gnu;
Windows is forward-compat in the dispatcher mapping but not yet shipped
(#359).

Adds `.github/workflows/cli-build.yml` matrix build (mirrors
`napi-build.yml`); the `publish:` job is left as a stub until the
cutover publish.yml integration follow-up. The `bin/` directory under
each platform package is gitignored — populated by the matrix build.

Refs #240.
The umbrella `relayburn` package now lists per-platform Rust binary
packages (`@relayburn/cli-darwin-arm64`, …) as `optionalDependencies`.
Those don't exist on npm yet, so pnpm 10 silently drops them from the
lockfile during install — and CI's `pnpm install --frozen-lockfile`
then rejects the lockfile because the specifiers in `package.json`
aren't represented.

Mirror the `sdk-node` exclusion in `pnpm-workspace.yaml`: drop
`packages/relayburn` from the workspace. Nothing in-repo consumes it
(it's a thin install wrapper that spawns the Rust binary), so this is
a no-op for everyone except the install-time path.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Builds precompiled relayburn burn binaries for macOS (arm64/x64) and Linux glibc (arm64/x64), stages them as per-platform npm packages, adds a platform-resolving burn dispatcher, updates the main package to optionalDependencies, and adds CI build/publish/version-sync steps.

Changes

Prebuilt CLI Distribution

Layer / File(s) Summary
Main package optionalDependencies
packages/relayburn/package.json
Updates description and replaces workspace dependency with pinned optionalDependencies for @relayburn/cli and platform packages at 1.10.0.
Binary dispatcher (runtime)
packages/relayburn/bin/burn.js
Replaces direct import with a platform/arch/libc resolver that tries @relayburn/cli-<short>/bin/burn, falls back to @relayburn/cli/dist/cli.js, spawns child with inherited stdio, and propagates signal/exit codes.
GitHub Actions: cli-build workflow
.github/workflows/cli-build.yml
Adds a 4-target matrix build, installs Rust toolchain/targets, optionally installs cross-gcc for aarch64, caches Cargo/target, builds and strips release binaries, stages bin/burn into per-platform packages/relayburn/npm/<short>/, uploads artifacts, runs native smoke tests, and provides a manual publish stub.
Publish workflow: version sync
.github/workflows/publish.yml
Adds Node script to synchronize packages/relayburn and all packages/relayburn/npm/*/package.json versions and regenerates pinned optionalDependencies; ensures these files are committed during version bump.
Platform package manifests
packages/relayburn/npm/*/package.json
Adds four package manifests (@relayburn/cli-darwin-arm64, @relayburn/cli-darwin-x64, @relayburn/cli-linux-arm64-gnu, @relayburn/cli-linux-x64-gnu) with bin.burn, file whitelist, platform constraints, Node >=22, and publishConfig set to public/next.
Platform package READMEs
packages/relayburn/npm/*/README.md
Adds README files directing consumers to install relayburn (which selects the correct optional dependency) and linking to upstream repo.
Docs & Configuration
.gitignore, packages/relayburn/README.md, packages/relayburn/CHANGELOG.md, pnpm-workspace.yaml
Excludes staged prebuilt binaries from git, documents the optionalDependencies-based resolution and prebuilt platforms, updates changelog Unreleased, and excludes packages/relayburn from pnpm workspace to avoid CI frozen-lockfile issues pre-publish.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • AgentWorkforce/burn#353: Related publish/version-sync changes — #353 touches publish.yml version synchronization similar to the version-pin logic added here.

🐰 I stitched binaries across platforms tonight,
Hop-scoped artifacts in packages just right,
The dispatcher finds the matching file with care,
macOS and Linux now each have a pair,
A tiny hop for humans, a big leap for the hare.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'relayburn: install wrapper dispatches Rust burn binary via platform packages' accurately summarizes the main change—converting global relayburn installs to use prebuilt Rust binaries via platform-specific packages instead of TypeScript CLI.
Description check ✅ Passed The description provides detailed, relevant context about the changes: new platform packages, the dispatcher shim, build workflow, and manual testing—all directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cli-binary-swap

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58733a05d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +22 to +25
"@relayburn/cli-darwin-arm64": "1.10.0",
"@relayburn/cli-darwin-x64": "1.10.0",
"@relayburn/cli-linux-arm64-gnu": "1.10.0",
"@relayburn/cli-linux-x64-gnu": "1.10.0"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Derive platform optionalDependency versions from package version

Pinning the four @relayburn/cli-* optional dependencies to 1.10.0 will drift on the next lockstep release: .github/workflows/publish.yml only bumps/publishes reader ledger analyze ingest sdk mcp cli relayburn, so relayburn@1.10.1+ will still install @relayburn/cli-*@1.10.0. That means global installs can execute an older burn binary than the wrapper version (and eventually fail if that exact version is unavailable), which is a production regression for every future release unless these versions are automatically synchronized.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +21 to 26
"optionalDependencies": {
"@relayburn/cli-darwin-arm64": "1.10.0",
"@relayburn/cli-darwin-x64": "1.10.0",
"@relayburn/cli-linux-arm64-gnu": "1.10.0",
"@relayburn/cli-linux-x64-gnu": "1.10.0"
},
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.

🔴 Hardcoded optionalDependencies versions will silently drift from lockstep publish bumps

The old dependency "@relayburn/cli": "workspace:*" was automatically resolved by pnpm at pnpm pack time, keeping the umbrella in sync with every lockstep release. The replacement optionalDependencies use hardcoded "1.10.0" strings that npm version (used by the Bump versions step in publish.yml:200-221) does not touch.

On the next lockstep publish, relayburn bumps to e.g. 1.11.0, but the tarball still declares @relayburn/cli-*@1.10.0 as optional deps. Those versions either won't exist on npm (if the platform packages are also bumped to 1.11.0 by the cutover pipeline) or will be stale. relayburn IS in the lockstep pipeline (publish.yml:107: packages=reader ledger analyze ingest sdk mcp cli relayburn), so this will break the very next release.

How the publish workflow bumps versions without updating optionalDependencies

The Bump step at publish.yml:207-221 runs npm version "$BUMP" --no-git-tag-version inside each package dir, which only updates the top-level version field. Neither npm version nor pnpm pack rewrites hardcoded version strings in optionalDependencies. The sdk-node package (packages/sdk-node/package.json:45-49) has the same pattern but is explicitly excluded from the lockstep workspace (pnpm-workspace.yaml:11), so the issue hasn't surfaced there.

Prompt for agents
The optionalDependencies in packages/relayburn/package.json use hardcoded version 1.10.0 for the @relayburn/cli-* platform packages. The lockstep publish workflow (publish.yml) bumps each packages version field via npm version but does NOT update optionalDependencies references. After a lockstep bump, relayburn@1.11.0 would ship declaring deps on @relayburn/cli-*@1.10.0 which is wrong.

The fix needs to happen in one of two places (or both):

1. Update the publish.yml Bump versions step (around line 200-239) to also: (a) bump the version in each packages/relayburn/npm/*/package.json, and (b) rewrite the optionalDependencies versions in packages/relayburn/package.json to match the new version. A small node script inline (similar to the lockstep-heal script) could read the new version and sed/JSON-patch both locations.

2. Alternatively, use a version range like >=1.10.0 in optionalDependencies so exact version matching isnt required. However this is unusual for the platform-package pattern (napi-rs and similar tools use exact versions) and could pull in incompatible future versions.

Option 1 is the standard approach used by napi-rs publish workflows and is recommended here.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/cli-build.yml (1)

149-155: ⚡ Quick win

Smoke-test the dispatcher, not just the raw binary.

These checks only execute the staged artifact directly. A bad package name, missing bin/ entry, or broken require.resolve path in packages/relayburn/bin/burn.js would still pass this workflow. Please add one native-leg smoke test that installs the staged platform package and runs the umbrella launcher itself.

Minimal CI smoke test
       - name: Smoke test (`burn --help`)
         # Native legs only. The aarch64-linux leg cross-compiles on an x64
         # host so the runner's interpreter cannot execute the binary.
         if: matrix.target != 'aarch64-unknown-linux-gnu'
         run: |
           packages/relayburn/npm/${{ matrix.short }}/bin/burn --help
           packages/relayburn/npm/${{ matrix.short }}/bin/burn --version
+          npm install --no-save ./packages/relayburn/npm/${{ matrix.short }}
+          node packages/relayburn/bin/burn.js --help
+          node packages/relayburn/bin/burn.js --version
🤖 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/cli-build.yml around lines 149 - 155, Replace the
direct-exec smoke test with one that installs and exercises the staged platform
package so the published package metadata and bin resolution are validated: in
the native-leg block that currently runs packages/relayburn/npm/${{ matrix.short
}}/bin/burn --help/--version, first run an install of the staged package (e.g.,
npm ci / npm install ./packages/relayburn/npm/${{ matrix.short }} or npm pack +
npm install the tarball) and then invoke the installed umbrella launcher (npx
burn --help and npx burn --version) so that package.json "bin" resolution and
require.resolve paths in packages/relayburn/bin/burn.js are exercised. Ensure
this only runs for native matrix legs (keep the existing if: matrix.target !=
'aarch64-unknown-linux-gnu').
🤖 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 `@packages/relayburn/bin/burn.js`:
- Around line 58-84: The current startup hard-fails when the platform-specific
package (pkg from const pkg = `@relayburn/cli-${short}`) is missing; instead,
try falling back to the generic TypeScript CLI package `@relayburn/cli` before
exiting: after the require.resolve(binSpecifier) catch, attempt
require.resolve('@relayburn/cli/bin/burn' + binSuffix()) (or the appropriate
entry inside `@relayburn/cli`) and set binPath to that if it resolves; only
write the error and process.exit(1) if both resolution attempts (the
platform-specific pkg and the generic `@relayburn/cli`) fail. Keep detectShort()
logic unchanged but ensure the error message distinguishes the two resolution
failures so it's clear whether the generic fallback was attempted.

---

Nitpick comments:
In @.github/workflows/cli-build.yml:
- Around line 149-155: Replace the direct-exec smoke test with one that installs
and exercises the staged platform package so the published package metadata and
bin resolution are validated: in the native-leg block that currently runs
packages/relayburn/npm/${{ matrix.short }}/bin/burn --help/--version, first run
an install of the staged package (e.g., npm ci / npm install
./packages/relayburn/npm/${{ matrix.short }} or npm pack + npm install the
tarball) and then invoke the installed umbrella launcher (npx burn --help and
npx burn --version) so that package.json "bin" resolution and require.resolve
paths in packages/relayburn/bin/burn.js are exercised. Ensure this only runs for
native matrix legs (keep the existing if: matrix.target !=
'aarch64-unknown-linux-gnu').
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8563599b-f523-4b0d-8bf5-907dccb3f059

📥 Commits

Reviewing files that changed from the base of the PR and between 1d25abb and ca3a0a6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • .github/workflows/cli-build.yml
  • .gitignore
  • packages/relayburn/CHANGELOG.md
  • packages/relayburn/README.md
  • packages/relayburn/bin/burn.js
  • packages/relayburn/npm/darwin-arm64/README.md
  • packages/relayburn/npm/darwin-arm64/package.json
  • packages/relayburn/npm/darwin-x64/README.md
  • packages/relayburn/npm/darwin-x64/package.json
  • packages/relayburn/npm/linux-arm64-gnu/README.md
  • packages/relayburn/npm/linux-arm64-gnu/package.json
  • packages/relayburn/npm/linux-x64-gnu/README.md
  • packages/relayburn/npm/linux-x64-gnu/package.json
  • packages/relayburn/package.json
  • pnpm-workspace.yaml

Comment thread packages/relayburn/bin/burn.js
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/publish.yml (1)

715-745: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Switch relayburn and platform packages to artifact-based publishing.

The current pack/publish loop cannot handle relayburn because it's excluded from pnpm-workspace.yaml (line 101), and pnpm --filter only matches workspace members. Additionally, the platform packages (@relayburn/cli-darwin-arm64, etc.) are not listed in steps.targets.outputs.packages (line 107), so they're never packed or published. The artifacts from cli-build.yml are never downloaded, leaving packages/relayburn/npm/*/bin/burn empty.

Add a step before pack/publish to download artifacts from the cli-build matrix into packages/relayburn/npm/*/bin/burn, then iterate over the platform packages in packages/relayburn/npm/*/package.json to pack and publish them before publishing the umbrella relayburn package.

🤖 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/publish.yml around lines 715 - 745, The pack/publish loop
(variables PACK_DIR, COMMON_FLAGS and the for pkg in ${{
steps.targets.outputs.packages }}) fails for non-workspace `relayburn` and
missing platform artifacts; add a new step before the existing pack/publish
block that downloads the cli-build matrix artifacts into
packages/relayburn/npm/*/bin/burn, then modify the workflow to first iterate
over platform packages discovered by reading
packages/relayburn/npm/*/package.json (use their name/version to compute
TARBALL_BASENAME as done in the loop) to pnpm pack (or pack existing tarballs)
and npm publish them with COMMON_FLAGS, and only after those platform packages
are published, proceed to package and publish the umbrella relayburn package
using the existing TARBALL creation and npm publish flow so ordering and
artifact availability are ensured.
🤖 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.

Outside diff comments:
In @.github/workflows/publish.yml:
- Around line 715-745: The pack/publish loop (variables PACK_DIR, COMMON_FLAGS
and the for pkg in ${{ steps.targets.outputs.packages }}) fails for
non-workspace `relayburn` and missing platform artifacts; add a new step before
the existing pack/publish block that downloads the cli-build matrix artifacts
into packages/relayburn/npm/*/bin/burn, then modify the workflow to first
iterate over platform packages discovered by reading
packages/relayburn/npm/*/package.json (use their name/version to compute
TARBALL_BASENAME as done in the loop) to pnpm pack (or pack existing tarballs)
and npm publish them with COMMON_FLAGS, and only after those platform packages
are published, proceed to package and publish the umbrella relayburn package
using the existing TARBALL creation and npm publish flow so ordering and
artifact availability are ensured.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 42a1a4d1-a16b-4eaa-9853-58e4b465925c

📥 Commits

Reviewing files that changed from the base of the PR and between ca3a0a6 and 964190c.

📒 Files selected for processing (7)
  • .github/workflows/cli-build.yml
  • .github/workflows/publish.yml
  • packages/relayburn/CHANGELOG.md
  • packages/relayburn/README.md
  • packages/relayburn/bin/burn.js
  • packages/relayburn/package.json
  • pnpm-workspace.yaml
✅ Files skipped from review due to trivial changes (1)
  • packages/relayburn/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/relayburn/README.md
  • packages/relayburn/package.json

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