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
+45
View File
@@ -2073,9 +2073,11 @@ function Install-Desktop {
"$desktopDir\release\win-arm64-unpacked\Hermes.exe"
)
$found = $false
$desktopExe = $null
foreach ($cand in $exeCandidates) {
if (Test-Path $cand) {
Write-Success "Desktop ready: $cand"
$desktopExe = $cand
$found = $true
break
}
@@ -2083,6 +2085,49 @@ function Install-Desktop {
if (-not $found) {
throw "Desktop build completed but no Hermes.exe was found under $desktopDir\release\*-unpacked\"
}
# 4. Create Start Menu + Desktop shortcuts pointing DIRECTLY at the packed
# Hermes.exe. We deliberately do NOT point them at `hermes desktop`: that
# command rebuilds (npm install + electron-builder) on every launch,
# which would cost minutes each time. The packed exe is the consumer —
# launching it directly is instant, and updates flow through the
# installer's --update path (which rebuilds once, then relaunches).
New-DesktopShortcuts -TargetExe $desktopExe
}
function New-DesktopShortcuts {
param([Parameter(Mandatory = $true)][string]$TargetExe)
# Best-effort: a shortcut failure must never fail an otherwise-good install.
try {
$shell = New-Object -ComObject WScript.Shell
$workDir = Split-Path -Parent $TargetExe
$targets = @(
(Join-Path ([Environment]::GetFolderPath('Programs')) 'Hermes.lnk'),
(Join-Path ([Environment]::GetFolderPath('Desktop')) 'Hermes.lnk')
)
foreach ($lnkPath in $targets) {
try {
$parent = Split-Path -Parent $lnkPath
if (-not (Test-Path $parent)) {
New-Item -ItemType Directory -Force -Path $parent | Out-Null
}
$sc = $shell.CreateShortcut($lnkPath)
$sc.TargetPath = $TargetExe
$sc.WorkingDirectory = $workDir
$sc.IconLocation = "$TargetExe,0"
$sc.Description = 'Hermes Agent'
$sc.Save()
Write-Success "Shortcut created: $lnkPath"
} catch {
Write-Warn "Could not create shortcut $lnkPath : $($_.Exception.Message)"
}
}
} catch {
Write-Warn "Skipping shortcut creation: $($_.Exception.Message)"
}
}
function Install-PlatformSdks {