From ccca1fa816382d9a23ced7877ff93b4d99f0f021 Mon Sep 17 00:00:00 2001 From: Thales Pereira <31625914+thcp@users.noreply.github.com> Date: Sun, 10 May 2026 21:08:44 +0100 Subject: [PATCH 1/5] ignore build files. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 38c3cc35..6dc0dc1f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ htmlcov/ data/ jobs/ .run/ +.build # Local env / secrets .env From 732228cb272573bf7673e5932d63924c23a34f85 Mon Sep 17 00:00:00 2001 From: Thales Pereira <31625914+thcp@users.noreply.github.com> Date: Mon, 11 May 2026 23:04:36 +0100 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20macOS=20native=20app=20=E2=80=94=20?= =?UTF-8?q?Tauri=20shell,=20runtime=20pack,=20MPS,=20CI=20pipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tauri 2 macOS app with setup wizard that downloads and installs a self-contained Python/backend runtime pack on first launch - Runtime pack download now streams via reqwest with real-time progress events (runtime-download-progress) replacing the blocking curl call; progress bar shown in setup UI with indeterminate fallback - MPS (Apple Silicon) GPU detection and torch device selection; CUDA path gated to non-macOS targets - macOS data dir uses ~/Library/Application Support/StemDeck - macOS FFmpeg downloaded from evermeet.cx and extracted from zip - Backend watchdog: Python process exits when parent Tauri PID disappears - CloseRequested handler stops backend and exits cleanly - Woodpecker CI pipeline for macOS: arm64 and x64 builds in parallel, DMG inspection, artifact upload to GitHub releases - Build scripts: make-runtime-pack.sh, make-app.sh, make-dmg.sh, make-iconset.sh with LOCAL_DEV_TEST version default - Version stamped from CI_COMMIT_TAG (or LOCAL_DEV_TEST) at build time across Cargo.toml, tauri.conf.json, package.json - SVG logo assets, DMG packaging files, macOS README and notices - README updated with macOS download and build instructions - Bump version to 0.4.0-alpha.1 --- .woodpecker/macos-release.yml | 143 ++++ README.md | 65 +- app/main.py | 24 + desktop/package.json | 2 +- desktop/src-tauri/Cargo.lock | 331 +++++++- desktop/src-tauri/Cargo.toml | 4 +- desktop/src-tauri/icons/icon.icns | Bin 0 -> 1340829 bytes desktop/src-tauri/icons/icon.png | Bin 223957 -> 895686 bytes desktop/src-tauri/src/main.rs | 728 ++++++++++++++++-- desktop/src-tauri/tauri.conf.json | 31 +- desktop/ui/index.html | 5 +- desktop/ui/runtime-manifest.json | 8 + desktop/ui/setup.css | 26 + desktop/ui/setup.js | 133 +++- stemdeck.png => imgs/screenshot/stemdeck.png | Bin imgs/stemdeck-svg-assets/stemdeck-icon.svg | 28 + .../stemdeck-logo-horizontal.svg | 25 + .../stemdeck-logo-stacked.svg | 24 + .../stemdeck-tray-light.svg | 12 + .../stemdeck-tray-monochrome.svg | 12 + .../stemdeck-waveform-symbol.svg | 22 + .../stemdeck-svg-assets/stemdeck-wordmark.svg | 6 + packaging/macos/README-macOS.txt | 31 + packaging/macos/THIRD_PARTY_NOTICES.txt | 20 + packaging/macos/dmg-background.svg | 32 + pyproject.toml | 16 +- scripts/macos/make-app.sh | 68 ++ scripts/macos/make-dmg.sh | 139 ++++ scripts/macos/make-iconset.sh | 54 ++ scripts/macos/make-runtime-pack.sh | 196 +++++ static/css/appbar.css | 6 + static/css/responsive.css | 3 + static/css/widgets.css | 22 +- static/imgs/stemdeck-logo-horizontal.svg | 25 + static/index.html | 4 +- uv.lock | 293 +++++-- 36 files changed, 2357 insertions(+), 181 deletions(-) create mode 100644 .woodpecker/macos-release.yml create mode 100644 desktop/src-tauri/icons/icon.icns create mode 100644 desktop/ui/runtime-manifest.json rename stemdeck.png => imgs/screenshot/stemdeck.png (100%) create mode 100644 imgs/stemdeck-svg-assets/stemdeck-icon.svg create mode 100644 imgs/stemdeck-svg-assets/stemdeck-logo-horizontal.svg create mode 100644 imgs/stemdeck-svg-assets/stemdeck-logo-stacked.svg create mode 100644 imgs/stemdeck-svg-assets/stemdeck-tray-light.svg create mode 100644 imgs/stemdeck-svg-assets/stemdeck-tray-monochrome.svg create mode 100644 imgs/stemdeck-svg-assets/stemdeck-waveform-symbol.svg create mode 100644 imgs/stemdeck-svg-assets/stemdeck-wordmark.svg create mode 100644 packaging/macos/README-macOS.txt create mode 100644 packaging/macos/THIRD_PARTY_NOTICES.txt create mode 100644 packaging/macos/dmg-background.svg create mode 100755 scripts/macos/make-app.sh create mode 100755 scripts/macos/make-dmg.sh create mode 100755 scripts/macos/make-iconset.sh create mode 100755 scripts/macos/make-runtime-pack.sh create mode 100644 static/imgs/stemdeck-logo-horizontal.svg diff --git a/.woodpecker/macos-release.yml b/.woodpecker/macos-release.yml new file mode 100644 index 00000000..d596924d --- /dev/null +++ b/.woodpecker/macos-release.yml @@ -0,0 +1,143 @@ +when: + - event: release + +labels: + platform: darwin/arm64 + backend: local + +steps: + prepare-macos-version: + image: bash + commands: + - | + if [ -z "${CI_COMMIT_TAG:-}" ]; then + echo "CI_COMMIT_TAG is not set" >&2 + exit 1 + fi + VERSION="${CI_COMMIT_TAG#v}" + printf '{ "version": "%s" }\n' "$VERSION" > static/version.json + echo "VERSION=$VERSION" > .macos-release.env + echo "Wrote static/version.json for $VERSION" + + build-macos-arm64: + image: bash + depends_on: + - prepare-macos-version + commands: + - . ./.macos-release.env + - command -v zstd + - scripts/macos/make-iconset.sh + - ARCH=arm64 VERSION="$VERSION" scripts/macos/make-runtime-pack.sh + - ARCH=arm64 VERSION="$VERSION" scripts/macos/make-app.sh + - ARCH=arm64 VERSION="$VERSION" scripts/macos/make-dmg.sh + + build-macos-x64: + image: bash + depends_on: + - prepare-macos-version + commands: + - . ./.macos-release.env + - command -v zstd + - | + if ! arch -x86_64 /usr/bin/true >/dev/null 2>&1; then + echo "ERROR: Rosetta 2 is required to build the x64 runtime on this agent." >&2 + exit 1 + fi + - | + if ! command -v rustup >/dev/null 2>&1 || ! rustup target list --installed | grep -q x86_64-apple-darwin; then + echo "ERROR: x86_64-apple-darwin Rust target not installed. Run: rustup target add x86_64-apple-darwin" >&2 + exit 1 + fi + - ARCH=x64 VERSION="$VERSION" scripts/macos/make-runtime-pack.sh + - ARCH=x64 VERSION="$VERSION" scripts/macos/make-app.sh + - ARCH=x64 VERSION="$VERSION" scripts/macos/make-dmg.sh + + inspect-macos-artifacts: + image: bash + depends_on: + - build-macos-arm64 + - build-macos-x64 + commands: + - test -f .build/macos-dist/StemDeck-macOS-arm64.dmg + - test -f .build/StemDeck-runtime-macOS-arm64.tar.zst + - test -f .build/macos-dist/SHA256SUMS-macOS-arm64.txt + - test -f .build/macos-dist/StemDeck-macOS-x64.dmg + - test -f .build/StemDeck-runtime-macOS-x64.tar.zst + - test -f .build/macos-dist/SHA256SUMS-macOS-x64.txt + - cat .build/macos-dist/SHA256SUMS-macOS-arm64.txt + - cat .build/macos-dist/SHA256SUMS-macOS-x64.txt + - du -sh .build/macos-dist/StemDeck-macOS-arm64.dmg .build/StemDeck-runtime-macOS-arm64.tar.zst + - du -sh .build/macos-dist/StemDeck-macOS-x64.dmg .build/StemDeck-runtime-macOS-x64.tar.zst + - | + if find desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/macos/StemDeck.app \ + \( -iname '*python*' -o -iname '*torch*' -o -iname '*ffmpeg*' -o -iname '*ffprobe*' \) | + grep -q .; then + echo "arm64 StemDeck.app contains runtime binaries that should stay outside the DMG." >&2 + exit 1 + fi + - | + if find desktop/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/StemDeck.app \ + \( -iname '*python*' -o -iname '*torch*' -o -iname '*ffmpeg*' -o -iname '*ffprobe*' \) | + grep -q .; then + echo "x64 StemDeck.app contains runtime binaries that should stay outside the DMG." >&2 + exit 1 + fi + - | + for arch in arm64 x64; do + mountpoint="$(mktemp -d /tmp/stemdeck-dmg.XXXXXX)" + hdiutil attach ".build/macos-dist/StemDeck-macOS-${arch}.dmg" -readonly -nobrowse -mountpoint "$mountpoint" + trap 'hdiutil detach "$mountpoint" >/dev/null 2>&1 || true; rmdir "$mountpoint" >/dev/null 2>&1 || true' EXIT + test -d "$mountpoint/StemDeck.app" + test -L "$mountpoint/Applications" + test -f "$mountpoint/README-macOS.txt" + test -f "$mountpoint/THIRD_PARTY_NOTICES.txt" + hdiutil detach "$mountpoint" + rmdir "$mountpoint" + trap - EXIT + done + + upload-macos-artifacts: + image: bash + when: + - event: release + depends_on: + - inspect-macos-artifacts + environment: + GH_TOKEN: + from_secret: github_token + commands: + - | + if [ -z "${CI_COMMIT_TAG:-}" ]; then + echo "CI_COMMIT_TAG is required to upload release assets." >&2 + exit 1 + fi + - | + if ! command -v gh >/dev/null 2>&1; then + echo "GitHub CLI is required on the macOS agent to upload release assets." >&2 + exit 1 + fi + - | + scan_note="macOS arm64 and x64 DMGs and runtime packs were built and inspected on a macOS Woodpecker agent before upload." + body="$(gh release view "$CI_COMMIT_TAG" --repo "thcp/stemdeck" --json body --jq ".body")" + case "$body" in + *"$scan_note"*) ;; + *) + notes_path="$(mktemp /tmp/stemdeck-release-notes.XXXXXX.md)" + { + printf '%s\n\n' "$body" + printf '### Artifact build\n\n' + printf -- '- %s\n' "$scan_note" + } > "$notes_path" + gh release edit "$CI_COMMIT_TAG" --repo "thcp/stemdeck" --notes-file "$notes_path" + rm -f "$notes_path" + ;; + esac + - gh release upload "$CI_COMMIT_TAG" + ".build/macos-dist/StemDeck-macOS-arm64.dmg" + ".build/StemDeck-runtime-macOS-arm64.tar.zst" + ".build/macos-dist/SHA256SUMS-macOS-arm64.txt" + ".build/macos-dist/StemDeck-macOS-x64.dmg" + ".build/StemDeck-runtime-macOS-x64.tar.zst" + ".build/macos-dist/SHA256SUMS-macOS-x64.txt" + --repo "thcp/stemdeck" + --clobber diff --git a/README.md b/README.md index 06ee049b..659e5e66 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@