mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-21 03:39:54 +00:00
install.ps1: harden Install-SystemPackages against winget msstore failures
The previous winget invocation discarded stdout/stderr and trusted no signal at all -- not the exit code (winget exits 0 even when it bails "please specify --source"), not output (sent to Out-Null), not the catch handler (winget returning 0 means no exception fires). The only trust signal was a post-install Get-Command rg / Get-Command ffmpeg check, which would also miss the package because %LOCALAPPDATA%\ Microsoft\WinGet\Links (where winget puts command aliases) is added to PATH by AppExecutionAlias machinery only in fresh shells. End result on machines where the msstore source has a cert problem (0x8a15005e -- common on Windows-on-ARM and some corporate networks): silent failure, no log, no breadcrumb, and the user is told the install succeeded. Specifically: - Pin --source winget on every winget install call. Defeats the broken- msstore-source path. We ship nothing from msstore so this is safe and forward-compatible. - Add --exact --id for a tighter package match. - Capture each winget invocation's combined stdout/stderr + exit code to %TEMP%\hermes-winget-<pkg>-<n>.log instead of Out-Null. On the happy path the log is deleted after the post-install check confirms the binary is on PATH; on failure the log is kept and its path is named in a Write-Warn so the user has something to grep. - Refresh PATH to include %LOCALAPPDATA%\Microsoft\WinGet\Links in addition to the User/Machine env-var hives, so Get-Command sees newly- installed winget aliases in the same process. - No behavior change on the happy path. Same Write-Info/Success/Warn cadence, same fallback order (winget -> choco -> scoop -> manual), same $script:HasRipgrep / $script:HasFfmpeg outputs. Verified end-to-end on a real Snapdragon ARM64 Windows host: ripgrep uninstalled, stage re-run, [OK] ripgrep installed in 1.4s, ok:true.
This commit is contained in:
+39
-4
@@ -913,22 +913,57 @@ function Install-SystemPackages {
|
||||
# Try winget first (most common on modern Windows)
|
||||
if ($hasWinget) {
|
||||
Write-Info "Installing $description via winget..."
|
||||
# Per-package log paths -- key the lookup by package id so we can
|
||||
# decide AFTER the post-install Get-Command check whether to keep
|
||||
# the log (still missing -> keep as breadcrumb) or delete it (now
|
||||
# present -> happy path, no clutter).
|
||||
$pkgLogs = @{}
|
||||
foreach ($pkg in $wingetPkgs) {
|
||||
$log = "$env:TEMP\hermes-winget-$($pkg -replace '[^A-Za-z0-9]','_')-$(Get-Random).log"
|
||||
$pkgLogs[$pkg] = $log
|
||||
# --source winget pins us to the github-backed source. Without this,
|
||||
# a broken msstore source (cert validation failures like 0x8a15005e
|
||||
# are common on Windows-on-ARM and some corporate networks) makes
|
||||
# winget bail with "please specify --source" *before* attempting any
|
||||
# install -- and it exits 0, so the surrounding try/catch never fires.
|
||||
# We don't ship anything from msstore, so pinning is safe.
|
||||
try {
|
||||
winget install $pkg --silent --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null
|
||||
} catch { }
|
||||
$output = winget install --exact --id $pkg --source winget --silent `
|
||||
--accept-package-agreements --accept-source-agreements 2>&1
|
||||
$output | Out-File -FilePath $log -Encoding utf8
|
||||
"winget exit: $LASTEXITCODE" | Out-File -FilePath $log -Encoding utf8 -Append
|
||||
} catch {
|
||||
$_ | Out-File -FilePath $log -Encoding utf8 -Append
|
||||
"winget exit: <exception>" | Out-File -FilePath $log -Encoding utf8 -Append
|
||||
}
|
||||
}
|
||||
# Refresh PATH and recheck
|
||||
$env:Path = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
|
||||
# Refresh PATH from both env-var hives AND winget's alias shim directory.
|
||||
# winget exposes packages via "command line aliases" in %LOCALAPPDATA%\
|
||||
# Microsoft\WinGet\Links, which is added to PATH by the AppExecutionAlias
|
||||
# machinery only in *newly-spawned* shells -- not the current process.
|
||||
# Without this addition, Get-Command rg below would falsely return null
|
||||
# immediately after a successful install.
|
||||
$wingetLinks = Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Links"
|
||||
$envPath = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
|
||||
if (Test-Path $wingetLinks) {
|
||||
$envPath = "$envPath;$wingetLinks"
|
||||
}
|
||||
$env:Path = $envPath
|
||||
if ($needRipgrep -and (Get-Command rg -ErrorAction SilentlyContinue)) {
|
||||
Write-Success "ripgrep installed"
|
||||
$script:HasRipgrep = $true
|
||||
$needRipgrep = $false
|
||||
Remove-Item -Path $pkgLogs["BurntSushi.ripgrep.MSVC"] -ErrorAction SilentlyContinue
|
||||
} elseif ($pkgLogs.ContainsKey("BurntSushi.ripgrep.MSVC")) {
|
||||
Write-Warn "winget could not install ripgrep; details: $($pkgLogs['BurntSushi.ripgrep.MSVC'])"
|
||||
}
|
||||
if ($needFfmpeg -and (Get-Command ffmpeg -ErrorAction SilentlyContinue)) {
|
||||
Write-Success "ffmpeg installed"
|
||||
$script:HasFfmpeg = $true
|
||||
$needFfmpeg = $false
|
||||
Remove-Item -Path $pkgLogs["Gyan.FFmpeg"] -ErrorAction SilentlyContinue
|
||||
} elseif ($pkgLogs.ContainsKey("Gyan.FFmpeg")) {
|
||||
Write-Warn "winget could not install ffmpeg; details: $($pkgLogs['Gyan.FFmpeg'])"
|
||||
}
|
||||
if (-not $needRipgrep -and -not $needFfmpeg) { return }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user