mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-19 10:02:16 +00:00
* 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>
57 lines
1.8 KiB
JavaScript
57 lines
1.8 KiB
JavaScript
"use strict"
|
|
|
|
// Resolve electronDist at runtime (#38673, #47917): electron-builder 26.8.x can
|
|
// re-unpack a broken Electron.app; reusing the installed dist dodges that.
|
|
// npm workspace hoisting is non-deterministic — require.resolve finds electron
|
|
// wherever it landed. Dist present → -c.electronDist=<abs>/dist; absent → let
|
|
// electron-builder fetch via @electron/get (electronVersion + ELECTRON_MIRROR).
|
|
|
|
const fs = require("node:fs")
|
|
const path = require("node:path")
|
|
const { spawnSync } = require("node:child_process")
|
|
|
|
function electronDistDir() {
|
|
try {
|
|
return path.join(path.dirname(require.resolve("electron/package.json")), "dist")
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
function distBinary(dist) {
|
|
if (process.platform === "darwin") {
|
|
return path.join(dist, "Electron.app", "Contents", "MacOS", "Electron")
|
|
}
|
|
if (process.platform === "win32") {
|
|
return path.join(dist, "electron.exe")
|
|
}
|
|
return path.join(dist, "electron")
|
|
}
|
|
|
|
function electronBuilderCli() {
|
|
const pkgJson = require.resolve("electron-builder/package.json")
|
|
const bin = require(pkgJson).bin
|
|
const rel = typeof bin === "string" ? bin : bin["electron-builder"]
|
|
return path.join(path.dirname(pkgJson), rel)
|
|
}
|
|
|
|
const dist = electronDistDir()
|
|
const args = []
|
|
if (dist && fs.existsSync(distBinary(dist))) {
|
|
args.push(`-c.electronDist=${dist}`)
|
|
} else {
|
|
console.warn(
|
|
"[run-electron-builder] no local electron dist; electron-builder will fetch " +
|
|
"via @electron/get (electronVersion + ELECTRON_MIRROR)."
|
|
)
|
|
}
|
|
args.push(...process.argv.slice(2))
|
|
|
|
const result = spawnSync(process.execPath, [electronBuilderCli(), ...args], {
|
|
stdio: "inherit",
|
|
})
|
|
if (result.error) {
|
|
console.error(`[run-electron-builder] spawn failed: ${result.error.message}`)
|
|
process.exit(1)
|
|
}
|
|
process.exit(result.status == null ? 1 : result.status)
|