fix: 补强 Windows rg 与 PowerShell 诊断
This commit is contained in:
@@ -62,7 +62,7 @@ if ($null -ne $nativeRg) {
|
||||
if (-not $filesOnly) { foreach ($line in $selected) { if ($line -match '^([A-Za-z]:\\.*?):\d+:') { [void]$matchedFiles.Add($Matches[1]) } } }
|
||||
$fileCount = if ($filesOnly) { $selected.Count } else { $matchedFiles.Count }
|
||||
[Console]::Error.WriteLine('UNIDESK_WINDOWS_RG_SUMMARY matched=' + $selected.Count + ' fileCount=' + $fileCount + ' elapsedMs=' + $stopwatch.ElapsedMilliseconds + ' timeout=' + $timedOut.ToString().ToLowerInvariant() + ' skipped=0 fileLimit=' + ($filesOnly -and $truncated).ToString().ToLowerInvariant() + ' matchLimit=' + ((-not $filesOnly) -and $truncated).ToString().ToLowerInvariant() + ' engine=native-rg config=config/unidesk-cli.yaml#trans.windowsFs.rg')
|
||||
if ($timedOut) { exit 124 }
|
||||
if ($timedOut) { [Console]::Error.WriteLine('UNIDESK_WINDOWS_RG_HINT code=timeout exitCode=124 action=narrow-scope-or-add-glob message=retry-with-a-narrower-path-or-g/--glob'); exit 124 }
|
||||
if ($process.ExitCode -ne 0) { exit $process.ExitCode }
|
||||
exit 0
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ describe("ssh windows fs read-only operations", () => {
|
||||
expect(rgScript).toContain("$operation = 'rg';");
|
||||
expect(rgScript).toContain("unsupported rg option on Windows route");
|
||||
expect(rgScript).toContain("UNIDESK_WINDOWS_RG_SUMMARY");
|
||||
expect(rgScript).toContain("UNIDESK_WINDOWS_RG_HINT code=timeout exitCode=124 action=narrow-scope-or-add-glob");
|
||||
expect(rgScript).toContain("engine=native-rg");
|
||||
expect(rgScript).toContain("config/unidesk-cli.yaml#trans.windowsFs.rg");
|
||||
expect(rgScript).toContain("--files");
|
||||
@@ -142,6 +143,27 @@ describe("ssh windows fs read-only operations", () => {
|
||||
expect(() => parseSshInvocation("D601:win/F/Work/ConStart", ["win", "ps"])).toThrow("route D601:win/F/Work/ConStart already selects the Windows plane");
|
||||
expect(() => parseSshInvocation("D601:win/F/Work/ConStart", ["git", "commit"])).toThrow("ssh win git commit would open an editor");
|
||||
});
|
||||
|
||||
test("diagnoses locally expanded PowerShell variables before remote execution", () => {
|
||||
try {
|
||||
parseSshInvocation("G14-WSL:win/d/Work/demo", ["ps", "= Start-Process python -PassThru; .Id"]);
|
||||
throw new Error("expected local PowerShell expansion diagnosis");
|
||||
} catch (error) {
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
const payload = error as Error & {
|
||||
code?: string;
|
||||
replacementExamples?: { oneLine?: string; pipeline?: string; stdin?: string };
|
||||
migrationHint?: string;
|
||||
};
|
||||
expect(payload.code).toBe("ssh-windows-powershell-local-expansion");
|
||||
expect(payload.replacementExamples?.oneLine).toContain("ps '$p = Start-Process python -PassThru; $p.Id'");
|
||||
expect(payload.replacementExamples?.pipeline).toContain("Where-Object { $_.CPU -gt 0 }");
|
||||
expect(payload.replacementExamples?.stdin).toContain("ps <<'PS'");
|
||||
expect(payload.migrationHint).toContain("local single quotes");
|
||||
}
|
||||
|
||||
expect(() => parseSshInvocation("G14-WSL:win/d/Work/demo", ["ps", "$p = Start-Process python -PassThru; $p.Id"])).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("ssh direct argv boundaries and plane diagnostics", () => {
|
||||
|
||||
+33
-1
@@ -129,6 +129,32 @@ export class SshRemovedShellAliasError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export class SshWindowsPowerShellLocalExpansionError extends Error {
|
||||
code = "ssh-windows-powershell-local-expansion";
|
||||
level = "error";
|
||||
entrypoint: string;
|
||||
route: string;
|
||||
operation = "ps";
|
||||
replacementExamples: { oneLine: string; pipeline: string; stdin: string };
|
||||
migrationHint: string;
|
||||
note = "Local Bash expands $p and $_ inside double quotes before trans receives the PowerShell source.";
|
||||
|
||||
constructor(route: string) {
|
||||
const entrypoint = sshDisplayEntrypoint();
|
||||
const replacementExamples = {
|
||||
oneLine: `${entrypoint} ${route} ps '$p = Start-Process python -PassThru; $p.Id'`,
|
||||
pipeline: `${entrypoint} ${route} ps 'Get-Process | Where-Object { $_.CPU -gt 0 }'`,
|
||||
stdin: `${entrypoint} ${route} ps <<'PS'`,
|
||||
};
|
||||
super("ssh win ps source looks like a PowerShell variable was expanded by the local shell before trans received it");
|
||||
this.name = "SshWindowsPowerShellLocalExpansionError";
|
||||
this.entrypoint = entrypoint;
|
||||
this.route = route;
|
||||
this.replacementExamples = replacementExamples;
|
||||
this.migrationHint = `Wrap the complete PowerShell source in local single quotes, for example: ${replacementExamples.oneLine}. Use a quoted PS heredoc for multiline source.`;
|
||||
}
|
||||
}
|
||||
|
||||
export interface SshStdoutTruncationHint {
|
||||
code: "ssh-stdout-truncated" | "ssh-stderr-truncated";
|
||||
level: "warning";
|
||||
@@ -522,8 +548,10 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
|
||||
invocationKind: "argv",
|
||||
};
|
||||
}
|
||||
const command = commandArgs[0] ?? "";
|
||||
if (looksLikeLocallyExpandedPowerShellSource(command)) throw new SshWindowsPowerShellLocalExpansionError(route.raw);
|
||||
return {
|
||||
remoteCommand: buildWindowsPowerShellInvocation(buildWindowsPowerShellInlineLauncherScript(commandArgs[0] ?? "", route.workspace)),
|
||||
remoteCommand: buildWindowsPowerShellInvocation(buildWindowsPowerShellInlineLauncherScript(command, route.workspace)),
|
||||
requiresStdin: false,
|
||||
invocationKind: "helper",
|
||||
};
|
||||
@@ -546,6 +574,10 @@ function parseWinRouteArgs(route: ParsedSshRoute, args: string[]): ParsedSshArgs
|
||||
};
|
||||
}
|
||||
|
||||
function looksLikeLocallyExpandedPowerShellSource(command: string): boolean {
|
||||
return /(?:^|[;{}]\s*)=\s*[^=]/u.test(command);
|
||||
}
|
||||
|
||||
function windowsRouteRepeatedWinOperationMessage(route: ParsedSshRoute, nextArgs: string[]): string {
|
||||
const entrypoint = sshDisplayEntrypoint();
|
||||
const suffix = nextArgs.length > 0 ? ` ${nextArgs.join(" ")}` : " ps";
|
||||
|
||||
Reference in New Issue
Block a user