tersify 0.5.0

Universal LLM context compressor — pipe anything, get token-optimized output
Documentation
name: Release

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'

env:
  CARGO_TERM_COLOR: always
  BINARY_NAME: tersify

jobs:
  build:
    name: Build — ${{ matrix.target }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: macos-latest
            target: aarch64-apple-darwin
            archive: tersify-aarch64-apple-darwin.tar.gz
          - os: macos-latest
            target: x86_64-apple-darwin
            archive: tersify-x86_64-apple-darwin.tar.gz
          - os: ubuntu-latest
            target: x86_64-unknown-linux-musl
            archive: tersify-x86_64-unknown-linux-musl.tar.gz
          - os: ubuntu-latest
            target: aarch64-unknown-linux-musl
            archive: tersify-aarch64-unknown-linux-musl.tar.gz
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            archive: tersify-x86_64-pc-windows-msvc.zip

    steps:
      - uses: actions/checkout@v4

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

      - name: Install musl tools (Linux x86_64)
        if: matrix.target == 'x86_64-unknown-linux-musl'
        run: sudo apt-get update -y && sudo apt-get install -y musl-tools

      - name: Install musl tools (Linux ARM64)
        if: matrix.target == 'aarch64-unknown-linux-musl'
        run: |
          sudo apt-get update -y
          sudo apt-get install -y musl-tools gcc-aarch64-linux-gnu
          echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
          # Disable glibc fortification — aarch64-linux-gnu-gcc is a glibc cross-compiler
          # but the target is musl, so __fprintf_chk/__snprintf_chk are unavailable.
          echo "CFLAGS=-D_FORTIFY_SOURCE=0" >> $GITHUB_ENV
          echo "CXXFLAGS=-D_FORTIFY_SOURCE=0" >> $GITHUB_ENV

      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Build release binary
        run: cargo build --release --target ${{ matrix.target }}

      - name: Package (Unix)
        if: matrix.os != 'windows-latest'
        run: |
          cp target/${{ matrix.target }}/release/${{ env.BINARY_NAME }} .
          tar czf ${{ matrix.archive }} ${{ env.BINARY_NAME }} README.md LICENSE
          sha256sum ${{ matrix.archive }} > ${{ matrix.archive }}.sha256

      - name: Package (Windows)
        if: matrix.os == 'windows-latest'
        shell: pwsh
        run: |
          Copy-Item "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}.exe" .
          Compress-Archive -Path "${{ env.BINARY_NAME }}.exe", "README.md", "LICENSE" -DestinationPath "${{ matrix.archive }}"
          $hash = (Get-FileHash "${{ matrix.archive }}" -Algorithm SHA256).Hash.ToLower()
          "$hash  ${{ matrix.archive }}" | Out-File -Encoding ascii "${{ matrix.archive }}.sha256"

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.archive }}
          path: |
            ${{ matrix.archive }}
            ${{ matrix.archive }}.sha256

  release:
    name: GitHub Release
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - uses: actions/checkout@v4

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

      - name: Copy install script
        run: cp install.sh artifacts/install.sh

      - name: Create release
        uses: softprops/action-gh-release@v2
        with:
          name: tersify ${{ github.ref_name }}
          body: |
            ## Install

            **Homebrew (macOS / Linux)**
            ```bash
            brew tap rustkit-ai/tap
            brew install tersify
            ```

            **One-liner (macOS / Linux)**
            ```bash
            curl -fsSL https://raw.githubusercontent.com/rustkit-ai/tersify/main/install.sh | bash
            ```
            Downloads the binary, adds it to `~/.local/bin`, and hooks into all detected AI editors automatically.

            **Cargo**
            ```bash
            cargo install tersify
            tersify install --all
            ```

            **Direct download** — pick the archive for your platform below, verify the `.sha256`, put the binary on your `$PATH`, then run `tersify install --all`.

            See [CHANGELOG](https://github.com/rustkit-ai/tersify/blob/main/CHANGELOG.md) for what changed.
          files: |
            artifacts/**/*.tar.gz
            artifacts/**/*.zip
            artifacts/**/*.sha256
            artifacts/install.sh

  homebrew:
    name: Update Homebrew tap
    needs: release
    runs-on: ubuntu-latest
    # Only run if the homebrew-tap repo exists (set secret HOMEBREW_TAP_TOKEN)
    if: ${{ vars.HOMEBREW_TAP_ENABLED == 'true' }}
    steps:
      - uses: actions/checkout@v4

      - name: Compute source tarball SHA256
        id: sha
        run: |
          TAG=${{ github.ref_name }}
          URL="https://github.com/rustkit-ai/tersify/archive/refs/tags/${TAG}.tar.gz"
          SHA=$(curl -fsSL "$URL" | sha256sum | cut -d' ' -f1)
          echo "sha256=$SHA" >> "$GITHUB_OUTPUT"
          echo "url=$URL" >> "$GITHUB_OUTPUT"
          echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"

      - name: Update formula in homebrew-tap
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
          script: |
            const { sha256, url, version } = ${{ toJson(steps.sha.outputs) }};
            const formula = `class Tersify < Formula
              desc "Universal LLM context compressor — pipe anything, get token-optimized output"
              homepage "https://github.com/rustkit-ai/tersify"
              url "${url}"
              sha256 "${sha256}"
              license "MIT"

              depends_on "rust" => :build

              def install
                system "cargo", "install", *std_cargo_args
              end

              def post_install
                system "\#{bin}/tersify", "install", "--all"
              rescue StandardError
                nil
              end

              test do
                assert_match version.to_s, shell_output("\#{bin}/tersify --version")
                (testpath/"test.rs").write("// comment\\nfn main() {}\\n")
                output = shell_output("\#{bin}/tersify \#{testpath}/test.rs")
                refute_match "// comment", output
              end
            end
            `;
            const owner = 'rustkit-ai';
            const repo = 'homebrew-tap';
            const path = 'Formula/tersify.rb';
            let sha_file;
            try {
              const { data } = await github.rest.repos.getContent({ owner, repo, path });
              sha_file = data.sha;
            } catch {}
            await github.rest.repos.createOrUpdateFileContents({
              owner, repo, path,
              message: `tersify ${version}`,
              content: Buffer.from(formula).toString('base64'),
              sha: sha_file,
            });