hermes-agent/apps/desktop/electron
Teknium 6495ef82f7 fix(desktop): hand-off hardening - fail-closed gates, truthful completion, progress UI, result surfacing
Review feedback on the #82328/#82366 hand-off, all four points plus the
missing progress GUI:

1. FAIL CLOSED. Both preflight gates aborted-open: a Desktop still alive
   after 30s proceeded anyway, and a shim locked after 20s proceeded
   with --force - both mutate a potentially locked install (the exact
   Access-denied brick class). Now: desktop-alive -> exit 4, nothing
   changed; shim-locked -> exit 5, nothing changed. Both relaunch the
   Desktop so the user is never stranded.

2. TRUTHFUL COMPLETION. `hermes update` treats a Desktop GUI build
   failure as non-fatal (warns, exits 0) - correct for CLI use, a lie
   for a Desktop-driven update that then relaunches the OLD exe as
   "success". The script now detects the warning in the update output,
   retries the build once (`hermes desktop --force-build --build-only`),
   and exits 6 with an honest message when it still fails.

3. MARKER OWNERSHIP. Cleanup now removes the marker only while OUR pid
   still owns it - a handoff partner that rewrote the marker keeps its
   claim (same rule as UpdateLock.release).

4. RESULT SURFACING. The script writes .hermes-update-result.json on
   every exit path (ok, exit_code, message, branch, finished_at). New
   electron/handoff-result.ts consumes it exactly once at the boot
   update-gate: success logs, failure shows a real dialog pointing at
   desktop-update-handoff.log. Stale (>30min) and malformed results are
   consumed silently. Previously a failed detached update was
   indistinguishable from "nothing happened" - the exact live report
   that triggered this work.

5. PROGRESS UI. The old Tauri updater showed a window; the script ran
   in a hidden console with zero feedback. It now shows a WinForms
   progress window (marquee bar + streaming log) pumped via DoEvents
   during the update; -NoUi keeps tests/headless sessions clean, and a
   WinForms-unavailable session degrades to log-only.

Also: subprocess execution moved from Start-Process (ExitCode
unreliably $null under PS 5.1 even with the Handle workaround -
observed live: happy path reported "failed (exit )") to
System.Diagnostics.Process with synchronous stdout pumping, which
keeps the UI alive and the exit code real.

E2E on a real Windows box, sandbox HERMES_HOME + compiled fake
hermes.exe, all five paths:
- happy: exit 0, result {ok:true, "Update complete."}
- shim held open via O_RDWR: exit 5, nothing mutated, honest result
- desktop pid alive (60s ping child): exit 4 after the 30s gate
- update exits 0 printing "Desktop build failed" + rebuild fails:
  exit 6, result names the stale build and the retry command
- foreign-owned marker: overwritten by step-0 claim, removed as owner;
  ownership check verified in the cleanup path
vitest 18/18 (5 new handoff-result tests), typecheck 3 projects clean,
eslint clean, PS 5.1 parse + footguns + ASCII-only clean.

