| author | |
| committer | |
| log | b0b7b38da1dc4b19833d13f84eb907b1e2adfb63 |
| tree | 121145229de1ac152b0473fbcd055349ad9c1af5 |
| parent | fd3b96b487a9aac8a011c27f977067d63d942ac1 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>2 files changed, 33 insertions(+), 2 deletions(-)
apps/server/src/processRunner.test.ts+19-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | import { describe, expect, it } from "vitest"; | 1 | import { describe, expect, it } from "vitest"; |
| 2 | 2 | ||
| 3 | import { runProcess } from "./processRunner.ts"; | 3 | import { isWindowsCommandNotFound, runProcess } from "./processRunner.ts"; |
| 4 | 4 | ||
| 5 | describe("runProcess", () => { | 5 | describe("runProcess", () => { |
| 6 | it("fails when output exceeds max buffer in default mode", async () => { | 6 | it("fails when output exceeds max buffer in default mode", async () => { |
| ... | @@ -21,3 +21,21 @@ describe("runProcess", () => { | ... | @@ -21,3 +21,21 @@ describe("runProcess", () => { |
| 21 | expect(result.stderrTruncated).toBe(false); | 21 | expect(result.stderrTruncated).toBe(false); |
| 22 | }); | 22 | }); |
| 23 | }); | 23 | }); |
| 24 | |||
| 25 | describe("isWindowsCommandNotFound", () => { | ||
| 26 | it("matches the localized German cmd.exe error text", () => { | ||
| 27 | const originalPlatform = process.platform; | ||
| 28 | Object.defineProperty(process, "platform", { value: "win32", configurable: true }); | ||
| 29 | |||
| 30 | try { | ||
| 31 | expect( | ||
| 32 | isWindowsCommandNotFound( | ||
| 33 | 1, | ||
| 34 | "wird nicht als interner oder externer Befehl, betriebsfahiges Programm oder Batch-Datei erkannt", | ||
| 35 | ), | ||
| 36 | ).toBe(true); | ||
| 37 | } finally { | ||
| 38 | Object.defineProperty(process, "platform", { value: originalPlatform, configurable: true }); | ||
| 39 | } | ||
| 40 | }); | ||
| 41 | }); |
apps/server/src/processRunner.ts+14-1| ... | @@ -37,10 +37,23 @@ function normalizeSpawnError(command: string, args: readonly string[], error: un | ... | @@ -37,10 +37,23 @@ function normalizeSpawnError(command: string, args: readonly string[], error: un |
| 37 | return new Error(`Failed to run ${commandLabel(command, args)}: ${error.message}`); | 37 | return new Error(`Failed to run ${commandLabel(command, args)}: ${error.message}`); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | const WINDOWS_COMMAND_NOT_FOUND_PATTERNS = [ | ||
| 41 | /is not recognized as an internal or external command/i, | ||
| 42 | /n.o . reconhecido como um comando interno/i, | ||
| 43 | /non . riconosciuto come comando interno o esterno/i, | ||
| 44 | /n.est pas reconnu en tant que commande interne/i, | ||
| 45 | /no se reconoce como un comando interno o externo/i, | ||
| 46 | /wird nicht als interner oder externer befehl/i, | ||
| 47 | ] as const; | ||
| 48 | |||
| 49 | function hasWindowsCommandNotFoundMessage(output: string): boolean { | ||
| 50 | return WINDOWS_COMMAND_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(output)); | ||
| 51 | } | ||
| 52 | |||
| 40 | export function isWindowsCommandNotFound(code: number | null, stderr: string): boolean { | 53 | export function isWindowsCommandNotFound(code: number | null, stderr: string): boolean { |
| 41 | if (process.platform !== "win32") return false; | 54 | if (process.platform !== "win32") return false; |
| 42 | if (code === 9009) return true; | 55 | if (code === 9009) return true; |
| 43 | return /is not recognized as an internal or external command/i.test(stderr); | 56 | return hasWindowsCommandNotFoundMessage(stderr); |
| 44 | } | 57 | } |
| 45 | 58 | ||
| 46 | function normalizeExitError( | 59 | function normalizeExitError( |