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
..
ci fix(ci): follow artifact download redirect without auth 2026-08-05 11:16:18 -04:00
lib fix(install): restore installs — engines floor no shipping toolchain can meet 2026-08-01 22:56:52 -05:00
observability fix(monitoring): drain terminal lifecycle events 2026-07-24 18:54:45 +00:00
sandbox feat(dev-sandbox): support fake installer / fake main / git clones 2026-08-04 17:36:26 -04:00
tests test(install): exercise 8.3 normalization by running install.ps1, not by parsing it 2026-08-04 15:34:32 -06:00
toolperf_abeval feat(scripts): reproducible core-toolset A/B eval harness (toolperf_abeval) 2026-08-05 13:43:30 -07:00
whatsapp-bridge fix(deps): patch 31 known CVEs across Python and npm lockfiles 2026-08-08 14:06:48 -07:00
LIVETEST_README.md
…
add_contributor.py fix(scripts): accept legacy consecutive-hyphen GitHub logins in add_contributor 2026-07-24 22:40:15 -07:00
analyze_livetest.py
…
audit_pr_attribution.py feat(ci): auto-fixable contributor attribution — audit_pr_attribution.py + gate points at it 2026-08-02 15:26:59 -07:00
benchmark_browser_eval.py
…
build_model_catalog.py
…
build_skills_index.py fix(skills-hub): include owner in ClawHub source URLs and add retry on 429 (#51236) 2026-07-31 22:33:11 -07:00
capture-cage-terminal.sh feat(devshell): add terminal UI capture tools (#69629) 2026-07-22 17:28:21 -04:00
check-windows-footguns.py feat(lint): close the fdopen + chained-call gaps in the encoding footgun gate 2026-08-08 12:32:23 -07:00
check_subprocess_stdin.py fix(windows): sweep remaining bare read_text/write_text sites + linter rule 2026-07-24 17:10:39 -07:00
contributor_audit.py chore: release v0.20.0 (2026.8.3) 2026-08-03 09:57:23 -07:00
desktop-update.ps1 fix(desktop): hand-off hardening - fail-closed gates, truthful completion, progress UI, result surfacing 2026-08-09 01:26:14 -07:00
dev-sandbox.sh feat(dev-sandbox): support fake installer / fake main / git clones 2026-08-04 17:36:26 -04:00
discord-voice-doctor.py
…
docker_config_migrate.py refactor: config auto-migration support floor at v12 + deprecated shim retirement 2026-07-29 16:44:31 -07:00
docker_rebootstrap_nous_session.py
…
generate_conformance_vectors.py feat(conformance): vector generator — native renderers as executable spec (#71666) 2026-07-26 16:52:25 +10:00
hermes-gateway
…
install.cmd
…
install.ps1 fix(install): replay npm's debug log into the bootstrap stream on failure 2026-08-08 22:55:00 -07:00
install.sh fix(install): sync the lockfile engines mirrors with the manifests 2026-08-01 23:28:28 -05:00
install_psutil_android.py
…
iso-certify.py fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
keystroke_diagnostic.py
…
kill_modal.sh
…
lint_diff.py fix(windows): sweep remaining bare read_text/write_text sites + linter rule 2026-07-24 17:10:39 -07:00
micro_compaction_report.py feat(agent): report context occupancy, not just tokens saved 2026-07-31 17:44:19 +05:30
profile-tui.py fix(windows): sweep remaining bare read_text/write_text sites + linter rule 2026-07-24 17:10:39 -07:00
release.py chore: map kweiner contributor email 2026-08-08 14:06:30 +05:30
run_tests.sh fix(tests): forward HERMES_TEST_* knobs through the hermetic runner 2026-08-05 19:46:43 -04:00
run_tests_parallel.py fix(tests): Windows-aware path-list split and UTF-8 progress output in parallel runner 2026-08-08 12:33:19 -07:00
sample_and_compress.py
…
smoke_nemo_relay_shared_metrics.py Merge updated client resource metrics into active-install metrics 2026-08-04 15:10:41 -07:00
tool_search_livetest.py bench: Unreal-scale live benchmark — Epic's real 830 UE 5.8 schemas replayed (Opus 4.8) 2026-07-26 08:26:09 -07:00
tool_search_livetest2.py fix(lint): encode remaining write_text calls in the tool_search livetest harness 2026-07-26 11:54:03 -07:00
tool_search_livetest_ue.py fix(lint): explicit encoding on probe-file open in UE harness (PLW1514 + windows-footguns) 2026-07-26 08:26:09 -07:00
tool_search_livetest_ue_disc.py bench: discovery-bound suite — paraphrase/absence/survey tasks isolate the listing's structural advantage 2026-07-26 08:26:09 -07:00
tool_search_livetest_ue_hard.py bench: adversarial 830-tool gauntlet — confusion clusters, type-aware error mocks, strict scoring 2026-07-26 08:26:09 -07:00