From 9df645a776d7a197bceca86f9aa5771c1ec59433 Mon Sep 17 00:00:00 2001 From: cheezone <41314020+cheezone@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:09:28 +0800 Subject: [PATCH 1/3] fix(windows): improve install.ps1 errors for missing VC++ runtime Detect STATUS_DLL_NOT_FOUND (0xC0000135) when vp.exe install fails on clean Windows and print VC++ Redistributable guidance. Stop using exit in interactive irm | iex installs so the PowerShell session stays open. --- packages/cli/install.ps1 | 71 +++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/packages/cli/install.ps1 b/packages/cli/install.ps1 index 6adc7ed2ec..edcf2244fb 100644 --- a/packages/cli/install.ps1 +++ b/packages/cli/install.ps1 @@ -46,11 +46,47 @@ function Write-Warn { Write-Host $Message } +# Exit code when a Windows native binary cannot load required DLLs (STATUS_DLL_NOT_FOUND). +$script:DllNotFoundExitCode = -1073741515 + +function Test-IsDllNotFoundExitCode { + param([int]$ExitCode) + return $ExitCode -eq $script:DllNotFoundExitCode -or [uint32][int32]$ExitCode -eq 0xC0000135 +} + +function Get-DllNotFoundInstallMessage { + $arch = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "arm64" } else { "x64" } + $vcUrl = if ($arch -eq "arm64") { + "https://aka.ms/vs/17/release/vc_redist.arm64.exe" + } else { + "https://aka.ms/vs/17/release/vc_redist.x64.exe" + } + return @" +vp.exe could not start (exit code 0xC0000135). +This usually means Microsoft Visual C++ 2015-2022 Redistributable ($arch) is not installed. + +Install: $vcUrl +Then re-run: irm https://vite.plus/ps1 | iex +"@ +} + +# Internal stop signal: halts install without re-printing an error we already wrote. +$script:InstallStopSignal = 'VP_INSTALL_STOP' + +function Exit-Installer { + param([int]$Code = 1) + $global:LASTEXITCODE = $Code + if ($env:CI -eq "true") { + exit $Code + } + throw $script:InstallStopSignal +} + function Write-Error-Exit { param([string]$Message) Write-Host "error: " -ForegroundColor Red -NoNewline Write-Host $Message - exit 1 + Exit-Installer } function Test-ReleaseAgeError { @@ -114,11 +150,26 @@ function Write-ReleaseAgeOverride { } function Write-InstallFailure { - param([string]$LogPath) + param( + [string]$LogPath, + [int]$ExitCode = 0 + ) + + if (Test-IsDllNotFoundExitCode $ExitCode) { + $message = Get-DllNotFoundInstallMessage + if ($env:CI -eq "true") { + Write-Host "error: " -ForegroundColor Red -NoNewline + Write-Host $message + Exit-Installer + } + Write-Error-Exit $message + } + if ($env:CI -eq "true") { Write-Host "error: " -ForegroundColor Red -NoNewline Write-Host "Failed to install dependencies. Log output:" Get-Content -Path $LogPath | ForEach-Object { Write-Host $_ } + Exit-Installer } else { Write-Error-Exit "Failed to install dependencies. See log for details: $LogPath" } @@ -593,16 +644,14 @@ function Main { $retryExitCode = $LASTEXITCODE $retryOutput | Out-File $installLog if ($retryExitCode -ne 0) { - Write-InstallFailure $installLog - exit 1 + Write-InstallFailure -LogPath $installLog -ExitCode $retryExitCode } } else { Write-ReleaseAgeFailure $installLog - exit 1 + Exit-Installer } } else { - Write-InstallFailure $installLog - exit 1 + Write-InstallFailure -LogPath $installLog -ExitCode $installExitCode } } } finally { @@ -749,4 +798,10 @@ exec "`$VP_HOME/current/bin/vp.exe" "`$@" Write-Host "" } -Main +try { + Main +} catch { + if ($_.Exception.Message -ne $script:InstallStopSignal) { + throw + } +} From 61c90a60bef59a4f12b192d757f641e855b72863 Mon Sep 17 00:00:00 2001 From: cheezone <41314020+cheezone@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:54:30 +0800 Subject: [PATCH 2/3] fix(windows): address Codex review on install.ps1 exit handling - Exit with non-zero code when invoked as a script file (not only CI=true) - Compare NTSTATUS exit codes without unsafe UInt32 casts - Rethrow install stop signal from nested metadata catch blocks --- packages/cli/install.ps1 | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/cli/install.ps1 b/packages/cli/install.ps1 index edcf2244fb..72547fa5c6 100644 --- a/packages/cli/install.ps1 +++ b/packages/cli/install.ps1 @@ -51,7 +51,17 @@ $script:DllNotFoundExitCode = -1073741515 function Test-IsDllNotFoundExitCode { param([int]$ExitCode) - return $ExitCode -eq $script:DllNotFoundExitCode -or [uint32][int32]$ExitCode -eq 0xC0000135 + if ($ExitCode -eq $script:DllNotFoundExitCode) { + return $true + } + if ($ExitCode -eq 3221225781) { + return $true + } + if ($ExitCode -lt 0) { + $hex = '{0:X8}' -f ($ExitCode -band 0xFFFFFFFF) + return $hex -eq 'C0000135' + } + return $false } function Get-DllNotFoundInstallMessage { @@ -73,10 +83,19 @@ Then re-run: irm https://vite.plus/ps1 | iex # Internal stop signal: halts install without re-printing an error we already wrote. $script:InstallStopSignal = 'VP_INSTALL_STOP' +function Test-IsInstallStopException { + param( + [System.Management.Automation.ErrorRecord]$ErrorRecord + ) + return $ErrorRecord.Exception.Message -eq $script:InstallStopSignal +} + function Exit-Installer { param([int]$Code = 1) $global:LASTEXITCODE = $Code - if ($env:CI -eq "true") { + # CI and script-file invocations must propagate a non-zero process exit code. + # `irm ... | iex` has no $PSCommandPath; use a catchable stop signal to keep the shell open. + if ($env:CI -eq "true" -or $PSCommandPath) { exit $Code } throw $script:InstallStopSignal @@ -208,6 +227,7 @@ function Get-PackageMetadata { try { $script:PackageMetadata = Invoke-RestMethod $metadataUrl } catch { + if (Test-IsInstallStopException $_) { throw } # Try to extract npm error message from response $errorMsg = $_.ErrorDetails.Message if ($errorMsg) { @@ -217,6 +237,7 @@ function Get-PackageMetadata { Write-Error-Exit "Failed to fetch version '${versionPath}': $($errorJson.error)`n URL: $metadataUrl" } } catch { + if (Test-IsInstallStopException $_) { throw } # JSON parsing failed, fall through to generic error } } @@ -230,6 +251,7 @@ function Get-PackageMetadata { try { $script:PackageMetadata = $script:PackageMetadata | ConvertFrom-Json } catch { + if (Test-IsInstallStopException $_) { throw } # Not valid JSON - treat as plain string error Write-Error-Exit "Failed to fetch version '${versionPath}': $script:PackageMetadata`n URL: $metadataUrl" } @@ -801,7 +823,7 @@ exec "`$VP_HOME/current/bin/vp.exe" "`$@" try { Main } catch { - if ($_.Exception.Message -ne $script:InstallStopSignal) { + if (-not (Test-IsInstallStopException $_)) { throw } } From fba7366cb1182a2b5ce86d4181f45a33d2378102 Mon Sep 17 00:00:00 2001 From: cheezone <41314020+cheezone@users.noreply.github.com> Date: Sat, 27 Jun 2026 22:05:24 +0800 Subject: [PATCH 3/3] fix(windows): only keep shell open for interactive irm | iex Non-interactive powershell -Command callers should still exit non-zero after install failure; detect -Command via process command line on Windows. --- packages/cli/install.ps1 | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/cli/install.ps1 b/packages/cli/install.ps1 index 72547fa5c6..a3e18caf79 100644 --- a/packages/cli/install.ps1 +++ b/packages/cli/install.ps1 @@ -90,12 +90,33 @@ function Test-IsInstallStopException { return $ErrorRecord.Exception.Message -eq $script:InstallStopSignal } +function Test-ShouldKeepShellOpenAfterFailure { + # Only `irm ... | iex` typed in an already-open interactive shell should keep the + # session alive. CI, script files, and `powershell -Command "..."` must exit non-zero. + if ($env:CI -eq "true") { + return $false + } + if ($PSCommandPath) { + return $false + } + if (-not [Environment]::UserInteractive) { + return $false + } + try { + $commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$PID").CommandLine + if ($commandLine -match '(^|\s)-Command(\s|$)') { + return $false + } + } catch { + return $false + } + return $true +} + function Exit-Installer { param([int]$Code = 1) $global:LASTEXITCODE = $Code - # CI and script-file invocations must propagate a non-zero process exit code. - # `irm ... | iex` has no $PSCommandPath; use a catchable stop signal to keep the shell open. - if ($env:CI -eq "true" -or $PSCommandPath) { + if (-not (Test-ShouldKeepShellOpenAfterFailure)) { exit $Code } throw $script:InstallStopSignal @@ -823,7 +844,11 @@ exec "`$VP_HOME/current/bin/vp.exe" "`$@" try { Main } catch { - if (-not (Test-IsInstallStopException $_)) { - throw + if (Test-IsInstallStopException $_) { + if (Test-ShouldKeepShellOpenAfterFailure) { + return + } + exit $global:LASTEXITCODE } + throw }