macOS desktop: install + in-app self-update#35607
Conversation
paths.rs computed the macOS Hermes home as ~/Library/Application Support/ hermes, but nothing else does: hermes_constants.get_hermes_home() (Python), scripts/install.sh, and the Electron desktop's resolveHermesHome() all use ~/.hermes on macOS. The drift meant the Tauri installer wrote the install to one directory and the desktop looked for it in another, so a fresh GUI install never found its backend (the file's own comment warned this exact drift would break things). Use ~/.hermes on macOS to match.
Stage helpers (clone_repo, install_deps, check_python, …) were written for
the monolithic flow and call `exit 1` on failure. Under `--stage`, that
terminated the process before the JSON result frame was printed, so the
installer's parse_stage_result saw "no frame" instead of a clean
{ok:false,...} contract response. Run the stage body in a subshell so an
`exit` only unwinds the subshell and the parent still emits the frame.
…all.ps1)
install.ps1 downloads PortableGit on Windows, but install.sh just printed a
"please install git" hint and exited — so a fresh Mac with no developer tools
(no Xcode CLT → no git) couldn't get past the clone step. check_git now tries
to install git before bailing:
- macOS: Homebrew if present (headless), else `xcode-select --install`
(the CLT prompt also provides the compiler some wheels need), polling for
git to appear.
- Linux: apt/dnf/pacman via sudo when available.
Falls back to the manual instructions only if auto-provision fails.
On Windows the staged Hermes-Setup binary drives updates (quit → hermes
update → hermes desktop --build-only → relaunch). The mac drag-install has no
such binary, so "Update now" previously just printed `hermes update`.
Since there's no venv-shim file lock on POSIX, the desktop can drive the whole
update itself. applyUpdates now, when no staged updater exists on mac/linux:
1. runs `hermes update --yes [--branch <current>]` (backend git pull + deps),
2. runs `hermes desktop --build-only` (OS-aware GUI rebuild) with the
Hermes-managed Node + venv on PATH,
3. spawns a detached swapper that waits for this process to exit, dittos the
freshly built Hermes.app over the running bundle, clears quarantine, and
relaunches.
Degrades to "backend updated — restart to load the new GUI" if the rebuild
fails or there's no .app bundle to swap (dev run, Linux AppImage).
|
Pushed two more commits toward true normie-mac happy-path:
Tested locally: install.sh syntax + git happy-path; Still needs real-install E2E (can't fully exercise here): dragged |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved ✅
Review
Fixes macOS installer HERMES_HOME drift (Tauri was using ~/Library/Application Support/hermes while everything else uses ~/.hermes) and hardens install.sh stage protocol for subshell failure-frame handling.
✅ Looks Good
- Correct fix: Removes the macOS cfg branch in
paths.rsso it falls through to existing~/.hermespath. - Subshell fix: Stage body in subshell so
exit 1only unwinds the subshell and the parent emits{ok:false,...}. - Well-documented: Clear explanation of the two macOS distribution models (drag .dmg vs Tauri installer) with open decision.
- Verified: Drag-install
.dmgworks with proper icon.
Reviewed by Hermes Agent (cron job)
Local verification of the in-app update pathRan the exact commands
So the three steps the mac updater chains all work. Not yet exercised: the full Electron click-through (the "Update now" button driving these + the detached swap/relaunch) on a live dragged app — components proven, glue not GUI-tested. Caveat worth a follow-up (pre-existing
|
Makes the macOS desktop install/update path work end to end. Targets
bb/gui.Changes
Installer/runtime path alignment
paths.rs: the Tauri installer computed macOSHERMES_HOMEas~/Library/Application Support/hermes, but Python (hermes_constants.get_hermes_home()),install.sh, and the Electron app all use~/.hermes. The drift meant the installer wrote to one dir and the desktop read from another. Aligned to~/.hermes.install.shstage protocol--stagebody in a subshell so a stage helper that callsexit 1still emits its JSON result frame instead of terminating before it (the Rust/Electron parser expects a{ok:false,…}frame, not a missing one).git auto-provision (parity with
install.ps1)install.ps1downloads PortableGit on Windows;install.shpreviously just printed a "please install git" hint and exited, so a fresh machine with no developer tools couldn't clone.check_gitnow provisions git first: macOS → Homebrew if present, elsexcode-select --install; Linux → apt/dnf/pacman. Falls back to manual instructions only if that fails.In-app self-update (macOS/Linux)
hermes update. POSIX has no venv-shim file lock, so the desktop now drives the update itself:hermes update --yes [--branch <current>](backend) →hermes desktop --build-only(OS-aware GUI rebuild, with the managed Node + venv on PATH) → a detached swapper waits for the app to exit,dittos the rebuiltHermes.appover the running bundle, clears quarantine, and relaunches. Degrades to "backend updated — restart to load the new GUI" if the rebuild fails or there's no bundle to swap (dev run / AppImage).Verified locally
.dmg(npm run dist:mac:dmg): mounts to a volume withHermes.app+/Applicationsshortcut and the correct icon on both the app and the volume.install.sh --manifest/--stageJSON contract: valid manifest, unknown-stage → exit 2 + frame, failure still emits a frame;check_githappy path..appswap mechanism in isolation (old bundle replaced, no leftover temp dirs).main.cjsparses + lints clean.Not in this PR / follow-ups