making it faster for prioritising new tools #128
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: Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (leave empty for auto)' | |
| required: false | |
| channel: | |
| description: 'Release channel' | |
| required: true | |
| default: 'release' | |
| type: choice | |
| options: | |
| - alpha | |
| - release | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| prepare: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| channel: ${{ steps.determine.outputs.channel }} | |
| version: ${{ steps.version.outputs.version }} | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Determine release channel | |
| id: determine | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "channel=${{ github.event.inputs.channel }}" >> $GITHUB_OUTPUT | |
| elif [ "${{ github.ref }}" = "refs/heads/main" ]; then | |
| echo "channel=alpha" >> $GITHUB_OUTPUT | |
| else | |
| echo "channel=alpha" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check if should release | |
| id: check | |
| run: | | |
| # Allow manual trigger to force release | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| echo "📦 Manual trigger - forcing release" | |
| # Check if last commit is a version bump (skip if so) | |
| elif git log -1 --pretty=%B | grep -q "chore(release):"; then | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| echo "⏭️ Skipping - last commit is a release commit" | |
| else | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v1 | |
| with: | |
| bun-version: 1.2.22 | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Get version | |
| id: version | |
| run: | | |
| CURRENT_VERSION=$(node -p "require('./package.json').version") | |
| CHANNEL="${{ steps.determine.outputs.channel }}" | |
| SHORT_SHA="${GITHUB_SHA::7}" | |
| # Manual version override takes priority | |
| if [ -n "${{ github.event.inputs.version }}" ]; then | |
| NEW_VERSION="${{ github.event.inputs.version }}" | |
| echo "🎯 Using manual version override: ${NEW_VERSION}" | |
| # For manual trigger without version, use current package.json version | |
| elif [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "$CHANNEL" = "release" ]; then | |
| NEW_VERSION="${CURRENT_VERSION}" | |
| echo "🎯 Using existing package.json version: ${NEW_VERSION}" | |
| elif [ "$CHANNEL" = "alpha" ]; then | |
| # Alpha: bump patch from current version and append -alpha.<sha> | |
| MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) | |
| MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) | |
| PATCH=$(echo $CURRENT_VERSION | cut -d. -f3 | cut -d- -f1) | |
| PATCH=$((PATCH + 1)) | |
| NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}-alpha.${SHORT_SHA}" | |
| echo "🎯 Alpha version: ${NEW_VERSION}" | |
| else | |
| # Fallback: bump patch | |
| MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) | |
| MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) | |
| PATCH=$(echo $CURRENT_VERSION | cut -d. -f3 | cut -d- -f1) | |
| PATCH=$((PATCH + 1)) | |
| NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| fi | |
| echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT | |
| echo "🎯 Version: ${NEW_VERSION} (${CHANNEL})" | |
| test: | |
| needs: prepare | |
| if: needs.prepare.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v1 | |
| with: | |
| bun-version: 1.2.22 | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Type check | |
| run: bun run typecheck | |
| - name: Run tests | |
| run: bun run test | |
| build: | |
| needs: [prepare, test] | |
| if: needs.prepare.outputs.should_release == 'true' | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| target: darwin-arm64 | |
| artifact: autohand-macos-arm64 | |
| - os: macos-latest | |
| target: darwin-x64 | |
| artifact: autohand-macos-x64 | |
| - os: ubuntu-latest | |
| target: linux-x64 | |
| artifact: autohand-linux-x64 | |
| - os: ubuntu-latest | |
| target: linux-arm64 | |
| artifact: autohand-linux-arm64 | |
| - os: windows-latest | |
| target: windows-x64 | |
| artifact: autohand-windows-x64.exe | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v1 | |
| with: | |
| bun-version: 1.2.22 | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Update version before build | |
| run: | | |
| echo "Setting version to: ${{ needs.prepare.outputs.version }}" | |
| npm version "${{ needs.prepare.outputs.version }}" --no-git-tag-version --allow-same-version | |
| - name: Build TypeScript | |
| run: bun run build | |
| - name: Compile binary | |
| run: | | |
| mkdir -p binaries | |
| bun build ./src/index.ts --compile --target=bun-${{ matrix.target }} --outfile ./binaries/${{ matrix.artifact }} | |
| - name: Verify binary | |
| if: runner.os != 'Windows' && !contains(matrix.target, 'arm64') || matrix.os == 'macos-latest' && contains(matrix.target, 'arm64') | |
| run: | | |
| chmod +x ./binaries/${{ matrix.artifact }} | |
| file ./binaries/${{ matrix.artifact }} | |
| - name: Smoke test binary | |
| if: runner.os != 'Windows' && !contains(matrix.target, 'arm64') || matrix.os == 'macos-latest' && contains(matrix.target, 'arm64') | |
| shell: bash | |
| run: | | |
| # Helper: run a command with a timeout (works on both Linux and macOS) | |
| run_with_timeout() { | |
| local secs="$1"; shift | |
| "$@" & | |
| local pid=$! | |
| ( sleep "$secs" && kill "$pid" 2>/dev/null ) & | |
| local watchdog=$! | |
| wait "$pid" 2>/dev/null | |
| local rc=$? | |
| kill "$watchdog" 2>/dev/null | |
| wait "$watchdog" 2>/dev/null || true | |
| return $rc | |
| } | |
| echo "Testing --version..." | |
| run_with_timeout 10 ./binaries/${{ matrix.artifact }} --version < /dev/null | |
| echo "" | |
| echo "Testing --help..." | |
| run_with_timeout 10 ./binaries/${{ matrix.artifact }} --help < /dev/null > /dev/null | |
| echo "Smoke test passed!" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: ./binaries/${{ matrix.artifact }} | |
| retention-days: 1 | |
| release: | |
| needs: [prepare, build] | |
| if: needs.prepare.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v1 | |
| - name: Configure Git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Update version in package.json (stable only) | |
| if: needs.prepare.outputs.channel == 'release' | |
| run: | | |
| bun --version | |
| VERSION="${{ needs.prepare.outputs.version }}" | |
| echo "Updating to version: $VERSION" | |
| npm version $VERSION --no-git-tag-version --allow-same-version | |
| node scripts/sync-homebrew-version.cjs | |
| git add package.json homebrew/autohand.rb | |
| git commit -m "chore(release): v$VERSION [skip ci]" || echo "No changes to commit" | |
| git push origin ${{ github.ref_name }} || echo "No changes to push" | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Prepare release binaries | |
| run: | | |
| mkdir -p release-binaries | |
| find artifacts -type f -exec cp {} release-binaries/ \; | |
| ls -lh release-binaries/ | |
| - name: Create bundled archives for installers and ACP registry | |
| run: | | |
| set -euo pipefail | |
| cd release-binaries | |
| RIPGREP_REPO="BurntSushi/ripgrep" | |
| RIPGREP_VERSION=15.1.0 | |
| echo "Using ripgrep ${RIPGREP_VERSION}" | |
| verify_checksum() { | |
| local archive="$1" | |
| local checksum_file="$2" | |
| local expected | |
| local actual | |
| expected=$(awk '{print $1}' "$checksum_file") | |
| actual=$(sha256sum "$archive" | awk '{print $1}') | |
| if [ "$expected" != "$actual" ]; then | |
| echo "Checksum verification failed for $archive" >&2 | |
| exit 1 | |
| fi | |
| } | |
| bundle_unix() { | |
| local binary="$1" | |
| local rg_target="$2" | |
| local temp_dir | |
| temp_dir=$(mktemp -d) | |
| local rg_archive="ripgrep-${RIPGREP_VERSION}-${rg_target}.tar.gz" | |
| local rg_url="https://github.com/${RIPGREP_REPO}/releases/download/${RIPGREP_VERSION}/${rg_archive}" | |
| curl -fsSL "$rg_url" -o "${temp_dir}/${rg_archive}" | |
| curl -fsSL "${rg_url}.sha256" -o "${temp_dir}/${rg_archive}.sha256" | |
| verify_checksum "${temp_dir}/${rg_archive}" "${temp_dir}/${rg_archive}.sha256" | |
| tar -xzf "${temp_dir}/${rg_archive}" -C "$temp_dir" | |
| mkdir -p "${temp_dir}/bundle" | |
| cp "$binary" "${temp_dir}/bundle/autohand" | |
| cp "${temp_dir}/ripgrep-${RIPGREP_VERSION}-${rg_target}/rg" "${temp_dir}/bundle/rg" | |
| chmod +x "${temp_dir}/bundle/autohand" "${temp_dir}/bundle/rg" | |
| tar -czf "${binary}.tar.gz" -C "${temp_dir}/bundle" autohand rg | |
| sha256sum "${binary}.tar.gz" > "${binary}.tar.gz.sha256" | |
| rm -rf "$temp_dir" | |
| echo "Created ${binary}.tar.gz" | |
| } | |
| bundle_windows() { | |
| local binary="$1" | |
| local rg_target="$2" | |
| local archive_name="$3" | |
| local output_path="${PWD}/${archive_name}" | |
| local temp_dir | |
| temp_dir=$(mktemp -d) | |
| local rg_archive="ripgrep-${RIPGREP_VERSION}-${rg_target}.zip" | |
| local rg_url="https://github.com/${RIPGREP_REPO}/releases/download/${RIPGREP_VERSION}/${rg_archive}" | |
| curl -fsSL "$rg_url" -o "${temp_dir}/${rg_archive}" | |
| curl -fsSL "${rg_url}.sha256" -o "${temp_dir}/${rg_archive}.sha256" | |
| verify_checksum "${temp_dir}/${rg_archive}" "${temp_dir}/${rg_archive}.sha256" | |
| unzip -q "${temp_dir}/${rg_archive}" -d "$temp_dir" | |
| mkdir -p "${temp_dir}/bundle" | |
| cp "$binary" "${temp_dir}/bundle/autohand.exe" | |
| cp "${temp_dir}/ripgrep-${RIPGREP_VERSION}-${rg_target}/rg.exe" "${temp_dir}/bundle/rg.exe" | |
| ( | |
| cd "${temp_dir}/bundle" | |
| zip -q "$output_path" autohand.exe rg.exe | |
| ) | |
| sha256sum "${archive_name}" > "${archive_name}.sha256" | |
| rm -rf "$temp_dir" | |
| echo "Created ${archive_name}" | |
| } | |
| # Create tar.gz bundles for Unix platforms | |
| if [ -f "autohand-macos-arm64" ]; then | |
| chmod +x autohand-macos-arm64 | |
| bundle_unix "autohand-macos-arm64" "aarch64-apple-darwin" | |
| fi | |
| if [ -f "autohand-macos-x64" ]; then | |
| chmod +x autohand-macos-x64 | |
| bundle_unix "autohand-macos-x64" "x86_64-apple-darwin" | |
| fi | |
| if [ -f "autohand-linux-x64" ]; then | |
| chmod +x autohand-linux-x64 | |
| bundle_unix "autohand-linux-x64" "x86_64-unknown-linux-musl" | |
| fi | |
| if [ -f "autohand-linux-arm64" ]; then | |
| chmod +x autohand-linux-arm64 | |
| bundle_unix "autohand-linux-arm64" "aarch64-unknown-linux-musl" | |
| fi | |
| # Create bundled zip for Windows | |
| if [ -f "autohand-windows-x64.exe" ]; then | |
| bundle_windows "autohand-windows-x64.exe" "x86_64-pc-windows-msvc" "autohand-windows-x64.zip" | |
| fi | |
| ls -lh *.tar.gz *.tar.gz.sha256 *.zip *.zip.sha256 2>/dev/null || true | |
| - name: Generate changelog | |
| id: changelog | |
| uses: actions/github-script@v7 | |
| env: | |
| RELEASE_VERSION: ${{ needs.prepare.outputs.version }} | |
| RELEASE_CHANNEL: ${{ needs.prepare.outputs.channel }} | |
| with: | |
| script: | | |
| const { execSync } = require('child_process'); | |
| const version = process.env.RELEASE_VERSION; | |
| const channel = process.env.RELEASE_CHANNEL; | |
| // Get commits since last tag | |
| let commits; | |
| let lastTag = null; | |
| try { | |
| lastTag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim(); | |
| commits = execSync(`git log ${lastTag}..HEAD --pretty=format:"%s"`, { encoding: 'utf8' }); | |
| } catch { | |
| commits = execSync('git log --pretty=format:"%s" -n 20', { encoding: 'utf8' }); | |
| } | |
| const lines = commits.split('\n').filter(line => line.trim() && !line.includes('chore(release)')); | |
| // Helper to humanize commit messages | |
| const humanize = (msg) => { | |
| return msg | |
| .replace(/^feat(\([^)]+\))?:\s*/i, '') | |
| .replace(/^fix(\([^)]+\))?:\s*/i, '') | |
| .replace(/^chore(\([^)]+\))?:\s*/i, '') | |
| .replace(/^docs(\([^)]+\))?:\s*/i, '') | |
| .replace(/^refactor(\([^)]+\))?:\s*/i, '') | |
| .replace(/^test(\([^)]+\))?:\s*/i, '') | |
| .replace(/^ci(\([^)]+\))?:\s*/i, '') | |
| .replace(/^perf(\([^)]+\))?:\s*/i, '') | |
| .trim(); | |
| }; | |
| // Capitalize first letter | |
| const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1); | |
| // Categorize commits | |
| const features = []; | |
| const fixes = []; | |
| const improvements = []; | |
| const breaking = []; | |
| for (const msg of lines) { | |
| const clean = humanize(msg); | |
| if (!clean) continue; | |
| if (msg.includes('BREAKING CHANGE') || msg.includes('!:')) { | |
| breaking.push(capitalize(clean)); | |
| } else if (msg.match(/^feat(\(|:)/i)) { | |
| features.push(capitalize(clean)); | |
| } else if (msg.match(/^fix(\(|:)/i)) { | |
| fixes.push(capitalize(clean)); | |
| } else if (msg.match(/^(refactor|perf|chore|docs|test|ci)(\(|:)/i)) { | |
| improvements.push(capitalize(clean)); | |
| } | |
| } | |
| // Build a friendly changelog | |
| let changelog = ''; | |
| // Channel badge for alpha | |
| if (channel === 'alpha') { | |
| changelog += '> **Alpha Release** — This is a pre-release build from the latest `main` branch. It may contain bugs or incomplete features.\n\n'; | |
| } | |
| // Intro | |
| if (lastTag) { | |
| changelog += `Hey there! We've been busy making Autohand better. Here's what's new since ${lastTag}:\n\n`; | |
| } else { | |
| changelog += `Hey there! Here's what's new in this release:\n\n`; | |
| } | |
| // Breaking changes (serious tone) | |
| if (breaking.length > 0) { | |
| changelog += '### Heads up! Breaking Changes\n\n'; | |
| changelog += 'These changes might require updates to your setup:\n\n'; | |
| breaking.forEach(item => { changelog += `- ${item}\n`; }); | |
| changelog += '\n'; | |
| } | |
| // Features (excited tone) | |
| if (features.length > 0) { | |
| changelog += '### New Stuff\n\n'; | |
| features.forEach(item => { changelog += `- ${item}\n`; }); | |
| changelog += '\n'; | |
| } | |
| // Fixes (helpful tone) | |
| if (fixes.length > 0) { | |
| changelog += '### Bug Fixes\n\n'; | |
| if (fixes.length === 1) { | |
| changelog += `We squashed a bug:\n\n`; | |
| } else { | |
| changelog += `We squashed ${fixes.length} bugs:\n\n`; | |
| } | |
| fixes.forEach(item => { changelog += `- ${item}\n`; }); | |
| changelog += '\n'; | |
| } | |
| // Improvements (casual tone) | |
| if (improvements.length > 0 && improvements.length <= 8) { | |
| changelog += '### Under the Hood\n\n'; | |
| changelog += 'Some housekeeping and improvements:\n\n'; | |
| improvements.forEach(item => { changelog += `- ${item}\n`; }); | |
| changelog += '\n'; | |
| } | |
| // If nothing categorized, add a generic message | |
| if (features.length === 0 && fixes.length === 0 && improvements.length === 0 && breaking.length === 0) { | |
| changelog += 'Minor updates and improvements to keep things running smoothly.\n\n'; | |
| } | |
| // Installation section | |
| const cb = '`' + '`' + '`'; | |
| changelog += '---\n\n'; | |
| changelog += '### Get it\n\n'; | |
| if (channel === 'alpha') { | |
| changelog += '**Install this alpha build:**\n'; | |
| changelog += cb + 'bash\ncurl -fsSL https://autohand.ai/install.sh | sh -s -- --alpha\n' + cb + '\n\n'; | |
| changelog += '**Or install the latest stable release:**\n'; | |
| changelog += cb + 'bash\ncurl -fsSL https://autohand.ai/install.sh | sh\n' + cb + '\n\n'; | |
| } else { | |
| changelog += '**Quickest way:**\n'; | |
| changelog += cb + 'bash\ncurl -fsSL https://autohand.ai/install.sh | sh\n' + cb + '\n\n'; | |
| changelog += '**Via npm or bun:**\n'; | |
| changelog += cb + 'bash\nnpm install -g autohand-cli\n' + cb + '\n\n'; | |
| } | |
| changelog += '**Or grab a binary below** for your platform.\n\n'; | |
| changelog += '| Platform | Architecture | Binary |\n'; | |
| changelog += '|----------|--------------|--------|\n'; | |
| changelog += '| macOS | Apple Silicon | `autohand-macos-arm64` |\n'; | |
| changelog += '| macOS | Intel | `autohand-macos-x64` |\n'; | |
| changelog += '| Linux | x64 | `autohand-linux-x64` |\n'; | |
| changelog += '| Linux | ARM64 | `autohand-linux-arm64` |\n'; | |
| changelog += '| Windows | x64 | `autohand-windows-x64.exe` |\n'; | |
| core.setOutput('changelog', changelog); | |
| return changelog; | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.prepare.outputs.version }} | |
| name: ${{ needs.prepare.outputs.channel == 'release' && format('Release v{0}', needs.prepare.outputs.version) || format('Alpha v{0}', needs.prepare.outputs.version) }} | |
| body: ${{ steps.changelog.outputs.changelog }} | |
| files: | | |
| release-binaries/* | |
| install.sh | |
| install.ps1 | |
| draft: false | |
| prerelease: ${{ needs.prepare.outputs.channel != 'release' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Update Homebrew tap (release only) | |
| if: needs.prepare.outputs.channel == 'release' | |
| env: | |
| TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} | |
| run: | | |
| if [ -z "$TAP_GITHUB_TOKEN" ]; then | |
| echo "⚠️ TAP_GITHUB_TOKEN not set, skipping Homebrew tap update" | |
| else | |
| VERSION="${{ needs.prepare.outputs.version }}" | |
| echo "Updating Homebrew tap to v${VERSION}..." | |
| # Wait for release assets to be available | |
| sleep 10 | |
| # Download release archives and compute sha256 | |
| SHA_MACOS_ARM64=$(curl -sL "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-macos-arm64.tar.gz" | shasum -a 256 | cut -d' ' -f1) | |
| SHA_MACOS_X64=$(curl -sL "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-macos-x64.tar.gz" | shasum -a 256 | cut -d' ' -f1) | |
| SHA_LINUX_X64=$(curl -sL "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-linux-x64.tar.gz" | shasum -a 256 | cut -d' ' -f1) | |
| SHA_LINUX_ARM64=$(curl -sL "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-linux-arm64.tar.gz" | shasum -a 256 | cut -d' ' -f1) | |
| echo "SHA256 checksums computed:" | |
| echo " macOS ARM64: ${SHA_MACOS_ARM64}" | |
| echo " macOS x64: ${SHA_MACOS_X64}" | |
| echo " Linux x64: ${SHA_LINUX_X64}" | |
| echo " Linux ARM64: ${SHA_LINUX_ARM64}" | |
| # Clone tap repo | |
| git clone "https://x-access-token:${TAP_GITHUB_TOKEN}@github.com/autohandai/homebrew-code.git" homebrew-tap | |
| cd homebrew-tap | |
| # Write updated formula using sed replacements on the existing template | |
| cp Formula/autohand-code.rb Formula/autohand-code.rb.bak 2>/dev/null || true | |
| cat > Formula/autohand-code.rb << FORMULA_EOF | |
| class AutohandCode < Formula | |
| desc "Autonomous LLM-powered coding agent CLI" | |
| homepage "https://autohand.ai" | |
| version "${VERSION}" | |
| license "Apache-2.0" | |
| on_macos do | |
| if Hardware::CPU.arm? | |
| url "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-macos-arm64.tar.gz" | |
| sha256 "${SHA_MACOS_ARM64}" | |
| else | |
| url "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-macos-x64.tar.gz" | |
| sha256 "${SHA_MACOS_X64}" | |
| end | |
| end | |
| on_linux do | |
| if Hardware::CPU.arm? | |
| url "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-linux-arm64.tar.gz" | |
| sha256 "${SHA_LINUX_ARM64}" | |
| else | |
| url "https://github.com/autohandai/code-cli/releases/download/v${VERSION}/autohand-linux-x64.tar.gz" | |
| sha256 "${SHA_LINUX_X64}" | |
| end | |
| end | |
| def install | |
| bin.install "autohand" => "autohand-code" | |
| end | |
| test do | |
| assert_match version.to_s, shell_output("#{bin}/autohand-code --version") | |
| end | |
| end | |
| FORMULA_EOF | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/autohand-code.rb | |
| git commit -m "Update autohand-code to v${VERSION}" | |
| git push | |
| echo "Homebrew tap updated to v${VERSION}" | |
| fi | |
| - name: Build JS dist for npm | |
| if: needs.prepare.outputs.channel == 'release' | |
| run: | | |
| bun install | |
| bun run build | |
| ls -lh dist/ | |
| - name: Publish to npm (release only) | |
| if: needs.prepare.outputs.channel == 'release' | |
| env: | |
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| if [ -z "$NPM_TOKEN" ]; then | |
| echo "⚠️ NPM_TOKEN not set, skipping npm publish" | |
| exit 0 | |
| fi | |
| echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc | |
| npm publish --access public |