Skip to content

Conversation

@StillKnotKnown
Copy link
Collaborator

@StillKnotKnown StillKnotKnown commented Jan 10, 2026

Base Branch

  • This PR targets the `develop` branch (required for all feature/fix PRs)

Description

Fixes Claude Code detection failure when Windows username contains spaces (e.g., `C:\Users\First Last\AppData\Roaming\npm\claude.cmd`).

When `spawn()` is called with `shell:true` for .cmd/.bat files on Windows, the command path must be quoted to prevent the shell from breaking at spaces. Without quoting, a path like `C:\Users\First Last...` is incorrectly parsed as `C:\Users\First` (command) and `Last...` (arguments), causing a "command not recognized" error.

Changes:

  • Add `getSpawnCommand()` helper to wrap .cmd/.bat paths in quotes on Windows
  • Update `spawn()` calls in `env-handlers.ts` to use `getSpawnCommand()`
  • Add comprehensive tests for `getSpawnCommand()` covering paths with spaces, uppercase extensions, .exe files, and non-Windows platforms

Related Issue

Closes ACS-176

Type of Change

  • 🐛 Bug fix

Area

  • Frontend

Commit Message Format

Conventional commit: `fix: properly quote Windows .cmd/.bat paths in spawn() calls`

Checklist

  • I've tested my changes locally (all env-utils and cli-tool-manager tests pass)
  • I've followed the code principles (SOLID, DRY, KISS)
  • My PR is small and focused (~100 lines changed)

CI/Testing Requirements

  • All existing tests pass (32 env-utils tests, 28 cli-tool-manager tests)
  • Bug fixes include regression tests (new tests for getSpawnCommand)

Breaking Changes

Breaking: No

Summary by CodeRabbit

  • New Features

    • More consistent CLI command handling for spawning external tools across Windows and non-Windows platforms.
  • Bug Fixes

    • Prevents incorrect quoting, double-quoting, and whitespace-related issues when running external commands.
  • Tests

    • Added comprehensive cross-platform tests covering quoting rules, idempotence, whitespace trimming, and extension-specific behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

Fixes Claude Code detection failure when Windows username contains spaces
(e.g., C:\Users\First Last\AppData\Roaming\npm\claude.cmd).

When spawn() is called with shell:true for .cmd/.bat files, the command
path must be quoted to prevent the shell from breaking at spaces. Without
quoting, a path like "C:\Users\First Last\..." is parsed as:
  - Command: "C:\Users\First"
  - Args: "Last\..."

Changes:
- Add getSpawnCommand() to wrap .cmd/.bat paths in quotes on Windows
- Update spawn() calls to use getSpawnCommand() for proper quoting
- Add comprehensive tests for getSpawnCommand() with space handling

Fixes ACS-176
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 10, 2026

Warning

Rate limit exceeded

@AndyMik90 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 32 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b2865a3 and fe7a02f.

📒 Files selected for processing (1)
  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
📝 Walkthrough

Walkthrough

Adds exported utility getSpawnCommand(command: string) to normalize/quote commands (Windows .cmd/.bat special-casing); updates env-utils logic and docs, adds tests for quoting behavior, and wires getSpawnCommand into IPC handlers and CLI tool manager when spawning the Claude CLI.

Changes

Cohort / File(s) Summary
env-utils (implementation & docs)
apps/frontend/src/main/env-utils.ts
Adds exported getSpawnCommand(command: string): string, trims and normalizes input, special-cases .cmd/.bat quoting for Windows, updates docs/examples referencing getSpawnOptions.
env-utils tests
apps/frontend/src/main/__tests__/env-utils.test.ts
Adds comprehensive tests for getSpawnCommand and extends shouldUseShell tests (Windows quoting rules, idempotence, uppercase extensions, whitespace trimming, non-Windows behavior).
IPC handlers integration
apps/frontend/src/main/ipc-handlers/env-handlers.ts, apps/frontend/src/main/cli-tool-manager.ts
Import and apply getSpawnCommand to wrap claudeCmd in spawn calls (version check, auth/api help, setup-token, and CLI validation paths) replacing direct command usage.

Sequence Diagram(s)

