fix: add windows powershell passthrough

This commit is contained in:
Codex
2026-06-06 12:17:32 +00:00
parent 5b8ddcaf01
commit 3f26f4f359
5 changed files with 121 additions and 26 deletions
+66 -1
View File
@@ -1048,8 +1048,23 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
invocationKind: "helper",
};
}
if (operation === "ps" || operation === "powershell" || operation === "powershell.exe") {
const commandArgs = args[1] === "--" ? args.slice(2) : args.slice(1);
if (commandArgs.length === 0) {
return {
remoteCommand: buildWindowsPowerShellInvocation(buildWindowsPowerShellStdinLauncherScript(route.workspace)),
requiresStdin: true,
invocationKind: "helper",
};
}
return {
remoteCommand: buildWindowsPowerShellInvocation(buildWindowsPowerShellInlineLauncherScript(commandArgs.join(" "), route.workspace)),
requiresStdin: false,
invocationKind: "helper",
};
}
if (operation !== "cmd" && operation !== "cmd.exe") {
throw new Error(`unsupported ssh win operation: ${operation}; use ssh ${route.providerId}:win cmd <command-line>, ssh ${route.providerId}:win apply-patch, or ssh ${route.providerId}:win skills`);
throw new Error(`unsupported ssh win operation: ${operation}; use ssh ${route.providerId}:win ps, ssh ${route.providerId}:win cmd <command-line>, ssh ${route.providerId}:win apply-patch, or ssh ${route.providerId}:win skills`);
}
const commandArgs = args[1] === "--" ? args.slice(2) : args.slice(1);
if (commandArgs.length === 0) {
@@ -1205,6 +1220,56 @@ function buildWindowsCmdStdinLauncherScript(cwd: string | null): string {
].join(" ");
}
function windowsPowerShellScriptPrelude(cwd: string | null): string {
return [
"$ErrorActionPreference = 'Stop'",
"$ProgressPreference = 'SilentlyContinue'",
"[Console]::InputEncoding = [System.Text.UTF8Encoding]::new()",
"[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()",
"$OutputEncoding = [System.Text.UTF8Encoding]::new()",
"$env:PYTHONUTF8 = '1'",
"$env:PYTHONIOENCODING = 'utf-8'",
...(cwd === null ? [] : [`Set-Location -LiteralPath ${powerShellSingleQuote(cwd)}`]),
].join("\r\n") + "\r\n";
}
function buildWindowsPowerShellInlineLauncherScript(command: string, cwd: string | null): string {
if (command.trim().length === 0) throw new Error("ssh win ps requires a command or stdin PowerShell script");
return buildWindowsPowerShellScriptRunner(powerShellSingleQuote(command), cwd);
}
function buildWindowsPowerShellStdinLauncherScript(cwd: string | null): string {
return buildWindowsPowerShellScriptRunner("[Console]::In.ReadToEnd()", cwd);
}
function buildWindowsPowerShellScriptRunner(scriptExpression: string, cwd: string | null): string {
return [
"$ErrorActionPreference = 'Stop';",
"$ProgressPreference = 'SilentlyContinue';",
"[Console]::InputEncoding = [System.Text.UTF8Encoding]::new();",
"[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new();",
"$OutputEncoding = [System.Text.UTF8Encoding]::new();",
`$script = ${scriptExpression};`,
"$script = $script -replace \"`r`n\", \"`n\";",
"$script = $script -replace \"`r\", \"`n\";",
"$script = $script -replace \"`n\", \"`r`n\";",
"if (-not $script.EndsWith(\"`r`n\")) { $script += \"`r`n\" }",
"if ([string]::IsNullOrWhiteSpace($script)) { [Console]::Error.WriteLine('ssh win ps requires a command or stdin PowerShell script'); exit 2 }",
"$script += \"`r`nif (`$global:LASTEXITCODE -is [int] -and `$global:LASTEXITCODE -ne 0) { exit `$global:LASTEXITCODE }`r`n\";",
`$prefix = ${powerShellSingleQuote(windowsPowerShellScriptPrelude(cwd))};`,
"$temp = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), ('unidesk-win-ps-' + [guid]::NewGuid().ToString('N') + '.ps1'));",
"try {",
" [System.IO.File]::WriteAllText($temp, $prefix + $script, [System.Text.UTF8Encoding]::new($true));",
" & (Join-Path $PSHOME 'powershell.exe') -NoProfile -ExecutionPolicy Bypass -File $temp;",
" $code = $LASTEXITCODE;",
" if ($null -eq $code) { $code = 0 }",
"} finally {",
" Remove-Item -LiteralPath $temp -Force -ErrorAction SilentlyContinue;",
"}",
"exit $code;",
].join(" ");
}
export function buildWindowsPowerShellInvocation(script: string): string {
return shellArgv([
windowsPowerShellExePath,