feat: add tran win cmd route

This commit is contained in:
Codex
2026-05-25 18:02:40 +00:00
parent 974a7ac666
commit a1841adcaa
8 changed files with 160 additions and 11 deletions
+98 -2
View File
@@ -15,7 +15,7 @@ export type SshHelperName = "apply_patch" | "glob" | "skill-discover";
export interface ParsedSshRoute {
providerId: string;
plane: "host" | "k3s";
plane: "host" | "k3s" | "win";
entry: string | null;
namespace: string | null;
resource: string | null;
@@ -59,6 +59,9 @@ export interface SshRuntimeTimingHint {
const argvQuotedSshSubcommands = new Set(["git", "rg", "grep", "sed", "nl", "stat", "du", "ls", "cat", "head", "tail", "wc", "pwd"]);
const nativeK3sKubeconfig = "/etc/rancher/k3s/k3s.yaml";
const windowsBridgeCwd = "/mnt/c/Windows";
const windowsPowerShellExePath = "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe";
const windowsCmdExeNativePath = "C:\\Windows\\System32\\cmd.exe";
const defaultSshSlowWarningMs = 10_000;
const k3sResourceKindAliases = new Set(["pod", "po", "pods", "deployment", "deploy", "deployments", "statefulset", "sts", "daemonset", "ds", "job", "jobs"]);
const legacyK3sOperationRouteSegments = new Set([
@@ -859,6 +862,9 @@ export function parseSshInvocation(target: string, args: string[]): ParsedSshInv
if (route.plane === "k3s") {
return { providerId: route.providerId, route, parsed: parseK3sRouteArgs(route, args) };
}
if (route.plane === "win") {
return { providerId: route.providerId, route, parsed: parseWinRouteArgs(route, args) };
}
if ((args[0] ?? "") === "k3s") {
throw new Error(`ssh k3s shorthand is unsupported; use route syntax instead: ssh ${route.providerId}:k3s ${args.slice(1).join(" ")}`.trim());
}
@@ -880,6 +886,15 @@ export function parseSshRoute(target: string): ParsedSshRoute {
if (tail.startsWith("/")) {
return hostSshRoute(providerId, target, tail);
}
if (tail === "win32" || tail.startsWith("win32/") || tail.startsWith("win32:")) {
throw new Error(`unsupported ssh route plane: win32; use ${providerId}:win or ${providerId}:win/c/path`);
}
if (tail === "win" || tail.startsWith("win/")) {
return winSshRoute(providerId, target, parseWinRouteWorkspace(providerId, tail));
}
if (tail.startsWith("win:")) {
throw new Error(`ssh win workspace route uses slash syntax, for example: ssh ${providerId}:win/c/test cmd cd`);
}
const [plane, ...rest] = tail.split(":");
if (plane === undefined || plane.length === 0 || plane === "host") {
const workspace = rest.length > 0 ? rest.join(":") : null;
@@ -908,6 +923,87 @@ function hostSshRoute(providerId: string, raw: string, workspace: string | null)
return { providerId, plane: "host", entry: null, namespace: null, resource: null, container: null, workspace, raw };
}
function winSshRoute(providerId: string, raw: string, workspace: string | null): ParsedSshRoute {
return { providerId, plane: "win", entry: null, namespace: null, resource: null, container: null, workspace, raw };
}
function parseWinRouteWorkspace(providerId: string, tail: string): string | null {
if (tail === "win") return null;
const suffix = tail.slice("win/".length);
const slashIndex = suffix.indexOf("/");
const drive = slashIndex < 0 ? suffix : suffix.slice(0, slashIndex);
if (!/^[A-Za-z]$/u.test(drive)) {
throw new Error(`ssh win workspace route requires a drive letter, for example: ssh ${providerId}:win/c/test cmd cd`);
}
const rest = slashIndex < 0 ? "" : suffix.slice(slashIndex + 1);
const segments = rest.split("/").filter((segment) => segment.length > 0);
return `${drive.toUpperCase()}:\\${segments.join("\\")}`;
}
function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs {
const operation = args[0] ?? "";
if (operation.length === 0) {
throw new Error(`ssh ${route.raw} requires a Windows operation, for example: ssh ${route.providerId}:win cmd ver`);
}
if (operation !== "cmd" && operation !== "cmd.exe") {
throw new Error(`unsupported ssh win operation: ${operation}; use ssh ${route.providerId}:win cmd <command-line>`);
}
const commandArgs = args[1] === "--" ? args.slice(2) : args.slice(1);
if (commandArgs.length === 0) throw new Error(`ssh ${route.raw} cmd requires a command line, for example: ssh ${route.providerId}:win cmd ver`);
return {
remoteCommand: shellArgv([
windowsPowerShellExePath,
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-EncodedCommand",
buildWindowsPowerShellEncodedCommand(buildWindowsCmdLine(commandArgs.join(" "), route.workspace)),
]),
requiresStdin: false,
invocationKind: "argv",
};
}
function buildWindowsCmdLine(userCommand: string, cwd: string | null): string {
const parts = [
"chcp 65001>nul",
"set PYTHONUTF8=1",
"set PYTHONIOENCODING=utf-8",
];
if (cwd !== null) parts.push(`cd /d ${windowsCmdQuote(cwd)}`);
parts.push(userCommand);
return parts.join(" && ");
}
function windowsCmdQuote(value: string): string {
if (/[\r\n"]/u.test(value)) throw new Error("ssh win workspace path must not contain quotes or newlines");
return `"${value}"`;
}
function powerShellSingleQuote(value: string): string {
return `'${value.replace(/'/g, "''")}'`;
}
function buildWindowsPowerShellEncodedCommand(cmdLine: string): string {
const script = [
"$ErrorActionPreference = 'Stop';",
"[Console]::InputEncoding = [System.Text.UTF8Encoding]::new();",
"[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new();",
"$OutputEncoding = [System.Text.UTF8Encoding]::new();",
"$env:PYTHONUTF8 = '1';",
"$env:PYTHONIOENCODING = 'utf-8';",
`& ${powerShellSingleQuote(windowsCmdExeNativePath)} /d /s /c ${powerShellSingleQuote(cmdLine)};`,
"exit $LASTEXITCODE;",
].join(" ");
return Buffer.from(script, "utf16le").toString("base64");
}
export function sshRoutePayloadCwd(route: ParsedSshRoute): string | undefined {
if (route.plane === "host") return route.workspace ?? undefined;
if (route.plane === "win") return windowsBridgeCwd;
return undefined;
}
function routeSegmentHead(segment: string): string {
return segment.split("/")[0] ?? segment;
}
@@ -1806,7 +1902,7 @@ export async function runSsh(config: UniDeskConfig, providerId: string, args: st
const payload = {
providerId: invocation.providerId,
command: wrapSshRemoteCommand(parsed.remoteCommand, parsed.requiredHelpers),
cwd: invocation.route.plane === "host" ? invocation.route.workspace ?? undefined : undefined,
cwd: sshRoutePayloadCwd(invocation.route),
tty: parsed.remoteCommand === null,
stdinEotOnEnd: parsed.remoteCommand !== null,
openTimeoutMs,