claude-code-rust 0.3.0

A native Rust terminal interface for Claude Code
Documentation
name: Release

on:
  workflow_dispatch:
  push:
    branches: [main]
    paths:
      - 'Cargo.toml'

permissions:
  contents: write
  id-token: write

jobs:
  verify:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.get_version.outputs.version }}
      tag: ${{ steps.get_version.outputs.tag }}
      tag-exists: ${{ steps.check_tag.outputs.exists }}
      should-publish-cargo: ${{ steps.check_crates.outputs.should_publish }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Get crate version
        id: get_version
        run: |
          VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "tag=v$VERSION" >> $GITHUB_OUTPUT

      - name: Check if tag exists
        id: check_tag
        run: |
          if git rev-parse "refs/tags/${{ steps.get_version.outputs.tag }}" >/dev/null 2>&1; then
            echo "exists=true" >> $GITHUB_OUTPUT
          else
            echo "exists=false" >> $GITHUB_OUTPUT
          fi

      - name: Check if version is already published on crates.io
        id: check_crates
        run: |
          PUBLISHED=$(cargo search claude-code-rust --limit 1 | head -1 | sed 's/.*"\(.*\)".*/\1/' || echo "")
          if [ "$PUBLISHED" = "${{ steps.get_version.outputs.version }}" ]; then
            echo "should_publish=false" >> $GITHUB_OUTPUT
          else
            echo "should_publish=true" >> $GITHUB_OUTPUT
          fi

  publish-cargo:
    needs: verify
    if: needs.verify.outputs.tag-exists == 'false'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Publish to crates.io
        if: needs.verify.outputs.should-publish-cargo == 'true'
        run: cargo publish --locked
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

      - name: Skip cargo publish (already published)
        if: needs.verify.outputs.should-publish-cargo != 'true'
        run: echo "Cargo version already exists on crates.io, skipping publish."

  build-binaries:
    needs: [verify, publish-cargo]
    if: needs.verify.outputs.tag-exists == 'false'
    name: Build (${{ matrix.target }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            exe_suffix: ""
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            exe_suffix: ".exe"
          - os: macos-15-intel
            target: x86_64-apple-darwin
            exe_suffix: ""
          - os: macos-15
            target: aarch64-apple-darwin
            exe_suffix: ""
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

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

      - uses: Swatinem/rust-cache@v2

      - name: Build release binary
        run: cargo build --release --locked --target ${{ matrix.target }} --bin claude-rs

      - name: Stage release asset
        shell: bash
        run: |
          BINARY="claude-rs${{ matrix.exe_suffix }}"
          ASSET="claude-code-rust-${{ matrix.target }}${{ matrix.exe_suffix }}"
          mkdir -p dist
          cp "target/${{ matrix.target }}/release/$BINARY" "dist/$ASSET"

      - name: Upload staged asset
        uses: actions/upload-artifact@v6
        with:
          name: claude-code-rust-${{ matrix.target }}
          path: dist/*
          if-no-files-found: error

  create-release:
    needs: [verify, publish-cargo, build-binaries]
    if: needs.verify.outputs.tag-exists == 'false'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Create and push tag
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git tag -a "${{ needs.verify.outputs.tag }}" -m "Release ${{ needs.verify.outputs.tag }}"
          git push origin "${{ needs.verify.outputs.tag }}"

      - name: Download all assets
        uses: actions/download-artifact@v7
        with:
          pattern: claude-code-rust-*
          merge-multiple: true
          path: dist

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.verify.outputs.tag }}
          files: dist/*
          fail_on_unmatched_files: true
          generate_release_notes: true

  publish-npm:
    needs: [verify, create-release]
    if: needs.verify.outputs.tag-exists == 'false'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: "24"
          registry-url: "https://registry.npmjs.org"

      - name: Install latest npm
        run: npm install -g npm@latest

      - name: Sync npm version from Cargo.toml
        run: npm version "${{ needs.verify.outputs.version }}" --no-git-tag-version --allow-same-version

      - name: Publish to npm
        run: npm publish --access public --provenance