From 9d4fee11d144a76676ef80ee17c3f7d8c2ede692 Mon Sep 17 00:00:00 2001 From: nekomoyi Date: Mon, 27 Apr 2026 00:08:35 +0800 Subject: [PATCH 1/5] fix(env): support PowerShell on non-Windows platforms --- crates/vite_global_cli/src/commands/env/setup.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/vite_global_cli/src/commands/env/setup.rs b/crates/vite_global_cli/src/commands/env/setup.rs index 1748a9b8fd..c8a62b1f44 100644 --- a/crates/vite_global_cli/src/commands/env/setup.rs +++ b/crates/vite_global_cli/src/commands/env/setup.rs @@ -641,10 +641,10 @@ if ($env:Path -split ';' -notcontains $__vp_bin) { function vp { if ($args.Count -ge 2 -and $args[0] -eq "env" -and $args[1] -eq "use") { if ($args -contains "-h" -or $args -contains "--help") { - & (Join-Path $__vp_bin "vp.exe") @args; return + & (Join-Path $__vp_bin "vp") @args; return } $env:VP_ENV_USE_EVAL_ENABLE = "1" - $output = & (Join-Path $__vp_bin "vp.exe") @args 2>&1 | ForEach-Object { + $output = & (Join-Path $__vp_bin "vp") @args 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { Write-Host $_.Exception.Message } else { @@ -656,13 +656,13 @@ function vp { Invoke-Expression ($output -join "`n") } } else { - & (Join-Path $__vp_bin "vp.exe") @args + & (Join-Path $__vp_bin "vp") @args } } # Dynamic shell completion for PowerShell $env:VP_COMPLETE = "powershell" -& (Join-Path $__vp_bin "vp.exe") | Out-String | Invoke-Expression +& (Join-Path $__vp_bin "vp") | Out-String | Invoke-Expression Remove-Item Env:\VP_COMPLETE -ErrorAction SilentlyContinue $__vpr_comp = { @@ -674,7 +674,7 @@ $__vpr_comp = { $args = $args -replace '^(vpr\.exe|vpr)\b', 'vp run' if ($wordToComplete -eq "") { $args += " ''" } $results = Invoke-Expression @" -& (Join-Path $__vp_bin 'vp.exe') -- $args +& (Join-Path $__vp_bin 'vp') -- $args "@; if ($prev) { $env:VP_COMPLETE = $prev } else { Remove-Item Env:\VP_COMPLETE } $results | ForEach-Object { From 46038f85264de977bb2b8e9e1605f4fbe0df72a2 Mon Sep 17 00:00:00 2001 From: nekomoyi Date: Tue, 28 Apr 2026 00:26:28 +0800 Subject: [PATCH 2/5] ci: add non-windows pwsh e2e coverage --- .github/workflows/ci.yml | 58 +++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17af2ee299..f88374940b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,32 +269,34 @@ jobs: RUST_MIN_STACK: 8388608 - name: Test global package install (powershell) - if: ${{ matrix.os == 'windows-latest' }} shell: pwsh run: | - echo "PATH: $env:Path" - where.exe node - where.exe npm - where.exe npx - where.exe vp + $vpHome = Join-Path $HOME ".vite-plus" + $vpBin = Join-Path $vpHome "bin" + + Write-Host "PATH: $env:Path" + Get-Command node + Get-Command npm + Get-Command npx + Get-Command vp vp env doctor # Test 1: Install a JS-based CLI (typescript) vp install -g typescript tsc --version - where.exe tsc + Get-Command tsc # Test 2: Verify the package was installed correctly - Get-ChildItem "$env:USERPROFILE\.vite-plus\packages\typescript\" - Get-ChildItem "$env:USERPROFILE\.vite-plus\bin\" + Get-ChildItem (Join-Path $vpHome "packages/typescript") + Get-ChildItem $vpBin # Test 3: Uninstall vp uninstall -g typescript # Test 4: Verify uninstall removed shim Write-Host "Checking bin dir after uninstall:" - Get-ChildItem "$env:USERPROFILE\.vite-plus\bin\" - $shimPath = "$env:USERPROFILE\.vite-plus\bin\tsc.cmd" + Get-ChildItem $vpBin + $shimPath = if ($IsWindows) { Join-Path $vpBin "tsc.cmd" } else { Join-Path $vpBin "tsc" } if (Test-Path $shimPath) { Write-Error "tsc shim file still exists at $shimPath" exit 1 @@ -444,14 +446,14 @@ jobs: fi - name: Test upgrade (powershell) - if: ${{ matrix.os == 'windows-latest' }} shell: pwsh run: | - Get-ChildItem "$env:USERPROFILE\.vite-plus\" + $vpHome = Join-Path $HOME ".vite-plus" + Get-ChildItem $vpHome # Helper to read the installed CLI version from package.json function Get-CliVersion { - node -p "require(require('path').resolve(process.env.USERPROFILE, '.vite-plus', 'current', 'node_modules', 'vite-plus', 'package.json')).version" + node -p "require(require('path').resolve(process.env.USERPROFILE || process.env.HOME, '.vite-plus', 'current', 'node_modules', 'vite-plus', 'package.json')).version" } # Save initial (dev build) version @@ -466,7 +468,7 @@ jobs: vp --version vp env doctor - Get-ChildItem "$env:USERPROFILE\.vite-plus\" + Get-ChildItem $vpHome # Verify version changed after update $updatedVersion = Get-CliVersion @@ -552,20 +554,26 @@ jobs: vp --version - name: Test implode (powershell) - if: ${{ matrix.os == 'windows-latest' }} shell: pwsh run: | - # Retry — Windows file locks can cause transient "Access is denied" errors - foreach ($i in 1..3) { - vp implode --yes - if ($LASTEXITCODE -eq 0) { break } - Write-Host "Retry $i`: vp implode failed, waiting 5s..." + $vpHome = Join-Path $HOME ".vite-plus" + + if ($IsWindows) { + # Retry — Windows file locks can cause transient "Access is denied" errors + foreach ($i in 1..3) { + vp implode --yes + if ($LASTEXITCODE -eq 0) { break } + Write-Host "Retry $i`: vp implode failed, waiting 5s..." + Start-Sleep -Seconds 5 + } Start-Sleep -Seconds 5 + } else { + vp implode --yes } - Start-Sleep -Seconds 5 - dir "$env:USERPROFILE\" - if (Test-Path "$env:USERPROFILE\.vite-plus") { - Write-Error "~/.vite-plus still exists after implode" + + Get-ChildItem $HOME + if (Test-Path $vpHome) { + Write-Error "$vpHome still exists after implode" exit 1 } pnpm bootstrap-cli:ci From 02d061b1f7129b792af0a47856cf14cc251fc58d Mon Sep 17 00:00:00 2001 From: nekomoyi Date: Tue, 28 Apr 2026 00:42:51 +0800 Subject: [PATCH 3/5] ci: run pwsh e2e through env wrapper --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f88374940b..1ddb980398 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -273,6 +273,7 @@ jobs: run: | $vpHome = Join-Path $HOME ".vite-plus" $vpBin = Join-Path $vpHome "bin" + . (Join-Path $vpHome 'env.ps1') Write-Host "PATH: $env:Path" Get-Command node @@ -449,6 +450,7 @@ jobs: shell: pwsh run: | $vpHome = Join-Path $HOME ".vite-plus" + . (Join-Path $vpHome 'env.ps1') Get-ChildItem $vpHome # Helper to read the installed CLI version from package.json @@ -557,6 +559,7 @@ jobs: shell: pwsh run: | $vpHome = Join-Path $HOME ".vite-plus" + . (Join-Path $vpHome 'env.ps1') if ($IsWindows) { # Retry — Windows file locks can cause transient "Access is denied" errors From 5f321f0ada53f4b603d83dafa6b0646d0b4f4b55 Mon Sep 17 00:00:00 2001 From: nekomoyi Date: Tue, 28 Apr 2026 01:33:52 +0800 Subject: [PATCH 4/5] feat(env): add PowerShell eval signal and update shell detection --- crates/vite_global_cli/src/commands/env/setup.rs | 2 ++ crates/vite_global_cli/src/commands/env/use.rs | 9 +++------ crates/vite_shared/src/env_config.rs | 7 +++++++ crates/vite_shared/src/env_vars.rs | 3 +++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/vite_global_cli/src/commands/env/setup.rs b/crates/vite_global_cli/src/commands/env/setup.rs index c8a62b1f44..6d4c48a1d4 100644 --- a/crates/vite_global_cli/src/commands/env/setup.rs +++ b/crates/vite_global_cli/src/commands/env/setup.rs @@ -644,6 +644,7 @@ function vp { & (Join-Path $__vp_bin "vp") @args; return } $env:VP_ENV_USE_EVAL_ENABLE = "1" + $env:VP_SHELL_PWSH = "1" $output = & (Join-Path $__vp_bin "vp") @args 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { Write-Host $_.Exception.Message @@ -652,6 +653,7 @@ function vp { } } Remove-Item Env:VP_ENV_USE_EVAL_ENABLE -ErrorAction SilentlyContinue + Remove-Item Env:VP_SHELL_PWSH -ErrorAction SilentlyContinue if ($LASTEXITCODE -eq 0 -and $output) { Invoke-Expression ($output -join "`n") } diff --git a/crates/vite_global_cli/src/commands/env/use.rs b/crates/vite_global_cli/src/commands/env/use.rs index 27ee6dc819..9bf51fef0b 100644 --- a/crates/vite_global_cli/src/commands/env/use.rs +++ b/crates/vite_global_cli/src/commands/env/use.rs @@ -36,7 +36,7 @@ fn detect_shell() -> Shell { Shell::Fish } else if config.vp_shell_nu { Shell::NuShell - } else if cfg!(windows) && config.ps_module_path.is_some() { + } else if config.vp_shell_pwsh { Shell::PowerShell } else if cfg!(windows) { Shell::Cmd @@ -178,15 +178,12 @@ mod tests { use super::*; #[test] - fn test_detect_shell_posix_even_with_psmodulepath() { + fn test_detect_shell_pwsh() { let _guard = vite_shared::EnvConfig::test_guard(vite_shared::EnvConfig { - ps_module_path: Some("/some/path".into()), + vp_shell_pwsh: true, ..vite_shared::EnvConfig::for_test() }); let shell = detect_shell(); - #[cfg(not(windows))] - assert!(matches!(shell, Shell::Posix)); - #[cfg(windows)] assert!(matches!(shell, Shell::PowerShell)); } diff --git a/crates/vite_shared/src/env_config.rs b/crates/vite_shared/src/env_config.rs index 6818058c5b..841e2b4b14 100644 --- a/crates/vite_shared/src/env_config.rs +++ b/crates/vite_shared/src/env_config.rs @@ -135,6 +135,11 @@ pub struct EnvConfig { /// /// Env: `VP_SHELL_NU` pub vp_shell_nu: bool, + + /// Explicit PowerShell eval signal set by the `env.ps1` wrapper. + /// + /// Env: `VP_SHELL_PWSH` + pub vp_shell_pwsh: bool, } impl EnvConfig { @@ -166,6 +171,7 @@ impl EnvConfig { ps_module_path: std::env::var("PSModulePath").ok(), nu_version: std::env::var("NU_VERSION").ok(), vp_shell_nu: std::env::var(env_vars::VP_SHELL_NU).is_ok(), + vp_shell_pwsh: std::env::var(env_vars::VP_SHELL_PWSH).is_ok(), } } @@ -250,6 +256,7 @@ impl EnvConfig { ps_module_path: None, nu_version: None, vp_shell_nu: false, + vp_shell_pwsh: false, } } diff --git a/crates/vite_shared/src/env_vars.rs b/crates/vite_shared/src/env_vars.rs index 5618e416fc..55badcfdab 100644 --- a/crates/vite_shared/src/env_vars.rs +++ b/crates/vite_shared/src/env_vars.rs @@ -43,6 +43,9 @@ pub const VP_ENV_USE_EVAL_ENABLE: &str = "VP_ENV_USE_EVAL_ENABLE"; /// bash/zsh is launched from a Nushell session. pub const VP_SHELL_NU: &str = "VP_SHELL_NU"; +/// Explicit signal set by the PowerShell wrapper to indicate PowerShell eval context. +pub const VP_SHELL_PWSH: &str = "VP_SHELL_PWSH"; + /// Filter for update task types. pub const VITE_UPDATE_TASK_TYPES: &str = "VITE_UPDATE_TASK_TYPES"; From 1b850ec1cacb1cf2d221c426f8ad60249468a907 Mon Sep 17 00:00:00 2001 From: nekomoyi Date: Tue, 28 Apr 2026 01:34:09 +0800 Subject: [PATCH 5/5] fix(ci): exclude 'namespace-profile-linux-x64-default' --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ddb980398..790c3c7957 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,6 +269,7 @@ jobs: RUST_MIN_STACK: 8388608 - name: Test global package install (powershell) + if: ${{ matrix.os != 'namespace-profile-linux-x64-default' }} shell: pwsh run: | $vpHome = Join-Path $HOME ".vite-plus" @@ -447,6 +448,7 @@ jobs: fi - name: Test upgrade (powershell) + if: ${{ matrix.os != 'namespace-profile-linux-x64-default' }} shell: pwsh run: | $vpHome = Join-Path $HOME ".vite-plus" @@ -556,6 +558,7 @@ jobs: vp --version - name: Test implode (powershell) + if: ${{ matrix.os != 'namespace-profile-linux-x64-default' }} shell: pwsh run: | $vpHome = Join-Path $HOME ".vite-plus"