-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix: resolve Claude CLI not found on Windows - PATH, prompt size, cwd (#1661) #1843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4bb2e56
d646c84
63ef050
90df55c
17345df
17eb196
3f617a0
1a02d00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,18 @@ | |
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| # ============================================================================= | ||
| # Windows System Prompt Limits | ||
| # ============================================================================= | ||
| # Windows CreateProcessW has a 32,768 character limit for the entire command line. | ||
| # When CLAUDE.md is very large and passed as --system-prompt, the command can exceed | ||
| # this limit, causing ERROR_FILE_NOT_FOUND. We cap CLAUDE.md content to stay safe. | ||
| # 20,000 chars leaves ~12KB headroom for CLI overhead (model, tools, MCP config, etc.) | ||
| WINDOWS_MAX_SYSTEM_PROMPT_CHARS = 20000 | ||
| WINDOWS_TRUNCATION_MESSAGE = ( | ||
| "\n\n[... CLAUDE.md truncated due to Windows command-line length limit ...]" | ||
| ) | ||
|
|
||
| # ============================================================================= | ||
| # Project Index Cache | ||
| # ============================================================================= | ||
|
|
@@ -821,8 +833,31 @@ def create_client( | |
| if should_use_claude_md(): | ||
| claude_md_content = load_claude_md(project_dir) | ||
| if claude_md_content: | ||
| # On Windows, the SDK passes system_prompt as a --system-prompt CLI argument. | ||
| # Windows CreateProcessW has a 32,768 character limit for the entire command line. | ||
| # When CLAUDE.md is very large, the command can exceed this limit, causing Windows | ||
| # to return ERROR_FILE_NOT_FOUND which the SDK misreports as "Claude Code not found". | ||
| # Cap CLAUDE.md content to keep total command line under the limit. (#1661) | ||
| was_truncated = False | ||
| if is_windows(): | ||
| max_claude_md_chars = ( | ||
| WINDOWS_MAX_SYSTEM_PROMPT_CHARS | ||
| - len(base_prompt) | ||
| - len(WINDOWS_TRUNCATION_MESSAGE) | ||
| - len("\n\n# Project Instructions (from CLAUDE.md)\n\n") | ||
| ) | ||
| if len(claude_md_content) > max_claude_md_chars > 0: | ||
| claude_md_content = ( | ||
| claude_md_content[:max_claude_md_chars] | ||
| + WINDOWS_TRUNCATION_MESSAGE | ||
| ) | ||
| print( | ||
| " - CLAUDE.md: truncated (exceeded Windows command-line limit)" | ||
| ) | ||
| was_truncated = True | ||
| base_prompt = f"{base_prompt}\n\n# Project Instructions (from CLAUDE.md)\n\n{claude_md_content}" | ||
| print(" - CLAUDE.md: included in system prompt") | ||
| if not was_truncated: | ||
| print(" - CLAUDE.md: included in system prompt") | ||
|
Comment on lines
836
to
860
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edge case: when If Proposed fix: omit CLAUDE.md when budget is exhausted if is_windows():
max_claude_md_chars = (
WINDOWS_MAX_SYSTEM_PROMPT_CHARS
- len(base_prompt)
- len(WINDOWS_TRUNCATION_MESSAGE)
)
- if len(claude_md_content) > max_claude_md_chars > 0:
+ if max_claude_md_chars <= 0:
+ claude_md_content = ""
+ print(
+ " - CLAUDE.md: omitted (base prompt already near Windows limit)"
+ )
+ was_truncated = True
+ elif len(claude_md_content) > max_claude_md_chars:
claude_md_content = (
claude_md_content[:max_claude_md_chars]
+ WINDOWS_TRUNCATION_MESSAGE
)🤖 Prompt for AI Agents |
||
| else: | ||
| print(" - CLAUDE.md: not found in project root") | ||
| else: | ||
|
|
||
| Original file line number | Diff line number | Diff line change | |||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,10 +22,10 @@ | ||||||||||||||||||||||||||||
| import { buildMemoryEnvVars } from '../memory-env-builder'; | |||||||||||||||||||||||||||||
| import { readSettingsFile } from '../settings-utils'; | |||||||||||||||||||||||||||||
| import type { AppSettings } from '../../shared/types/settings'; | |||||||||||||||||||||||||||||
| import { getOAuthModeClearVars } from './env-utils'; | |||||||||||||||||||||||||||||
| import { getOAuthModeClearVars, normalizeEnvPathKey, mergePythonEnvPath } from './env-utils'; | |||||||||||||||||||||||||||||
Check noticeCode scanning / CodeQL Unused variable, import, function or class Note
Unused import normalizeEnvPathKey.
Copilot AutofixAI 1 day ago In general, to fix an unused import, remove the unused symbol from the import clause, or, if all imported symbols are unused, remove the entire import statement. This avoids confusion and keeps the module’s dependency surface minimal. Here, only Concretely:
Suggested changeset
1
apps/frontend/src/main/agent/agent-process.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
|||||||||||||||||||||||||||||
| import { getAugmentedEnv } from '../env-utils'; | |||||||||||||||||||||||||||||
| import { getToolInfo, getClaudeCliPathForSdk } from '../cli-tool-manager'; | |||||||||||||||||||||||||||||
| import { killProcessGracefully, isWindows } from '../platform'; | |||||||||||||||||||||||||||||
| import { killProcessGracefully, isWindows, getPathDelimiter } from '../platform'; | |||||||||||||||||||||||||||||
| import { debugLog } from '../../shared/utils/debug-logger'; | |||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||
| /** | |||||||||||||||||||||||||||||
|
|
@@ -679,15 +679,25 @@ | ||||||||||||||||||||||||||||
| }, | |||||||||||||||||||||||||||||
| }); | |||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||
| // Parse Python commandto handle space-separated commands like "py -3" | |||||||||||||||||||||||||||||
| // Merge PATH from pythonEnv with augmented PATH from env. | |||||||||||||||||||||||||||||
| // pythonEnv may contain its own PATH (e.g., on Windows with pywin32_system32 prepended). | |||||||||||||||||||||||||||||
| // Simply spreading pythonEnv after env would overwrite the augmented PATH (which includes | |||||||||||||||||||||||||||||
| // npm globals, homebrew, etc.), causing "Claude code not found" on Windows (#1661). | |||||||||||||||||||||||||||||
| // mergePythonEnvPath() normalizes PATH key casing and prepends pythonEnv-specific paths. | |||||||||||||||||||||||||||||
| const mergedPythonEnv = { ...pythonEnv }; | |||||||||||||||||||||||||||||
| const pathSep = getPathDelimiter(); | |||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||
| mergePythonEnvPath(env as Record<string, string | undefined>, mergedPythonEnv as Record<string, string | undefined>, pathSep); | |||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||
| // Parse Python command to handle space-separated commands like "py -3" | |||||||||||||||||||||||||||||
| const [pythonCommand, pythonBaseArgs] = parsePythonCommand(this.getPythonPath()); | |||||||||||||||||||||||||||||
| let childProcess; | |||||||||||||||||||||||||||||
| try { | |||||||||||||||||||||||||||||
| childProcess = spawn(pythonCommand, [...pythonBaseArgs, ...args], { | |||||||||||||||||||||||||||||
| cwd, | |||||||||||||||||||||||||||||
| env: { | |||||||||||||||||||||||||||||
| ...env, // Already includes process.env, extraEnv, profileEnv, PYTHONUNBUFFERED, PYTHONUTF8 | |||||||||||||||||||||||||||||
| ...pythonEnv, // Include Python environment (PYTHONPATH for bundled packages) | |||||||||||||||||||||||||||||
| ...mergedPythonEnv, // Python env with merged PATH (preserves augmented PATH entries) | |||||||||||||||||||||||||||||
| ...oauthModeClearVars, // Clear stale ANTHROPIC_* vars when in OAuth mode | |||||||||||||||||||||||||||||
| ...apiProfileEnv // Include active API profile config (highest priority for ANTHROPIC_* vars) | |||||||||||||||||||||||||||||
| } | |||||||||||||||||||||||||||||
|
Comment on lines
696
to
703
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Find pythonEnvManager.getPythonEnv() calls and implementation
rg -n "getPythonEnv" --type=ts -A5 -B5 | head -100Repository: AndyMik90/Auto-Claude Length of output: 10363 🏁 Script executed: #!/bin/bash
# Look for pythonEnvManager definition and initialization
rg -n "pythonEnvManager\s*=" --type=ts -A3 -B3Repository: AndyMik90/Auto-Claude Length of output: 615 🏁 Script executed: #!/bin/bash
# Check the file where pythonEnvManager is defined
fd pythonEnvManager --type=tsRepository: AndyMik90/Auto-Claude Length of output: 234 🏁 Script executed: #!/bin/bash
# Read the getPythonEnv() method implementation
sed -n '690,750p' apps/frontend/src/main/python-env-manager.tsRepository: AndyMik90/Auto-Claude Length of output: 3204 🏁 Script executed: #!/bin/bash
# Read more of the getPythonEnv() implementation to see all returned keys
sed -n '690,800p' apps/frontend/src/main/python-env-manager.tsRepository: AndyMik90/Auto-Claude Length of output: 4692 🏁 Script executed: #!/bin/bash
# Look at agent-process.ts to see mergedPythonEnv construction and context
sed -n '700,750p' apps/frontend/src/main/agent/agent-process.tsRepository: AndyMik90/Auto-Claude Length of output: 2573 🏁 Script executed: #!/bin/bash
# Look at env construction before it's passed to spawn
sed -n '650,730p' apps/frontend/src/main/agent/agent-process.ts | head -100Repository: AndyMik90/Auto-Claude Length of output: 3992 🏁 Script executed: #!/bin/bash
# Check what extraEnv, profileEnv, and other env components contain
rg -n "extraEnv|profileEnv|oauthModeClearVars" apps/frontend/src/main/agent/agent-process.ts -B2 -A2 | head -80Repository: AndyMik90/Auto-Claude Length of output: 3624 🏁 Script executed: #!/bin/bash
# Check setupProcessEnvironment to see what's set in env
sed -n '176,260p' apps/frontend/src/main/agent/agent-process.tsRepository: AndyMik90/Auto-Claude Length of output: 4017 Clarify redundant Python environment variable overrides and document override semantics.
🤖 Prompt for AI Agents |
|||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: The
CLAUDE.mdtruncation logic can be bypassed on Windows ifmax_claude_md_charsbecomes negative, causing the> 0check in theifcondition to fail.Severity: CRITICAL
Suggested Fix
Modify the conditional logic to handle cases where
max_claude_md_charsis not positive. For example, change the check toif max_claude_md_chars < len(claude_md_content):and ensuremax_claude_md_charsis clamped at a minimum of 0 before being used for slicing, preventing negative budget issues.Prompt for AI Agent
Did we get this right? 👍 / 👎 to inform future reviews.