- 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>
Default torch on PyPI is CPU-only on Windows. Must use PyTorch's own
package index (cu126) to get CUDA-enabled wheels. This also pins the
CUDA version on Linux for deterministic builds.
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>
- transcribe: catch model load failures on CUDA and retry with CPU
- hardware detect: test CUDA runtime actually works (torch.zeros on cuda)
before recommending GPU, since CPU-only builds detect CUDA via driver
but lack cublas/cuDNN libraries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Exclude ctranslate2.converters from PyInstaller bundle — these modules
import torch at module level causing circular import crashes, and are
only needed for model conversion (never used at runtime)
- Defer all heavy ML imports to first handler call instead of startup,
so the sidecar can send its ready message without loading torch/whisper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix is_running() to check actual process liveness via try_wait()
instead of just checking if the handle exists
- Auto-restart sidecar on pipe errors (broken pipe, closed stdout)
with one retry attempt
- Hide sidecar console window on Windows (CREATE_NO_WINDOW flag)
- Log sidecar stderr to sidecar.log file for crash diagnostics
- Include exit status in error message when sidecar fails to start
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>
- uv pip --python works better with the venv directory path than the
python binary path (avoids "No virtual environment found" on Windows)
- Add .exe suffix to Windows python path for non-uv fallback
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>