hermes-agent/scripts
brooklyn! c1f9eb0ec4
fix(desktop): resolve electronDist dynamically + self-heal blocked installs (supersedes #48081/#48082) (#48091)
* fix(desktop): resolve electronDist dynamically + self-heal blocked installs

Supersedes the static-path approach (#48081) and the install-step self-heal
(#48082) with a fix that removes the whole failure class instead of chasing each
symptom. Three distinct faults converged into the June desktop-build outage; this
closes all three.

Root cause (the part #48081 left open — "Gap B"):
  build.electronDist was a static relative path in apps/desktop/package.json, but
  npm workspace hoisting is NOT deterministic — depending on the npm version and
  what else is installed, npm nests the workspace-only electron devDep under
  apps/desktop/node_modules/electron OR hoists it to the repo root. A static path
  matches only one layout, so a clean install intermittently fails with "The
  specified electronDist does not exist". #48081 re-pointed the path at the
  nested layout (correct today) but electron-builder reads electronDist
  STATICALLY, so any future hoist change silently breaks it again — only caught
  by a CI invariant, never self-corrected.

Fix:
- scripts/run-electron-builder.cjs: resolve electron the way Node's runtime does
  — require.resolve("electron/package.json") walks node_modules from the desktop
  project upward and finds electron wherever npm actually put it. The path can
  never drift out of sync with the install layout again, on any OS/npm version.
    * dist present -> pass -c.electronDist=<abs>/dist so electron-builder reuses
      the unpacked runtime (keeps the #38673 fast path that dodges the 26.8.x
      missing-binary re-unpack bug).
    * dist absent  -> omit electronDist; electron-builder fetches Electron itself
      via @electron/get honoring electronVersion + ELECTRON_MIRROR.
  package.json: builder script now runs the wrapper; the static build.electronDist
  is removed (the resolver owns it).
- main.py / install.sh / install.ps1: on a dependency-install failure where the
  electron package staged but its dist is missing (electron's install.js
  process.exit(1) on a blocked/throttled binary download — #47266/#47917/#48021),
  repopulate the dist via electron's downloader (canonical, then npmmirror.com)
  and CONTINUE to the build instead of aborting. npm runs postinstall LAST, so
  the only casualty is electron/dist; bailing here is what made the pack-time
  mirror self-heal unreachable on a blocked network. Hard-fail only when electron
  never staged at all (a genuine dependency error).
- The pack-time mirror fallback now retries the build even when the pre-fetch
  can't populate the dist: the wrapper lets electron-builder download Electron
  itself via the mirror, so the retry is no longer a no-op (it was, when
  electronDist was a static path).

The exact 40.10.2 pin (already on main) keeps the third mode — the native
@electron-internal/extract-zip win32 binding that 40.10.3/40.10.4 ship without a
published prebuild — from recurring.

Tests:
- test_desktop_electron_pin.py: replace the static-path-matches-lockfile
  invariant with contracts that there is no hardcoded electronDist to drift, the
  builder script routes through the resolver, and the resolver uses Node module
  resolution + injects -c.electronDist.
- test_gui_command.py: install-failure self-heal continues to build; genuine
  (electron-never-staged) install failure still hard-fails; pack retries under
  the mirror even when the pre-fetch is blocked.

Salvages/supersedes the overlapping community work in #48003 (sitkarev),
#48012 (omegazheng), #48033 (james47kjv), and #48082.

Co-authored-by: sitkarev <59806492+sitkarev@users.noreply.github.com>
Co-authored-by: omegazheng <zheng@omegasys.eu>
Co-authored-by: james47kjv <220877172+james47kjv@users.noreply.github.com>

* fix(desktop): narrow Electron self-heal to real missing-dist failures

Follow-up on #48091 to remove the remaining misdiagnosis risk from the
installer/build fallback path (#46785 concern): only take the Electron
repair/retry path when Electron's package files are staged and dist is actually
missing/corrupt.

- main.py: add _electron_pkg_staged_missing_dist() and use it to gate install
  failure recovery; fail fast for unrelated npm install errors.
- main.py/install.sh/install.ps1: run cache purge + retry only when dist is
  missing; do not retry unrelated tsc/vite/build failures under an
  Electron-specific narrative.
- install.sh/install.ps1: tighten install-stage self-heal guard to require both
  package.json + install.js and missing dist.
- tests: add coverage that install failure hard-fails when Electron dist already
  exists, and update retry test to reflect the tightened recovery condition.

Validation:
- Python tests: 64 passed
- install.sh-related tests included in the run
- Real mac build on this machine:
  - npm ci at repo root: success
  - cd apps/desktop && npm run pack: success
  - electron-builder packaged darwin arm64 and used custom unpacked Electron dist

* refactor(desktop): trim electron self-heal helpers and comments

Deduplicate mirror-retry into _try_redownload_electron_dist / shell
counterparts; shorten wrapper and install-script commentary without
changing recovery semantics.

---------

Co-authored-by: sitkarev <59806492+sitkarev@users.noreply.github.com>
Co-authored-by: omegazheng <zheng@omegasys.eu>
Co-authored-by: james47kjv <220877172+james47kjv@users.noreply.github.com>
2026-06-17 18:48:35 -05:00
..
lib fix(install): repair existing managed-Node global prefix on re-run 2026-06-14 17:34:11 +07:00
tests fix(install.ps1): trim completion banner + strip em-dash in test 2026-05-16 22:55:12 -07:00
whatsapp-bridge fix(whatsapp): restart stale bridge processes instead of silently reusing them (#44205) 2026-06-11 03:47:29 -07:00
analyze_livetest.py test(tool-search): add live A/B harness, drop checked-in transcripts 2026-05-29 02:04:12 -07:00
benchmark_browser_eval.py perf(browser): route browser_console eval through supervisor's persistent CDP WS (180x faster) (#23226) 2026-05-10 07:37:55 -07:00
build_model_catalog.py codebase: add encoding='utf-8' to all bare open() calls (PLW1514) 2026-05-08 14:27:40 -07:00
build_skills_index.py fix(skills): let ClawHub index build walk past the 12s browse budget (#44500) 2026-06-11 18:03:11 -04:00
check-windows-footguns.py fix(scripts): fix UnicodeEncodeError in footgun checker on Windows 2026-05-16 23:05:27 -07:00
check_subprocess_stdin.py fix: keep interactive OAuth setup-token inheriting stdin 2026-06-08 22:46:57 -07:00
contributor_audit.py chore: release v0.16.0 (2026.6.5) (#40206) 2026-06-05 17:55:43 -07:00
discord-voice-doctor.py codebase: add encoding='utf-8' to all bare open() calls (PLW1514) 2026-05-08 14:27:40 -07:00
docker_config_migrate.py fix(docker): run config migrations during container boot (salvage #35508) (#36627) 2026-06-04 11:11:27 +10:00
hermes-gateway fix: prevent systemd restart storm on gateway connection failure 2026-03-21 09:26:39 -07:00
install.cmd fix(docs): update all install instructions everywhere 2026-06-04 21:07:45 -04:00
install.ps1 fix(desktop): resolve electronDist dynamically + self-heal blocked installs (supersedes #48081/#48082) (#48091) 2026-06-17 18:48:35 -05:00
install.sh fix(desktop): resolve electronDist dynamically + self-heal blocked installs (supersedes #48081/#48082) (#48091) 2026-06-17 18:48:35 -05:00
install_psutil_android.py fix(android): reject unsafe tar members in psutil compatibility installer 2026-05-28 02:36:09 -07:00
keystroke_diagnostic.py docs: add Windows-Specific Quirks section to hermes-agent skill + keystroke diagnostic 2026-05-08 14:27:40 -07:00
kill_modal.sh refactor: replace swe-rex with native Modal SDK for Modal backend (#3538) 2026-03-28 11:21:44 -07:00
lint_diff.py feat(ci): add typecheck (warnings only in CI) 2026-05-06 10:58:12 -04:00
LIVETEST_README.md test(tool-search): add live A/B harness, drop checked-in transcripts 2026-05-29 02:04:12 -07:00
profile-tui.py Merge remote-tracking branch 'origin/main' into fix/bundle-size 2026-05-11 16:01:04 -04:00
release.py fix(desktop): resolve electronDist to the actual electron install location (#48081) 2026-06-17 18:08:01 -05:00
run_tests.sh fix(ci): remove pytest-timeout, use per-file timeout only 2026-06-12 13:42:42 -04:00
run_tests_parallel.py fix(tests): remove no-longer-needed forensics 2026-06-12 13:42:42 -04:00
sample_and_compress.py refactor: codebase-wide lint cleanup — unused imports, dead code, and inefficient patterns (#5821) 2026-04-07 10:25:31 -07:00
setup_open_webui.sh fix(install): use resolved python variable in setup_open_webui.sh 2026-05-16 22:54:22 -07:00
tool_search_livetest.py test(tool-search): redact secrets from harness transcripts + console 2026-05-29 02:04:12 -07:00