From 1e856bb3b711d45a822afaa90781d229b7c31d45 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 12 Jun 2026 01:55:36 -0400 Subject: [PATCH 1/2] ci(release): build macOS and Linux portable artifacts Add mac (.dmg + .zip, x64/arm64) and linux (AppImage, x64) targets to electron-builder alongside the existing Windows portable .exe. Convert the release workflow to a 3-OS matrix that builds each platform on its native runner, then aggregates all artifacts into one GitHub Release with a single combined SHA256SUMS.txt. Document per-platform downloads, the macOS Gatekeeper workaround, and Linux AppImage usage in the README. No native deps (node:sqlite), so each runner just bundles the matching Electron binary; no per-platform native rebuild. --- .github/workflows/release.yml | 96 ++++++++++++++++++++++--------- README.md | 34 +++++++++-- apps/desktop/electron-builder.yml | 36 +++++++++++- 3 files changed, 130 insertions(+), 36 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b345d7f..ee0277c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,12 @@ name: release -# Build a Windows portable .exe and publish it as a GitHub Release whenever a -# v* tag is pushed. Example: `git tag v0.1.0 && git push --tags`. +# Build portable desktop binaries for Windows, macOS, and Linux and publish them +# as a single GitHub Release whenever a v* tag is pushed. +# Example: `git tag v0.1.0 && git push --tags`. +# +# Each OS builds on its own native runner (no native deps to cross-rebuild — the +# app uses node:sqlite), uploads its binaries as workflow artifacts, and a final +# `publish` job collects them, writes one combined SHA256SUMS.txt, and publishes. on: push: @@ -14,8 +19,19 @@ permissions: contents: write jobs: - build-windows: - runs-on: windows-latest + build: + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + name: windows + - os: macos-latest + name: macos + - os: ubuntu-latest + name: linux + + runs-on: ${{ matrix.os }} steps: - name: Checkout @@ -44,7 +60,7 @@ jobs: - name: Build shared package run: pnpm -C packages/shared build - # Gate the release on a green build: never publish a .exe that fails + # Gate the release on a green build: never publish a binary that fails # typecheck or tests. Runs after services/shared are built so the desktop # typecheck can resolve their emitted .d.ts. - name: Typecheck (all packages) @@ -53,42 +69,66 @@ jobs: - name: Test (all packages) run: pnpm -r test - - name: Package portable .exe (electron-vite + electron-builder) + - name: Package desktop app (electron-vite + electron-builder) env: - # No code signing on v0.1 — SmartScreen warning is documented in the README. + # No code signing — SmartScreen (Windows) / Gatekeeper (macOS) warnings + # are documented in the README. electron-builder targets the host OS. CSC_IDENTITY_AUTO_DISCOVERY: 'false' - # --publish never: electron-builder only BUILDS the .exe. Publishing to - # the GitHub Release is done by the softprops step below. Without this, - # a defined tag makes electron-builder try to self-publish and fail on - # repository detection. + # --publish never: electron-builder only BUILDS the binaries. Publishing + # to the GitHub Release is the dedicated `publish` job below. Without this, + # a defined tag makes electron-builder try to self-publish and fail. run: pnpm -C apps/desktop exec electron-vite build && pnpm -C apps/desktop exec electron-builder --publish never - # Publish a checksum file so users can verify the unsigned download's - # integrity (`Get-FileHash file.exe -Algorithm SHA256` and compare). - - name: Generate SHA-256 checksums - shell: pwsh - run: | - $lines = Get-ChildItem apps/desktop/dist/*.exe | ForEach-Object { - "$((Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()) $($_.Name)" - } - $lines | Set-Content -Encoding ascii apps/desktop/dist/SHA256SUMS.txt - Get-Content apps/desktop/dist/SHA256SUMS.txt - - - name: Upload build artifact (for manual workflow_dispatch runs) - if: github.event_name == 'workflow_dispatch' + # Hand the freshly built binaries off to the publish job. Distributables + # only (electron-builder also drops blockmaps / unpacked dirs we don't ship). + - name: Upload build artifacts uses: actions/upload-artifact@v7 with: - name: StarcallOS-portable-windows - path: apps/desktop/dist/*.exe + name: dist-${{ matrix.name }} + path: | + apps/desktop/dist/*.exe + apps/desktop/dist/*.dmg + apps/desktop/dist/*.zip + apps/desktop/dist/*.AppImage if-no-files-found: error + publish: + needs: build + runs-on: ubuntu-latest + + steps: + - name: Download all platform artifacts + uses: actions/download-artifact@v5 + with: + # All dist-* artifacts flattened into one directory. + pattern: dist-* + merge-multiple: true + path: dist + + - name: List collected artifacts + run: ls -lh dist + + # One combined checksum file across every platform so users can verify + # the unsigned download's integrity (e.g. `shasum -a 256 -c SHA256SUMS.txt` + # on macOS/Linux, or `Get-FileHash` on Windows). + - name: Generate SHA-256 checksums + run: | + cd dist + # Exclude the output file itself from the glob (no spaces in artifact names). + files=$(ls | grep -v '^SHA256SUMS.txt$') + sha256sum $files > SHA256SUMS.txt + cat SHA256SUMS.txt + - name: Publish to GitHub Release (for tag pushes) if: startsWith(github.ref, 'refs/tags/v') uses: softprops/action-gh-release@v3 with: files: | - apps/desktop/dist/*.exe - apps/desktop/dist/SHA256SUMS.txt + dist/*.exe + dist/*.dmg + dist/*.zip + dist/*.AppImage + dist/SHA256SUMS.txt generate_release_notes: true draft: false prerelease: false diff --git a/README.md b/README.md index 3964c36..86e26d1 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,32 @@ clinical guidelines, language grammars, internal docs. ## Download -Get the latest build from the **[Releases page](https://github.com/ericckzhou/StarcallOS/releases/latest)** — a single portable `.exe` (Windows x64) that runs without installation. +Get the latest build from the **[Releases page](https://github.com/ericckzhou/StarcallOS/releases/latest)** — a portable download for each platform that runs without installation: -> Because the build is unsigned, Windows may show a *"Windows protected your PC"* SmartScreen dialog on first launch. Click **More info → Run anyway**. +| Platform | File | Notes | +| --- | --- | --- | +| **Windows** (x64) | `StarcallOS-*-portable-x64.exe` | self-extracting portable `.exe` | +| **macOS** (Apple Silicon / Intel) | `StarcallOS-*-arm64.dmg` / `StarcallOS-*-x64.dmg` | also a `.zip` of the `.app` if you prefer no disk image | +| **Linux** (x64) | `StarcallOS-*-x64.AppImage` | `chmod +x` and run | -**Verify your download (optional).** Each release ships a `SHA256SUMS.txt`. Confirm the `.exe` wasn't corrupted or tampered with in transit: +> **Windows** — because the build is unsigned, Windows may show a *"Windows protected your PC"* SmartScreen dialog on first launch. Click **More info → Run anyway**. + +> **macOS** — the app is unsigned and un-notarized, so Gatekeeper blocks it on first launch (*"StarcallOS can't be opened"*). Right-click the app → **Open** → **Open**, or clear the quarantine flag: `xattr -dr com.apple.quarantine /Applications/StarcallOS.app`. + +> **Linux** — make the AppImage executable (`chmod +x StarcallOS-*-x64.AppImage`) then run it. If it won't start, your distro may lack FUSE; extract and run with `./StarcallOS-*-x64.AppImage --appimage-extract-and-run`. + +**Verify your download (optional).** Each release ships a `SHA256SUMS.txt` covering every platform's binaries. Confirm your download wasn't corrupted or tampered with in transit: ```powershell +# Windows (PowerShell) Get-FileHash StarcallOS-*-portable-x64.exe -Algorithm SHA256 ``` +```sh +# macOS / Linux +shasum -a 256 -c SHA256SUMS.txt # checks every file listed +``` + Compare the printed hash against the matching line in `SHA256SUMS.txt` — they should be identical. Add an LLM key in **Settings** if you want enrichment and grading (or skip — extraction works with zero keys), drop a PDF in, promote a candidate. @@ -216,7 +232,7 @@ Each layer has a single responsibility and a single direction of dependency. See ## Build from source -If you don't want to download the prebuilt `.exe`, you can run the dev shell or +If you don't want to download a prebuilt binary, you can run the dev shell or produce your own portable build: ```sh @@ -225,14 +241,20 @@ pnpm install pnpm -C packages/shared build && pnpm -C packages/services build pnpm -C apps/desktop dev # hot-reload dev shell # or -pnpm -C apps/desktop dist # produces apps/desktop/dist/StarcallOS-*-portable-x64.exe +pnpm -C apps/desktop dist # packages for your current OS into apps/desktop/dist/ ``` +`dist` builds for whichever OS you run it on: a portable `.exe` on Windows, a +`.dmg` + `.zip` on macOS, an `.AppImage` on Linux. (There are no native +dependencies — the app uses `node:sqlite` — so packaging is just bundling the +matching Electron binary; no per-platform native rebuild.) + Requirements: Node **22.5+**, pnpm 11+. The app uses the built-in `node:sqlite` module (no native bindings), which is experimental and only available on Node 22.5 or newer — older Node versions cannot run it. On Windows, packaging a portable `.exe` locally needs either an elevated shell or Developer Mode enabled (electron-builder -unpacks signing tooling with symlinks). Otherwise let CI build it for you on tag push. +unpacks signing tooling with symlinks). The tagged-release CI builds all three +platforms on their native runners and publishes them to one GitHub Release. ## Contributing diff --git a/apps/desktop/electron-builder.yml b/apps/desktop/electron-builder.yml index baf25dc..8aa982a 100644 --- a/apps/desktop/electron-builder.yml +++ b/apps/desktop/electron-builder.yml @@ -28,5 +28,37 @@ win: - x64 artifactName: ${productName}-${version}-portable-${arch}.${ext} -# v0.1 ships unsigned — the SmartScreen warning is documented in the README. -# To sign later, set CSC_LINK + CSC_KEY_PASSWORD env vars at build time. +# macOS: ship a .dmg (drag-to-install) and a .zip (true portable .app) for both +# Intel (x64) and Apple Silicon (arm64). No native deps means electron-builder +# can cross-pack both arches from a single arm64 runner. Unsigned/un-notarized — +# Gatekeeper workaround is documented in the README. icon.png (512x512+) is +# auto-converted to .icns. +mac: + icon: build/icon.png + category: public.app-category.education + target: + - target: dmg + arch: + - x64 + - arm64 + - target: zip + arch: + - x64 + - arm64 + artifactName: ${productName}-${version}-${arch}.${ext} + +# Linux: AppImage is the single-file portable analog of the Windows portable +# .exe — chmod +x and run, no install. x64 only for now. +linux: + icon: build/icon.png + category: Education + maintainer: Eric Zhou + target: + - target: AppImage + arch: + - x64 + artifactName: ${productName}-${version}-${arch}.${ext} + +# v0.1 ships unsigned on all platforms — the SmartScreen (Windows) and Gatekeeper +# (macOS) warnings are documented in the README. To sign later, set +# CSC_LINK + CSC_KEY_PASSWORD (and Apple notarization creds) at build time. From 4a685f0922ab99a82a4e2b60563a77bcd268f343 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 12 Jun 2026 02:01:43 -0400 Subject: [PATCH 2/2] docs(readme): match Linux AppImage filename (x86_64, not x64) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 86e26d1..e202dda 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ Get the latest build from the **[Releases page](https://github.com/ericckzhou/St | --- | --- | --- | | **Windows** (x64) | `StarcallOS-*-portable-x64.exe` | self-extracting portable `.exe` | | **macOS** (Apple Silicon / Intel) | `StarcallOS-*-arm64.dmg` / `StarcallOS-*-x64.dmg` | also a `.zip` of the `.app` if you prefer no disk image | -| **Linux** (x64) | `StarcallOS-*-x64.AppImage` | `chmod +x` and run | +| **Linux** (x64) | `StarcallOS-*-x86_64.AppImage` | `chmod +x` and run | > **Windows** — because the build is unsigned, Windows may show a *"Windows protected your PC"* SmartScreen dialog on first launch. Click **More info → Run anyway**. > **macOS** — the app is unsigned and un-notarized, so Gatekeeper blocks it on first launch (*"StarcallOS can't be opened"*). Right-click the app → **Open** → **Open**, or clear the quarantine flag: `xattr -dr com.apple.quarantine /Applications/StarcallOS.app`. -> **Linux** — make the AppImage executable (`chmod +x StarcallOS-*-x64.AppImage`) then run it. If it won't start, your distro may lack FUSE; extract and run with `./StarcallOS-*-x64.AppImage --appimage-extract-and-run`. +> **Linux** — make the AppImage executable (`chmod +x StarcallOS-*-x86_64.AppImage`) then run it. If it won't start, your distro may lack FUSE; extract and run with `./StarcallOS-*-x86_64.AppImage --appimage-extract-and-run`. **Verify your download (optional).** Each release ships a `SHA256SUMS.txt` covering every platform's binaries. Confirm your download wasn't corrupted or tampered with in transit: