Add Windows Electron desktop support (#1093)

* fix: make upstream sync actions target the selected remote

Ensure fetch and pull actually honor upstream selection so fork maintenance works from the Git sidebar, and surface upstream branch status alongside the primary origin-tracking indicators.

* feat: add Windows Electron desktop foundation

* fix(electron): stabilize Windows desktop packaging

* fix(electron): stabilize Windows desktop chrome

Use native Windows titlebar behavior with an Alt-accessible hidden menu, and harden Windows dev command launching so the desktop app follows platform conventions.

* fix(electron): stabilize Windows dev startup

* fix(electron): clarify desktop artifact names

* fix(electron): harden Windows desktop release and launch

* fix(electron): address Windows release review

* fix(electron): point updater and release links to org repo

* Fix Windows settings persistence fallback

* Fix Windows Electron dev startup

* Add Windows Electron window controls

* Fix Windows Electron install and opencode launch

* fix: resolve git status for repositories without upstream

Fixes repository detection stuck on Checking repository
Handles git status when no upstream is configured
Adds regression coverage for git status loading

* Add Windows app menu button

* fix: preserve file editor line endings

* ci: add desktop release smoke workflow

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Dave Otero
2026-05-26 18:13:59 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent cc7969ac00
commit becd240168
59 changed files with 2260 additions and 246 deletions
+224
View File
@@ -0,0 +1,224 @@
name: Desktop Release Build Smoke
on:
workflow_dispatch:
inputs:
repository:
description: Repository to checkout, for example openchamber/openchamber or daveotero/openchamber
required: false
default: openchamber/openchamber
type: string
ref:
description: Git ref to build (branch, tag, or sha)
required: true
default: feat/windows-desktop-app
type: string
build_macos:
description: Build signed/notarized macOS Electron artifacts
required: false
default: true
type: boolean
build_windows:
description: Build Windows Electron installer artifacts
required: false
default: true
type: boolean
retention_days:
description: Artifact retention days
required: false
default: "7"
type: choice
options:
- "1"
- "3"
- "7"
- "14"
permissions:
contents: read
jobs:
build-macos-electron:
if: ${{ inputs.build_macos }}
name: Build macOS Electron (${{ matrix.arch }})
runs-on: macos-26
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-apple-darwin
arch: arm64
platform: darwin-aarch64
- target: x86_64-apple-darwin
arch: x64
platform: darwin-x86_64
steps:
- name: Checkout selected ref
uses: actions/checkout@v4
with:
repository: ${{ inputs.repository || github.repository }}
ref: ${{ inputs.ref || github.ref }}
- name: Setup bun
uses: oven-sh/setup-bun@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Install Apple Certificate
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/electron-signing.keychain-db
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
security import $RUNNER_TEMP/certificate.p12 \
-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:,codesign: \
-s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
- name: Build Electron app
working-directory: packages/electron
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
ELECTRON_BUILDER_ARCH: ${{ matrix.arch }}
run: |
bun run build:web-assets
bun run bundle:main
# npmRebuild=false in package.json, so electron-builder won't
# recompile native deps on its own. Rebuild against the target
# Electron ABI before packaging, matching the release workflow.
bun run rebuild:native
bunx electron-builder --mac --${{ matrix.arch }} --publish=never
- name: Verify signature + entitlements + notarization
run: |
set -euo pipefail
APP_DIR="packages/electron/dist/mac"
[ -d "packages/electron/dist/mac-arm64" ] && APP_DIR="packages/electron/dist/mac-arm64"
APP_PATH=$(find "$APP_DIR" -maxdepth 2 -name "*.app" -print -quit)
if [ -z "$APP_PATH" ]; then
echo "Error: .app not found under packages/electron/dist/mac*"
ls -la packages/electron/dist/
exit 1
fi
echo "Verifying $APP_PATH"
codesign -vv --deep --strict "$APP_PATH"
CS_INFO=$(codesign -dv --verbose=4 "$APP_PATH" 2>&1)
echo "$CS_INFO"
if ! echo "$CS_INFO" | grep -q "flags=.*runtime"; then
echo "Error: hardened runtime flag missing"
exit 1
fi
xcrun stapler validate "$APP_PATH"
ENTITLEMENTS=$(codesign -d --entitlements :- "$APP_PATH" 2>&1 || true)
if echo "$ENTITLEMENTS" | grep -q "com.apple.security.app-sandbox"; then
echo "Error: app sandbox entitlement is present"
exit 1
fi
for key in \
com.apple.security.cs.allow-jit \
com.apple.security.cs.allow-unsigned-executable-memory \
com.apple.security.cs.disable-library-validation
do
if ! echo "$ENTITLEMENTS" | grep -q "<key>$key</key>"; then
echo "Error: required entitlement missing: $key"
exit 1
fi
done
- name: Upload macOS installable artifacts
uses: actions/upload-artifact@v4
with:
name: desktop-release-smoke-macos-${{ matrix.arch }}
path: |
packages/electron/dist/*.dmg
packages/electron/dist/*.zip
packages/electron/dist/*.blockmap
packages/electron/dist/latest-mac.yml
if-no-files-found: error
retention-days: ${{ fromJSON(inputs.retention_days) }}
build-windows-electron:
if: ${{ inputs.build_windows }}
name: Build Windows Electron (x64)
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- arch: x64
target: x86_64-pc-windows-msvc
platform: win32-x64
steps:
- name: Checkout selected ref
uses: actions/checkout@v4
with:
repository: ${{ inputs.repository || github.repository }}
ref: ${{ inputs.ref || github.ref }}
- name: Setup bun
uses: oven-sh/setup-bun@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Build web assets
working-directory: packages/electron
run: bun run build:web-assets
- name: Bundle main process
working-directory: packages/electron
run: bun run bundle:main
- name: Rebuild native modules
working-directory: packages/electron
shell: bash
# npmRebuild=false in package.json, so electron-builder won't
# recompile native deps on its own. Rebuild against the target
# Electron ABI before packaging, matching the release workflow.
run: node ./scripts/rebuild-native.mjs
- name: Build Windows app
working-directory: packages/electron
shell: bash
run: node ./scripts/package.mjs --win --${{ matrix.arch }} --publish=never
- name: Upload Windows installable artifacts
uses: actions/upload-artifact@v4
with:
name: desktop-release-smoke-windows-${{ matrix.arch }}
path: |
packages/electron/dist/*.exe
packages/electron/dist/*.blockmap
packages/electron/dist/latest.yml
if-no-files-found: error
retention-days: ${{ fromJSON(inputs.retention_days) }}
+75 -5
View File
@@ -185,7 +185,7 @@ jobs:
# target Electron ABI before packaging, otherwise better-sqlite3/
# node-pty/bun-pty crash on require inside the packaged app.
bun run rebuild:native
./node_modules/.bin/electron-builder --mac --${{ matrix.arch }} --publish=never
bunx electron-builder --mac --${{ matrix.arch }} --publish=never
- name: Verify signature + entitlements + notarization
run: |
@@ -275,6 +275,68 @@ jobs:
path: packages/electron/dist/latest-mac.yml
retention-days: 1
build-desktop-electron-windows:
needs: create-release
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- arch: x64
target: x86_64-pc-windows-msvc
platform: win32-x64
steps:
- uses: actions/checkout@v4
- name: Setup bun
uses: oven-sh/setup-bun@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Build web assets
working-directory: packages/electron
run: bun run build:web-assets
- name: Bundle main process
working-directory: packages/electron
run: bun run bundle:main
- name: Rebuild native modules
working-directory: packages/electron
shell: bash
# npmRebuild=false in package.json, so electron-builder won't
# recompile native deps on its own — we must rebuild against the
# target Electron ABI before packaging.
run: node ./scripts/rebuild-native.mjs
- name: Build Windows app
working-directory: packages/electron
shell: bash
run: node ./scripts/package.mjs --win --${{ matrix.arch }} --publish=never
- name: Upload installer to release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.create-release.outputs.version }}
files: |
packages/electron/dist/*.exe
packages/electron/dist/*.blockmap
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload update manifest as artifact
uses: actions/upload-artifact@v4
with:
name: latest-yml-${{ matrix.target }}
path: packages/electron/dist/latest.yml
retention-days: 1
repackage-electron-as-tauri-update:
needs: [create-release, build-desktop-electron-macos]
runs-on: macos-26
@@ -449,7 +511,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
combine-electron-manifests:
needs: [create-release, build-desktop-electron-macos]
needs: [create-release, build-desktop-electron-macos, build-desktop-electron-windows]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -465,6 +527,12 @@ jobs:
pattern: latest-yml-*-apple-darwin
path: artifacts
- name: Download Windows latest.yml
uses: actions/download-artifact@v4
with:
pattern: latest-yml-*-pc-windows-*
path: artifacts
- name: Finalize combined latest-mac.yml
env:
LATEST_YML_DIR: ${{ github.workspace }}/artifacts
@@ -472,16 +540,18 @@ jobs:
OPENCHAMBER_VERSION: ${{ needs.create-release.outputs.version }}
run: node packages/electron/scripts/finalize-latest-yml.mjs
- name: Upload combined latest-mac.yml to release
- name: Upload combined manifests to release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.create-release.outputs.version }}
files: ${{ runner.temp }}/latest-mac.yml
files: |
${{ runner.temp }}/latest-mac.yml
${{ runner.temp }}/latest.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
finalize-release:
needs: [create-release, build-desktop-electron-macos, repackage-electron-as-tauri-update, publish-npm, combine-manifests, combine-electron-manifests]
needs: [create-release, build-desktop-electron-macos, build-desktop-electron-windows, repackage-electron-as-tauri-update, publish-npm, combine-manifests, combine-electron-manifests]
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}