Tray + lifecycle: - tauri-plugin-single-instance — second launch focuses existing window instead of racing for port 3900. - Window close hides instead of destroying; backend shutdown moved to RunEvent::ExitRequested so only the tray "Quit" item (or Cmd+Q on macOS) actually exits. - Tray icon flips to red-dot variant during dictation recording. Hotkey customization: - Settings → Capture tab. Records any modifier+key combo, persists to app config, re-registers on launch. - set_dictation_shortcut rolls back to the previous binding on register failure so a bad combo never leaves the user with no shortcut. Dictation latency / correctness: - WS-final treated as source of truth; HTTP POST /transcribe runs only as fallback (WS error / timeout / no-WS path). Audio transcribed once instead of twice. Server accepts an "EOF" text frame (or empty binary frame) so the socket stays open for `final` to be delivered before the client closes. - MediaRecorder chunks queued during the WS handshake are drained in ws.onopen — the server's final transcript no longer drops the first ~250 ms of audio. - Fallback timeout scales with recording length (max(15s, recordedMs+10s)) so long-form dictations don't trip duplicate transcription. Donate page: - Drop Patreon, Bitcoin / Ethereum / Solana cards. Drop qrcode.react. - Move "Commercial License" CTA from page bottom to top-right header bar. Docker hygiene: - docker-compose binds 127.0.0.1 by default. README documents the LAN exposure trade-off + recommends a reverse proxy with auth. CI: - New cross-platform `tauri-cross-platform` job runs `cargo check` against the Tauri shell on macOS / Windows / Linux per PR. Catches platform cfg-gate regressions without paying the full ~15min/platform bundle cost (full bundling stays in release.yml on tag push). Tests: - tests/test_capture_ws.py (3 cases) covers EOF text-frame, empty-binary EOF, and legacy disconnect-finalize paths. Includes the user's previously-staged 0.2.5 polish: cross-platform desktop-prod.sh, Dockerfile base-image fix, bun.lock churn. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
165 lines
5.4 KiB
YAML
165 lines
5.4 KiB
YAML
# PR-gated continuous integration — runs backend pytest + frontend node:test
|
|
# + TypeScript typecheck on every pull request and push to main. Keeps the
|
|
# heavy 4-platform Tauri bundle off this path (that's release.yml on tag
|
|
# push) so PRs turn around in a few minutes instead of ~40.
|
|
|
|
name: CI
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
push:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
# Run all JavaScript actions on Node 24 (GH deprecates Node 20 in Sep 2026).
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
|
|
jobs:
|
|
test:
|
|
name: Tests (backend + frontend)
|
|
runs-on: ubuntu-22.04
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Python 3.11
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.11"
|
|
|
|
# enable-cache persists ~/.cache/uv across runs, keyed on uv.lock —
|
|
# turns `uv sync` from ~45 s cold to ~5 s warm.
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v3
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: "uv.lock"
|
|
|
|
# Node 22 is needed for --experimental-strip-types so node:test can
|
|
# import .ts files directly from frontend/src/api/*.
|
|
- name: Setup Node 22
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v1
|
|
|
|
# apt install ffmpeg is ~30 s every run; cache the resolved .debs.
|
|
- name: System deps (ffmpeg)
|
|
uses: awalsh128/cache-apt-pkgs-action@latest
|
|
with:
|
|
packages: ffmpeg
|
|
version: 1.0
|
|
|
|
- name: Install Python deps
|
|
run: uv sync
|
|
|
|
- name: Run pytest
|
|
run: uv run pytest tests/ -q --tb=short
|
|
|
|
# Cache ~/.bun/install/cache keyed on bun.lock — `bun install` drops
|
|
# from ~15 s cold to near-instant on warm cache.
|
|
- name: Cache bun deps
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.bun/install/cache
|
|
key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock', 'bun.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-bun-
|
|
|
|
- name: Install frontend deps
|
|
working-directory: frontend
|
|
run: bun install
|
|
|
|
- name: Frontend typecheck
|
|
working-directory: frontend
|
|
run: bunx tsc --noEmit
|
|
|
|
# Invoke node directly (not `bun run test`) because `bun run` auto-aliases
|
|
# `node` to `bun` in script bodies, and bun doesn't support
|
|
# --experimental-strip-types.
|
|
- name: Run frontend node:test
|
|
working-directory: frontend
|
|
run: node --experimental-strip-types --no-warnings --test ../tests/frontend/*.test.mjs
|
|
|
|
# ── Cross-platform Tauri shell check ────────────────────────────────────
|
|
# Catches platform-specific Rust regressions on PR (cfg(target_os=...)
|
|
# gates, missing Windows/macOS deps, etc.) without spending the 15+ min
|
|
# per-platform that a full `tauri build` takes. `cargo check` is the
|
|
# lightest gate that exercises type-checking + linking for each target.
|
|
# Full bundling stays in release.yml on tag push.
|
|
tauri-cross-platform:
|
|
name: Tauri shell check (${{ matrix.label }})
|
|
needs: test
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: macos-14
|
|
label: macOS
|
|
rust_target: aarch64-apple-darwin
|
|
- os: windows-2022
|
|
label: Windows
|
|
rust_target: x86_64-pc-windows-msvc
|
|
- os: ubuntu-22.04
|
|
label: Linux
|
|
rust_target: x86_64-unknown-linux-gnu
|
|
runs-on: ${{ matrix.os }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Rust (stable)
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: ${{ matrix.rust_target }}
|
|
|
|
# Per-target cache key so we don't conflict with the release matrix.
|
|
- name: Rust cache
|
|
uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: frontend/src-tauri -> target
|
|
key: ${{ matrix.rust_target }}-check
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v1
|
|
|
|
# Linux is the only host with non-trivial Tauri build deps —
|
|
# webkit2gtk + libayatana-appindicator + xdo. Mirror release.yml.
|
|
- name: Linux system deps
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
libwebkit2gtk-4.1-dev \
|
|
build-essential curl wget file libxdo-dev libssl-dev \
|
|
libayatana-appindicator3-dev librsvg2-dev \
|
|
libasound2-dev
|
|
|
|
- name: Cache bun deps
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.bun/install/cache
|
|
key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock', 'bun.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-bun-
|
|
|
|
- name: Install frontend deps
|
|
working-directory: frontend
|
|
run: bun install
|
|
|
|
# tauri-build's setup hook reads tauri.conf.json's `frontendDist`
|
|
# ("../dist"), which only exists after a frontend build. Without this,
|
|
# `cargo check` would fail on a fresh checkout because the embedded
|
|
# asset map can't resolve.
|
|
- name: Build frontend (for tauri.conf.json frontendDist)
|
|
working-directory: frontend
|
|
run: bun run build
|
|
|
|
- name: Cargo check (Tauri shell)
|
|
working-directory: frontend/src-tauri
|
|
run: cargo check --target ${{ matrix.rust_target }} --message-format=short
|