fix: remove setx calls to not permanently edit the windows shell PATH (#5821)
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import { spawn } from 'child_process';
|
|
||||||
import log from './logger';
|
import log from './logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,8 +20,8 @@ export async function ensureWinShims(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
await fs.promises.mkdir(tgtDir, { recursive: true });
|
await fs.promises.mkdir(tgtDir, { recursive: true });
|
||||||
|
|
||||||
// Only copy the command-line tools, NOT goosed.exe (which should always be used locally)
|
// Copy command-line tools, NOT goosed.exe (which should always be used locally)
|
||||||
const shims = ['uvx.exe', 'npx.cmd', 'install-node.cmd'];
|
const shims = ['uvx.exe', 'uv.exe', 'npx.cmd', 'install-node.cmd'];
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
shims.map(async (shim) => {
|
shims.map(async (shim) => {
|
||||||
@@ -39,12 +38,12 @@ export async function ensureWinShims(): Promise<void> {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prepend to PATH **for this process & all children**.
|
// Prepend to PATH **for this process & all children only**.
|
||||||
// Make sure our bin directory is at the VERY BEGINNING of PATH
|
// This does NOT modify the user's permanent system PATH.
|
||||||
const currentPath = process.env.PATH ?? '';
|
const currentPath = process.env.PATH ?? '';
|
||||||
if (!currentPath.toLowerCase().includes(tgtDir.toLowerCase())) {
|
if (!currentPath.toLowerCase().includes(tgtDir.toLowerCase())) {
|
||||||
process.env.PATH = `${tgtDir}${path.delimiter}${currentPath}`;
|
process.env.PATH = `${tgtDir}${path.delimiter}${currentPath}`;
|
||||||
log.info(`Added ${tgtDir} to PATH for current process`);
|
log.info(`Added ${tgtDir} to PATH for Goose processes only`);
|
||||||
} else {
|
} else {
|
||||||
// If it's already in PATH, make sure it's at the beginning
|
// If it's already in PATH, make sure it's at the beginning
|
||||||
const pathParts = currentPath.split(path.delimiter);
|
const pathParts = currentPath.split(path.delimiter);
|
||||||
@@ -54,71 +53,10 @@ export async function ensureWinShims(): Promise<void> {
|
|||||||
// Remove it from its current position and add to beginning
|
// Remove it from its current position and add to beginning
|
||||||
pathParts.splice(binDirIndex, 1);
|
pathParts.splice(binDirIndex, 1);
|
||||||
process.env.PATH = `${tgtDir}${path.delimiter}${pathParts.join(path.delimiter)}`;
|
process.env.PATH = `${tgtDir}${path.delimiter}${pathParts.join(path.delimiter)}`;
|
||||||
log.info(`Moved ${tgtDir} to beginning of PATH for current process`);
|
log.info(`Moved ${tgtDir} to beginning of PATH for Goose processes only`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Persist PATH for user's external PowerShell/CMD sessions
|
|
||||||
await persistPathForUser(tgtDir);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Failed to ensure Windows shims:', error);
|
log.error('Failed to ensure Windows shims:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the Goose bin directory to the user's PATH environment variable.
|
|
||||||
* Uses only user PATH to avoid overwriting with system PATH and respects setx 1024 char limit.
|
|
||||||
*/
|
|
||||||
async function persistPathForUser(binDir: string): Promise<void> {
|
|
||||||
try {
|
|
||||||
const psScript = `
|
|
||||||
$bin = "${binDir.replace(/\\/g, '\\\\')}"
|
|
||||||
|
|
||||||
$userPath = [System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
||||||
if ($userPath -eq $null) { $userPath = "" }
|
|
||||||
|
|
||||||
$pathParts = $userPath -split ';' | Where-Object { $_.Trim() -ne "" }
|
|
||||||
$binExists = $pathParts | Where-Object { $_ -ieq $bin }
|
|
||||||
|
|
||||||
if (-not $binExists) {
|
|
||||||
$newUserPath = if ($userPath -eq "") { $bin } else { "$bin;$userPath" }
|
|
||||||
|
|
||||||
if ($newUserPath.Length -gt 1024) {
|
|
||||||
Write-Warning "Cannot add to PATH: would exceed 1024 character limit for setx ($($newUserPath.Length) chars)"
|
|
||||||
Write-Host "Current user PATH length: $($userPath.Length) chars"
|
|
||||||
Write-Host "Consider using system PATH or cleaning up existing PATH entries"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setx PATH $newUserPath >$null
|
|
||||||
Write-Host "Added Goose bin directory to beginning of user PATH"
|
|
||||||
Write-Host "New user PATH length: $($newUserPath.Length) chars"
|
|
||||||
} else {
|
|
||||||
if ($pathParts[0] -ieq $bin) {
|
|
||||||
Write-Host "Goose bin directory already at beginning of user PATH"
|
|
||||||
} else {
|
|
||||||
$filteredParts = $pathParts | Where-Object { $_ -ine $bin }
|
|
||||||
$newUserPath = @($bin) + $filteredParts -join ';'
|
|
||||||
|
|
||||||
if ($newUserPath.Length -gt 1024) {
|
|
||||||
Write-Warning "Cannot reorder PATH: would exceed 1024 character limit for setx ($($newUserPath.Length) chars)"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setx PATH $newUserPath >$null
|
|
||||||
Write-Host "Moved Goose bin directory to beginning of user PATH"
|
|
||||||
Write-Host "New user PATH length: $($newUserPath.Length) chars"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
spawn('powershell', ['-NoProfile', '-NonInteractive', '-Command', psScript], {
|
|
||||||
windowsHide: true,
|
|
||||||
shell: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
log.info('Attempted to persist Goose bin directory to user PATH');
|
|
||||||
} catch (error) {
|
|
||||||
log.warn('Failed to persist PATH for user (non-critical):', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user