Files
hermes-agent/scripts
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
..