CI split:
- release.yml: version bump + lightweight app builds (no Python/sidecar)
- build-sidecar.yml: builds CPU + CUDA sidecar variants per platform,
uploads as separate release assets, runs in parallel with app builds
- Sidecar workflow uses retry loop to find release (race with version bump)
Fixes:
- Add reqwest "json" feature for .json() method
- Add explicit type annotations for reqwest Response and bytes::Bytes
- Reuse client instance for download (was using reqwest::get directly)
Bundle targets: deb, rpm, nsis, msi, dmg (all formats, app is small now)
Windows upload finds both *.msi and *-setup.exe
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major refactor: sidecar is no longer bundled in the installer. Instead,
it's downloaded on first launch with a setup screen offering CPU vs CUDA
choice. This solves the 2GB+ installer size limit and decouples app/sidecar.
Backend:
- New commands: check_sidecar, download_sidecar, check_sidecar_update
- Streaming download with progress events via reqwest
- Added reqwest + futures-util dependencies
- Removed sidecar.zip from bundle resources
- Restored NSIS target (no longer size-constrained)
CI:
- Each platform builds both CPU and CUDA sidecar variants (except macOS: CPU only)
- Sidecar zips uploaded as separate release assets
- Asset naming: sidecar-{os}-{arch}-{variant}.zip
Frontend:
- SidecarSetup.svelte: first-launch setup with CPU/CUDA radio choice,
progress bar, error/retry handling
- Update banner on launch if newer sidecar version available
- Conditional rendering: setup screen → main app flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add rpm to bundle targets and install rpm on Linux CI
- Upload both .deb and .rpm from Linux build
- Install 7-Zip via choco if not already available on Windows runner
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace Compress-Archive (2GB limit) with 7z for sidecar packaging
- Remove NSIS from bundle targets — NSIS has a 2GB per-file limit that
breaks with CUDA-sized sidecar.zip; MSI (WiX) handles large files
by splitting into multiple CABs
- Update Windows upload to look for .msi only
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Windows and Linux sidecar builds now use --with-cuda for GPU acceleration
(macOS stays CPU-only — Apple Silicon uses Metal, not CUDA)
- Windows upload switched from --data-binary to -T streaming for 2GB+ files
- Add cleanup_old_sidecars() that removes stale sidecar-* directories on
startup, keeping only the current version
- Add NSIS uninstall hook to remove sidecar data dir on Windows uninstall
(user data in ~/.voicetonotes is preserved)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pushes from within a workflow don't trigger other workflows in Gitea,
so the separate tag-triggered build files never ran. Moved all 3
platform build jobs into release.yml with needs: bump-version so they
run directly after the version bump, tag, and release creation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New release.yml: bumps patch version, commits with skip-ci marker, tags, creates Gitea release
- Build workflows now trigger on v* tags only (not branch push)
- Simplified upload steps: use tag directly, retry loop for release lookup
- Fix macOS: install jq if missing
- Sync python/pyproject.toml version to 0.2.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pushing to main + a tag triggered 6 workflows (3 per trigger).
Now only main pushes trigger builds. The upload step detects version
tags on the current commit via git tag --points-at HEAD.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AppImage bundler compresses the entire sidecar.zip into squashfs,
causing builds to hang/timeout. Limit targets to deb (Linux),
nsis+msi (Windows), and dmg (macOS).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Invoke-RestMethod loads entire files into memory, causing connection
failures on 360MB+ installer files. Switch to curl which streams
the upload.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Upload step now runs on both main pushes and v* tag pushes
- Tag pushes create a versioned release (e.g., "Voice to Notes v0.2.0")
- Main pushes update the "latest" prerelease as before
- Windows: filter for *-setup.exe to avoid uploading non-installer binaries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The TAURI_CONFIG env var approach for resources wasn't being applied
by the NSIS bundler, so sidecar.zip was never included in the installer.
- Add resources: ["sidecar.zip"] directly to tauri.conf.json
- build.rs creates a minimal placeholder zip for dev builds so
compilation succeeds even without the real sidecar
- Remove TAURI_CONFIG env var from all CI workflows (no longer needed)
- Add sidecar.zip to .gitignore (generated by CI, not tracked)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tauri's build script overflows the stack when processing resource globs
matching thousands of files from PyInstaller's ML output (torch, pyannote).
Instead of bundling the sidecar directory directly:
- CI zips the sidecar output into a single sidecar.zip
- Tauri bundles just the one zip file (no recursion)
- On first launch, Rust extracts the zip to the app data directory
- Versioned extraction dir (sidecar-{version}) ensures updates re-extract
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tauri's externalBin only bundled the single sidecar executable, but
PyInstaller's onedir output requires companion DLLs and _internal/.
The binary was also renamed with a target triple suffix that
resolve_sidecar_path() didn't look for, causing it to fall back to
dev mode which used a compile-time CI path (CARGO_MANIFEST_DIR).
- Switch from externalBin to bundle.resources to include all sidecar files
- Pass Tauri resource_dir to sidecar manager for platform-aware path resolution
- Remove rename_binary() since externalBin target triple naming is no longer needed
- Remove broken production-to-dev fallback that could never work on user machines
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removes the artifact upload/download overhead between sidecar and app
build steps. Each platform now runs as a single job: build sidecar,
copy it into src-tauri/binaries, build Tauri app, upload to release.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use [System.Uri]::EscapeDataString for proper encoding of filenames
containing spaces in the Gitea API URL. Add size logging and error handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use curl -T (streaming) instead of --data-binary (loads into memory)
to handle large .deb/.AppImage files
- URL-encode spaces in filenames for the Gitea API
- Use IFS= read -r to handle filenames with spaces
- Add HTTP status code logging for upload debugging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each platform (Linux, macOS, Windows) now has its own workflow file
that builds the sidecar, builds the Tauri app, and uploads to a shared
"latest" release independently. A failure on one platform no longer
blocks releases for the others.
- build-linux.yml: bash throughout, apt for deps
- build-macos.yml: bash throughout, brew for deps
- build-windows.yml: powershell throughout, choco for deps
- All use uv for Python, upload to shared "latest" release tag
- Each platform replaces its own artifacts on the release
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Linux: add xdg-utils to system deps (provides xdg-open needed by
Tauri's AppImage bundler)
- Windows: replace dtolnay/rust-toolchain action (uses bash internally)
with direct rustup install via PowerShell
- Unix: install Rust via rustup.rs shell script instead of GitHub action
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pyannote.audio requires ffmpeg at import time (torchcodec loads
FFmpeg shared libraries). Install via brew (macOS), apt (Linux),
choco (Windows) before building the sidecar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Windows runner doesn't have bash. Split Python setup and build steps
into Unix (default shell) and Windows (powershell) variants.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- build_sidecar.py: pip_install() now includes 'install' in the command,
callers pass only package names (was doubling up as 'uv pip install install torch')
- CI: set shell: bash on uv steps so Windows doesn't try to use cmd.exe
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Unix runners use the bash install script, Windows uses the PowerShell
installer. Both check if uv is already present first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
astral-sh/setup-uv is not available on Gitea's action registry.
Use the official install script instead, skipping if uv is already present.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CI: install uv via astral-sh/setup-uv, use uv to install Python
and run the build script (replaces setup-python which fails on
self-hosted macOS runners)
- build_sidecar.py: auto-detects uv and uses it for venv creation
and package installation (much faster), falls back to standard
venv + pip when uv is not available
- Remove .github/workflows duplicate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Set AGENT_TOOLSDIRECTORY via step-level env on setup-python (not
GITHUB_ENV which only applies to subsequent steps)
- Use runner.temp for toolcache dir (always writable, no sudo needed)
- Remove .github/workflows/build.yml to prevent duplicate CI runs
- Remove unused Windows env check step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set AGENT_TOOLSDIRECTORY to a workspace-local path so setup-python
doesn't need /Users/runner or sudo access.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
upload-artifact@v4 and download-artifact@v4 require GitHub's backend
and are not supported on Gitea. v3 works with Gitea Actions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create /Users/runner directory on macOS before setup-python (permission fix)
- Use `python -m pip` everywhere instead of calling pip directly (Windows fix)
- Refactor build_sidecar.py to use pip_install() helper via python -m pip
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- pip/setuptools/wheel for sidecar build step
- jq/curl for release API calls
- create-dmg for macOS bundling
- Linux system deps (gtk, webkit, patchelf)
- Validation check on release creation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Creates a pre-release with all platform artifacts on every push to main.
Uses BUILD_TOKEN secret for Gitea API authentication.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>