opencrabs 0.3.22

The autonomous, self-improving AI agent. Single Rust binary. Every channel. Install with: cargo install opencrabs
Documentation
name: Release

on:
  push:
    tags:
      - 'v*'

permissions:
  contents: read

env:
  CARGO_TERM_COLOR: always
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
  wait-for-ci:
    name: Wait for CI
    runs-on: ubuntu-latest
    steps:
      - name: Wait for CI to pass on this commit
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          SHA="${{ github.sha }}"
          REPO="${{ github.repository }}"
          echo "Waiting for CI workflow to complete on $SHA..."
          for i in $(seq 1 60); do
            STATUS=$(gh api "repos/$REPO/commits/$SHA/check-runs" \
              --jq '.check_runs[] | select(.name == "Test (ubuntu-latest)") | .conclusion' 2>/dev/null || echo "pending")
            if [ "$STATUS" = "success" ]; then
              echo "CI passed!"
              exit 0
            elif [ "$STATUS" = "failure" ] || [ "$STATUS" = "cancelled" ]; then
              echo "CI failed ($STATUS) — aborting release"
              exit 1
            fi
            echo "CI still running... (attempt $i/60)"
            sleep 30
          done
          echo "Timed out waiting for CI"
          exit 1

  publish-crate:
    name: Publish to crates.io
    needs: [wait-for-ci, build-release]
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.check.outputs.version }}
    steps:
      - uses: actions/checkout@v4

      - name: Check if already published
        id: check
        run: |
          VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          if curl -sf "https://crates.io/api/v1/crates/opencrabs/$VERSION" > /dev/null 2>&1; then
            echo "published=true" >> "$GITHUB_OUTPUT"
            echo "v$VERSION already on crates.io — skipping build"
          else
            echo "published=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Install Rust
        if: steps.check.outputs.published == 'false'
        uses: dtolnay/rust-toolchain@stable

      - name: Install ALSA dev
        if: steps.check.outputs.published == 'false'
        run: sudo apt-get update && sudo apt-get install -y libasound2-dev

      - name: Publish
        if: steps.check.outputs.published == 'false'
        continue-on-error: true
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: cargo publish --allow-dirty

  build-release:
    name: Build Release
    needs: wait-for-ci
    runs-on: ${{ matrix.os }}
    permissions:
      contents: write
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            artifact_name: opencrabs
            asset_suffix: linux-amd64

          - os: ubuntu-24.04-arm
            target: aarch64-unknown-linux-gnu
            artifact_name: opencrabs
            asset_suffix: linux-arm64

          - os: windows-latest
            target: x86_64-pc-windows-msvc
            artifact_name: opencrabs.exe
            asset_suffix: windows-amd64

          - os: macos-latest
            target: x86_64-apple-darwin
            artifact_name: opencrabs
            asset_suffix: macos-amd64

          - os: macos-latest
            target: aarch64-apple-darwin
            artifact_name: opencrabs
            asset_suffix: macos-arm64

    steps:
      - uses: actions/checkout@v4

      - name: Set version
        id: version
        shell: bash
        run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install Linux dependencies
        if: contains(matrix.os, 'ubuntu')
        run: |
          sudo apt-get update
          sudo apt-get install -y libasound2-dev

      - name: Install CMake (Windows)
        if: matrix.os == 'windows-latest'
        uses: lukka/get-cmake@latest

      - name: Install NASM (Windows)
        if: matrix.os == 'windows-latest'
        uses: ilammy/setup-nasm@v1

      - name: Build
        shell: bash
        env:
          CFLAGS: ${{ matrix.target == 'aarch64-apple-darwin' && '-march=armv8-a+crypto' || '' }}
          CXXFLAGS: ${{ matrix.target == 'aarch64-apple-darwin' && '-march=armv8-a+crypto' || '' }}
          AWS_LC_SYS_CMAKE_BUILDER: ${{ matrix.os == 'windows-latest' && '1' || '' }}
        run: cargo build --release --target ${{ matrix.target }} --all-features

      - name: Strip binary (Unix)
        if: matrix.os != 'windows-latest'
        run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }}

      - name: Create archive
        shell: bash
        run: |
          ASSET_NAME="opencrabs-v${{ steps.version.outputs.version }}-${{ matrix.asset_suffix }}"
          cd target/${{ matrix.target }}/release
          if [ "${{ matrix.os }}" = "windows-latest" ]; then
            7z a ../../../${ASSET_NAME}.zip ${{ matrix.artifact_name }}
          else
            tar czf ../../../${ASSET_NAME}.tar.gz ${{ matrix.artifact_name }}
          fi

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: opencrabs-v${{ steps.version.outputs.version }}-${{ matrix.asset_suffix }}
          path: |
            opencrabs-v${{ steps.version.outputs.version }}-${{ matrix.asset_suffix }}.tar.gz
            opencrabs-v${{ steps.version.outputs.version }}-${{ matrix.asset_suffix }}.zip

  create-release:
    name: Create Release
    needs: [publish-crate, build-release]
    if: always() && needs.publish-crate.result != 'cancelled' && needs.build-release.result != 'cancelled'
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4

      - name: Extract version from tag
        id: version
        run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"

      - name: Extract changelog for this version
        id: changelog
        run: |
          # Extract the section for this version from CHANGELOG.md
          version="${{ steps.version.outputs.version }}"
          body=$(awk "/^## \\[${version}\\]/{found=1; next} /^## \\[/{if(found) exit} found{print}" CHANGELOG.md)
          # Write to file to preserve newlines
          echo "$body" > /tmp/release_notes.md
          # Add full changelog link (extract previous version from CHANGELOG.md)
          echo "" >> /tmp/release_notes.md
          prev_version=$(awk "/^## \\[${version}\\]/{found=1; next} found && /^## \\[/{match(\$0, /\\[([^]]+)\\]/, m); print m[1]; exit}" CHANGELOG.md)
          if [ -n "$prev_version" ]; then
            echo "**Full Changelog:** https://github.com/${{ github.repository }}/compare/v${prev_version}...v${version}" >> /tmp/release_notes.md
          fi

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

      - name: Collect release assets
        run: |
          mkdir -p release-assets
          find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec cp {} release-assets/ \;
          ls -la release-assets/

      - name: Create GitHub Release
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          # Use --clobber so the workflow can attach binaries to a release
          # that was already created manually (e.g. via `gh release create`)
          if gh release view "v${{ steps.version.outputs.version }}" &>/dev/null; then
            # Release exists -- upload assets and ensure it's not a draft
            gh release upload "v${{ steps.version.outputs.version }}" \
              release-assets/* --clobber
            gh release edit "v${{ steps.version.outputs.version }}" --draft=false
          else
            gh release create "v${{ steps.version.outputs.version }}" \
              --title "v${{ steps.version.outputs.version }}" \
              --notes-file /tmp/release_notes.md \
              --latest \
              release-assets/*
          fi