sequenceDiagram
  participant Renderer
  participant IPC_Handler as IPC Env-Handler
  participant Util as env-utils.getSpawnCommand
  participant Spawn as ChildProcess.spawn
  participant Claude as Claude CLI

  Renderer->>IPC_Handler: request to run Claude CLI action
  IPC_Handler->>Util: getSpawnCommand(claudeCmd)
  Util-->>IPC_Handler: quotedOrNormalizedCmd
  IPC_Handler->>Spawn: spawn(quotedOrNormalizedCmd, options)
  Spawn->>Claude: execute command
  Claude-->>Spawn: stdout/stderr
  Spawn-->>IPC_Handler: exit/result
  IPC_Handler-->>Renderer: result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

area/frontend, size/XS

Suggested reviewers

  • AndyMik90

Poem

🐰 I hop and I wrap each Windowsy name,
Quoting the batches so spawns stay the same,
Tests snug and tidy, the handler now wise,
Commands hop the fence and reach their prize,
A tiny rabbit clap—huzzah for correct CLI!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a new utility function to properly quote Windows .cmd/.bat paths in spawn() calls to fix failures when usernames contain spaces.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @StillKnotKnown, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a critical fix for executing .cmd and .bat files on Windows systems, particularly when their paths contain spaces. By implementing a new utility function, getSpawnCommand(), the system now correctly quotes these paths before invoking spawn(), preventing "command not recognized" errors and ensuring reliable operation of tools like the Claude CLI in diverse user environments.

Highlights

  • Windows Path Quoting Fix: Implemented a new helper function, getSpawnCommand(), to correctly quote Windows .cmd and .bat file paths when they contain spaces. This resolves a bug where spawn() calls would fail due to incorrect path parsing.
  • Integration with Spawn Calls: Updated all relevant spawn() calls within env-handlers.ts to utilize the new getSpawnCommand() helper, ensuring robust command execution for tools like the Claude CLI across various Windows environments.
  • Comprehensive Testing: Added a dedicated suite of unit tests for getSpawnCommand() to verify its behavior on Windows (with and without spaces, different extensions like .cmd, .bat, .exe) and non-Windows platforms, ensuring its reliability.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fix for an issue on Windows where command paths with spaces are not handled correctly by spawn(). The solution involves adding a getSpawnCommand helper to quote .cmd and .bat file paths. The implementation is sound and the accompanying tests are comprehensive. My review includes a suggestion to make the getSpawnCommand function more robust by preventing double-quoting of already quoted paths, along with a corresponding test case to ensure this behavior.

