-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(changelog): validate Claude CLI exists before generation #1305
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
base: develop
Are you sure you want to change the base?
fix(changelog): validate Claude CLI exists before generation #1305
Conversation
When Claude CLI is not found by the detection logic, the code was
falling back to the string 'claude' and attempting to execute it,
which fails with FileNotFoundError on systems where Claude CLI is
not in PATH.
Now uses getToolInfo('claude') to properly check if Claude CLI
was actually found before attempting changelog generation, and
provides a clear error message with install instructions.
Fixes AndyMik90#1302
Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughRefactors ChangelogService to centralize prerequisite validation by adding a private ensurePrerequisites() that resolves and validates the auto-build source path and the Claude CLI via getToolInfo; getGenerator() and getVersionSuggester() now call this helper and receive the resolved claudePath. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant ChangelogService
participant CliToolManager
participant FileSystem
Client->>ChangelogService: call getGenerator()/getVersionSuggester()
ChangelogService->>ChangelogService: ensurePrerequisites()
ChangelogService->>FileSystem: validate/resolve autoBuildSource
FileSystem-->>ChangelogService: autoBuildSource path
ChangelogService->>CliToolManager: getToolInfo("claude")
CliToolManager-->>ChangelogService: { claudePath, info }
ChangelogService-->>Client: initialize generator/suggester with claudePath
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
Summary of ChangesHello @kaigler, 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 enhances the stability and user experience of the changelog generation process. It resolves an issue where the application would crash with a FileNotFoundError if the Claude CLI was not present on the system. The core change involves refining the detection mechanism for the Claude CLI, ensuring that its absence is gracefully handled and communicated to the user with helpful installation guidance. Highlights
Using Gemini Code AssistThe 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
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 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
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Code Review
This pull request correctly fixes a FileNotFoundError that occurred when generating a changelog without the Claude CLI installed. The new validation logic using getToolInfo('claude') is more robust and provides a much clearer error message to the user. While the fix is correct, I've noticed that the new validation logic is duplicated in two different methods. I've left a comment with a suggestion to refactor this into a shared helper method to improve maintainability.
| // Verify claude CLI is available using proper detection | ||
| const claudeInfo = getToolInfo('claude'); | ||
| if (!claudeInfo.found) { | ||
| throw new Error(`Claude CLI not found. Please install Claude Code from https://claude.ai/download. ${claudeInfo.message || ''}`); | ||
| } |
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.
This validation logic is duplicated in getVersionSuggester on lines 235-239. To improve maintainability and follow the DRY (Don't Repeat Yourself) principle, consider extracting these prerequisite checks into a private helper method.
For example, you could create a method that handles both the autoBuildSource check and the Claude CLI check:
private ensurePrerequisites(): { autoBuildSource: string } {
const autoBuildSource = this.getAutoBuildSourcePath();
if (!autoBuildSource) {
throw new Error('Auto-build source path not found');
}
const claudeInfo = getToolInfo('claude');
if (!claudeInfo.found) {
throw new Error(`Claude CLI not found. Please install Claude Code from https://claude.ai/download. ${claudeInfo.message || ''}`);
}
return { autoBuildSource };
}Then, both getGenerator() and getVersionSuggester() can call this helper method, which centralizes the validation logic.
Extract duplicated validation logic into ensurePrerequisites() method to follow DRY principle. Both getGenerator() and getVersionSuggester() now use this centralized helper for auto-build source and Claude CLI validation. Co-Authored-By: Claude Opus 4.5 <[email protected]>
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/frontend/src/main/changelog/changelog-service.ts`:
- Around line 188-191: The current throw in changelog-service.ts uses a
hardcoded, user-facing string from getToolInfo('claude'); instead, throw an
Error that contains a stable, translatable error identifier (e.g., code:
"CLAUDE_CLI_NOT_FOUND") and preserve claudeInfo.message in a non-user-facing
detail field so the renderer can map the code to an i18n key and display a
localized message; update the throw in the block that checks claudeInfo.found to
include the error code (or set error.name/error.code) and any diagnostic text on
the Error object rather than a literal message so useChangelog (renderer) can
translate the code into the localized text.
♻️ Duplicate comments (1)
apps/frontend/src/main/changelog/changelog-service.ts (1)
182-193: Use the resolved Claude CLI path after validation.
ensurePrerequisites()validates viagetToolInfo, but the generator/suggester still receivethis.claudePathcached at construction time. If Claude gets installed after startup or is resolved outside PATH, validation will pass and the subprocess will still receive a stale path. Return/update the resolved path and pass it through.✅ Suggested fix (propagate resolved path)
- private ensurePrerequisites(): { autoBuildSource: string } { + private ensurePrerequisites(): { autoBuildSource: string; claudePath: string } { const autoBuildSource = this.getAutoBuildSourcePath(); if (!autoBuildSource) { throw new Error('Auto-build source path not found'); } const claudeInfo = getToolInfo('claude'); - if (!claudeInfo.found) { + if (!claudeInfo.found || !claudeInfo.path) { throw new Error(`Claude CLI not found. Please install Claude Code from https://claude.ai/download. ${claudeInfo.message || ''}`); } - return { autoBuildSource }; + this.claudePath = claudeInfo.path; + return { autoBuildSource, claudePath: claudeInfo.path }; }- const { autoBuildSource } = this.ensurePrerequisites(); + const { autoBuildSource, claudePath } = this.ensurePrerequisites(); ... - this.claudePath, + claudePath,- const { autoBuildSource } = this.ensurePrerequisites(); + const { autoBuildSource, claudePath } = this.ensurePrerequisites(); ... - this.claudePath, + claudePath,Also applies to: 201-208, 239-244
| const claudeInfo = getToolInfo('claude'); | ||
| if (!claudeInfo.found) { | ||
| throw new Error(`Claude CLI not found. Please install Claude Code from https://claude.ai/download. ${claudeInfo.message || ''}`); | ||
| } |
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.
🧩 Analysis chain
🏁 Script executed:
# First, verify the file exists and check the exact content at lines 188-191
cat -n apps/frontend/src/main/changelog/changelog-service.ts | sed -n '180,200p'Repository: AndyMik90/Auto-Claude
Length of output: 882
🏁 Script executed:
# Check the full structure of the file to understand context
wc -l apps/frontend/src/main/changelog/changelog-service.ts
head -30 apps/frontend/src/main/changelog/changelog-service.tsRepository: AndyMik90/Auto-Claude
Length of output: 1042
🏁 Script executed:
# Search for i18n usage in this file
rg "t\(" apps/frontend/src/main/changelog/changelog-service.ts -A 2 -B 2Repository: AndyMik90/Auto-Claude
Length of output: 2519
🏁 Script executed:
# Search for generation-error handling
rg "generation-error" apps/frontend/src/main/changelog/changelog-service.ts -A 3 -B 3Repository: AndyMik90/Auto-Claude
Length of output: 586
🏁 Script executed:
# Check how other errors are thrown/handled in this file
rg "throw new Error" apps/frontend/src/main/changelog/changelog-service.ts -B 2 -A 1Repository: AndyMik90/Auto-Claude
Length of output: 436
🏁 Script executed:
# Check if i18n is used in any files in apps/frontend/src/main
rg "import.*i18n\|from.*i18n" apps/frontend/src/main/ --type ts --type tsxRepository: AndyMik90/Auto-Claude
Length of output: 92
🏁 Script executed:
# Check cli-tool-manager for getToolInfo implementation
cat -n apps/frontend/src/main/cli-tool-manager.ts | head -100Repository: AndyMik90/Auto-Claude
Length of output: 3970
🏁 Script executed:
# Search for how generation-error is handled on the renderer/frontend side
rg "generation-error" apps/frontend/src/ --type ts --type tsx -B 2 -A 3 | head -50Repository: AndyMik90/Auto-Claude
Length of output: 92
🏁 Script executed:
# Search for generation-error handling in renderer code
rg "generation-error" apps/frontend/src --type ts -B 3 -A 5Repository: AndyMik90/Auto-Claude
Length of output: 2924
🏁 Script executed:
# Check how errors are typically displayed in renderer
rg "generation-error\|emit.*error" apps/frontend/src/main --type ts -B 2 -A 3Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Look for error code patterns or error handling elsewhere in main
rg "error.*code\|errorCode" apps/frontend/src/main --type ts -B 1 -A 1Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check if there's an error handling/translation pattern in the app
find apps/frontend/src -name "*error*" -o -name "*exception*" | head -20Repository: AndyMik90/Auto-Claude
Length of output: 230
🏁 Script executed:
# Check the errors.json to see the i18n pattern
cat apps/frontend/src/shared/i18n/locales/en/errors.json | head -80Repository: AndyMik90/Auto-Claude
Length of output: 406
🏁 Script executed:
# Check IPC handlers to see how error is sent
cat -n apps/frontend/src/main/ipc-handlers/changelog-handlers.ts | grep -A 10 "generation-error"Repository: AndyMik90/Auto-Claude
Length of output: 663
🏁 Script executed:
# Check renderer side for how it handles CHANGELOG_GENERATION_ERROR
rg "CHANGELOG_GENERATION_ERROR" apps/frontend/src/renderer --type ts -B 3 -A 5Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check IPC channels definitions
rg "CHANGELOG_GENERATION_ERROR" apps/frontend/src --type ts | head -10Repository: AndyMik90/Auto-Claude
Length of output: 554
🏁 Script executed:
# Check how renderer displays the error message
rg "changelog-api\|generationError" apps/frontend/src/renderer --type ts -B 5 -A 5Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Look for any error message handling in renderer
rg "onChangelogGenerationError\|generation.*error" apps/frontend/src/renderer -B 3 -A 5Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check the preload API to see how error is passed
cat -n apps/frontend/src/preload/api/modules/changelog-api.tsRepository: AndyMik90/Auto-Claude
Length of output: 6389
🏁 Script executed:
# Check if i18n is available/used in main process
rg "i18n\|i18next" apps/frontend/src/main --type tsRepository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check how other generation errors are handled (if any)
rg "emit.*error\|generation.*error" apps/frontend/src/main/changelog --type ts -B 5 -A 5Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check the full error flow in changelog-handlers to see if there's any translation happening
cat -n apps/frontend/src/main/ipc-handlers/changelog-handlers.ts | head -60Repository: AndyMik90/Auto-Claude
Length of output: 2560
🏁 Script executed:
# Check if renderer has any error translation logic
find apps/frontend/src/renderer -name "*.ts" -o -name "*.tsx" | xargs grep -l "error.*i18n\|i18n.*error\|t\(" | head -10Repository: AndyMik90/Auto-Claude
Length of output: 88
🏁 Script executed:
# Check how the renderer handles other i18n for errors
rg "errors:" apps/frontend/src/renderer --type ts -B 2 -A 2 | head -40Repository: AndyMik90/Auto-Claude
Length of output: 3459
🏁 Script executed:
# Check if there's a pattern for error codes in the codebase
rg "errorCode\|error.*code\|code.*error" apps/frontend/src/shared --type ts | head -20Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Look for other hardcoded error strings in main process that might be user-facing
rg "throw new Error\|emit.*error" apps/frontend/src/main --type ts | grep -v node_modules | head -30Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check how changelog generation errors are handled in renderer
rg "onChangelogGenerationError\|CHANGELOG_GENERATION_ERROR" apps/frontend/src/renderer --type ts -B 5 -A 10Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check if there's any error translation happening for generation errors
rg "generation.*error\|generationError" apps/frontend/src/renderer --type ts -B 3 -A 3Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check if there's an error handler in the renderer for changelog generation
find apps/frontend/src/renderer -type f -name "*.ts" -o -name "*.tsx" | xargs grep -l "changelog" | head -10Repository: AndyMik90/Auto-Claude
Length of output: 653
🏁 Script executed:
# Look for where generation errors are displayed
rg "generation" apps/frontend/src/renderer --type ts -l | head -5Repository: AndyMik90/Auto-Claude
Length of output: 336
🏁 Script executed:
# Check if main process uses error codes or error objects anywhere
rg "error.*code\|errorCode\|error\s*:\s*\{" apps/frontend/src/main/changelog --type ts -B 2 -A 2Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check changelog-store to see how errors are handled
cat -n apps/frontend/src/renderer/stores/changelog-store.ts | head -150Repository: AndyMik90/Auto-Claude
Length of output: 5619
🏁 Script executed:
# Check the Changelog component for error handling
rg "onChangelogGenerationError\|generation.*error" apps/frontend/src/renderer/components/changelog --type ts -B 5 -A 10Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check how the changelog-store handles errors
rg "generation-error\|generationError\|onChangelogGenerationError" apps/frontend/src/renderer/stores/changelog-store.ts -B 3 -A 5Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Check the rest of changelog-store for error handling
cat -n apps/frontend/src/renderer/stores/changelog-store.ts | sed -n '150,300p'Repository: AndyMik90/Auto-Claude
Length of output: 6587
🏁 Script executed:
# Check the main Changelog component for error handling
cat -n apps/frontend/src/renderer/components/changelog/Changelog.tsx | head -150Repository: AndyMik90/Auto-Claude
Length of output: 5710
🏁 Script executed:
# Search for where setError is called in changelog context
rg "setError\|onChangelogGenerationError" apps/frontend/src/renderer --type ts -B 3 -A 3Repository: AndyMik90/Auto-Claude
Length of output: 47
🏁 Script executed:
# Search for where the error state is set in the hooks
rg "setError" apps/frontend/src/renderer --type ts -B 3 -A 3 | head -60Repository: AndyMik90/Auto-Claude
Length of output: 4737
🏁 Script executed:
# Look for the useChangelog hook implementation
cat -n apps/frontend/src/renderer/components/changelog/hooks/useChangelog.ts | head -200Repository: AndyMik90/Auto-Claude
Length of output: 9655
Localize the Claude CLI error message for users.
The error string at line 190 is user-facing—it flows through the IPC channel to the renderer and is displayed directly to users via the error state (see useChangelog hook line 155). Per the coding guidelines, all user-facing text must use i18n translation keys. Consider passing an error code from the main process and translating it in the renderer, or using an i18n key reference that the renderer can resolve.
🤖 Prompt for AI Agents
In `@apps/frontend/src/main/changelog/changelog-service.ts` around lines 188 -
191, The current throw in changelog-service.ts uses a hardcoded, user-facing
string from getToolInfo('claude'); instead, throw an Error that contains a
stable, translatable error identifier (e.g., code: "CLAUDE_CLI_NOT_FOUND") and
preserve claudeInfo.message in a non-user-facing detail field so the renderer
can map the code to an i18n key and display a localized message; update the
throw in the block that checks claudeInfo.found to include the error code (or
set error.name/error.code) and any diagnostic text on the Error object rather
than a literal message so useChangelog (renderer) can translate the code into
the localized text.
AndyMik90
left a comment
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.
🤖 Auto Claude PR Review
Merge Verdict: 🔴 BLOCKED
🔴 Blocked - 4 CI check(s) failing. Fix CI before merge.
Blocked: 4 CI check(s) failing. Fix CI before merge.
Risk Assessment
| Factor | Level | Notes |
|---|---|---|
| Complexity | Low | Based on lines changed |
| Security Impact | None | Based on security findings |
| Scope Coherence | Good | Based on structural review |
🚨 Blocking Issues (Must Fix)
- Branch Out of Date: PR branch is behind the base branch and needs to be updated
- CI Failed: CI Complete
- CI Failed: test-frontend (ubuntu-latest)
- CI Failed: test-frontend (windows-latest)
- CI Failed: test-frontend (macos-latest)
Findings Summary
- Low: 1 issue(s)
Generated by Auto Claude PR Review
Findings (1 selected of 1 total)
🔵 [b1a7c6de82e0] [LOW] Minor error message redundancy when appending claudeInfo.message
📁 apps/frontend/src/main/changelog/changelog-service.ts:190
The error message construction may result in redundant text. The code uses Claude CLI not found. Please install Claude Code from https://claude.ai/download. ${claudeInfo.message || ''} but claudeInfo.message already contains the full error message from cli-tool-manager ('Claude CLI not found. Install from https://claude.ai/download'). This could result in a message like: 'Claude CLI not found. Please install Claude Code from https://claude.ai/download. Claude CLI not found. Install from https://claude.ai/download'.
Suggested fix:
Consider using claudeInfo.message directly: `throw new Error(claudeInfo.message || 'Claude CLI not found. Install from https://claude.ai/download');` to avoid duplication and maintain consistency with the canonical error message.
This review was generated by Auto Claude.
…iteToPty The implementation was refactored to use PtyManager.writeToPty() instead of terminal.pty.write() directly. Update tests to mock the new method. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1. subprocess-spawn.test.ts: Fix mock profile manager to match ClaudeProfile interface - Use correct properties: id, name, isDefault, oauthToken (not profileId/profileName) - Add missing methods: getActiveProfileToken(), getProfileToken(), getProfile() - Fixes Windows CI test failure where tasks weren't being tracked 2. pre-commit hook: Change npm audit from high to critical level - Known tar vulnerability (CVE-2026-23745) in electron-builder cannot be fixed - electron-builder requires tar@^6.x which is vulnerable - This is a build dependency, not runtime code - Will re-enable high level when electron-builder releases [email protected] support Co-Authored-By: Claude Opus 4.5 <[email protected]>
* fix: bundle runtime deps for packaged app * fix: verify pydantic_core binary in bundled python * fix: bundle minimatch by using esm import * chore: throw on command failures in packager * chore: drop redundant PATH filter in packager * Use shared platform helper for packager * Use platform helper in resolvePlatforms * Harden packaging helpers --------- Co-authored-by: StillKnotKnown <[email protected]>
…ndyMik90#1340) On Windows, spawnSync cannot execute .cmd files directly without a shell context. This adds shell: isWindows() to the spawnSync options in runCommand() to properly execute electron-vite.cmd and electron-builder.cmd during packaging. Additionally, adds argument validation to prevent potential command injection via shell metacharacters when shell: true is used on Windows. When using shell: true, cmd.exe interprets certain characters (& | > < ^ % ; $ $`) as special operators, which could enable command injection if present in user- controlled arguments. The validateArgs() function checks for these metacharacters on Windows and throws an error if any are found, following the same security pattern used in apps/frontend/src/main/ipc-handlers/mcp-handlers.ts. This follows the existing pattern used throughout the codebase for Windows .cmd file execution (env-utils.ts, mcp-handlers.ts). Fixes ACS-365 Co-authored-by: StillKnotKnown <[email protected]>
…yMik90#1341) * fix: Windows CLI detection and version selection UX improvements - Add fallback to default npm global path (%APPDATA%\npm) when npm.cmd is not in PATH (happens when packaged app launches from GUI) - Apply fallback to both sync and async versions of getNpmGlobalPrefix() - Update version selection warning dialogs with clear terminal messaging - Change button text to "Open Terminal & Switch/Update" for clarity - Add i18n translations for terminal note (en/fr) Fixes Claude Code CLI not being detected in packaged Windows builds. Improves UX by clearly indicating terminal will open for version changes. * fix: use APPDATA env var for Windows npm path fallback Use process.env.APPDATA instead of hardcoded 'AppData\Roaming' path for better robustness on Windows systems with custom or localized AppData locations. Provides fallback to hardcoded path for minimal environments. Addresses feedback from PR review. * refactor: use established APPDATA pattern from platform/paths.ts Update Windows npm fallback to use the concise pattern `process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming')` which matches the established pattern in platform/paths.ts (lines 224, 277). This improves codebase consistency and is more concise than the previous ternary expression. Addresses MEDIUM findings from Auto Claude PR Review. * refactor: use platform module helpers and extract npm path constant - Use getNpmCommand() from platform module instead of inline ternary - Extract Windows npm fallback path as WINDOWS_NPM_FALLBACK_PATH constant This eliminates code duplication and improves consistency with the codebase's platform abstraction layer. Addresses LOW findings from Auto Claude PR Review: - [e3eaee8f94e5] Duplicated Windows fallback path constant - [7ae39c782e02] Could use getNpmCommand() from platform module --------- Co-authored-by: StillKnotKnown <[email protected]>
- Fix error message redundancy by using claudeInfo.message directly instead of appending it to a hardcoded message - Use resolved Claude CLI path from getToolInfo() instead of stale cached path from constructor, ensuring freshly validated path is passed to generator and version suggester - Add !claudeInfo.path check for additional safety Addresses CodeRabbit and Auto Claude PR review feedback. Co-Authored-By: Claude Opus 4.5 <[email protected]>
67a743f to
e83e445
Compare
Summary
getToolInfo('claude')to properly detect if Claude CLI was found (instead of checking if path equals fallback string'claude')Root Cause
When Claude CLI is not found by the detection logic,
getToolPath('claude')returns the fallback string'claude'. The previous validation logic:This skipped validation when the fallback was returned, causing the code to proceed and spawn a Python subprocess that tries to execute
['claude', ...]which fails withFileNotFoundError: [WinError 2].Fix
Now uses proper detection:
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.