triage-tui 0.4.1

TUI to monitor parallel Claude Code and Codex CLI sessions across tmux panes — triage by attention priority
name: Release

# One workflow, two jobs (the pattern from the release-please-action README):
#   1. release-please runs on every push to main, maintaining the open Release
#      PR. When that PR merges it creates the vX.Y.Z tag + GitHub Release.
#   2. publish is gated on release-please's `release_created` output (or a manual
#      dispatch) and does the actual artifact work in the same run — building the
#      mac binary, publishing to crates.io, and bumping the Homebrew tap. Doing it
#      here sidesteps GitHub's rule that a tag pushed by GITHUB_TOKEN can't itself
#      trigger another workflow.
#
# Re-publish an existing tag (e.g. after a registry hiccup) with:
#   gh workflow run release.yml -f tag=v0.2.3
on:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      tag:
        description: "Tag to (re)publish, e.g. v0.2.3 — manual dispatch only"
        required: true
        type: string

jobs:
  release-please:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    outputs:
      release_created: ${{ steps.release.outputs.release_created }}
      tag_name: ${{ steps.release.outputs.tag_name }}
    steps:
      - uses: googleapis/release-please-action@v4
        id: release
        with:
          config-file: release-please-config.json
          manifest-file: .release-please-manifest.json

  publish:
    needs: release-please
    if: |
      always() &&
      (
        (needs.release-please.result == 'success' && needs.release-please.outputs.release_created == 'true')
        || github.event_name == 'workflow_dispatch'
      )
    runs-on: macos-latest
    permissions:
      contents: write # upload release assets
      id-token: write # crates.io Trusted Publishing (OIDC), if configured
    # HOMEBREW_TAP_TOKEN is job-level env so the `if: env.X != ''` guard on the
    # bump step can read it (step-level env is not visible to that step's `if`).
    # crates.io uses Trusted Publishing (OIDC) — no static token.
    env:
      TAG: ${{ github.event.inputs.tag || needs.release-please.outputs.tag_name }}
      HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ github.event.inputs.tag || needs.release-please.outputs.tag_name }}
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-apple-darwin,x86_64-apple-darwin

      # Universal binary + the notify .app, tarred together so direct downloads
      # and the Homebrew formula both get click-to-jump notifications.
      - name: Build universal macOS binary + notify helper
        run: |
          cargo build --release --target aarch64-apple-darwin
          cargo build --release --target x86_64-apple-darwin
          # Assemble artifacts under target/ (already gitignored) so the working
          # tree stays clean for the `cargo publish` step below — no
          # --allow-dirty, and no genuine source change gets masked.
          mkdir -p target/dist
          lipo -create -output target/dist/triage \
            target/aarch64-apple-darwin/release/triage \
            target/x86_64-apple-darwin/release/triage
          bash scripts/triage-notify/build.sh target/dist
          tar -czf "target/triage-macos-universal.tar.gz" -C target/dist triage triage-notify.app

      - name: Attach binary to the GitHub Release
        env:
          GH_TOKEN: ${{ github.token }}
        run: gh release upload "$TAG" target/triage-macos-universal.tar.gz --clobber

      # crates.io publish via Trusted Publishing (OIDC). The crate is configured
      # to require Trusted Publishing, so a static CARGO_REGISTRY_TOKEN is
      # rejected (403). This action exchanges the workflow's OIDC identity
      # (id-token: write, above) for a short-lived publish token.
      - name: Authenticate to crates.io (Trusted Publishing)
        id: crates-auth
        uses: rust-lang/crates-io-auth-action@v1
      - name: Publish to crates.io
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.crates-auth.outputs.token }}
        run: cargo publish

      # Bump the Homebrew tap formula (inkless/homebrew-triage). The formula
      # builds from the crates.io source crate, so we point it at the new
      # .crate and refresh url/version/sha256. Runs after the crates.io publish
      # above so the .crate exists. Skipped until HOMEBREW_TAP_TOKEN is set.
      - name: Bump Homebrew formula
        if: env.HOMEBREW_TAP_TOKEN != ''
        run: |
          set -euo pipefail
          VERSION="${TAG#v}"
          CRATE_URL="https://static.crates.io/crates/triage-tui/triage-tui-${VERSION}.crate"
          # Wait for the crates.io CDN to serve the freshly published .crate.
          for i in $(seq 1 12); do
            if curl -fsSL "$CRATE_URL" -o crate.tgz; then break; fi
            echo "waiting for $CRATE_URL ($i)…"; sleep 15
          done
          SHA=$(shasum -a 256 crate.tgz | awk '{print $1}')
          git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/inkless/homebrew-triage.git" tap
          cd tap
          # macos runner → BSD sed (-i '').
          sed -i '' -E "s|triage-tui-[0-9]+\.[0-9]+\.[0-9]+\.crate|triage-tui-${VERSION}.crate|" Formula/triage.rb
          sed -i '' -E "s|^  version \".*\"|  version \"${VERSION}\"|" Formula/triage.rb
          sed -i '' -E "s|^  sha256 \".*\"|  sha256 \"${SHA}\"|" Formula/triage.rb
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git commit -am "triage ${VERSION}"
          git push