From 3b86003a6b45c532617a682e0a781d2469acdaa9 Mon Sep 17 00:00:00 2001 From: aaddrick Date: Thu, 14 May 2026 06:04:42 -0400 Subject: [PATCH] fix(deps): pin electron@41.5.0 to match upstream app.asar ABI Re-add the exact Electron version pin that #586 had, hoisted to a named local in scripts/setup/dependencies.sh so the next bump is intentional. Upstream Claude Desktop's app.asar binds to a specific V8/NAPI ABI, Chromium pairing, and node-pty native surface; running a different Electron major against it is unsupported and was the reproducibility hole left when this PR dropped the ^41 pin. Also: - Wrap node fetch-electron-binary.js in a 2-attempt retry so a transient 503 from electron's CDN doesn't red the whole build. - Whitelist supported archs (x64, arm64, armv7l, ia32) with an actionable error in fetch-electron-binary.js, instead of 404'ing on electron's release server for exotic-arch hosts. - Document ELECTRON_MIRROR / ELECTRON_CUSTOM_DIR in docs/BUILDING.md and clarify that ELECTRON_CACHE is NOT honored by @electron/get (the original PR body's claim was wrong). Refs #584. Addresses self-review feedback on #587. Co-Authored-By: Claude --- docs/BUILDING.md | 11 ++++++++++ scripts/setup/dependencies.sh | 29 +++++++++++++++++++------- scripts/setup/fetch-electron-binary.js | 8 +++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 5bf6dc9..638b80b 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -41,6 +41,17 @@ The build script automatically detects your distribution and selects the appropr | Arch Linux | `.AppImage` (via AUR) | yay/paru | | Other | `.AppImage` | - | +## Build Environment Variables + +The build pulls the Electron prebuilt binary from `github.com/electron/electron/releases` via `@electron/get`. Two upstream environment variables let you redirect that fetch: + +- `ELECTRON_MIRROR` — base URL to fetch Electron releases from instead of GitHub. Useful for mirrors or local proxies. Example: `ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`. +- `ELECTRON_CUSTOM_DIR` — overrides the path segment after the mirror. Defaults to `v{version}`. + +The cache location is fixed at `~/.cache/electron/` (resolved by `@electron/get` via `envPaths`) and is reused across builds. `ELECTRON_CACHE` is **not** read by `@electron/get` — set `ELECTRON_MIRROR` if you need to avoid the public CDN. + +The pinned Electron version lives in `scripts/setup/dependencies.sh` (`electron_version`) and must match `build-reference/app-extracted/package.json` — the upstream Claude Desktop `app.asar` is built against a specific Electron major and running a different one is unsupported. + ## Installing the Built Package ### For .deb packages (Debian/Ubuntu) diff --git a/scripts/setup/dependencies.sh b/scripts/setup/dependencies.sh index 1b58bdd..3f39425 100644 --- a/scripts/setup/dependencies.sh +++ b/scripts/setup/dependencies.sh @@ -198,6 +198,13 @@ setup_nodejs() { setup_electron_asar() { section_header 'Electron & Asar Handling' + # Pin Electron to the exact version upstream Claude Desktop ships + # (build-reference/app-extracted/package.json). The shipped app.asar + # binds to specific V8/NAPI ABI, Chromium pairing, and node-pty + # native surface — running a different Electron major against this + # asar is unsupported. Bump when upstream bumps. + local electron_version='41.5.0' + echo "Ensuring local Electron and Asar installation in $work_dir..." cd "$work_dir" || exit 1 @@ -214,9 +221,9 @@ setup_electron_asar() { [[ ! -f $asar_bin_path ]] && echo 'Asar binary not found.' && install_needed=true if [[ $install_needed == true ]]; then - echo "Installing Electron and Asar locally into $work_dir..." + echo "Installing electron@${electron_version} and Asar locally into $work_dir..." if ! npm install --no-save \ - electron @electron/asar @electron/get extract-zip; then + "electron@${electron_version}" @electron/asar @electron/get extract-zip; then echo 'Failed to install Electron and/or Asar locally.' >&2 cd "$project_root" || exit 1 exit 1 @@ -226,13 +233,21 @@ setup_electron_asar() { # electron@42+ no longer ships a postinstall script that fetches # the prebuilt binary into dist/. If npm didn't populate it, fetch # the matching binary explicitly via @electron/get. See #584. + # Retry once on transient CDN failures (503, network drops). if [[ ! -d $electron_dist_path ]]; then echo 'Electron postinstall did not populate dist/; fetching binary explicitly...' - if ! node "$project_root/scripts/setup/fetch-electron-binary.js"; then - echo 'Failed to fetch Electron binary via @electron/get.' >&2 - cd "$project_root" || exit 1 - exit 1 - fi + local fetch_attempts=0 + while ! node "$project_root/scripts/setup/fetch-electron-binary.js"; do + fetch_attempts=$((fetch_attempts + 1)) + if (( fetch_attempts >= 2 )); then + echo 'Failed to fetch Electron binary via @electron/get after 2 attempts.' >&2 + echo 'For air-gapped or mirrored builds set ELECTRON_MIRROR or ELECTRON_CUSTOM_DIR; see docs/BUILDING.md.' >&2 + cd "$project_root" || exit 1 + exit 1 + fi + echo "Retrying Electron binary fetch (attempt $((fetch_attempts + 1))/2)..." + sleep 2 + done fi else echo 'Local Electron distribution and Asar binary already present.' diff --git a/scripts/setup/fetch-electron-binary.js b/scripts/setup/fetch-electron-binary.js index b9e8c30..e398863 100644 --- a/scripts/setup/fetch-electron-binary.js +++ b/scripts/setup/fetch-electron-binary.js @@ -40,6 +40,14 @@ async function main() { // except 'arm' which electron publishes as 'armv7l'. const arch = process.arch === 'arm' ? 'armv7l' : process.arch; + const supportedArchs = ['x64', 'arm64', 'armv7l', 'ia32']; + if (!supportedArchs.includes(arch)) { + throw new Error( + `Unsupported architecture: ${arch}. ` + + `Electron publishes Linux binaries for ${supportedArchs.join(', ')}.`, + ); + } + const { downloadArtifact } = require('@electron/get'); const extractZip = require('extract-zip');