name: Build Desktop

on:
  workflow_dispatch:
    inputs:
      release_tag:
        description: "Upload to this release tag (e.g. v1.0.0). Leave empty for artifact-only build."
        required: false
        default: ""
  push:
    tags:
      - "v*"

permissions:
  contents: write

env:
  TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
  TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}

jobs:
  # ──────────────────────────────────────────────
  # Windows
  # ──────────────────────────────────────────────
  build-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set vcpkg path
        shell: bash
        run: echo "VCPKG_INSTALLED=$VCPKG_INSTALLATION_ROOT/installed" >> $GITHUB_ENV

      - name: Restore vcpkg cache
        id: vcpkg-cache
        uses: actions/cache/restore@v4
        with:
          path: ${{ env.VCPKG_INSTALLED }}
          key: vcpkg-win-v2

      - name: Install Windows dependencies (vcpkg)
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        shell: bash
        env:
          VCPKG_BINARY_SOURCES: "clear"
        run: |
          vcpkg install "harfbuzz[graphite2]:x64-windows-static-release" \
            fontconfig:x64-windows-static-release \
            freetype:x64-windows-static-release \
            icu:x64-windows-static-release

      - name: Save vcpkg cache
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: ${{ env.VCPKG_INSTALLED }}
          key: vcpkg-win-v2

      - name: Set Windows build environment
        shell: bash
        run: |
          echo "TECTONIC_DEP_BACKEND=vcpkg" >> $GITHUB_ENV
          echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
          echo "VCPKGRS_TRIPLET=x64-windows-static-release" >> $GITHUB_ENV
          echo "VCPKG_DEFAULT_HOST_TRIPLET=x64-windows-static-release" >> $GITHUB_ENV
          echo "RUSTFLAGS=-Ctarget-feature=+crt-static" >> $GITHUB_ENV
          echo "CXXFLAGS=/std:c++17" >> $GITHUB_ENV
          echo "CFLAGS=" >> $GITHUB_ENV

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-pc-windows-msvc

      - uses: swatinem/rust-cache@v2
        with:
          workspaces: apps/desktop/src-tauri -> target

      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - run: pnpm install

      - name: Build Tauri app
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ZOTERO_CONSUMER_KEY: ${{ secrets.ZOTERO_CONSUMER_KEY }}
          ZOTERO_CONSUMER_SECRET: ${{ secrets.ZOTERO_CONSUMER_SECRET }}
        run: pnpm --filter @claude-prism/desktop tauri build --target x86_64-pc-windows-msvc

      - name: Collect updater artifacts
        id: collect
        shell: bash
        run: |
          BUNDLE="apps/desktop/src-tauri/target/x86_64-pc-windows-msvc/release/bundle"
          NSIS_SIG=$(find "$BUNDLE/nsis" -name '*-setup.exe.sig' 2>/dev/null | head -1)
          NSIS_EXE=$(find "$BUNDLE/nsis" -name '*-setup.exe' ! -name '*.sig' 2>/dev/null | head -1)

          if [ -n "$NSIS_SIG" ] && [ -n "$NSIS_EXE" ]; then
            echo "sig=$(cat "$NSIS_SIG")" >> $GITHUB_OUTPUT
            echo "url=$(basename "$NSIS_EXE")" >> $GITHUB_OUTPUT
          fi

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: desktop-windows
          path: |
            apps/desktop/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.exe
            apps/desktop/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.msi
            apps/desktop/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.sig
          if-no-files-found: warn

    outputs:
      sig: ${{ steps.collect.outputs.sig }}
      url: ${{ steps.collect.outputs.url }}

  # ──────────────────────────────────────────────
  # macOS (Apple Silicon)
  # ──────────────────────────────────────────────
  build-macos:
    runs-on: macos-14
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # Build tools required by vcpkg ports (autotools for gperf, fontconfig, etc.)
      # These are compile-time only — they do NOT create runtime dylib dependencies.
      - name: Install build tools
        run: brew install autoconf autoconf-archive automake libtool pkg-config

      # Static linking via vcpkg — avoids runtime dependency on Homebrew dylibs.
      # Ref: https://tectonic-typesetting.github.io/book/latest/howto/build-tectonic/
      # Ref: https://learn.microsoft.com/en-us/vcpkg/users/triplets (arm64-osx defaults to static)
      - name: Setup vcpkg
        run: |
          git clone --depth 1 https://github.com/microsoft/vcpkg $HOME/vcpkg
          $HOME/vcpkg/bootstrap-vcpkg.sh
          echo "VCPKG_ROOT=$HOME/vcpkg" >> $GITHUB_ENV

      - name: Restore vcpkg cache
        id: vcpkg-cache
        uses: actions/cache/restore@v4
        with:
          path: ~/vcpkg/installed
          key: vcpkg-macos-arm64-v1

      - name: Install macOS dependencies (vcpkg)
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        env:
          VCPKG_BINARY_SOURCES: "clear"
        run: |
          $HOME/vcpkg/vcpkg install \
            "harfbuzz[graphite2]:arm64-osx" \
            fontconfig:arm64-osx \
            freetype:arm64-osx \
            icu:arm64-osx

      - name: Save vcpkg cache
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: ~/vcpkg/installed
          key: vcpkg-macos-arm64-v1

      - name: Set macOS build environment
        run: |
          echo "TECTONIC_DEP_BACKEND=vcpkg" >> $GITHUB_ENV
          echo "CXXFLAGS=-std=c++17" >> $GITHUB_ENV
          echo "CFLAGS=" >> $GITHUB_ENV

      - name: Import Apple certificate
        env:
          APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
          APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
        run: |
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
          KEYCHAIN_PASSWORD=$(openssl rand -base64 32)

          # Create temporary keychain
          security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
          security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"

          # Import certificate
          echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
          security import $RUNNER_TEMP/certificate.p12 \
            -k "$KEYCHAIN_PATH" \
            -P "$APPLE_CERTIFICATE_PASSWORD" \
            -T /usr/bin/codesign \
            -T /usr/bin/security
          security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
          security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain-db

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-apple-darwin

      - uses: swatinem/rust-cache@v2
        with:
          workspaces: apps/desktop/src-tauri -> target

      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - run: pnpm install

      - name: Build Tauri app
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ZOTERO_CONSUMER_KEY: ${{ secrets.ZOTERO_CONSUMER_KEY }}
          ZOTERO_CONSUMER_SECRET: ${{ secrets.ZOTERO_CONSUMER_SECRET }}
          APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
        run: pnpm --filter @claude-prism/desktop tauri build --target aarch64-apple-darwin

      - name: Notarize DMG
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
        run: |
          TARGET="aarch64-apple-darwin"
          BUNDLE="apps/desktop/src-tauri/target/$TARGET/release/bundle"
          DMG_PATH=$(find "$BUNDLE/dmg" -name '*.dmg' | head -1)
          APP_PATH="$BUNDLE/macos/ClaudePrism.app"

          if [ -z "$DMG_PATH" ]; then
            echo "Error: DMG not found"
            exit 1
          fi

          echo "==> Notarizing $DMG_PATH ..."
          xcrun notarytool submit "$DMG_PATH" \
            --apple-id "$APPLE_ID" \
            --team-id "$APPLE_TEAM_ID" \
            --password "$APPLE_PASSWORD" \
            --wait --timeout 30m

          echo "==> Stapling..."
          xcrun stapler staple "$DMG_PATH"
          xcrun stapler staple "$APP_PATH"

      - name: Collect updater artifacts
        id: collect
        run: |
          BUNDLE="apps/desktop/src-tauri/target/aarch64-apple-darwin/release/bundle"
          TAR_SIG=$(find "$BUNDLE/macos" -name '*.app.tar.gz.sig' 2>/dev/null | head -1)
          TAR_GZ=$(find "$BUNDLE/macos" -name '*.app.tar.gz' ! -name '*.sig' 2>/dev/null | head -1)

          if [ -n "$TAR_SIG" ] && [ -n "$TAR_GZ" ]; then
            echo "sig=$(cat "$TAR_SIG")" >> $GITHUB_OUTPUT
            echo "url=$(basename "$TAR_GZ")" >> $GITHUB_OUTPUT
          fi

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: desktop-macos
          path: |
            apps/desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.dmg
            apps/desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.app.tar.gz
            apps/desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.sig
          if-no-files-found: warn

    outputs:
      sig: ${{ steps.collect.outputs.sig }}
      url: ${{ steps.collect.outputs.url }}

  # ──────────────────────────────────────────────
  # macOS (Intel x86_64)
  # Ref: https://github.com/actions/runner-images/issues/13045
  #      macos-13 retired 2025-12-04, macos-15-intel is the replacement
  #      Intel runners available until Fall 2027
  # Ref: https://v2.tauri.app/distribute/pipelines/github/
  # Ref: https://v2.tauri.app/plugin/updater/ (platform key: darwin-x86_64)
  # ──────────────────────────────────────────────
  build-macos-intel:
    runs-on: macos-15-intel
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # Build tools required by vcpkg ports (autotools for gperf, fontconfig, etc.)
      - name: Install build tools
        run: brew install autoconf autoconf-archive automake libtool pkg-config

      # Static linking via vcpkg — same approach as Apple Silicon and Windows.
      - name: Setup vcpkg
        run: |
          git clone --depth 1 https://github.com/microsoft/vcpkg $HOME/vcpkg
          $HOME/vcpkg/bootstrap-vcpkg.sh
          echo "VCPKG_ROOT=$HOME/vcpkg" >> $GITHUB_ENV

      - name: Restore vcpkg cache
        id: vcpkg-cache
        uses: actions/cache/restore@v4
        with:
          path: ~/vcpkg/installed
          key: vcpkg-macos-x64-v1

      - name: Install macOS dependencies (vcpkg)
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        env:
          VCPKG_BINARY_SOURCES: "clear"
        run: |
          $HOME/vcpkg/vcpkg install \
            "harfbuzz[graphite2]:x64-osx" \
            fontconfig:x64-osx \
            freetype:x64-osx \
            icu:x64-osx

      - name: Save vcpkg cache
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: ~/vcpkg/installed
          key: vcpkg-macos-x64-v1

      - name: Set macOS build environment
        run: |
          echo "TECTONIC_DEP_BACKEND=vcpkg" >> $GITHUB_ENV
          echo "CXXFLAGS=-std=c++17" >> $GITHUB_ENV
          echo "CFLAGS=" >> $GITHUB_ENV

      - name: Import Apple certificate
        env:
          APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
          APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
        run: |
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
          KEYCHAIN_PASSWORD=$(openssl rand -base64 32)

          # Create temporary keychain
          security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
          security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"

          # Import certificate
          echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
          security import $RUNNER_TEMP/certificate.p12 \
            -k "$KEYCHAIN_PATH" \
            -P "$APPLE_CERTIFICATE_PASSWORD" \
            -T /usr/bin/codesign \
            -T /usr/bin/security
          security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
          security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain-db

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-apple-darwin

      - uses: swatinem/rust-cache@v2
        with:
          workspaces: apps/desktop/src-tauri -> target

      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - run: pnpm install

      - name: Build Tauri app
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ZOTERO_CONSUMER_KEY: ${{ secrets.ZOTERO_CONSUMER_KEY }}
          ZOTERO_CONSUMER_SECRET: ${{ secrets.ZOTERO_CONSUMER_SECRET }}
          APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
        run: pnpm --filter @claude-prism/desktop tauri build --target x86_64-apple-darwin

      - name: Notarize DMG
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
        run: |
          TARGET="x86_64-apple-darwin"
          BUNDLE="apps/desktop/src-tauri/target/$TARGET/release/bundle"
          DMG_PATH=$(find "$BUNDLE/dmg" -name '*.dmg' | head -1)
          APP_PATH="$BUNDLE/macos/ClaudePrism.app"

          if [ -z "$DMG_PATH" ]; then
            echo "Error: DMG not found"
            exit 1
          fi

          echo "==> Notarizing $DMG_PATH ..."
          xcrun notarytool submit "$DMG_PATH" \
            --apple-id "$APPLE_ID" \
            --team-id "$APPLE_TEAM_ID" \
            --password "$APPLE_PASSWORD" \
            --wait --timeout 30m

          echo "==> Stapling..."
          xcrun stapler staple "$DMG_PATH"
          xcrun stapler staple "$APP_PATH"

      - name: Collect updater artifacts
        id: collect
        run: |
          BUNDLE="apps/desktop/src-tauri/target/x86_64-apple-darwin/release/bundle"
          TAR_SIG=$(find "$BUNDLE/macos" -name '*.app.tar.gz.sig' 2>/dev/null | head -1)
          TAR_GZ=$(find "$BUNDLE/macos" -name '*.app.tar.gz' ! -name '*.sig' 2>/dev/null | head -1)

          if [ -n "$TAR_SIG" ] && [ -n "$TAR_GZ" ]; then
            echo "sig=$(cat "$TAR_SIG")" >> $GITHUB_OUTPUT
            echo "url=$(basename "$TAR_GZ")" >> $GITHUB_OUTPUT
          fi

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: desktop-macos-intel
          path: |
            apps/desktop/src-tauri/target/x86_64-apple-darwin/release/bundle/**/*.dmg
            apps/desktop/src-tauri/target/x86_64-apple-darwin/release/bundle/**/*.app.tar.gz
            apps/desktop/src-tauri/target/x86_64-apple-darwin/release/bundle/**/*.sig
          if-no-files-found: warn

    outputs:
      sig: ${{ steps.collect.outputs.sig }}
      url: ${{ steps.collect.outputs.url }}

  # ──────────────────────────────────────────────
  # Linux
  # ──────────────────────────────────────────────
  build-linux:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Linux dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf \
            autoconf autoconf-archive automake libtool pkg-config

      # Static linking via vcpkg — avoids runtime dependency on system ICU/harfbuzz.
      # Without this, the binary links against the build host's libicuuc.so.70
      # (Ubuntu 22.04) and fails on distros shipping newer ICU (e.g. Ubuntu 25.10
      # with libicuuc.so.76). Mirrors the macOS approach (commit 9566956).
      - name: Setup vcpkg
        run: |
          git clone --depth 1 https://github.com/microsoft/vcpkg $HOME/vcpkg
          $HOME/vcpkg/bootstrap-vcpkg.sh
          echo "VCPKG_ROOT=$HOME/vcpkg" >> $GITHUB_ENV

      - name: Restore vcpkg cache
        id: vcpkg-cache
        uses: actions/cache/restore@v4
        with:
          path: ~/vcpkg/installed
          key: vcpkg-linux-x64-v1

      - name: Install Linux dependencies (vcpkg)
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        env:
          VCPKG_BINARY_SOURCES: "clear"
        run: |
          $HOME/vcpkg/vcpkg install \
            "harfbuzz[graphite2]:x64-linux" \
            fontconfig:x64-linux \
            freetype:x64-linux \
            icu:x64-linux

      - name: Save vcpkg cache
        if: steps.vcpkg-cache.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: ~/vcpkg/installed
          key: vcpkg-linux-x64-v1

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-unknown-linux-gnu

      - uses: swatinem/rust-cache@v2
        with:
          workspaces: apps/desktop/src-tauri -> target

      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - run: pnpm install

      - name: Build Tauri app
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ZOTERO_CONSUMER_KEY: ${{ secrets.ZOTERO_CONSUMER_KEY }}
          ZOTERO_CONSUMER_SECRET: ${{ secrets.ZOTERO_CONSUMER_SECRET }}
          TECTONIC_DEP_BACKEND: vcpkg
          CXXFLAGS: "-std=c++17"
          CFLAGS: ""
        run: pnpm --filter @claude-prism/desktop tauri build --target x86_64-unknown-linux-gnu

      - name: Collect updater artifacts
        id: collect
        run: |
          BUNDLE="apps/desktop/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle"
          APPIMAGE_SIG=$(find "$BUNDLE/appimage" -name '*.AppImage.sig' 2>/dev/null | head -1)
          APPIMAGE=$(find "$BUNDLE/appimage" -name '*.AppImage' ! -name '*.sig' 2>/dev/null | head -1)

          if [ -n "$APPIMAGE_SIG" ] && [ -n "$APPIMAGE" ]; then
            echo "sig=$(cat "$APPIMAGE_SIG")" >> $GITHUB_OUTPUT
            echo "url=$(basename "$APPIMAGE")" >> $GITHUB_OUTPUT
          fi

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: desktop-linux
          path: |
            apps/desktop/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.deb
            apps/desktop/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.rpm
            apps/desktop/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.AppImage
            apps/desktop/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.sig
          if-no-files-found: warn

    outputs:
      sig: ${{ steps.collect.outputs.sig }}
      url: ${{ steps.collect.outputs.url }}

  # ──────────────────────────────────────────────
  # Publish: generate latest.json & upload to release
  # ──────────────────────────────────────────────
  publish:
    needs: [build-windows, build-macos, build-macos-intel, build-linux]
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v') || inputs.release_tag != ''

    steps:
      - uses: actions/checkout@v4

      - name: Determine tag
        id: tag
        run: |
          if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
            echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
          else
            echo "tag=${{ inputs.release_tag }}" >> $GITHUB_OUTPUT
          fi

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

      - name: Generate latest.json
        env:
          TAG: ${{ steps.tag.outputs.tag }}
          WIN_SIG: ${{ needs.build-windows.outputs.sig }}
          WIN_URL: ${{ needs.build-windows.outputs.url }}
          MAC_SIG: ${{ needs.build-macos.outputs.sig }}
          MAC_URL: ${{ needs.build-macos.outputs.url }}
          MAC_INTEL_SIG: ${{ needs.build-macos-intel.outputs.sig }}
          MAC_INTEL_URL: ${{ needs.build-macos-intel.outputs.url }}
          LIN_SIG: ${{ needs.build-linux.outputs.sig }}
          LIN_URL: ${{ needs.build-linux.outputs.url }}
        run: |
          VERSION="${TAG#v}"
          PUB_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
          export BASE_URL="https://github.com/delibae/claude-prism/releases/download/$TAG"

          node -e "
            const BASE = process.env.BASE_URL;
            const platforms = {};
            if (process.env.MAC_SIG)
              platforms['darwin-aarch64'] = { signature: process.env.MAC_SIG, url: BASE + '/ClaudePrism-macOS.app.tar.gz' };
            if (process.env.MAC_INTEL_SIG)
              platforms['darwin-x86_64'] = { signature: process.env.MAC_INTEL_SIG, url: BASE + '/ClaudePrism-macOS-Intel.app.tar.gz' };
            if (process.env.LIN_SIG)
              platforms['linux-x86_64'] = { signature: process.env.LIN_SIG, url: BASE + '/ClaudePrism-Linux.AppImage' };
            if (process.env.WIN_SIG)
              platforms['windows-x86_64'] = { signature: process.env.WIN_SIG, url: BASE + '/ClaudePrism-Windows-setup.exe' };

            const data = {
              version: '$VERSION',
              notes: 'ClaudePrism $TAG',
              pub_date: '$PUB_DATE',
              platforms
            };
            require('fs').writeFileSync('latest.json', JSON.stringify(data, null, 2));
            console.log(JSON.stringify(data, null, 2));
          "

      - name: Create draft release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          TAG="${{ steps.tag.outputs.tag }}"
          gh release view "$TAG" > /dev/null 2>&1 || \
            gh release create "$TAG" --title "ClaudePrism $TAG" --generate-notes --draft

      - name: Rename and upload assets
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          TAG="${{ steps.tag.outputs.tag }}"
          mkdir -p upload

          # Rename platform artifacts to version-free names
          # macOS Apple Silicon (from desktop-macos artifact)
          find artifacts/desktop-macos -name "*.dmg" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-macOS.dmg
          find artifacts/desktop-macos -name "*.app.tar.gz" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-macOS.app.tar.gz
          # macOS Intel (from desktop-macos-intel artifact)
          find artifacts/desktop-macos-intel -name "*.dmg" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-macOS-Intel.dmg
          find artifacts/desktop-macos-intel -name "*.app.tar.gz" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-macOS-Intel.app.tar.gz
          # Windows
          find artifacts/desktop-windows -name "*-setup.exe" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-Windows-setup.exe
          find artifacts/desktop-windows -name "*.msi" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-Windows.msi
          # Linux
          find artifacts/desktop-linux -name "*.deb" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-Linux.deb
          find artifacts/desktop-linux -name "*.rpm" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-Linux.rpm
          find artifacts/desktop-linux -name "*.AppImage" 2>/dev/null | head -1 | xargs -I{} cp {} upload/ClaudePrism-Linux.AppImage

          cp latest.json upload/

          echo "==> Uploading:"
          ls -la upload/

          for file in upload/*; do
            gh release upload "$TAG" "$file" --clobber
          done

      # Release stays as draft — publish manually from GitHub Releases UI
