Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions .github/workflows/napi-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
name: napi build

# Build prebuilt napi-rs `.node` artifacts for every platform we publish to
# npm under `@relayburn/sdk-*`. PRs validate the matrix; tags / manual
# dispatch *would* publish, but the publish step is stubbed off for now —
# wired up properly in #249 (cutover release workflow).
#
# Caches Cargo registry + git + target dir, plus pnpm store, so the matrix
# stays fast on the hot path.

on:
pull_request:
paths:
- 'crates/relayburn-sdk/**'
- 'crates/relayburn-sdk-node/**'
- 'packages/sdk-node/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- '.github/workflows/napi-build.yml'
push:
branches: [main]
paths:
- 'crates/relayburn-sdk/**'
- 'crates/relayburn-sdk-node/**'
- 'packages/sdk-node/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- '.github/workflows/napi-build.yml'
workflow_dispatch:
inputs:
publish:
description: 'Publish prebuilt artifacts to npm under the `next` tag (stubbed; full wiring in #249)'
type: boolean
default: false

permissions:
contents: read

concurrency:
group: napi-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: build ${{ matrix.target }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
os: macos-15-intel
short: darwin-x64
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- target: aarch64-apple-darwin
os: macos-14
short: darwin-arm64
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
short: linux-x64-gnu
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
short: linux-arm64-gnu
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup pnpm
uses: pnpm/action-setup@v5

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: '22.14.0'
cache: 'pnpm'

- name: Setup Rust toolchain
# rust-toolchain.toml at the repo root pins channel + components.
# `cross` handles the aarch64 linux target via container, so we
# only register the host target by default and add the matrix
# target explicitly when it's a supported native cross.
run: |
rustup toolchain install
rustup target add ${{ matrix.target }}

- name: Install aarch64-linux cross toolchain (linux-arm64 only)
if: matrix.target == 'aarch64-unknown-linux-gnu'
# `napi build` calls `cargo build --target aarch64-unknown-linux-gnu`
# directly (it does not auto-route through `cross`), so we need a real
# aarch64 cross-compiler available on the runner. `libsqlite3-sys` (a
# transitive dep via `rusqlite`) compiles bundled SQLite C source via
# `cc-rs`, which probes for `aarch64-linux-gnu-gcc`.
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu

- name: Cache cargo registry + target
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml', 'rust-toolchain.toml') }}
restore-keys: |
cargo-${{ runner.os }}-${{ matrix.target }}-
cargo-${{ runner.os }}-

- name: Install workspace deps
run: pnpm install --frozen-lockfile

- name: Install packages/sdk-node deps
# `packages/sdk-node` is intentionally excluded from the pnpm
# workspace until the 2.0 cutover (see pnpm-workspace.yaml), so
# `pnpm install` at the root won't pull its devDependencies
# (`@napi-rs/cli`, `esbuild`). `--ignore-workspace` makes pnpm
# treat this directory as a standalone project and install into
# `packages/sdk-node/node_modules/` directly.
working-directory: packages/sdk-node
run: pnpm install --ignore-workspace --no-frozen-lockfile

- name: Build napi binding for ${{ matrix.target }}
# `napi build` reads `packages/sdk-node/package.json`'s `napi`
# block to learn the binary name, then dispatches to `cargo build`
# under the hood. The output is a per-target `.node` file and a
# generated `binding.cjs` / `binding.d.ts` co-located with it.
# `--cargo-cwd` points at the binding crate (which lives under
# `crates/relayburn-sdk-node/`, not co-located with the npm package)
# so the `cargo metadata` step that resolves the cdylib succeeds.
# The CC_/linker env vars only take effect for the aarch64-linux leg
# (cargo ignores per-target vars when the host matches the target);
# native legs are unaffected.
working-directory: packages/sdk-node
env:
CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc
CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
run: |
pnpm exec napi build \
--platform \
--release \
--target ${{ matrix.target }} \
--cargo-cwd ../../crates/relayburn-sdk-node \
--js src/binding.cjs \
--dts src/binding.d.ts

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: relayburn-sdk-${{ matrix.short }}
path: packages/sdk-node/*.node
if-no-files-found: warn
retention-days: 7

- name: Bundle smoke test (esbuild)
# Confirms the umbrella facade resolves + bundles cleanly. Runs on
# every matrix leg so we catch platform-specific resolution issues
# (path casing, native-binding aliases) close to where they'd
# surface for an embedder.
working-directory: packages/sdk-node
run: node --test 'test/esbuild-smoke.test.js'

- name: Conformance test (skipped until #247-a binding lands)
# While #247-a is in flight the binding crate has no exports, so
# the conformance suite skips itself. Once those bindings land,
# flipping `RELAYBURN_SDK_NAPI_BUILT=1` here turns the skip into a
# real deep-equal gate against TS @relayburn/sdk@1.x.
working-directory: packages/sdk-node
env:
RELAYBURN_SDK_NAPI_BUILT: '0'
run: node --test 'test/conformance.test.js'

publish:
# Stub. Real publish wiring lands in #249 (Wave 3 cutover) — at that
# point this job downloads the matrix artifacts, drops each into the
# right `npm/<platform>/` directory, and runs `npm publish --tag=next`
# for the umbrella + each per-platform package via OIDC trusted
# publisher. Until then, calling `workflow_dispatch` with
# `publish: true` exercises the artifact download path so we catch
# wiring errors early without actually pushing to npm.
needs: build
if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup pnpm
uses: pnpm/action-setup@v5

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: '22.14.0'
cache: 'pnpm'

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: packages/sdk-node/artifacts

- name: Inspect artifacts (publish stub)
run: |
echo 'Publish step is currently a stub. Full wiring lands in #249.'
ls -lah packages/sdk-node/artifacts || true
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Cross-package release notes for relayburn. Package changelogs contain package-le
- `relayburn-cli` (Rust): introduce the harness substrate — `HarnessAdapter` trait, lazy compile-time `phf` registry (`lookup` / `list_harness_names`), and the shared `pending_stamp::adapter` factory codex + opencode will reuse. Adapter slots in the registry are reserved but empty pending the Wave 2 PRs (#248-d/e/f). `relayburn-sdk` re-exports `start_watch_loop`, `WatchController`, `write_pending_stamp`, `PendingStampHarness`, and friends so the CLI doesn't have to reach into private SDK modules. (#248)
- `relayburn-cli` (Rust): scaffold the clap v4 derive root with global `--json` / `--ledger-path` / `--no-color` flags, eight stub subcommands (`summary`, `hotspots`, `overhead`, `compare`, `run`, `state`, `ingest`, `mcp-server`), and shared `render::{table,json,error}` helpers. Stubs exit `1` with a `not yet implemented` message (or a `{"error": …}` envelope under `--json`); Wave 2 fan-out PRs replace each stub with a thin presenter over `relayburn-sdk`. (#248 part a)
- `relayburn-cli` (Rust): add the CLI golden-output test rig — synthetic fixture ledger under `tests/fixtures/cli-golden/`, a node script that captures TS-CLI stdout/stderr across 16 invocations (summary / hotspots / overhead / overhead-trim / compare / state-status in TTY + `--json`, plus help text for ingest / run / mcp-server / top-level), and `crates/relayburn-cli/tests/golden.rs` — a `BURN_GOLDEN=1`-gated diff runner Wave 2 PRs flip on per-command via `enabled: true` in `invocations.json`. (#248)
- `@relayburn/sdk` (npm 2.x): scaffold the `packages/sdk-node/` umbrella + four per-platform packages (`@relayburn/sdk-{darwin-arm64,darwin-x64,linux-arm64-gnu,linux-x64-gnu}`) resolved via `optionalDependencies`. Adds the napi-rs build matrix in `.github/workflows/napi-build.yml`, an esbuild bundle smoke test, and a deep-equal conformance test gate against the TS 1.x SDK across the six verbs (`ingest`, `summary`, `sessionCost`, `overhead`, `overheadTrim`, `hotspots`). Conformance test is skipped until `crates/relayburn-sdk-node` lands its bindings (#247 part a). (#247 part b)
- `relayburn-ingest` (Rust): port the per-process gap-warning state machine (`gap` module — `record_session_gap`, `emit_gap_warning`, `count_tool_call_gaps`, `reset_ingest_gap_warnings`, `set_ingest_gap_writer`) and `reingest_missing_content` (`reingest` module). Suppression mirrors the TS surface: one warning per fresh affected session, silent on steady-state, re-fires after the affected set decays back to empty. `relayburn-ledger` adds `Ledger::list_user_turn_session_ids` to power the `reingest_missing_content` skip filter alongside `list_content_session_ids`. (#278)
- `relayburn-analyze` (Rust): port the behavioral-pattern detectors (`patterns` module). `detect_patterns` runs retry-loop, failure-run, cancellation-run, compaction-loss, edit-revert, OpenCode skill-recall-dup, OpenCode skill-pruning-protection, OpenCode system-prompt-tax, and edit-heavy detectors against an ordered turn stream, with optional content-sidecar / tool-result-event / user-turn enrichment. Public surface: `detect_patterns`, `DetectPatternsOptions`; per-pattern result structs are re-exported from `findings` (`RetryLoop`, `FailureRun`, `CancellationRun`, `CompactionLoss`, `EditRevertCycle`, `SkillRecallDup`, `SkillPruningProtection`, `SystemPromptTax`, `EditHeavySession`, `SessionPatternSummary`, `PatternsResult`, `PatternEventSource`). (#275)
- `relayburn-analyze` (Rust): port the tool-output-bloat detector — Signal A's `BASH_MAX_OUTPUT_LENGTH` static-config check (with `~/.claude/settings.json` + `<cwd>/.claude/settings.json` loader) and Signal B's cross-harness observed-bloat aggregation, plus the `WasteFinding` adapter. Public surface mirrors `@relayburn/analyze`: `BASH_MAX_OUTPUT_ENV_KEY`, `DEFAULT_BLOAT_TOKEN_THRESHOLD`, `detect_observed_bloat`, `detect_static_config_bloat`, `detect_tool_output_bloat`, `load_claude_settings`, `project_claude_settings_path`, `user_claude_settings_path`, `tool_output_bloat_to_finding`. (#271)
Expand Down
9 changes: 9 additions & 0 deletions packages/sdk-node/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# @relayburn/sdk (2.x)

## [Unreleased]

- Initial scaffolding: umbrella package layout (`@relayburn/sdk`) +
per-platform packages (`@relayburn/sdk-{darwin-arm64,darwin-x64,linux-arm64-gnu,linux-x64-gnu}`)
resolved via `optionalDependencies`, TS facade re-exporting the napi-rs
binding, conformance scaffold against the TS 1.x SDK, esbuild bundle
smoke test. (#247 part b)
36 changes: 36 additions & 0 deletions packages/sdk-node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# @relayburn/sdk (2.x)

Embeddable Relayburn SDK — napi-rs bindings over the Rust `relayburn-sdk`
crate. Drop-in replacement for the TS `@relayburn/sdk@1.x` published from
`packages/sdk/`.

The 2.x umbrella resolves the right native binary for your platform via
`optionalDependencies`:

| Platform | Package |
|---|---|
| darwin-arm64 (Apple Silicon) | `@relayburn/sdk-darwin-arm64` |
| darwin-x64 (Intel Mac) | `@relayburn/sdk-darwin-x64` |
| linux-arm64-gnu | `@relayburn/sdk-linux-arm64-gnu` |
| linux-x64-gnu | `@relayburn/sdk-linux-x64-gnu` |

Windows (`win32-x64-msvc`) is not yet shipped — see #247 follow-up.

## Migration from 1.x

Same imports, same option shapes, same return shapes — except:

- **u64 token counts are `bigint`.** napi-rs maps Rust `u64` to JavaScript
`BigInt`. Code that does arithmetic on `summary().totalTokens` (and
similar fields on `hotspots`, `overhead`, `sessionCost`) needs to either
use `BigInt` literals (`100n`) or coerce with `Number(x)`. The TS
declarations widen these fields to `number | bigint` to keep existing
callers compiling.
- Otherwise byte-for-byte compatible. Run your test suite — the conformance
test in `test/conformance.test.js` is what we use to validate.

## Status

This is a `2.0.0-pre` build published to npm under the `next` tag while
the rest of the Rust port lands. Until the lockstep 2.0 cutover ships, the
1.x TS SDK at `packages/sdk/` is still the source of truth.
7 changes: 7 additions & 0 deletions packages/sdk-node/npm/darwin-arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @relayburn/sdk-darwin-arm64

Prebuilt native binding for `@relayburn/sdk` on `darwin-arm64`. You should
not depend on this package directly — install `@relayburn/sdk` and the right
platform binding is resolved via `optionalDependencies`.

See <https://github.com/AgentWorkforce/burn>.
29 changes: 29 additions & 0 deletions packages/sdk-node/npm/darwin-arm64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@relayburn/sdk-darwin-arm64",
"version": "2.0.0-pre.0",
"description": "Prebuilt napi-rs binding for @relayburn/sdk on darwin-arm64.",
"main": "relayburn-sdk.darwin-arm64.node",
"files": [
"relayburn-sdk.darwin-arm64.node",
"package.json",
"README.md"
],
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"engines": {
"node": ">=22"
},
"repository": {
"type": "git",
"url": "https://github.com/AgentWorkforce/burn",
"directory": "packages/sdk-node/npm/darwin-arm64"
},
"publishConfig": {
"access": "public",
"tag": "next"
}
}
7 changes: 7 additions & 0 deletions packages/sdk-node/npm/darwin-x64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @relayburn/sdk-darwin-x64

Prebuilt native binding for `@relayburn/sdk` on `darwin-x64`. You should
not depend on this package directly — install `@relayburn/sdk` and the right
platform binding is resolved via `optionalDependencies`.

See <https://github.com/AgentWorkforce/burn>.
29 changes: 29 additions & 0 deletions packages/sdk-node/npm/darwin-x64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@relayburn/sdk-darwin-x64",
"version": "2.0.0-pre.0",
"description": "Prebuilt napi-rs binding for @relayburn/sdk on darwin-x64.",
"main": "relayburn-sdk.darwin-x64.node",
"files": [
"relayburn-sdk.darwin-x64.node",
"package.json",
"README.md"
],
"os": [
"darwin"
],
"cpu": [
"x64"
],
"engines": {
"node": ">=22"
},
"repository": {
"type": "git",
"url": "https://github.com/AgentWorkforce/burn",
"directory": "packages/sdk-node/npm/darwin-x64"
},
"publishConfig": {
"access": "public",
"tag": "next"
}
}
7 changes: 7 additions & 0 deletions packages/sdk-node/npm/linux-arm64-gnu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @relayburn/sdk-linux-arm64-gnu

Prebuilt native binding for `@relayburn/sdk` on `linux-arm64-gnu` (glibc).
You should not depend on this package directly — install `@relayburn/sdk`
and the right platform binding is resolved via `optionalDependencies`.

See <https://github.com/AgentWorkforce/burn>.
32 changes: 32 additions & 0 deletions packages/sdk-node/npm/linux-arm64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@relayburn/sdk-linux-arm64-gnu",
"version": "2.0.0-pre.0",
"description": "Prebuilt napi-rs binding for @relayburn/sdk on linux-arm64-gnu (glibc).",
"main": "relayburn-sdk.linux-arm64-gnu.node",
"files": [
"relayburn-sdk.linux-arm64-gnu.node",
"package.json",
"README.md"
],
"os": [
"linux"
],
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"engines": {
"node": ">=22"
},
"repository": {
"type": "git",
"url": "https://github.com/AgentWorkforce/burn",
"directory": "packages/sdk-node/npm/linux-arm64-gnu"
},
"publishConfig": {
"access": "public",
"tag": "next"
}
}
7 changes: 7 additions & 0 deletions packages/sdk-node/npm/linux-x64-gnu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @relayburn/sdk-linux-x64-gnu

Prebuilt native binding for `@relayburn/sdk` on `linux-x64-gnu` (glibc).
You should not depend on this package directly — install `@relayburn/sdk`
and the right platform binding is resolved via `optionalDependencies`.

See <https://github.com/AgentWorkforce/burn>.
Loading
Loading