Skip to content

fix: note race condition (#1277) #2

fix: note race condition (#1277)

fix: note race condition (#1277) #2

name: Build and Notarize
on:
push:
branches: [main, develop]
paths-ignore:
- "**.md"
- "LICENSE"
- ".github/ISSUE_TEMPLATE/**"
pull_request:
branches: [main]
paths-ignore:
- "**.md"
- "LICENSE"
- ".github/ISSUE_TEMPLATE/**"
workflow_dispatch:
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Run tests
run: npm test
env:
# keeps require("electron") from throwing when postinstall was skipped
ELECTRON_OVERRIDE_DIST_PATH: /tmp
build-linux:
needs: tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Install platform-specific native binaries
run: npm install @rollup/rollup-linux-x64-gnu lightningcss-linux-x64-gnu @tailwindcss/oxide-linux-x64-gnu --no-save
- name: Cache native binaries
uses: actions/cache@v4
with:
path: resources/bin
key: linux-x64-bin-${{ hashFiles('scripts/download-*.js') }}
- name: Download whisper.cpp binaries
run: node scripts/download-whisper-cpp.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download llama-server binaries
run: node scripts/download-llama-server.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download sherpa-onnx binaries
run: node scripts/download-sherpa-onnx.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download yt-dlp binary
run: node scripts/download-yt-dlp.js --current
- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download meeting AEC helper
run: node scripts/download-meeting-aec-helper.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Cache Electron
uses: actions/cache@v4
with:
path: ~/.cache/electron
key: linux-electron-${{ hashFiles('**/package-lock.json') }}
restore-keys: linux-electron-
- name: Install Linux build and packaging dependencies
run: |
sudo apt-get update
sudo apt-get install -y rpm libx11-dev libxtst-dev libatspi2.0-dev libglib2.0-dev libpipewire-0.3-dev pkg-config
- name: Create runtime env
run: |
echo "GOOGLE_CALENDAR_CLIENT_ID=${{ secrets.GOOGLE_CALENDAR_CLIENT_ID }}" >> .env
echo "GOOGLE_CALENDAR_CLIENT_SECRET=${{ secrets.GOOGLE_CALENDAR_CLIENT_SECRET }}" >> .env
- name: Verify PipeWire system audio helper build
run: |
npm run compile:linux-system-audio
# supportsNativeCapture reflects compile-time PipeWire linkage, so this passes on CI runners with no PipeWire daemon (where "ok" is false).
resources/bin/linux-system-audio-helper probe | grep '"supportsNativeCapture":true'
- name: Build Application
run: npm run build:linux -- --publish never
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
VITE_NEON_AUTH_URL: ${{ vars.VITE_NEON_AUTH_URL }}
VITE_OPENWHISPR_API_URL: ${{ vars.VITE_OPENWHISPR_API_URL }}
VITE_OPENWHISPR_OAUTH_CALLBACK_URL: ${{ vars.VITE_OPENWHISPR_OAUTH_CALLBACK_URL }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: linux-build
path: dist/
retention-days: 7
build-windows:
needs: tests
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Install platform-specific native binaries
run: npm install @rollup/rollup-win32-x64-msvc lightningcss-win32-x64-msvc @tailwindcss/oxide-win32-x64-msvc --no-save
- name: Cache native binaries
uses: actions/cache@v4
with:
path: resources/bin
key: windows-x64-bin-${{ hashFiles('scripts/download-*.js') }}
- name: Download whisper.cpp binaries
run: node scripts/download-whisper-cpp.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download llama-server binaries
run: node scripts/download-llama-server.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download sherpa-onnx binaries
run: node scripts/download-sherpa-onnx.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download yt-dlp binary
run: node scripts/download-yt-dlp.js --current
- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download meeting AEC helper
run: node scripts/download-meeting-aec-helper.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download nircmd.exe
run: node scripts/download-nircmd.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download windows-fast-paste.exe
run: node scripts/download-windows-fast-paste.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download windows-key-listener.exe
run: node scripts/download-windows-key-listener.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download windows-mic-listener.exe
run: node scripts/download-windows-mic-listener.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Cache Electron
uses: actions/cache@v4
with:
path: ~/AppData/Local/electron/Cache
key: windows-electron-${{ hashFiles('**/package-lock.json') }}
restore-keys: windows-electron-
- name: Create runtime env
shell: bash
run: |
echo "GOOGLE_CALENDAR_CLIENT_ID=${{ secrets.GOOGLE_CALENDAR_CLIENT_ID }}" >> .env
echo "GOOGLE_CALENDAR_CLIENT_SECRET=${{ secrets.GOOGLE_CALENDAR_CLIENT_SECRET }}" >> .env
- name: Build and Sign Application
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
npm run build:win -- --publish never --config electron-builder.unsigned-win.json
else
npm run build:win -- --publish never
fi
shell: bash
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
VITE_NEON_AUTH_URL: ${{ vars.VITE_NEON_AUTH_URL }}
VITE_OPENWHISPR_API_URL: ${{ vars.VITE_OPENWHISPR_API_URL }}
VITE_OPENWHISPR_OAUTH_CALLBACK_URL: ${{ vars.VITE_OPENWHISPR_OAUTH_CALLBACK_URL }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: windows-build
path: dist/
retention-days: 7
build-macos:
needs: tests
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
arch: [x64, arm64]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Install ffmpeg-static for target architecture
if: matrix.arch == 'x64'
run: |
rm -f node_modules/ffmpeg-static/ffmpeg
npm_config_arch=x64 node node_modules/ffmpeg-static/install.js
- name: Cache native binaries
uses: actions/cache@v4
with:
path: resources/bin
key: macos-${{ matrix.arch }}-bin-${{ hashFiles('scripts/download-*.js', 'scripts/build-globe-listener.js', 'resources/macos-globe-listener.swift', 'scripts/build-macos-fast-paste.js', 'resources/macos-fast-paste.swift', 'scripts/build-media-remote.js', 'resources/macos-media-remote.swift', 'scripts/build-macos-audio-tap.js', 'resources/macos-audio-tap.swift') }}
- name: Compile macos-globe-listener binary
run: npm run compile:globe -- --arch ${{ matrix.arch }}
- name: Compile macos-fast-paste binary
run: npm run compile:fast-paste -- --arch ${{ matrix.arch }}
- name: Compile macos-media-remote binary
run: npm run compile:media-remote -- --arch ${{ matrix.arch }}
- name: Compile macos-audio-tap binary
run: npm run compile:audio-tap -- --arch ${{ matrix.arch }}
- name: Download whisper.cpp binaries
run: node scripts/download-whisper-cpp.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download llama-server binaries
run: node scripts/download-llama-server.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download sherpa-onnx binaries
run: node scripts/download-sherpa-onnx.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download yt-dlp binary
run: node scripts/download-yt-dlp.js --current --platform darwin --arch ${{ matrix.arch }}
- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Download meeting AEC helper
run: node scripts/download-meeting-aec-helper.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
- name: Cache Electron
uses: actions/cache@v4
with:
path: ~/.cache/electron
key: macos-${{ matrix.arch }}-electron-${{ hashFiles('**/package-lock.json') }}
restore-keys: macos-${{ matrix.arch }}-electron-
- name: Setup macOS Code Signing
if: github.event_name != 'pull_request'
env:
APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }}
run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
API_KEY_PATH=$RUNNER_TEMP/api_key.p8
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
echo "$APPLE_CERTIFICATE_BASE64" | base64 --decode > $CERTIFICATE_PATH
echo "$APPLE_API_KEY_BASE64" | base64 --decode > $API_KEY_PATH
security create-keychain -p "runner" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "runner" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -s -k "runner" $KEYCHAIN_PATH
echo "APPLE_API_KEY=$API_KEY_PATH" >> $GITHUB_ENV
- name: Create runtime env
run: |
echo "GOOGLE_CALENDAR_CLIENT_ID=${{ secrets.GOOGLE_CALENDAR_CLIENT_ID }}" >> .env
echo "GOOGLE_CALENDAR_CLIENT_SECRET=${{ secrets.GOOGLE_CALENDAR_CLIENT_SECRET }}" >> .env
- name: Build Application (${{ matrix.arch }})
run: npm run build:mac -- --${{ matrix.arch }} --publish never
env:
TARGET_ARCH: ${{ matrix.arch }}
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
VITE_NEON_AUTH_URL: ${{ vars.VITE_NEON_AUTH_URL }}
VITE_OPENWHISPR_API_URL: ${{ vars.VITE_OPENWHISPR_API_URL }}
VITE_OPENWHISPR_OAUTH_CALLBACK_URL: ${{ vars.VITE_OPENWHISPR_OAUTH_CALLBACK_URL }}
CSC_IDENTITY_AUTO_DISCOVERY: ${{ github.event_name != 'pull_request' && 'true' || 'false' }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- name: Verify packaged macOS native binaries
run: |
APP_PATH=$(ls -d dist/mac*/OpenWhispr.app | head -n1)
for bin in macos-audio-tap macos-globe-listener macos-fast-paste macos-mic-listener macos-text-monitor macos-media-remote; do
test -x "$APP_PATH/Contents/Resources/bin/$bin" || { echo "Missing in bundle: $bin"; exit 1; }
done
test -x "$APP_PATH/Contents/Resources/bin/MediaRemoteAdapter.framework/Versions/A/MediaRemoteAdapter" || { echo "Missing in bundle: MediaRemoteAdapter.framework"; exit 1; }
test -f "$APP_PATH/Contents/Resources/bin/mediaremote-adapter.pl" || { echo "Missing in bundle: mediaremote-adapter.pl"; exit 1; }
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: macos-${{ matrix.arch }}-build
path: dist/
retention-days: 7
- name: Cleanup Certificates
if: always() && github.event_name != 'pull_request'
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
rm -f $RUNNER_TEMP/build_certificate.p12
rm -f $RUNNER_TEMP/api_key.p8