Skip to content

fix: bypass Windows cmd shim length limit#518

Open
bbenshalom wants to merge 2 commits into
cline:mainfrom
bbenshalom:fix-windows-cmd-shim-limit
Open

fix: bypass Windows cmd shim length limit#518
bbenshalom wants to merge 2 commits into
cline:mainfrom
bbenshalom:fix-windows-cmd-shim-limit

Conversation

@bbenshalom
Copy link
Copy Markdown

Closes #83.

Summary

  • resolve Windows agent .cmd shims to their underlying executable or Node entrypoint before falling back to cmd.exe
  • reuse the same launch resolution in the PTY and Codex wrapper paths
  • add Windows regression tests for long prompt launches and document the shell-limit trap in AGENTS.md

Testing

  • npx vitest run test/runtime/core/windows-cmd-launch.test.ts test/runtime/hooks-codex-wrapper.test.ts test/runtime/terminal/pty-session.test.ts
  • npx @biomejs/biome check src/core/windows-cmd-launch.ts src/terminal/pty-session.ts src/commands/hooks.ts test/runtime/core/windows-cmd-launch.test.ts test/runtime/terminal/pty-session.test.ts test/runtime/hooks-codex-wrapper.test.ts

px tsc --noEmit still fails on pre-existing unrelated src/cline-sdk/* type errors in this checkout

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 27, 2026

Greptile Summary

This PR resolves a Windows cmd.exe command-line length limit by reading .cmd shim files, parsing their contents against three regex patterns (npm indirect-node, direct-node, direct-exe), and launching the underlying node binary or executable directly instead of wrapping everything in cmd.exe. The unified resolveWindowsSpawnLaunch entry point replaces the previous shouldUseWindowsCmdLaunch / resolveWindowsComSpec split in both the PTY and Codex-wrapper call sites.

  • New resolveWindowsBatchShimLaunch function reads .cmd shims, identifies their launch pattern via three regex patterns, and returns the real binary + args needed to bypass the shim and avoid cmd.exe's length limit.
  • resolveWindowsSpawnLaunch unifies resolution across PTY and hooks callers: it tries shim bypass first, falls back to the existing cmd-wrapping path if bypassing fails or isn't applicable.
  • Regression tests cover npm-style shims (indirect-node, direct-node), direct-exe shims, and graceful fallbacks when binaries or shim files are missing; existing tests are updated to set explicit PATH/PATHEXT so the new resolution path doesn't accidentally resolve bare binaries.

Confidence Score: 5/5

Safe to merge; the shim-resolution logic is well-structured and the fallback chain to cmd.exe is preserved for all unrecognised shim formats.

The core bypass logic is correct: shim patterns are checked in the right priority order, all three branches verify the binary exists before returning, and both callers correctly build cmd-shell args when the fallback path is taken. Findings are limited to an inconsistency in how the node-script paths handle a missing script file vs the exe path, and a test-organisation nit.

src/core/windows-cmd-launch.ts — the indirectNodeMatch and directNodeMatch branches should mirror the canAccessPath(scriptPath) guard added to directExecutableMatch.

Important Files Changed

Filename Overview
src/core/windows-cmd-launch.ts Core Windows launch resolution logic — adds shim-reading, three pattern-based shim branches, and a unified resolveWindowsSpawnLaunch entry point; directExecutableMatch now guards with canAccessPath (previous reviewer fix addressed), but the two node-script branches do not verify the script path exists before returning.
src/commands/hooks.ts Switches buildCodexWrapperSpawn to use the unified resolveWindowsSpawnLaunch; correctly continues to call buildWindowsCmdArgsArray(realBinary, childArgs) when useCmdShell: true rather than relying on resolvedLaunch.args.
src/terminal/pty-session.ts PTY spawn path updated to use resolveWindowsSpawnLaunch; correctly falls through to buildWindowsCmdArgsCommandLine when useCmdShell: true, preserving existing cmd-shell wrapping for PTY.
test/runtime/core/windows-cmd-launch.test.ts Five new test cases for shim resolution and fallback logic, but all new tests are placed inside the pre-existing describe("shouldUseWindowsCmdLaunch") block even though they exercise resolveWindowsBatchShimLaunch and resolveWindowsSpawnLaunch.
test/runtime/hooks-codex-wrapper.test.ts Adds a Windows cmd-shim integration test for buildCodexWrapperSpawn; uses try/finally for cleanup and correctly creates node.exe and the JS entrypoint on disk.
test/runtime/terminal/pty-session.test.ts Existing Windows tests updated to set PATH/PATHEXT explicitly; new test verifies PTY launches node directly instead of wrapping in cmd.exe.
AGENTS.md Documents the Windows cmd.exe command-line limit trap and the preferred shim-resolution approach.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
src/core/windows-cmd-launch.ts:193-204
The `indirectNodeMatch` branch returns a resolved launch without verifying the script file exists, unlike `directExecutableMatch` (where `canAccessPath` was added after the previous review). If the script is missing — e.g., a half-uninstalled package where only the shim remains — the function returns a non-null result pointing at a path node cannot find, bypassing the cmd.exe fallback entirely. The same gap exists in `directNodeMatch`.

```suggestion
	const indirectNodeMatch = shimContent.match(WINDOWS_BATCH_INDIRECT_NODE_PATTERN);
	if (indirectNodeMatch) {
		const nodeBinary = resolveWindowsBatchShimNodeBinary(resolvedBinaryPath, env);
		if (!nodeBinary) {
			return null;
		}
		const scriptPath = resolveWindowsBatchShimPath(indirectNodeMatch[1], resolvedBinaryPath);
		if (!canAccessPath(scriptPath)) {
			return null;
		}
		return {
			binary: nodeBinary,
			args: [scriptPath, ...args],
		};
	}
```

### Issue 2 of 3
src/core/windows-cmd-launch.ts:219-226
The `directNodeMatch` branch also doesn't verify `scriptPath` exists before returning, mirroring the inconsistency noted above. A shim with a valid node binary but a missing/moved JS entrypoint will resolve successfully here and then fail at node startup, with no fallback to cmd.exe.

```suggestion
		if (!nodeBinary || !canAccessPath(nodeBinary) || !canAccessPath(scriptPath)) {
			return null;
		}
		return {
			binary: nodeBinary,
			args: [scriptPath, ...args],
		};
	}
```

### Issue 3 of 3
test/runtime/core/windows-cmd-launch.test.ts:103
**New tests grouped under wrong describe block.** The five new test cases starting at this line exercise `resolveWindowsBatchShimLaunch` and `resolveWindowsSpawnLaunch`, not `shouldUseWindowsCmdLaunch`. They should live in their own `describe` blocks (e.g., `describe("resolveWindowsBatchShimLaunch")` / `describe("resolveWindowsSpawnLaunch")`), otherwise the test output groups the wrong subjects together and future grep-by-function searches miss them.

Reviews (2): Last reviewed commit: "fix(terminal): harden Windows shim fallb..." | Re-trigger Greptile

Comment thread src/core/windows-cmd-launch.ts
Comment thread src/core/windows-cmd-launch.ts
@bbenshalom
Copy link
Copy Markdown
Author

@greptileai please re-review

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(windows): stock Kanban 0.1.46 fails to launch Claude and Codex runtimes with 'The command line is too long'

1 participant