diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0dd4b49 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,92 @@ +name: Release + +on: + push: + tags: ['v*'] + +permissions: + contents: write + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - platform: macos-latest + target: aarch64-apple-darwin + label: macOS-ARM64 + - platform: macos-latest + target: x86_64-apple-darwin + label: macOS-x64 + - platform: ubuntu-22.04 + target: x86_64-unknown-linux-gnu + label: Linux-x64 + - platform: windows-latest + target: x86_64-pc-windows-msvc + label: Windows-x64 + + runs-on: ${{ matrix.platform }} + name: Build (${{ matrix.label }}) + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Rust cache + uses: swatinem/rust-cache@v2 + with: + workspaces: src-tauri + + - name: Install Linux dependencies + if: matrix.platform == 'ubuntu-22.04' + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libappindicator3-dev \ + librsvg2-dev \ + patchelf + + - name: Install frontend dependencies + run: npm ci + + - name: Build Tauri app + uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAURI_SIGNING_PRIVATE_KEY: '' + with: + tagName: ${{ github.ref_name }} + releaseName: ClawPal ${{ github.ref_name }} + releaseBody: | + ## ClawPal ${{ github.ref_name }} + + ### Installation + + **macOS** (unsigned — requires manual approval): + - Download the `.dmg` for your architecture (ARM for Apple Silicon, x64 for Intel) + - Open the DMG and drag ClawPal to Applications + - First launch: right-click the app → Open, or run `xattr -cr /Applications/ClawPal.app` + + **Windows** (unsigned — SmartScreen will warn): + - Download the `.exe` (NSIS installer) or `.msi` + - If SmartScreen blocks: click "More info" → "Run anyway" + + **Linux**: + - `.deb`: `sudo dpkg -i clawpal_*.deb` + - `.AppImage`: `chmod +x ClawPal_*.AppImage && ./ClawPal_*.AppImage` + releaseDraft: true + prerelease: false + args: --target ${{ matrix.target }} diff --git a/scripts/generate-icons.sh b/scripts/generate-icons.sh new file mode 100755 index 0000000..2bf0794 --- /dev/null +++ b/scripts/generate-icons.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Generate platform icons from a 1024x1024 source PNG +# Usage: ./scripts/generate-icons.sh [source.png] +# Defaults to src-tauri/icons/icon.png + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +SOURCE="${1:-$PROJECT_ROOT/src-tauri/icons/icon.png}" +ICON_DIR="$PROJECT_ROOT/src-tauri/icons" + +if [ ! -f "$SOURCE" ]; then + echo "Error: source image not found: $SOURCE" + exit 1 +fi + +echo "Generating icons from: $SOURCE" +echo "Output directory: $ICON_DIR" + +# sips -z modifies the source file in-place even with --out, so we work from a +# temporary copy to preserve the original 1024x1024 PNG. +TMP_DIR=$(mktemp -d) +SAFE_SOURCE="$TMP_DIR/source.png" +cp "$SOURCE" "$SAFE_SOURCE" + +resize() { + # resize + # Use -Z (resample to max dimension) instead of -z to preserve alpha/transparency + cp "$SAFE_SOURCE" "$2" + sips -Z "$1" "$2" >/dev/null +} + +# PNG sizes needed by Tauri +resize 32 "$ICON_DIR/32x32.png" +resize 128 "$ICON_DIR/128x128.png" +resize 256 "$ICON_DIR/128x128@2x.png" + +echo " Created 32x32.png, 128x128.png, 128x128@2x.png" + +# macOS .icns via iconutil +ICONSET_DIR="$TMP_DIR/icon.iconset" +mkdir -p "$ICONSET_DIR" + +resize 16 "$ICONSET_DIR/icon_16x16.png" +resize 32 "$ICONSET_DIR/icon_16x16@2x.png" +resize 32 "$ICONSET_DIR/icon_32x32.png" +resize 64 "$ICONSET_DIR/icon_32x32@2x.png" +resize 128 "$ICONSET_DIR/icon_128x128.png" +resize 256 "$ICONSET_DIR/icon_128x128@2x.png" +resize 256 "$ICONSET_DIR/icon_256x256.png" +resize 512 "$ICONSET_DIR/icon_256x256@2x.png" +resize 512 "$ICONSET_DIR/icon_512x512.png" +resize 1024 "$ICONSET_DIR/icon_512x512@2x.png" + +iconutil -c icns "$ICONSET_DIR" -o "$ICON_DIR/icon.icns" +echo " Created icon.icns" + +# Windows .ico +# Try magick (ImageMagick), then png2ico, then skip +if command -v magick &>/dev/null; then + magick "$SAFE_SOURCE" -define icon:auto-resize=256,128,64,48,32,16 "$ICON_DIR/icon.ico" + echo " Created icon.ico (via ImageMagick)" +elif command -v convert &>/dev/null; then + convert "$SAFE_SOURCE" -define icon:auto-resize=256,128,64,48,32,16 "$ICON_DIR/icon.ico" + echo " Created icon.ico (via convert)" +elif command -v png2ico &>/dev/null; then + # png2ico requires width < 256 and multiple of 8 + TMP_ICO_DIR="$TMP_DIR/ico" + mkdir -p "$TMP_ICO_DIR" + resize 128 "$TMP_ICO_DIR/128.png" + resize 48 "$TMP_ICO_DIR/48.png" + resize 32 "$TMP_ICO_DIR/32.png" + resize 16 "$TMP_ICO_DIR/16.png" + png2ico "$ICON_DIR/icon.ico" "$TMP_ICO_DIR/128.png" "$TMP_ICO_DIR/48.png" "$TMP_ICO_DIR/32.png" "$TMP_ICO_DIR/16.png" + echo " Created icon.ico (via png2ico)" +else + echo " WARNING: No tool found to create icon.ico (install ImageMagick: brew install imagemagick)" + echo " Skipping .ico generation" +fi + +rm -rf "$TMP_DIR" +echo "Done! Icons generated in $ICON_DIR" diff --git a/scripts/release.sh b/scripts/release.sh index b07b528..77b46fa 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -19,12 +19,21 @@ run_or_print() { fi } -say "ClawPal MVP release assistant" +VERSION=$(node -p "require('./package.json').version") + +say "ClawPal v${VERSION} release assistant" +say "======================================" + run_or_print "npm run typecheck" run_or_print "npm run build" run_or_print "cd src-tauri && cargo fmt --all --check" -run_or_print "cd src-tauri && cargo check" -run_or_print "cd src-tauri && cargo check --target-dir target/check" -run_or_print "cd src-tauri && cargo check" run_or_print "cd src-tauri && cargo tauri build" -say "Done." + +say "" +say "Local build complete!" +say "" +say "To publish via GitHub Actions (builds macOS + Windows + Linux):" +say " git tag v${VERSION}" +say " git push origin v${VERSION}" +say "" +say "This will trigger .github/workflows/release.yml and create a draft release." diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000..bb51bb7 Binary files /dev/null and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..27a685d Binary files /dev/null and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 0000000..7f2f8b1 Binary files /dev/null and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000..d4aa756 Binary files /dev/null and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 0000000..ca3535c Binary files /dev/null and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png index dd387af..b469740 100644 Binary files a/src-tauri/icons/icon.png and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 8bd60e1..85cea72 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -20,7 +20,21 @@ }, "bundle": { "active": true, - "icon": [], - "targets": ["deb", "dmg", "msi"] + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "targets": "all", + "macOS": { + "minimumSystemVersion": "10.15", + "signingIdentity": null + }, + "windows": { + "certificateThumbprint": null, + "timestampUrl": "" + } } }