fix: harden Windows trans helpers
Resolve #1691 by preserving argv boundaries, adding bounded native rg and wc/skill query support, surfacing WSL-to-Windows hints, and splitting the oversized SSH module and embedded remote scripts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+46
-1
@@ -16,6 +16,7 @@ import {
|
||||
sshStderrStreamMaxBytes,
|
||||
sshStdoutStreamMaxBytes,
|
||||
sshStdoutTruncationHint,
|
||||
sshWindowsPlaneHint,
|
||||
windowsFsReadOnlyScript,
|
||||
windowsPowerShellScriptPrelude,
|
||||
} from "./ssh";
|
||||
@@ -25,6 +26,12 @@ function sha256Hex(text: string): string {
|
||||
return createHash("sha256").update(text, "utf8").digest("hex");
|
||||
}
|
||||
|
||||
function decodedWindowsPowerShellCommand(remoteCommand: string | null): string {
|
||||
const encoded = remoteCommand?.match(/'([A-Za-z0-9+/=]+)'$/u)?.[1];
|
||||
if (encoded === undefined) throw new Error("Windows PowerShell command did not end in an encoded payload");
|
||||
return Buffer.from(encoded, "base64").toString("utf16le");
|
||||
}
|
||||
|
||||
function minimalConfig(publicHost = "203.0.113.10"): UniDeskConfig {
|
||||
return {
|
||||
network: { publicHost },
|
||||
@@ -89,7 +96,22 @@ describe("ssh windows fs read-only operations", () => {
|
||||
expect(lsScript).toContain("TYPE BYTES UPDATED NAME");
|
||||
expect(rgScript).toContain("$operation = 'rg';");
|
||||
expect(rgScript).toContain("unsupported rg option on Windows route");
|
||||
expect(rgScript).toContain("UNIDESK_WINDOWS_FS_SKIPPED");
|
||||
expect(rgScript).toContain("UNIDESK_WINDOWS_RG_SUMMARY");
|
||||
expect(rgScript).toContain("engine=native-rg");
|
||||
expect(rgScript).toContain("config/unidesk-cli.yaml#trans.windowsFs.rg");
|
||||
expect(rgScript).toContain("--files");
|
||||
expect(rgScript).toContain("--glob");
|
||||
});
|
||||
|
||||
test("supports wc flags, exact skill lookup, and Windows cmd argv boundaries", () => {
|
||||
const wcScript = windowsFsReadOnlyScript("F:\\Work\\demo", "wc", ["-l", "docs/read me.md"]);
|
||||
const skills = parseSshInvocation("D601:win", ["skills", "--scope", "agents", "--name", "mdtodo-edit"]);
|
||||
const cmd = parseSshInvocation("D601:win/F/Work/demo", ["cmd", "python", "tool.py", "71-FILTER 高频输出精度与频率跳变改进"]);
|
||||
|
||||
expect(wcScript).toContain("$arg -eq '-l'");
|
||||
expect(wcScript).toContain("unsupported wc option on Windows route");
|
||||
expect(decodedWindowsPowerShellCommand(skills.parsed.remoteCommand)).toContain("$exactName = 'mdtodo-edit'");
|
||||
expect(decodedWindowsPowerShellCommand(cmd.parsed.remoteCommand)).toContain('python tool.py "71-FILTER 高频输出精度与频率跳变改进"');
|
||||
});
|
||||
|
||||
test("rejects unsupported Windows read operations instead of treating them as POSIX", () => {
|
||||
@@ -102,6 +124,29 @@ describe("ssh windows fs read-only operations", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("ssh direct argv boundaries and plane diagnostics", () => {
|
||||
test("preserves a shell-formed argv token containing spaces and Chinese", () => {
|
||||
const invocation = parseSshInvocation("G14-WSL:/mnt/d/Work/CONSTAR_workspace", [
|
||||
"python3",
|
||||
"/tmp/mdtodo-edit-cli.py",
|
||||
"add",
|
||||
"docs/MDTODO/example.md",
|
||||
"71-FILTER 高频输出精度与频率跳变改进",
|
||||
]);
|
||||
|
||||
expect(invocation.parsed.remoteCommand).toContain("'python3' '/tmp/mdtodo-edit-cli.py' 'add' 'docs/MDTODO/example.md' '71-FILTER 高频输出精度与频率跳变改进'");
|
||||
});
|
||||
|
||||
test("suggests the matching Windows plane after WSL command-not-found", () => {
|
||||
const invocation = parseSshInvocation("G14-WSL:/mnt/d/Work/CONSTAR_workspace", ["python", "--version"]);
|
||||
const hint = sshWindowsPlaneHint(invocation, 127, "sh: python: command not found\n");
|
||||
|
||||
expect(hint).toContain("wsl-command-not-found-check-windows-plane");
|
||||
expect(hint).toContain("G14-WSL:win/d/Work/CONSTAR_workspace");
|
||||
expect(sshWindowsPlaneHint(invocation, 1, "no match")).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ssh host apply-patch fs backend", () => {
|
||||
test("uses POSIX bulk fs operations for host routes", async () => {
|
||||
const invocation = parseSshInvocation("D601:/mnt/f/Work/ConStart", ["apply-patch"]);
|
||||
|
||||
Reference in New Issue
Block a user