fix(install/windows): repair stale winget registration; refresh PATH after every package manager

When ripgrep/ffmpeg is missing, `winget install <id>` on a package winget
already has registered is treated as an upgrade: it finds no newer version and
exits 0x8A15002B (-1978335189, APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE)
without ensuring the binary is actually present. The installer only logged that
code and judged success by `Get-Command rg`, so a stale registration (files
removed outside winget, or a missing alias shim) became a permanent dead-end —
winget kept reporting "already installed" and the user could never reinstall.

Detect that exit code and retry once with `--force` to repair the registration
so the shim reappears.

Also refresh the process PATH after the choco and scoop fallbacks (not just
winget) via a shared helper, so a successful fallback install — or any install
on a box without winget — is no longer misreported as "not installed".
This commit is contained in:
xxxigm 2026-06-10 19:14:11 +07:00 committed by kshitijk4poor
parent 4829f8d2c5
commit 899acfe42f

View file

@ -892,6 +892,22 @@ function Test-Node {
return $true
}
function Update-ProcessPathForPackages {
# Rebuild the current process PATH from the persisted User+Machine hives plus
# winget's alias-shim directory, so a freshly-installed shim (rg.exe,
# ffmpeg.exe) becomes visible to Get-Command in THIS process without
# spawning a new shell. Called after every package-manager attempt
# (winget/choco/scoop): previously PATH was only refreshed inside the winget
# branch, so a successful choco/scoop fallback -- or any install on a box
# without winget -- could be misreported as "not installed".
$envPath = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
$wingetLinks = Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Links"
if (Test-Path $wingetLinks) {
$envPath = "$envPath;$wingetLinks"
}
$env:Path = $envPath
}
function Install-SystemPackages {
$script:HasRipgrep = $false
$script:HasFfmpeg = $false
@ -961,25 +977,33 @@ function Install-SystemPackages {
try {
$output = winget install --exact --id $pkg --source winget --silent `
--accept-package-agreements --accept-source-agreements 2>&1
$code = $LASTEXITCODE
$output | Out-File -FilePath $log -Encoding utf8
"winget exit: $LASTEXITCODE" | Out-File -FilePath $log -Encoding utf8 -Append
"winget exit: $code" | Out-File -FilePath $log -Encoding utf8 -Append
# 0x8A15002B (-1978335189) = APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE.
# winget treats `install` on a package it already has registered as
# an *upgrade*, finds no newer version, and bails with this code --
# even when the binary is gone from disk/PATH (stale registration,
# files removed outside winget, or a missing alias shim). We KNOW the
# command was missing (that's why we're here), so a plain install
# dead-ends forever. Force a reinstall to repair the registration so
# the shim reappears.
if ($code -eq -1978335189) {
"-> already-installed/no-upgrade; retrying with --force" | Out-File -FilePath $log -Encoding utf8 -Append
$output = winget install --exact --id $pkg --source winget --silent --force `
--accept-package-agreements --accept-source-agreements 2>&1
$output | Out-File -FilePath $log -Encoding utf8 -Append
"winget exit (force): $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 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
# Refresh PATH so packages winget exposed via "command line aliases" in
# %LOCALAPPDATA%\Microsoft\WinGet\Links (added to PATH only in
# newly-spawned shells, not this process) are visible to Get-Command below.
Update-ProcessPathForPackages
if ($needRipgrep -and (Get-Command rg -ErrorAction SilentlyContinue)) {
Write-Success "ripgrep installed"
$script:HasRipgrep = $true
@ -1005,6 +1029,7 @@ function Install-SystemPackages {
foreach ($pkg in $chocoPkgs) {
try { choco install $pkg -y 2>&1 | Out-Null } catch { }
}
Update-ProcessPathForPackages
if ($needRipgrep -and (Get-Command rg -ErrorAction SilentlyContinue)) {
Write-Success "ripgrep installed via chocolatey"
$script:HasRipgrep = $true
@ -1023,6 +1048,7 @@ function Install-SystemPackages {
foreach ($pkg in $scoopPkgs) {
try { scoop install $pkg 2>&1 | Out-Null } catch { }
}
Update-ProcessPathForPackages
if ($needRipgrep -and (Get-Command rg -ErrorAction SilentlyContinue)) {
Write-Success "ripgrep installed via scoop"
$script:HasRipgrep = $true