feat(installer): drive in-app updates through the Tauri installer

Converge update on the same principle as bootstrap: one driver owns all
repo mutation. The desktop becomes a pure consumer that hands off to
Hermes-Setup.exe --update instead of re-implementing git/pip in Electron.

- hermes desktop --build-only: build without launching, so the installer
  owns the post-update launch (CLI keeps build logic single-sourced).
- Installer AppMode {Install,Update} from argv; get_mode exposed to the UI.
- Installer self-copies to HERMES_HOME/hermes-setup.exe on install success
  (no-op guard during --update re-invocation to avoid the locked-exe copy).
- Installer --update flow (update.rs): wait for the desktop to release the
  venv shim, run 'hermes update --yes --gateway' (branch on exit 0/2/other),
  then 'hermes desktop --build-only', then launch the rebuilt desktop. Reuses
  the bootstrap event channel + progress UI via a synthetic two-stage manifest.
- Desktop applyUpdates() gutted (~105 lines of git/stash/pull/pyproject/pip
  removed) -> thin handoff: spawn updater, app.quit() to free the shim.
  Detection (checkUpdates, commit changelog, behind-count) kept intact.
- install.ps1 creates Start Menu + Desktop shortcuts to the packed Hermes.exe
  (never bare 'hermes desktop', which would rebuild every launch).
This commit is contained in:
emozilla
2026-05-28 23:48:21 -04:00
parent a4cfc8b740
commit 6381e70448
9 changed files with 709 additions and 128 deletions
+3 -3
View File
@@ -63,7 +63,7 @@ export function UpdatesOverlay() {
}
const handleInstall = () => {
void applyUpdates({ dirtyStrategy: status?.dirty ? 'stash' : 'abort' })
void applyUpdates()
}
return (
@@ -248,7 +248,7 @@ function ApplyingView({ apply }: { apply: UpdateApplyState }) {
<DialogTitle className="text-center text-xl">{label}</DialogTitle>
<DialogDescription className="text-center text-sm">
Hermes will reopen automatically when this is done.
The Hermes updater will take over in its own window and reopen Hermes when it&rsquo;s done.
</DialogDescription>
</div>
@@ -262,7 +262,7 @@ function ApplyingView({ apply }: { apply: UpdateApplyState }) {
/>
</div>
<p className="text-center text-xs text-muted-foreground">Please keep this window open.</p>
<p className="text-center text-xs text-muted-foreground">Hermes will close to apply the update.</p>
</div>
)
}