Skip to content

fix(code-review, windows): escape args for cmd.exe in review runner#2006

Open
AnExiledDev wants to merge 2 commits into
AgentWrapper:mainfrom
AnExiledDev:feat/issue-2003
Open

fix(code-review, windows): escape args for cmd.exe in review runner#2006
AnExiledDev wants to merge 2 commits into
AgentWrapper:mainfrom
AnExiledDev:feat/issue-2003

Conversation

@AnExiledDev
Copy link
Copy Markdown

Summary

  • Fix shell: true breaking review prompt argument passing on Windows by escaping args for cmd.exe in execFileWithClosedStdin
  • On Windows, spawn() with shell: true routes through cmd.exe, which concatenates args with spaces — splitting the multi-word review prompt into separate CLI tokens. codex exec then fails with unexpected argument 'are' found
  • Add escapeArgForCmd() that wraps args containing spaces or cmd.exe metacharacters (", &, |, <, >, ^) in double quotes so they survive the cmd.exe re-parse, while keeping shell: true for .cmd shim resolution

Closes #2003

Test plan

  • New unit tests for escapeArgForCmd: simple passthrough, space wrapping, double-quote escaping, metacharacter handling, empty string, multi-line prompt
  • All 6 new tests pass; all 21 pre-existing tests pass (1 pre-existing failure in prepareGitReviewerWorkspace is unrelated — Windows HOME path resolution)
  • TypeScript typecheck passes
  • Verify on Windows: codex exec receives the full review prompt as a single argument

…sedStdin

On Windows, spawn() with shell: true routes through cmd.exe, which
concatenates args with spaces and loses multi-word argument boundaries
(Node.js DEP0190). The review prompt — a multi-line string with spaces —
was split into separate tokens, causing codex exec to fail with
"unexpected argument 'are' found".

Add escapeArgForCmd() that wraps args containing spaces or cmd.exe
metacharacters in double quotes before passing them to spawn(). This
preserves argument boundaries through the cmd.exe re-parse while
keeping shell: true for .cmd shim resolution.

Closes AgentWrapper#2003
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 22, 2026

Greptile Summary

This PR fixes a Windows-only bug where spawn() with shell: true routes through cmd.exe, which splits multi-word arguments on spaces, causing codex exec to fail with unexpected argument 'are' found when a review prompt is passed as a single CLI token.

  • Adds escapeArgForCmd() that wraps args containing spaces or cmd.exe metacharacters (\", &, |, <, >, ^, %) in double quotes (with \"\" for embedded double quotes), matching the cmd.exe re-parse convention.
  • Applies escaping in execFileWithClosedStdin when options.shell is truthy and isWindows() is true, leaving POSIX paths unchanged.
  • Adds six unit tests for escapeArgForCmd and two tests that replicate the platform-guard branching logic inline.

Confidence Score: 5/5

The change is a narrow, well-scoped Windows arg-escaping fix with no impact on POSIX paths and a clear paper trail of the cmd.exe quoting convention being applied.

The only call site passes shell: isWindows() (a boolean), so the escaping fires exactly when cmd.exe is involved and is skipped everywhere else. The escaping logic itself is straightforward double-quote wrapping with "" substitution, which is correct for cmd.exe. No existing behavior is changed on POSIX.

No files require special attention; both changed files are self-contained.

Important Files Changed

Filename Overview
packages/core/src/code-review-manager.ts Adds escapeArgForCmd() and applies it in execFileWithClosedStdin when shell:true on Windows; the guard is correct for the current boolean-only call site but doesn't narrow to cmd.exe when shell is a string.
packages/core/src/tests/code-review-manager.test.ts Six new tests cover escapeArgForCmd in isolation and replicate the platform-guard branch logic manually; the integration test for execFileWithClosedStdin does not invoke the real function.

Sequence Diagram

sequenceDiagram
    participant RCR as runCodexCodeReview
    participant EWS as execFileWithClosedStdin
    participant EA as escapeArgForCmd
    participant SP as spawn (Node.js)
    participant CMD as cmd.exe (Windows)
    participant CX as codex exec

    RCR->>EWS: "file="codex", args=[...prompt], shell=isWindows()"
    EWS->>EWS: "options.shell && isWindows()?"
    alt Windows (shell: true)
        EWS->>EA: map(escapeArgForCmd) over args
        EA-->>EWS: args with spaces/metacharacters wrapped in ""
        EWS->>SP: "spawn("codex", escapedArgs, {shell: true})"
        SP->>CMD: cmd.exe /d /s /c codex exec ... "full prompt"
        CMD->>CX: receives prompt as single token
    else POSIX (shell: false)
        EWS->>SP: "spawn("codex", args, {shell: false})"
        SP->>CX: args passed directly, no shell re-parse
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/core/src/code-review-manager.ts:87
**cmd.exe escaping applied even when shell is not cmd.exe**

`options.shell` is typed as `boolean | string`. When it is a truthy string such as `"powershell"` or an absolute path to `pwsh.exe`, the guard `options.shell && isWindows()` still fires and applies cmd.exe-specific `""` doubling, but the actual subprocess shell will be PowerShell — which has different quoting rules. The escaping would be wrong in that scenario.

The current call site passes `shell: isWindows()` (always a boolean), so no bug today, but the function signature accepts strings and a future caller could trigger this silently.

Reviews (2): Last reviewed commit: "fix: add % to cmd.exe metachar regex and..." | Re-trigger Greptile

Comment thread packages/core/src/code-review-manager.ts Outdated
Comment thread packages/core/src/code-review-manager.ts
Comment thread packages/core/src/__tests__/code-review-manager.test.ts
Include % in the escapeArgForCmd detection regex so args containing
percent signs get double-quoted. Note: cmd.exe %VAR% expansion cannot
be fully suppressed inside double quotes, but the review prompt and
file-path args never contain literal % in practice.

Add platform-guard tests using Object.defineProperty(process, 'platform')
to verify the isWindows() branch in execFileWithClosedStdin fires
correctly on both platforms.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(code-review, windows): shell: true breaks review prompt argument passing on Windows

1 participant