Comment on lines +248 to +251
it('should handle uppercase .CMD and .BAT extensions', () => {
expect(getSpawnCommand('D:\\Tools\\CLAUDE.CMD')).toBe('"D:\\Tools\\CLAUDE.CMD"');
expect(getSpawnCommand('C:\\Scripts\\SETUP.BAT')).toBe('"C:\\Scripts\\SETUP.BAT"');
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To ensure the robustness of the getSpawnCommand function against double-quoting, it would be beneficial to add a test case that verifies it doesn't add quotes to a command that is already quoted. This would complement the proposed change in env-utils.ts.

    it('should handle uppercase .CMD and .BAT extensions', () => {
      expect(getSpawnCommand('D:\\Tools\\CLAUDE.CMD')).toBe('"D:\\Tools\\CLAUDE.CMD"');
      expect(getSpawnCommand('C:\\Scripts\\SETUP.BAT')).toBe('"C:\\Scripts\\SETUP.BAT"');
    });

    it('should NOT double-quote an already quoted .cmd file', () => {
      const cmd = getSpawnCommand('"C:\\Users\\Test User\\app.cmd"');
      expect(cmd).toBe('"C:\\Users\\Test User\\app.cmd"');
    });

Comment on lines 531 to 533
if (shouldUseShell(command)) {
return `"${command}"`;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of getSpawnCommand doesn't handle cases where the command string might already be quoted. This could lead to double-quoting (e.g., ""C:\\path\\to.cmd""), which would likely cause the spawn call to fail.

To make this utility function more robust and idempotent, I suggest adding a check to see if the command is already surrounded by double quotes before adding them.

Suggested change
if (shouldUseShell(command)) {
return `"${command}"`;
}
if (shouldUseShell(command)) {
return (command.startsWith('"') && command.endsWith('"')) ? command : `"${command}"`;
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/frontend/src/main/env-utils.ts (1)

460-468: Make shouldUseShell / getSpawnCommand robust to already-quoted paths (and keep quoting idempotent).

Right now shouldUseShell() won’t detect .cmd/.bat if the path is already wrapped in quotes (ends with "), which can silently flip shell to false if a caller ever passes a quoted command. Since getSpawnCommand() is now part of the public API, it’s safer if both helpers handle quoted inputs predictably.

Proposed fix
 export function shouldUseShell(command: string): boolean {
   // Only Windows needs special handling for .cmd/.bat files
   if (process.platform !== 'win32') {
     return false;
   }
 
-  // Check if command ends with .cmd or .bat (case-insensitive)
-  return /\.(cmd|bat)$/i.test(command);
+  const trimmed = command.trim();
+  const unquoted =
+    trimmed.startsWith('"') && trimmed.endsWith('"') ? trimmed.slice(1, -1) : trimmed;
+
+  // Check if command ends with .cmd or .bat (case-insensitive)
+  return /\.(cmd|bat)$/i.test(unquoted);
 }
 
 export function getSpawnCommand(command: string): string {
   // For .cmd/.bat files on Windows, quote the command to handle spaces
   // The shell will parse the quoted path correctly
-  if (shouldUseShell(command)) {
-    return `"${command}"`;
+  const trimmed = command.trim();
+  if (shouldUseShell(trimmed)) {
+    // Idempotent if already quoted
+    if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
+      return trimmed;
+    }
+    return `"${trimmed}"`;
   }
   return command;
 }

Also applies to: 528-535

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 91bd240 and c0431dd.

📒 Files selected for processing (3)
  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
  • apps/frontend/src/main/ipc-handlers/env-handlers.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/ipc-handlers/env-handlers.ts
  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/ipc-handlers/env-handlers.ts
  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/ipc-handlers/env-handlers.ts
  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: MikeeBuilds
Repo: AndyMik90/Auto-Claude PR: 661
File: apps/frontend/src/renderer/components/onboarding/OllamaModelSelector.tsx:176-189
Timestamp: 2026-01-04T23:59:48.743Z
Learning: In the AndyMik90/Auto-Claude repository, pre-existing i18n issues (hardcoded user-facing strings that should be localized) can be deferred to future i18n cleanup passes rather than requiring immediate fixes in PRs that don't introduce new i18n violations.
🧬 Code graph analysis (2)
apps/frontend/src/main/ipc-handlers/env-handlers.ts (1)
apps/frontend/src/main/env-utils.ts (2)
  • getSpawnCommand (528-535)
  • getSpawnOptions (489-510)
apps/frontend/src/main/__tests__/env-utils.test.ts (1)
apps/frontend/src/main/env-utils.ts (1)
  • getSpawnCommand (528-535)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (2)
apps/frontend/src/main/env-utils.ts (1)

470-487: Docs update is aligned with the new API (getSpawnCommand + getSpawnOptions).

apps/frontend/src/main/ipc-handlers/env-handlers.ts (1)

13-14: Correctly applies getSpawnCommand() at the spawn boundary without affecting getSpawnOptions() shell detection.

Also applies to: 606-609, 626-629, 695-699

…d paths

- shouldUseShell() now correctly detects .cmd/.bat extensions even when
  the path is already wrapped in quotes
- getSpawnCommand() is now idempotent - calling it multiple times or with
  an already-quoted command returns the same result
- Both functions now trim whitespace before processing

This makes the public API more robust to edge cases and prevents issues
if callers accidentally pass quoted commands.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @apps/frontend/src/main/__tests__/env-utils.test.ts:
- Around line 281-301: getSpawnCommand currently leaves leading/trailing
whitespace on non-Windows platforms, causing inconsistent behavior; update
getSpawnCommand to trim the input command (e.g., command = command.trim())
before returning in the non-Windows branch so macOS/Linux paths are normalized,
and add a unit test in env-utils.test.ts that sets process.platform to
'darwin'/'linux' and asserts getSpawnCommand('  /usr/local/bin/claude  ') ===
'/usr/local/bin/claude' to cover whitespace handling.

In @apps/frontend/src/main/env-utils.ts:
- Around line 532-544: getSpawnCommand inconsistently returns trimmed input only
for shell cases but returns the original untrimmed command for non-shell cases;
change it to always use the trimmed value: compute trimmed = command.trim(), use
trimmed in the shouldUseShell branch (preserving the existing idempotent quote
logic) and return trimmed for the non-shell branch instead of command so callers
get consistent whitespace handling; refer to getSpawnCommand and shouldUseShell
to locate the logic and ensure existing quote/idempotency checks
(trimmed.startsWith/endsWith) remain unchanged.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0431dd and 4ac77d3.

📒 Files selected for processing (2)
  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/__tests__/env-utils.test.ts
  • apps/frontend/src/main/env-utils.ts
🧬 Code graph analysis (1)
apps/frontend/src/main/__tests__/env-utils.test.ts (1)
apps/frontend/src/main/env-utils.ts (2)
  • getSpawnCommand (532-544)
  • shouldUseShell (460-472)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (5)
apps/frontend/src/main/env-utils.ts (2)

466-471: LGTM! Robust handling of quoted paths.

The updated logic correctly strips quotes before checking the file extension, enabling proper detection of .cmd/.bat files even when the path is already quoted. The trimming also improves resilience to whitespace.


480-490: LGTM! Clear documentation and helpful example.

The updated documentation properly explains the integration with getSpawnCommand() and provides a clear usage example.

apps/frontend/src/main/__tests__/env-utils.test.ts (3)

2-2: LGTM! Proper import addition.

The new getSpawnCommand function is correctly imported for testing.


214-279: LGTM! Comprehensive Windows test coverage.

The test suite thoroughly covers:

  • Paths with and without spaces
  • Both .cmd and .bat extensions
  • Case sensitivity (uppercase extensions)
  • Idempotence (preventing double-quoting)
  • Whitespace trimming
  • Non-quotable file types (.exe, extensionless)

304-343: LGTM! Excellent regression coverage for quoted path detection.

This test suite ensures that shouldUseShell() correctly handles already-quoted paths by stripping quotes before checking extensions. The whitespace handling test (lines 339-341) is particularly valuable for catching edge cases.

Comment on lines 281 to 301
describe('Non-Windows platforms', () => {
it('should NOT quote commands on macOS', () => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
writable: true,
configurable: true,
});
expect(getSpawnCommand('/usr/local/bin/claude')).toBe('/usr/local/bin/claude');
expect(getSpawnCommand('/opt/homebrew/bin/claude.cmd')).toBe('/opt/homebrew/bin/claude.cmd');
});

it('should NOT quote commands on Linux', () => {
Object.defineProperty(process, 'platform', {
value: 'linux',
writable: true,
configurable: true,
});
expect(getSpawnCommand('/usr/bin/claude')).toBe('/usr/bin/claude');
expect(getSpawnCommand('/home/user/.local/bin/claude.bat')).toBe('/home/user/.local/bin/claude.bat');
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add test coverage for whitespace handling on non-Windows platforms.

The tests verify that commands aren't quoted on macOS/Linux, but don't test whitespace trimming behavior. Adding a test case would catch the whitespace inconsistency identified in the implementation:

it('should trim whitespace on non-Windows platforms', () => {
  Object.defineProperty(process, 'platform', {
    value: 'darwin',
    writable: true,
    configurable: true,
  });
  expect(getSpawnCommand('  /usr/local/bin/claude  ')).toBe('/usr/local/bin/claude');
});

This test would currently fail due to the inconsistent whitespace handling in getSpawnCommand() at line 543 of env-utils.ts.

🤖 Prompt for AI Agents
In @apps/frontend/src/main/__tests__/env-utils.test.ts around lines 281 - 301,
getSpawnCommand currently leaves leading/trailing whitespace on non-Windows
platforms, causing inconsistent behavior; update getSpawnCommand to trim the
input command (e.g., command = command.trim()) before returning in the
non-Windows branch so macOS/Linux paths are normalized, and add a unit test in
env-utils.test.ts that sets process.platform to 'darwin'/'linux' and asserts
getSpawnCommand('  /usr/local/bin/claude  ') === '/usr/local/bin/claude' to
cover whitespace handling.

…atforms

Previously, getSpawnCommand() only trimmed whitespace for Windows shell
cases (.cmd/.bat files) but returned the original untrimmed command for
non-shell cases (macOS/Linux). This caused inconsistent behavior.

Now getSpawnCommand() always returns a trimmed value regardless of platform,
ensuring consistent whitespace handling for all callers.

Also added tests to verify whitespace trimming on macOS and Linux platforms.
@StillKnotKnown StillKnotKnown self-assigned this Jan 10, 2026
@StillKnotKnown StillKnotKnown added bug Something isn't working refactor Code improvement, no new features priority/medium Normal priority os/windows Windows specific size/M Medium (100-499 lines) v2.7.3 v2.7.4 stable-roadmap frontend Frontend related changes labels Jan 10, 2026
Copy link
Collaborator Author

@StillKnotKnown StillKnotKnown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

Merge Verdict: 🔴 BLOCKED

🔴 Blocked - 1 CI check(s) failing. Fix CI before merge.

Blocked: 1 CI check(s) failing. Fix CI before merge.

Risk Assessment

Factor Level Notes
Complexity Medium Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

🚨 Blocking Issues (Must Fix)

  • CI Failed: Require Re-review on Push

Findings Summary

  • Low: 2 issue(s)

Generated by Auto Claude PR Review

Findings (2 selected of 2 total)

🔵 [c8b2780e1b3d] [LOW] getSpawnCommand returns quoted .exe paths as-is instead of stripping quotes

📁 apps/frontend/src/main/env-utils.ts:535

When getSpawnCommand receives an already-quoted .exe path (e.g., '"C:\Program Files\Git\cmd\git.exe"'), it returns the quoted path unchanged because shouldUseShell returns false for .exe files. This creates a mismatch: spawn() would be called with a quoted command but shell:false. While this edge case cannot occur in practice (user-configured paths with quotes are rejected by isSecurePath in windows-paths.ts, and path detection returns unquoted paths), it's a defensive programming concern.

Suggested fix:

Add quote stripping for non-.cmd/.bat files: `if (!shouldUseShell(trimmed) && trimmed.startsWith('"') && trimmed.endsWith('"')) { return trimmed.slice(1, -1); }` before `return trimmed;`

🔵 [4647638f9048] [LOW] validateClaude manually quotes instead of using getSpawnCommand - DRY violation

📁 apps/frontend/src/main/cli-tool-manager.ts:926

In validateClaude() line 926 and validateClaudeAsync() line 1042, the code manually constructs quoted paths instead of using getSpawnCommand(). This duplicates quoting logic and lacks the idempotency check. While not currently problematic (isSecurePath prevents quoted paths), it's a DRY violation.

Suggested fix:

Replace manual quoting with getSpawnCommand() calls in validateClaude (line 926) and validateClaudeAsync (line 1042)

This review was generated by Auto Claude.

StillKnotKnown and others added 3 commits January 10, 2026 19:52
- Add quote stripping for non-.cmd/.bat files (.exe, extensionless) to
  prevent returning quoted commands with shell:false
- Update validateClaude/validateClaudeAsync to use getSpawnCommand()
  instead of manual quoting (DRY principle)
- Add tests for quote-stripping behavior on .exe and extensionless files

These changes make getSpawnCommand() more robust and ensure consistent
behavior across all file types, while eliminating duplicate quoting logic.
The env-utils mock in cli-tool-manager.test.ts was missing getSpawnCommand,
causing tests to fail when validateClaude() tried to call it.

Added getSpawnCommand mock that mirrors the actual implementation:
- On Windows: quotes .cmd/.bat files idempotently
- For other files: returns trimmed value (strips quotes if present)
Copy link
Owner

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

✅ Initial Review: Ready To Merge

✅ Ready to merge - All checks passing, no blocking issues found.

Findings Overview

2 issue(s) identified in this review:

  • 🔵 Low: 2 issue(s) - minor improvements

Risk Assessment

Factor Level Notes
Complexity Medium Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

Verdict

No blocking issues. 2 non-blocking suggestion(s) to consider

Review Process

Agents invoked: security-reviewer, quality-reviewer, structural-reviewer


This is an AI-generated initial review using parallel specialist analysis.

Findings (2 selected of 2 total)

🔵 [a09fe2a1abdb] [LOW] Missing test for quote-stripping on non-Windows platforms

📁 apps/frontend/src/main/__tests__/env-utils.test.ts:296

The tests verify that commands are NOT quoted on macOS/Linux, but don't explicitly test what happens when a pre-quoted path is passed on non-Windows. The implementation (env-utils.ts lines 544-546) correctly strips quotes from non-.cmd/.bat files as defensive behavior, but this cross-platform behavior is not tested. Adding a test like expect(getSpawnCommand('"/usr/local/bin/claude"')).toBe('/usr/local/bin/claude') on macOS/Linux would document this behavior.

Suggested fix:

Add test case in the 'Non-Windows platforms' describe block: `it('should strip quotes from paths on macOS', () => { expect(getSpawnCommand('"/usr/local/bin/claude"')).toBe('/usr/local/bin/claude'); });`

🔵 [74532ae9fd0b] [LOW] No test for empty string input edge case

📁 apps/frontend/src/main/__tests__/env-utils.test.ts:202

The test suite doesn't include a test for empty string or whitespace-only input to getSpawnCommand(). While TypeScript typing should prevent null/undefined, documenting the expected behavior for edge cases improves test completeness. The function handles this gracefully (returns empty string after trim), but this isn't explicitly tested.

Suggested fix:

Add test case: `it('should handle empty string input', () => { expect(getSpawnCommand('')).toBe(''); expect(getSpawnCommand('   ')).toBe(''); });`

This review was generated by Auto Claude.

@AndyMik90 AndyMik90 merged commit 6dc538c into AndyMik90:develop Jan 10, 2026
16 of 17 checks passed
@StillKnotKnown StillKnotKnown deleted the stillknotknown/acs-176-claude-code-detection-fails-when-username-contains-spaces branch January 10, 2026 23:22
arcker pushed a commit to arcker/Auto-Claude that referenced this pull request Jan 14, 2026
…90#889)

* fix: properly quote Windows .cmd/.bat paths in spawn() calls

Fixes Claude Code detection failure when Windows username contains spaces
(e.g., C:\Users\First Last\AppData\Roaming\npm\claude.cmd).

When spawn() is called with shell:true for .cmd/.bat files, the command
path must be quoted to prevent the shell from breaking at spaces. Without
quoting, a path like "C:\Users\First Last\..." is parsed as:
  - Command: "C:\Users\First"
  - Args: "Last\..."

Changes:
- Add getSpawnCommand() to wrap .cmd/.bat paths in quotes on Windows
- Update spawn() calls to use getSpawnCommand() for proper quoting
- Add comprehensive tests for getSpawnCommand() with space handling

Fixes ACS-176

* refactor: make shouldUseShell/getSpawnCommand robust to already-quoted paths

- shouldUseShell() now correctly detects .cmd/.bat extensions even when
  the path is already wrapped in quotes
- getSpawnCommand() is now idempotent - calling it multiple times or with
  an already-quoted command returns the same result
- Both functions now trim whitespace before processing

This makes the public API more robust to edge cases and prevents issues
if callers accidentally pass quoted commands.

* refactor: make getSpawnCommand consistently trim whitespace on all platforms

Previously, getSpawnCommand() only trimmed whitespace for Windows shell
cases (.cmd/.bat files) but returned the original untrimmed command for
non-shell cases (macOS/Linux). This caused inconsistent behavior.

Now getSpawnCommand() always returns a trimmed value regardless of platform,
ensuring consistent whitespace handling for all callers.

Also added tests to verify whitespace trimming on macOS and Linux platforms.

* fix: address PR review findings for getSpawnCommand

- Add quote stripping for non-.cmd/.bat files (.exe, extensionless) to
  prevent returning quoted commands with shell:false
- Update validateClaude/validateClaudeAsync to use getSpawnCommand()
  instead of manual quoting (DRY principle)
- Add tests for quote-stripping behavior on .exe and extensionless files

These changes make getSpawnCommand() more robust and ensure consistent
behavior across all file types, while eliminating duplicate quoting logic.

* test: add getSpawnCommand mock to cli-tool-manager tests

The env-utils mock in cli-tool-manager.test.ts was missing getSpawnCommand,
causing tests to fail when validateClaude() tried to call it.

Added getSpawnCommand mock that mirrors the actual implementation:
- On Windows: quotes .cmd/.bat files idempotently
- For other files: returns trimmed value (strips quotes if present)

---------

Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working frontend Frontend related changes os/windows Windows specific priority/medium Normal priority refactor Code improvement, no new features size/M Medium (100-499 lines) stable-roadmap v2.7.3 v2.7.4

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants