fix: improve trans windows route hints

This commit is contained in:
Codex
2026-06-27 02:05:42 +00:00
parent 3b2399c902
commit 4b71bed594
6 changed files with 100 additions and 5 deletions
+66 -1
View File
@@ -1147,6 +1147,9 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
if (operation.length === 0) {
throw new Error(`ssh ${route.raw} requires a Windows operation, for example: ssh ${route.providerId}:win cmd ver or ssh ${route.providerId}:win skills`);
}
if (operation === "win") {
throw new Error(windowsRouteRepeatedWinOperationMessage(route, args.slice(1)));
}
if (operation === "upload" || operation === "download") {
return { remoteCommand: null, requiresStdin: false, invocationKind: "helper" };
}
@@ -1179,6 +1182,9 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
invocationKind: "helper",
};
}
if (operation === "git") {
return parseWindowsGitInvocation(route, args.slice(1));
}
if (operation === "ps" || operation === "powershell" || operation === "powershell.exe") {
const commandArgs = args[1] === "--" ? args.slice(2) : args.slice(1);
if (commandArgs.length >= 2 && (commandArgs[0] === "-File" || commandArgs[0] === "-file")) {
@@ -1203,7 +1209,7 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
};
}
if (operation !== "cmd" && operation !== "cmd.exe") {
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 <pwd|ls|cat|head|tail|stat|wc|rg>, ssh ${route.providerId}:win apply-patch, or ssh ${route.providerId}:win skills`);
throw new Error(windowsUnsupportedOperationMessage(route, operation));
}
const commandArgs = args[1] === "--" ? args.slice(2) : args.slice(1);
if (commandArgs.length === 0) {
@@ -1220,6 +1226,56 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
};
}
function windowsRouteRepeatedWinOperationMessage(route: ParsedSshRoute, nextArgs: string[]): string {
const entrypoint = sshDisplayEntrypoint();
const suffix = nextArgs.length > 0 ? ` ${nextArgs.join(" ")}` : " ps";
return `unsupported ssh win operation: win; route ${route.raw} already selects the Windows plane. ` +
`Write the operation directly after the route, for example \`${entrypoint} ${route.raw}${suffix}\`, not \`${entrypoint} ${route.raw} win${suffix}\`.`;
}
function windowsUnsupportedOperationMessage(route: ParsedSshRoute, operation: string): string {
const entrypoint = sshDisplayEntrypoint();
const gitHint = operation === "sed" || operation === "bash" || operation === "sh"
? ` For repository commands on Windows, use \`${entrypoint} ${route.raw} git status --short --branch\`, \`${entrypoint} ${route.raw} git commit -m <message>\`, or wrap custom commands with \`${entrypoint} ${route.raw} ps <<'PS'\`.`
: ` If you meant to run a repository command, use \`${entrypoint} ${route.raw} git status --short --branch\`, \`${entrypoint} ${route.raw} git commit -m <message>\`, or wrap it with \`${entrypoint} ${route.raw} ps <<'PS'\`.`;
return `unsupported ssh win operation: ${operation}; Windows route operations are ps, cmd, skills, apply-patch, upload/download, git, and read-only fs helpers pwd|ls|cat|head|tail|stat|wc|rg.${gitHint}`;
}
function parseWindowsGitInvocation(route: ParsedSshRoute, gitArgs: string[]): ParsedSshArgs {
const subcommand = gitArgs[0] ?? "";
if (subcommand.length === 0) throw new Error(`ssh ${route.raw} git requires a git subcommand, for example: ${sshDisplayEntrypoint()} ${route.raw} git status --short --branch`);
if (subcommand === "commit") validateWindowsGitCommitArgs(route, gitArgs);
const commandLine = ["git", ...gitArgs].map((value) => windowsCmdArgument(value, route)).join(" ");
return {
remoteCommand: buildWindowsPowerShellInvocation(buildWindowsCmdLauncherScript(buildWindowsCmdLine(commandLine, route.workspace))),
requiresStdin: false,
invocationKind: "argv",
};
}
function validateWindowsGitCommitArgs(route: ParsedSshRoute, gitArgs: string[]): void {
const hasNonInteractiveMessage = gitArgs.slice(1).some((arg) => (
arg === "--dry-run" ||
arg === "--no-edit" ||
arg === "-m" ||
arg.startsWith("-m") ||
arg === "--message" ||
arg.startsWith("--message=") ||
arg === "-F" ||
arg.startsWith("-F") ||
arg === "--file" ||
arg.startsWith("--file=") ||
arg === "-C" ||
arg.startsWith("-C") ||
arg === "--reuse-message" ||
arg.startsWith("--reuse-message=") ||
arg.startsWith("--fixup=")
));
if (hasNonInteractiveMessage) return;
const entrypoint = sshDisplayEntrypoint();
throw new Error(`ssh win git commit would open an editor; use ${entrypoint} ${route.raw} git commit -m <message>, ${entrypoint} ${route.raw} git commit --no-edit, or wrap an interactive command with ${entrypoint} ${route.raw} ps <<'PS'`);
}
type WindowsFsReadOnlyOperation = "pwd" | "ls" | "cat" | "head" | "tail" | "stat" | "wc" | "rg";
const windowsFsReadOnlyOperations = new Set<string>(["pwd", "ls", "cat", "head", "tail", "stat", "wc", "rg"]);
const windowsFsReadOnlyDefaultMaxBytes = 256 * 1024;
@@ -1281,6 +1337,15 @@ function windowsCmdQuote(value: string): string {
return `"${value}"`;
}
function windowsCmdArgument(value: string, route: ParsedSshRoute): string {
if (value.length === 0) return "\"\"";
if (/[\r\n"]/u.test(value) || /[&|<>^%!]/u.test(value)) {
const entrypoint = sshDisplayEntrypoint();
throw new Error(`ssh win git argument contains characters that require shell review; use ${entrypoint} ${route.raw} ps <<'PS' for this command`);
}
return /\s/u.test(value) ? `"${value}"` : value;
}
function parseWindowsSkillsOptions(args: string[]): { limit: number; scopes: Array<"agents" | "codex"> } {
let limit = 100;
let scope: "agents" | "codex" | "all" = "agents";