Remaining known gap (deliberate): the full click-to-relaunch lifecycle
through a REAL Desktop build still needs one live Windows verification
after this lands - tracked in the PR body.
2026-08-09 01:26:14 -07:00
..
active-runtime-state.test.ts fix(desktop): launch a usable active runtime without a bootstrap marker 2026-07-26 16:12:14 -05:00
active-runtime-state.ts fix(desktop): launch a usable active runtime without a bootstrap marker 2026-07-26 16:12:14 -05:00
backend-child.ts fix(update): make orphan-backend reap tree-aware + drain Desktop update trees without pre-signalling 2026-08-08 20:01:03 -07:00
backend-command.test.ts
…
backend-command.ts
…
backend-connection-state.test.ts
…
backend-connection-state.ts
…
backend-env.test.ts fmt(js): `npm run fix` on merge (#76547) 2026-08-02 03:33:09 +00:00
backend-env.ts fix(desktop,install): keep bundled Node ahead of system Node on Windows 2026-08-01 20:09:35 -04:00
backend-health.test.ts fmt(js): `npm run fix` on merge (#71740) 2026-07-26 04:11:26 +00:00
backend-health.ts fix(desktop): read a readiness-probe 401 by whether it was credentialed 2026-07-25 21:52:26 -05:00
backend-probes.test.ts fix(desktop): raise backend probe timeout and retry on timeout 2026-07-29 13:59:11 +05:30
backend-probes.ts fix(desktop): widen probe-budget fix to sibling boot-path probes 2026-07-29 16:52:53 +05:30
backend-ready.test.ts
…
backend-ready.ts
…
backend-start-failure.test.ts fix(desktop): latch a confirmed remote reauth failure so the overlay stays clickable 2026-07-25 21:52:45 -05:00
backend-start-failure.ts fix(desktop): latch a confirmed remote reauth failure so the overlay stays clickable 2026-07-25 21:52:45 -05:00
bootstrap-platform.test.ts
…
bootstrap-platform.ts
…
bootstrap-repair-guard.test.ts fix(desktop): break renderer-led reinstall loop on transient backend stalls 2026-07-31 22:33:53 -07:00
bootstrap-repair-guard.ts fmt(js): `npm run fix` on merge (#76404) 2026-08-01 20:45:40 +00:00
bootstrap-runner.test.ts fmt(js): `npm run fix` on merge (#67749) 2026-07-19 23:42:14 +00:00
bootstrap-runner.ts fmt(js): `npm run fix` on merge (#67749) 2026-07-19 23:42:14 +00:00
connection-apply.test.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
connection-apply.ts feat(desktop): add "Connect to existing Hermes" option to first-run onboarding 2026-07-24 12:55:06 -05:00
connection-config.test.ts fix(desktop): reject reserved remote profile names 2026-08-01 14:30:16 -07:00
connection-config.ts fix(desktop): reject reserved remote profile names 2026-08-01 14:30:16 -07:00
crash-forensics.test.ts fix(desktop): record main-process faults in desktop.log 2026-07-27 13:41:59 -05:00
crash-forensics.ts fix(desktop): record main-process faults in desktop.log 2026-07-27 13:41:59 -05:00
dashboard-token.test.ts
…
dashboard-token.ts
…
desktop-electron-pin.test.ts
…
desktop-installation.test.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
desktop-installation.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
desktop-uninstall.test.ts
…
desktop-uninstall.ts
…
dev-cdp.test.ts feat(desktop): on by default for dev-server runs 2026-07-27 23:52:33 -05:00
dev-cdp.ts feat(desktop): on by default for dev-server runs 2026-07-27 23:52:33 -05:00
embed-referer.ts
…
entitlements.mac.inherit.plist build(desktop): declare camera usage for signed macOS builds 2026-07-28 13:40:44 -05:00
entitlements.mac.plist build(desktop): declare camera usage for signed macOS builds 2026-07-28 13:40:44 -05:00
event-dedupe.test.ts fix(desktop): de-dupe cross-window cues so peers don't spam 2026-07-20 18:33:14 -05:00
event-dedupe.ts refactor(desktop): tidy the cross-window deduper 2026-07-20 18:36:05 -05:00
find-git-bash.test.ts style(desktop): apply eslint/prettier conventions to find-git-bash module 2026-07-23 17:59:58 -07:00
find-git-bash.ts style(desktop): apply eslint/prettier conventions to find-git-bash module 2026-07-23 17:59:58 -07:00
find-in-page.test.ts fmt(js): `npm run fix` on merge (#72411) 2026-07-27 02:52:53 +00:00
find-in-page.ts fmt(js): `npm run fix` on merge (#72411) 2026-07-27 02:52:53 +00:00
first-run-setup-gate.test.ts feat(desktop): add "Connect to existing Hermes" option to first-run onboarding 2026-07-24 12:55:06 -05:00
first-run-setup-gate.ts feat(desktop): add "Connect to existing Hermes" option to first-run onboarding 2026-07-24 12:55:06 -05:00
first-run-setup-main-process.test.ts feat(desktop): add "Connect to existing Hermes" option to first-run onboarding 2026-07-24 12:55:06 -05:00
fs-read-dir.test.ts
…
fs-read-dir.ts
…
gateway-ws-probe.test.ts
…
gateway-ws-probe.ts
…
git-repo-scan.test.ts fmt(js): `npm run fix` on merge (#68681) 2026-07-21 14:28:28 +00:00
git-repo-scan.ts fmt(js): `npm run fix` on merge (#68681) 2026-07-21 14:28:28 +00:00
git-review-ops.test.ts fix(desktop): bound review workspace scans 2026-08-03 00:08:30 +05:30
git-review-ops.ts fix(desktop): bound review workspace scans 2026-08-03 00:08:30 +05:30
git-root.test.ts
…
git-root.ts
…
git-worktree-ops.test.ts fmt(js): `npm run fix` on merge (#79505) 2026-08-05 16:32:54 +00:00
git-worktree-ops.ts feat(desktop): let convert-a-branch reach remote branches too 2026-08-05 11:43:09 -04:00
handoff-result.test.ts fix(desktop): hand-off hardening - fail-closed gates, truthful completion, progress UI, result surfacing 2026-08-09 01:26:14 -07:00
handoff-result.ts fix(desktop): hand-off hardening - fail-closed gates, truthful completion, progress UI, result surfacing 2026-08-09 01:26:14 -07:00
hardening.test.ts fix(desktop): dedicated reader for large remote attachments 2026-07-28 19:20:14 -05:00
hardening.ts fix(desktop): dedicated reader for large remote attachments 2026-07-28 19:20:14 -05:00
hud-cursor.test.ts fix(desktop): keep the HUD clickable on Linux 2026-08-08 22:15:24 -05:00
hud-cursor.ts fix(desktop): keep the HUD clickable on Linux 2026-08-08 22:15:24 -05:00
link-title-window.test.ts
…
link-title-window.ts perf(desktop): let the hidden link-title window throttle 2026-07-31 00:38:11 -05:00
main-window-lifecycle.test.ts
…
main-window-lifecycle.ts
…
main.ts fix(desktop): hand-off hardening - fail-closed gates, truthful completion, progress UI, result surfacing 2026-08-09 01:26:14 -07:00
native-auth-decisions.test.ts fix(desktop): name the readiness-probe auth and password-gateway guard decisions 2026-07-25 21:52:40 -05:00
native-auth-decisions.ts fix(desktop): name the readiness-probe auth and password-gateway guard decisions 2026-07-25 21:52:40 -05:00
native-oauth-login.test.ts fmt(js): `npm run fix` on merge (#69503) 2026-07-22 16:30:14 +00:00
native-oauth-login.ts fmt(js): `npm run fix` on merge (#69503) 2026-07-22 16:30:14 +00:00
native-oauth.test.ts fmt(js): `npm run fix` on merge (#75517) 2026-07-31 16:22:58 +00:00
native-oauth.ts fix(desktop): restore native OAuth tokens after restart 2026-07-31 10:16:21 -04:00
native-token-store.test.ts fix(desktop): redact gateway credentials from token logs 2026-07-31 10:16:21 -04:00
native-token-store.ts fix(desktop): redact gateway credentials from token logs 2026-07-31 10:16:21 -04:00
oauth-net-request.test.ts
…
oauth-net-request.ts
…
power-save.test.ts feat(desktop): keep-computer-awake toggle + System settings section 2026-07-20 11:50:22 -05:00
power-save.ts feat(desktop): keep-computer-awake toggle + System settings section 2026-07-20 11:50:22 -05:00
preload.ts fix(desktop): keep the HUD clickable on Linux 2026-08-08 22:15:24 -05:00
primary-backend-startup.test.ts feat(desktop): add "Connect to existing Hermes" option to first-run onboarding 2026-07-24 12:55:06 -05:00
primary-backend-startup.ts fmt(js): `npm run fix` on merge (#75582) 2026-07-31 18:54:27 +00:00
primary-connection-rehome.ts feat(desktop): add "Connect to existing Hermes" option to first-run onboarding 2026-07-24 12:55:06 -05:00
profile-delete-routing.test.ts
…
profile-delete-routing.ts
…
profile-session-routing.test.ts fix(desktop): preserve OAuth sessions in sidebar 2026-07-27 13:41:56 -05:00
profile-session-routing.ts fix(desktop): preserve OAuth sessions in sidebar 2026-07-27 13:41:56 -05:00
quick-entry.test.ts feat(desktop): quick-entry window — global hotkey capture to any session 2026-07-26 17:48:19 -07:00
quick-entry.ts fmt(js): `npm run fix` on merge (#75582) 2026-07-31 18:54:27 +00:00
quit-guard.test.ts feat(desktop): confirm before quitting with a turn in flight 2026-07-27 15:47:57 -05:00
quit-guard.ts feat(desktop): confirm before quitting with a turn in flight 2026-07-27 15:47:57 -05:00
remote-lifecycle.test.ts fmt(js): `npm run fix` on merge (#76498) 2026-08-02 01:23:45 +00:00
remote-lifecycle.ts fix(desktop): map SSH profiles to remote profiles 2026-08-01 14:30:16 -07:00
remote-liveness.test.ts fix(desktop): record main-process faults in desktop.log 2026-07-27 13:41:59 -05:00
remote-liveness.ts fix(desktop): retire pooled remote backends whose host went away 2026-07-27 13:41:59 -05:00
session-windows.test.ts perf(desktop): scope background-throttling opt-out to live streaming 2026-07-31 00:38:11 -05:00
session-windows.ts perf(desktop): scope background-throttling opt-out to live streaming 2026-07-31 00:38:11 -05:00
spawn-helper-perms.test.ts fix(desktop): resolve unpacked spawn-helper before chmod (#71171) 2026-07-25 15:19:29 -04:00
spawn-helper-perms.ts fix(desktop): resolve unpacked spawn-helper before chmod (#71171) 2026-07-25 15:19:29 -04:00
ssh-bootstrap-coordinator.test.ts fix(desktop): map SSH profiles to remote profiles 2026-08-01 14:30:16 -07:00
ssh-bootstrap-coordinator.ts fix(desktop): map SSH profiles to remote profiles 2026-08-01 14:30:16 -07:00
ssh-config.test.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
ssh-config.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
ssh-connection.test.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
ssh-connection.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
stream-throttle.test.ts perf(desktop): scope background-throttling opt-out to live streaming 2026-07-31 00:38:11 -05:00
stream-throttle.ts perf(desktop): scope background-throttling opt-out to live streaming 2026-07-31 00:38:11 -05:00
titlebar-overlay-width.test.ts
…
titlebar-overlay-width.ts
…
update-count.test.ts
…
update-count.ts
…
update-gate.test.ts fix(desktop): gate backend respawns on updateInFlight, not just the update marker (#73822) 2026-07-28 23:53:25 -07:00
update-gate.ts fix(desktop): gate backend respawns on updateInFlight, not just the update marker (#73822) 2026-07-28 23:53:25 -07:00
update-marker.test.ts fix(desktop): refuse a second update hand-off while one is already live 2026-08-01 10:47:45 -07:00
update-marker.ts fix(desktop): refuse a second update hand-off while one is already live 2026-08-01 10:47:45 -07:00
update-rebuild.test.ts
…
update-rebuild.ts
…
update-relaunch.test.ts
…
update-relaunch.ts
…
update-remote.test.ts
…
update-remote.ts
…
updater-process.test.ts fix(desktop): give the update hand-off script its own console - a detached hidden powershell dies before -File runs 2026-08-09 01:26:14 -07:00
updater-process.ts fix(desktop): give the update hand-off script its own console - a detached hidden powershell dies before -File runs 2026-08-09 01:26:14 -07:00
venv-blocker-scan.test.ts fmt(js): `npm run fix` on merge (#73666) 2026-07-28 21:55:38 +00:00
venv-blocker-scan.ts fmt(js): `npm run fix` on merge (#73666) 2026-07-28 21:55:38 +00:00
vscode-marketplace.test.ts
…
vscode-marketplace.ts
…
wake-indicator-window.ts feat(desktop): add notch wake indicator 2026-08-01 14:30:11 -07:00
wake-indicator.test.ts fix(desktop): close wake indicator with main window 2026-08-01 14:30:11 -07:00
wake-indicator.ts feat(desktop): add notch wake indicator 2026-08-01 14:30:11 -07:00
window-below.test.ts fix(desktop): say why read_window_below cannot see the windows 2026-08-08 22:17:38 -05:00
window-below.ts fix(desktop): say why read_window_below cannot see the windows 2026-08-08 22:17:38 -05:00
window-reveal.test.ts fix(desktop): reveal every window after a missed ready event, not just the main one 2026-08-08 16:51:44 -05:00
window-reveal.ts fix(desktop): reveal every window after a missed ready event, not just the main one 2026-08-08 16:51:44 -05:00
window-state.test.ts fix(desktop): persist window geometry on Linux 2026-08-08 22:13:08 -05:00
window-state.ts fix(desktop): say why read_window_below cannot see the windows 2026-08-08 22:17:38 -05:00
windows-child-options.test.ts fix(update): make orphan-backend reap tree-aware + drain Desktop update trees without pre-signalling 2026-08-08 20:01:03 -07:00
windows-child-options.ts
…
windows-hermes-path.test.ts
…
windows-hermes-path.ts
…
windows-remote-lifecycle.test.ts fix(desktop): map SSH profiles to remote profiles 2026-08-01 14:30:16 -07:00
windows-remote-lifecycle.ts fix(desktop): map SSH profiles to remote profiles 2026-08-01 14:30:16 -07:00
windows-remote-live.test.ts style(desktop): satisfy merged eslint/prettier config 2026-07-20 23:01:49 +02:00
windows-sandbox-fallback.test.ts fix(desktop): harden Windows sandbox fallback against false-positive sandbox loss 2026-07-18 02:26:19 -07:00
windows-sandbox-fallback.ts fix(desktop): harden Windows sandbox fallback against false-positive sandbox loss 2026-07-18 02:26:19 -07:00
windows-system-ca.test.ts
…
windows-system-ca.ts
…
windows-user-env.test.ts
…
windows-user-env.ts
…
workspace-cwd.test.ts
…
workspace-cwd.ts
…
wsl-clipboard-image.test.ts
…
wsl-clipboard-image.ts
…
wsl-path-bridge.test.ts
…
wsl-path-bridge.ts
…
zoom.test.ts feat(desktop): add notch wake indicator 2026-08-01 14:30:11 -07:00
zoom.ts feat(desktop): HUD mode window and its session handoff 2026-08-08 01:38:57 -05:00