Publish Package #67
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish Package | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| package: | |
| description: "Package to publish" | |
| required: true | |
| type: choice | |
| options: | |
| - all | |
| - main | |
| - sdk | |
| default: "all" | |
| version: | |
| description: "Version bump type" | |
| required: true | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| - prepatch | |
| - preminor | |
| - premajor | |
| - prerelease | |
| custom_version: | |
| description: "Custom version (optional, overrides version type)" | |
| required: false | |
| type: string | |
| dry_run: | |
| description: "Dry run (do not actually publish)" | |
| required: false | |
| type: boolean | |
| default: false | |
| tag: | |
| description: "NPM dist-tag" | |
| required: false | |
| type: choice | |
| options: | |
| - latest | |
| - next | |
| - beta | |
| - alpha | |
| default: "latest" | |
| # Prevent concurrent publishes | |
| concurrency: | |
| group: publish-package | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| NPM_CONFIG_FUND: false | |
| jobs: | |
| # Build Rust binaries for all platforms (in parallel) | |
| build-binaries: | |
| name: Build relay-pty (${{ matrix.target }}) | |
| runs-on: ${{ matrix.os }} | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| strategy: | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| binary_name: relay-pty-darwin-arm64 | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| binary_name: relay-pty-darwin-x64 | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| binary_name: relay-pty-linux-x64 | |
| - os: ubuntu-latest | |
| target: aarch64-unknown-linux-gnu | |
| binary_name: relay-pty-linux-arm64 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install cross-compilation tools (Linux ARM64) | |
| if: matrix.target == 'aarch64-unknown-linux-gnu' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc-aarch64-linux-gnu | |
| - name: Cache cargo | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: relay-pty | |
| key: ${{ matrix.target }} | |
| - name: Build relay-pty | |
| working-directory: relay-pty | |
| run: cargo build --release --target ${{ matrix.target }} | |
| env: | |
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | |
| - name: Copy binary with platform name | |
| run: cp relay-pty/target/${{ matrix.target }}/release/relay-pty bin/${{ matrix.binary_name }} | |
| - name: Upload binary | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.binary_name }} | |
| path: bin/${{ matrix.binary_name }} | |
| retention-days: 1 | |
| # Build standalone binaries using bun compile (cross-platform, no Node.js required) | |
| build-standalone: | |
| name: Build standalone (${{ matrix.target }}) | |
| runs-on: ${{ matrix.os }} | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| target: bun-darwin-arm64 | |
| binary_name: agent-relay-darwin-arm64 | |
| - os: macos-latest | |
| target: bun-darwin-x64 | |
| binary_name: agent-relay-darwin-x64 | |
| - os: ubuntu-latest | |
| target: bun-linux-x64 | |
| binary_name: agent-relay-linux-x64 | |
| - os: ubuntu-latest | |
| target: bun-linux-arm64 | |
| binary_name: agent-relay-linux-arm64 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build TypeScript | |
| run: npm run build | |
| - name: Get version | |
| id: version | |
| run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT | |
| - name: Build standalone binary | |
| run: | | |
| mkdir -p release-binaries | |
| # Exclude native modules - bun runtime has built-in bun:sqlite | |
| bun build \ | |
| --compile \ | |
| --minify \ | |
| --target=${{ matrix.target }} \ | |
| --external=better-sqlite3 \ | |
| --external=ssh2 \ | |
| --define="process.env.AGENT_RELAY_VERSION=\"${{ steps.version.outputs.version }}\"" \ | |
| ./dist/src/cli/index.js \ | |
| --outfile release-binaries/${{ matrix.binary_name }} | |
| - name: Verify binary | |
| if: matrix.target == 'bun-linux-x64' || (matrix.target == 'bun-darwin-arm64' && runner.arch == 'ARM64') | |
| run: | | |
| chmod +x release-binaries/${{ matrix.binary_name }} | |
| ./release-binaries/${{ matrix.binary_name }} --version || echo "Binary created (cross-compiled)" | |
| - name: Compress binary with gzip | |
| run: | | |
| gzip -9 -k release-binaries/${{ matrix.binary_name }} | |
| echo "Uncompressed: $(du -h release-binaries/${{ matrix.binary_name }} | cut -f1)" | |
| echo "Compressed: $(du -h release-binaries/${{ matrix.binary_name }}.gz | cut -f1)" | |
| - name: Upload compressed binary | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.binary_name }}.gz | |
| path: release-binaries/${{ matrix.binary_name }}.gz | |
| retention-days: 1 | |
| - name: Upload uncompressed binary | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.binary_name }} | |
| path: release-binaries/${{ matrix.binary_name }} | |
| retention-days: 1 | |
| # Build all packages once, version them, and upload | |
| build: | |
| name: Build & Version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| new_version: ${{ steps.bump.outputs.new_version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: "npm" | |
| cache-dependency-path: package-lock.json | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Ensure rollup optional dependencies are installed | |
| run: npm install --no-save rollup || true | |
| - name: Version all packages | |
| id: bump | |
| run: | | |
| CUSTOM_VERSION="${{ github.event.inputs.custom_version }}" | |
| VERSION_TYPE="${{ github.event.inputs.version }}" | |
| CURRENT_VERSION=$(node -p "require('./package.json').version") | |
| echo "Current version: $CURRENT_VERSION" | |
| if [ -n "$CUSTOM_VERSION" ]; then | |
| echo "Setting version to custom value: $CUSTOM_VERSION" | |
| npm version "$CUSTOM_VERSION" --no-git-tag-version --allow-same-version | |
| else | |
| echo "Bumping version: $VERSION_TYPE" | |
| npm version "$VERSION_TYPE" --no-git-tag-version --preid=beta | |
| fi | |
| NEW_VERSION=$(node -p "require('./package.json').version") | |
| echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT | |
| echo "New version: $NEW_VERSION" | |
| # Sync all package versions and internal dependencies using node script | |
| # (avoids npm version which validates dependencies against registry) | |
| node -e " | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const version = '$NEW_VERSION'; | |
| // Update root package internal dependencies | |
| const rootPkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); | |
| for (const dep of Object.keys(rootPkg.dependencies || {})) { | |
| if (dep.startsWith('@agent-relay/')) { | |
| rootPkg.dependencies[dep] = version; | |
| } | |
| } | |
| fs.writeFileSync('package.json', JSON.stringify(rootPkg, null, 2) + '\n'); | |
| // Update all sub-packages: version + internal dependencies | |
| const packagesDir = 'packages'; | |
| for (const dir of fs.readdirSync(packagesDir)) { | |
| const pkgPath = path.join(packagesDir, dir, 'package.json'); | |
| if (fs.existsSync(pkgPath)) { | |
| const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); | |
| // Update package version | |
| pkg.version = version; | |
| console.log('@agent-relay/' + dir); | |
| console.log('v' + version); | |
| // Update internal dependencies | |
| for (const dep of Object.keys(pkg.dependencies || {})) { | |
| if (dep.startsWith('@agent-relay/')) { | |
| pkg.dependencies[dep] = version; | |
| } | |
| } | |
| fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n'); | |
| } | |
| } | |
| " | |
| - name: Clean reinstall after version bump | |
| run: | | |
| # Clear npm cache and node_modules to ensure fresh platform-specific deps | |
| npm cache clean --force | |
| rm -rf node_modules packages/*/node_modules package-lock.json | |
| npm install | |
| - name: Ensure rollup optional dependencies are installed | |
| run: npm install --no-save rollup || true | |
| - name: Build all packages | |
| run: npm run build | |
| - name: Run tests | |
| run: npm test | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-output | |
| path: | | |
| package.json | |
| package-lock.json | |
| packages/*/package.json | |
| packages/*/dist/ | |
| dist/ | |
| retention-days: 1 | |
| # Publish all packages in parallel (npm publish doesn't need deps published first) | |
| publish-packages: | |
| name: Publish ${{ matrix.package }} | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: github.event.inputs.package == 'all' | |
| strategy: | |
| fail-fast: false | |
| max-parallel: 10 | |
| matrix: | |
| package: | |
| # All packages - published in parallel | |
| - protocol | |
| - storage | |
| - state | |
| - policy | |
| - memory | |
| - utils | |
| - continuity | |
| - trajectory | |
| - hooks | |
| - resiliency | |
| - user-directory | |
| - api-types | |
| - spawner | |
| - mcp | |
| - config | |
| - bridge | |
| - wrapper | |
| - sdk | |
| - daemon | |
| - telemetry | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-output | |
| path: . | |
| - name: Update npm for OIDC support | |
| run: npm install -g npm@latest | |
| - name: Dry run check | |
| if: github.event.inputs.dry_run == 'true' | |
| working-directory: packages/${{ matrix.package }} | |
| run: | | |
| echo "Dry run - would publish @agent-relay/${{ matrix.package }}" | |
| npm publish --dry-run --access public --tag ${{ github.event.inputs.tag }} --ignore-scripts | |
| - name: Publish to NPM | |
| if: github.event.inputs.dry_run != 'true' | |
| working-directory: packages/${{ matrix.package }} | |
| run: npm publish --access public --provenance --tag ${{ github.event.inputs.tag }} --ignore-scripts | |
| # Publish SDK only (when selected) | |
| publish-sdk-only: | |
| name: Publish SDK to NPM | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: github.event.inputs.package == 'sdk' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-output | |
| path: . | |
| - name: Update npm for OIDC support | |
| run: npm install -g npm@latest | |
| - name: Dry run check | |
| if: github.event.inputs.dry_run == 'true' | |
| working-directory: packages/sdk | |
| run: npm publish --dry-run --access public --tag ${{ github.event.inputs.tag }} --ignore-scripts | |
| - name: Publish SDK to NPM | |
| if: github.event.inputs.dry_run != 'true' | |
| working-directory: packages/sdk | |
| run: npm publish --access public --provenance --tag ${{ github.event.inputs.tag }} --ignore-scripts | |
| # Pre-publish verification: ensure all binaries are valid before publishing | |
| verify-binaries-linux: | |
| name: Verify Binaries (Linux) | |
| needs: [build, build-binaries] | |
| runs-on: ubuntu-latest | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| steps: | |
| - name: Download all binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: relay-pty-* | |
| path: bin/ | |
| merge-multiple: true | |
| - name: List downloaded binaries | |
| run: | | |
| echo "Downloaded binaries:" | |
| ls -la bin/ | |
| - name: Verify all platform binaries exist | |
| run: | | |
| MISSING=0 | |
| for BINARY in relay-pty-darwin-arm64 relay-pty-darwin-x64 relay-pty-linux-x64 relay-pty-linux-arm64; do | |
| if [ -f "bin/$BINARY" ]; then | |
| echo "✓ $BINARY exists ($(stat -c%s "bin/$BINARY" 2>/dev/null || stat -f%z "bin/$BINARY") bytes)" | |
| else | |
| echo "✗ $BINARY MISSING" | |
| MISSING=1 | |
| fi | |
| done | |
| if [ $MISSING -eq 1 ]; then | |
| echo "" | |
| echo "ERROR: Some binaries are missing! Cannot publish." | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "All platform binaries present." | |
| - name: Make binaries executable | |
| run: chmod +x bin/relay-pty-* | |
| - name: Verify Linux binary works | |
| run: | | |
| echo "Testing relay-pty-linux-x64 --help..." | |
| OUTPUT=$(./bin/relay-pty-linux-x64 --help 2>&1) || true | |
| echo "$OUTPUT" | |
| if echo "$OUTPUT" | grep -q "PTY wrapper"; then | |
| echo "✓ Linux x64 binary works" | |
| else | |
| echo "✗ Linux x64 binary failed --help test" | |
| exit 1 | |
| fi | |
| - name: Verify binary sizes are reasonable | |
| run: | | |
| # Binaries should be at least 1MB (to catch empty/corrupt files) | |
| MIN_SIZE=1000000 | |
| for BINARY in bin/relay-pty-*; do | |
| SIZE=$(stat -c%s "$BINARY" 2>/dev/null || stat -f%z "$BINARY") | |
| if [ "$SIZE" -lt "$MIN_SIZE" ]; then | |
| echo "✗ $BINARY is suspiciously small: $SIZE bytes" | |
| exit 1 | |
| fi | |
| echo "✓ $BINARY size OK: $SIZE bytes" | |
| done | |
| - name: Summary | |
| run: | | |
| echo "## Pre-Publish Binary Verification (Linux)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Binary | Status | Size |" >> $GITHUB_STEP_SUMMARY | |
| echo "|--------|--------|------|" >> $GITHUB_STEP_SUMMARY | |
| for BINARY in bin/relay-pty-*; do | |
| NAME=$(basename "$BINARY") | |
| SIZE=$(stat -c%s "$BINARY" 2>/dev/null || stat -f%z "$BINARY") | |
| SIZE_MB=$(echo "scale=2; $SIZE / 1048576" | bc) | |
| echo "| $NAME | ✅ | ${SIZE_MB}MB |" >> $GITHUB_STEP_SUMMARY | |
| done | |
| # Verify macOS binaries actually work on macOS (critical - catches issues before publish) | |
| verify-binaries-macos: | |
| name: Verify Binaries (macOS ${{ matrix.arch }}) | |
| needs: [build-binaries] | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| arch: arm64 | |
| binary: relay-pty-darwin-arm64 | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Download binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ matrix.binary }} | |
| path: bin/ | |
| - name: Make binary executable | |
| run: chmod +x bin/${{ matrix.binary }} | |
| - name: Verify binary exists and has reasonable size | |
| run: | | |
| if [ ! -f "bin/${{ matrix.binary }}" ]; then | |
| echo "ERROR: Binary not found!" | |
| exit 1 | |
| fi | |
| SIZE=$(stat -f%z "bin/${{ matrix.binary }}") | |
| echo "Binary size: $SIZE bytes" | |
| # Should be at least 1MB | |
| if [ "$SIZE" -lt 1000000 ]; then | |
| echo "ERROR: Binary is suspiciously small!" | |
| exit 1 | |
| fi | |
| echo "✓ Binary exists with valid size" | |
| - name: Test binary --help | |
| run: | | |
| echo "Testing ${{ matrix.binary }} --help..." | |
| OUTPUT=$(./bin/${{ matrix.binary }} --help 2>&1) || true | |
| echo "$OUTPUT" | |
| if echo "$OUTPUT" | grep -q "PTY wrapper"; then | |
| echo "✓ ${{ matrix.binary }} --help works" | |
| else | |
| echo "✗ ${{ matrix.binary }} --help failed!" | |
| exit 1 | |
| fi | |
| - name: Summary | |
| run: | | |
| echo "## macOS ${{ matrix.arch }} Binary Verification" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ **${{ matrix.binary }}** verified on macOS ${{ matrix.arch }}" >> $GITHUB_STEP_SUMMARY | |
| # Verify standalone binaries on Linux | |
| verify-standalone-linux: | |
| name: Verify Standalone (Linux) | |
| needs: [build-standalone] | |
| runs-on: ubuntu-latest | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| steps: | |
| - name: Download Linux binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agent-relay-linux-x64 | |
| path: bin/ | |
| - name: Download compressed binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agent-relay-linux-x64.gz | |
| path: bin/ | |
| - name: Verify uncompressed binary | |
| run: | | |
| chmod +x bin/agent-relay-linux-x64 | |
| echo "Testing uncompressed binary..." | |
| ./bin/agent-relay-linux-x64 --version | |
| echo "✓ Uncompressed binary works" | |
| - name: Verify compressed binary | |
| run: | | |
| echo "Testing compressed binary decompression..." | |
| gunzip -c bin/agent-relay-linux-x64.gz > /tmp/agent-relay-test | |
| chmod +x /tmp/agent-relay-test | |
| /tmp/agent-relay-test --version | |
| echo "✓ Compressed binary decompresses and works" | |
| - name: Verify compression ratio | |
| run: | | |
| UNCOMPRESSED=$(stat -c%s bin/agent-relay-linux-x64) | |
| COMPRESSED=$(stat -c%s bin/agent-relay-linux-x64.gz) | |
| RATIO=$(echo "scale=0; 100 - ($COMPRESSED * 100 / $UNCOMPRESSED)" | bc) | |
| echo "Compression ratio: ${RATIO}% reduction" | |
| echo "Uncompressed: $(echo "scale=2; $UNCOMPRESSED / 1048576" | bc)MB" | |
| echo "Compressed: $(echo "scale=2; $COMPRESSED / 1048576" | bc)MB" | |
| # Verify reasonable compression (should be at least 50%) | |
| if [ "$RATIO" -lt 50 ]; then | |
| echo "WARNING: Compression ratio is lower than expected" | |
| else | |
| echo "✓ Compression ratio is good" | |
| fi | |
| # Verify standalone binaries on macOS | |
| verify-standalone-macos: | |
| name: Verify Standalone (macOS) | |
| needs: [build-standalone] | |
| runs-on: macos-latest | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| steps: | |
| - name: Download macOS binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agent-relay-darwin-arm64 | |
| path: bin/ | |
| - name: Download compressed binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agent-relay-darwin-arm64.gz | |
| path: bin/ | |
| - name: Verify uncompressed binary | |
| run: | | |
| chmod +x bin/agent-relay-darwin-arm64 | |
| echo "Testing uncompressed binary..." | |
| ./bin/agent-relay-darwin-arm64 --version | |
| echo "✓ Uncompressed binary works" | |
| - name: Verify compressed binary | |
| run: | | |
| echo "Testing compressed binary decompression..." | |
| gunzip -c bin/agent-relay-darwin-arm64.gz > /tmp/agent-relay-test | |
| chmod +x /tmp/agent-relay-test | |
| /tmp/agent-relay-test --version | |
| echo "✓ Compressed binary decompresses and works" | |
| # Gate job that requires both Linux and macOS verification to pass | |
| verify-binaries: | |
| name: All Binaries Verified | |
| needs: [verify-binaries-linux, verify-binaries-macos, verify-standalone-linux, verify-standalone-macos] | |
| runs-on: ubuntu-latest | |
| if: github.event.inputs.package == 'all' || github.event.inputs.package == 'main' | |
| steps: | |
| - name: All binary checks passed | |
| run: | | |
| echo "✅ All binary verification checks passed!" | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Binary Verification Gate" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ All platform binaries verified and ready for publish" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Verified Binaries" >> $GITHUB_STEP_SUMMARY | |
| echo "- relay-pty: Linux x64, Linux ARM64, macOS x64, macOS ARM64" >> $GITHUB_STEP_SUMMARY | |
| echo "- agent-relay: Linux x64, macOS ARM64 (both compressed and uncompressed)" >> $GITHUB_STEP_SUMMARY | |
| # Publish main package | |
| publish-main: | |
| name: Publish Main Package | |
| needs: [build, build-binaries, verify-binaries, publish-packages] | |
| runs-on: ubuntu-latest | |
| if: | | |
| always() && | |
| (github.event.inputs.package == 'all' || github.event.inputs.package == 'main') && | |
| needs.build.result == 'success' && | |
| needs.verify-binaries.result == 'success' && | |
| (needs.publish-packages.result == 'success' || needs.publish-packages.result == 'skipped') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-output | |
| path: . | |
| - name: Download relay-pty binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: relay-pty-* | |
| path: bin/ | |
| merge-multiple: true | |
| - name: Make binaries executable | |
| run: chmod +x bin/relay-pty-* | |
| - name: Update npm for OIDC support | |
| run: npm install -g npm@latest | |
| - name: Dry run check | |
| if: github.event.inputs.dry_run == 'true' | |
| run: | | |
| echo "Dry run - would publish agent-relay@${{ needs.build.outputs.new_version }}" | |
| npm publish --dry-run --access public --tag ${{ github.event.inputs.tag }} --ignore-scripts | |
| - name: Publish to NPM | |
| if: github.event.inputs.dry_run != 'true' | |
| run: npm publish --access public --provenance --tag ${{ github.event.inputs.tag }} --ignore-scripts | |
| # Create git tag and release | |
| create-release: | |
| name: Create Release | |
| needs: [build, build-binaries, build-standalone, verify-binaries, publish-main] | |
| runs-on: ubuntu-latest | |
| if: | | |
| always() && | |
| github.event.inputs.dry_run != 'true' && | |
| needs.publish-main.result == 'success' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-output | |
| path: . | |
| - name: Download relay-pty binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: relay-pty-* | |
| path: release-binaries/ | |
| merge-multiple: true | |
| - name: Download standalone binaries (uncompressed) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: agent-relay-* | |
| path: release-binaries/ | |
| merge-multiple: true | |
| - name: Make binaries executable | |
| run: | | |
| # Make uncompressed binaries executable (skip .gz files) | |
| for f in release-binaries/*; do | |
| if [[ "$f" != *.gz ]]; then | |
| chmod +x "$f" | |
| fi | |
| done | |
| - name: Verify all binaries present | |
| run: | | |
| echo "=== Verifying release binaries ===" | |
| ls -la release-binaries/ | |
| MISSING=0 | |
| # Check relay-pty binaries | |
| for BINARY in relay-pty-darwin-arm64 relay-pty-darwin-x64 relay-pty-linux-x64 relay-pty-linux-arm64; do | |
| if [ -f "release-binaries/$BINARY" ]; then | |
| echo "✓ $BINARY" | |
| else | |
| echo "✗ MISSING: $BINARY" | |
| MISSING=1 | |
| fi | |
| done | |
| # Check standalone binaries (both compressed and uncompressed) | |
| for BINARY in agent-relay-darwin-arm64 agent-relay-darwin-x64 agent-relay-linux-x64 agent-relay-linux-arm64; do | |
| # Check uncompressed | |
| if [ -f "release-binaries/$BINARY" ]; then | |
| echo "✓ $BINARY" | |
| else | |
| echo "✗ MISSING: $BINARY" | |
| MISSING=1 | |
| fi | |
| # Check compressed | |
| if [ -f "release-binaries/${BINARY}.gz" ]; then | |
| echo "✓ ${BINARY}.gz" | |
| else | |
| echo "⚠ MISSING: ${BINARY}.gz (compressed version)" | |
| # Don't fail on missing .gz - uncompressed is fallback | |
| fi | |
| done | |
| if [ $MISSING -eq 1 ]; then | |
| echo "" | |
| echo "ERROR: Some required binaries are missing!" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "All required binaries present." | |
| - name: Commit and tag | |
| run: | | |
| git config user.name "GitHub Actions" | |
| git config user.email "actions@github.com" | |
| NEW_VERSION="${{ needs.build.outputs.new_version }}" | |
| git add package.json package-lock.json packages/*/package.json | |
| if ! git diff --staged --quiet; then | |
| git commit -m "chore(release): v${NEW_VERSION}" | |
| git push origin HEAD:main | |
| fi | |
| git tag -a "v${NEW_VERSION}" -m "Release v${NEW_VERSION}" | |
| git push origin "v${NEW_VERSION}" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: v${{ needs.build.outputs.new_version }} | |
| name: v${{ needs.build.outputs.new_version }} | |
| body: | | |
| ## agent-relay v${{ needs.build.outputs.new_version }} | |
| ### Quick Install (no Node.js required!) | |
| ```bash | |
| curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash | |
| ``` | |
| ### npm install | |
| ```bash | |
| npm install -g agent-relay@${{ needs.build.outputs.new_version }} | |
| npm install @agent-relay/sdk@${{ needs.build.outputs.new_version }} | |
| ``` | |
| ### Standalone binaries | |
| Self-contained executables (no runtime dependencies). | |
| **Use `.gz` versions for faster downloads (~60-70% smaller).** | |
| | Platform | Compressed (recommended) | Uncompressed | | |
| |----------|--------------------------|--------------| | |
| | Linux x64 | `agent-relay-linux-x64.gz` | `agent-relay-linux-x64` | | |
| | Linux ARM64 | `agent-relay-linux-arm64.gz` | `agent-relay-linux-arm64` | | |
| | macOS Intel | `agent-relay-darwin-x64.gz` | `agent-relay-darwin-x64` | | |
| | macOS Apple Silicon | `agent-relay-darwin-arm64.gz` | `agent-relay-darwin-arm64` | | |
| ### relay-pty binaries | |
| PTY wrapper for spawning agents: | |
| - `relay-pty-linux-x64` - Linux x86_64 | |
| - `relay-pty-linux-arm64` - Linux ARM64 | |
| - `relay-pty-darwin-x64` - macOS Intel | |
| - `relay-pty-darwin-arm64` - macOS Apple Silicon | |
| files: | | |
| release-binaries/* | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Trigger post-publish verification | |
| verify-publish: | |
| name: Verify Published Package | |
| needs: [build, publish-main] | |
| if: | | |
| always() && | |
| github.event.inputs.dry_run != 'true' && | |
| needs.publish-main.result == 'success' | |
| uses: ./.github/workflows/verify-publish.yml | |
| with: | |
| version: ${{ needs.build.outputs.new_version }} | |
| summary: | |
| name: Summary | |
| needs: [build, build-binaries, build-standalone, verify-binaries, verify-standalone-linux, verify-standalone-macos, publish-packages, publish-main, verify-publish] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Summary | |
| run: | | |
| echo "## NPM Publish Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: \`${{ needs.build.outputs.new_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**NPM Tag**: \`${{ github.event.inputs.tag }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Dry Run**: \`${{ github.event.inputs.dry_run }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Results" >> $GITHUB_STEP_SUMMARY | |
| echo "| Stage | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Build | ${{ needs.build.result == 'success' && '✅' || '❌' }} ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Build Binaries (Rust) | ${{ needs.build-binaries.result == 'success' && '✅' || (needs.build-binaries.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.build-binaries.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Build Standalone (Bun) | ${{ needs.build-standalone.result == 'success' && '✅' || (needs.build-standalone.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.build-standalone.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Verify relay-pty | ${{ needs.verify-binaries.result == 'success' && '✅' || (needs.verify-binaries.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.verify-binaries.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Verify Standalone (Linux) | ${{ needs.verify-standalone-linux.result == 'success' && '✅' || (needs.verify-standalone-linux.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.verify-standalone-linux.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Verify Standalone (macOS) | ${{ needs.verify-standalone-macos.result == 'success' && '✅' || (needs.verify-standalone-macos.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.verify-standalone-macos.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Publish Packages | ${{ needs.publish-packages.result == 'success' && '✅' || (needs.publish-packages.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-packages.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Publish Main | ${{ needs.publish-main.result == 'success' && '✅' || (needs.publish-main.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-main.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Post-Publish Verify | ${{ needs.verify-publish.result == 'success' && '✅' || (needs.verify-publish.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.verify-publish.result }} |" >> $GITHUB_STEP_SUMMARY |