From 42beb1e91f8d12ec5388231cd24c4c197288c6e4 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Thu, 16 Apr 2026 08:05:37 +0000 Subject: [PATCH] Append to User PATH by default, close $envKey in finally Add-ToUserPath gains a -Position Append|Prepend parameter defaulting to Append so installing unsloth no longer prepends the bundled venv Scripts directory ahead of the user's existing python / pip on new shells. The four current call sites (install.ps1 launcher, studio/setup.ps1 CMake, nvcc, Python user Scripts) all take the Append default because each one that needs in-session precedence already does an inline $env:Path prepend independently. This matches rustup / cargo / nvm / pyenv / uv behavior. Also wrap the script-top $envKey.GetValue in a try/finally so the registry handle is released even if the read throws. Matches the pattern already used for $backupKey five lines below. --- install.ps1 | 18 ++++++++++++++++-- studio/setup.ps1 | 25 +++++++++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/install.ps1 b/install.ps1 index eb9b32f4ff..842ce90de9 100644 --- a/install.ps1 +++ b/install.ps1 @@ -134,9 +134,19 @@ function Install-UnslothStudio { # ── Helper: safely add a directory to the persistent User PATH ── # Uses direct registry access to preserve REG_EXPAND_SZ type # (avoids .NET SetEnvironmentVariable bug that converts to REG_SZ). + # + # Position: 'Append' (default) adds $Directory to the END of the persisted + # User PATH so existing user tools (e.g. system python, pip) keep taking + # precedence in new shells. This matches rustup/cargo/nvm/pyenv/uv behavior + # and avoids silently hijacking resolution of common executables. Pass + # 'Prepend' only when a caller truly needs the new entry to win over + # existing ones at registry scope. In-session precedence should be handled + # by an inline $env:Path = "$Dir;$env:Path" prepend instead. function Add-ToUserPath { param( - [Parameter(Mandatory = $true)][string]$Directory + [Parameter(Mandatory = $true)][string]$Directory, + [ValidateSet('Append','Prepend')] + [string]$Position = 'Append' ) try { $regKey = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Environment') @@ -171,7 +181,11 @@ function Install-UnslothStudio { if (-not $rawPath) { Write-Host "[WARN] User PATH is empty — initializing with $Directory" -ForegroundColor Yellow } - $newPath = if ($rawPath) { "$Directory;$rawPath" } else { $Directory } + $newPath = if ($rawPath) { + if ($Position -eq 'Prepend') { "$Directory;$rawPath" } else { "$rawPath;$Directory" } + } else { + $Directory + } $regKey.SetValue('Path', $newPath, [Microsoft.Win32.RegistryValueKind]::ExpandString) # Broadcast WM_SETTINGCHANGE so other processes pick up the change try { diff --git a/studio/setup.ps1 b/studio/setup.ps1 index 052bfc8f83..173f97b8f0 100644 --- a/studio/setup.ps1 +++ b/studio/setup.ps1 @@ -104,9 +104,19 @@ function Refresh-Environment { # ── Helper: safely add a directory to the persistent User PATH ── # Uses direct registry access to preserve REG_EXPAND_SZ type # (avoids .NET SetEnvironmentVariable bug that converts to REG_SZ). +# +# Position: 'Append' (default) adds $Directory to the END of the persisted +# User PATH so existing user tools (e.g. system python, pip) keep taking +# precedence in new shells. This matches rustup/cargo/nvm/pyenv/uv behavior +# and avoids silently hijacking resolution of common executables. Pass +# 'Prepend' only when a caller truly needs the new entry to win over +# existing ones at registry scope. In-session precedence should be handled +# by an inline $env:Path = "$Dir;$env:Path" prepend instead. function Add-ToUserPath { param( - [Parameter(Mandatory = $true)][string]$Directory + [Parameter(Mandatory = $true)][string]$Directory, + [ValidateSet('Append','Prepend')] + [string]$Position = 'Append' ) try { $regKey = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Environment') @@ -143,7 +153,11 @@ function Add-ToUserPath { if (-not $rawPath) { Write-Host "[WARN] User PATH is empty — initializing with $Directory" -ForegroundColor Yellow } - $newPath = if ($rawPath) { "$Directory;$rawPath" } else { $Directory } + $newPath = if ($rawPath) { + if ($Position -eq 'Prepend') { "$Directory;$rawPath" } else { "$rawPath;$Directory" } + } else { + $Directory + } $regKey.SetValue('Path', $newPath, [Microsoft.Win32.RegistryValueKind]::ExpandString) # Broadcast WM_SETTINGCHANGE so other processes pick up the change try { @@ -584,8 +598,11 @@ if ($script:StudioVtOk -and -not $env:NO_COLOR) { try { $envKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment', $false) if ($envKey) { - $rawPath = $envKey.GetValue('Path', '', [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) - $envKey.Close() + try { + $rawPath = $envKey.GetValue('Path', '', [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) + } finally { + $envKey.Close() + } if ($rawPath) { $backupKey = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Software\Unsloth') try {