From 8d58dd6fe46a4cc453878bb4605532c96f56cb65 Mon Sep 17 00:00:00 2001 From: Navid Date: Fri, 2 Jan 2026 01:08:11 +0300 Subject: [PATCH] fix: prefer versioned Homebrew Python over system python3 (#494) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enhance Python detection to find versioned Homebrew installations Fixes issue where users with Python 3.9.6 at /usr/bin/python3 would get "Auto Claude requires Python 3.10 or higher" error even when they had newer Python versions installed via Homebrew. Changes: - Updated findHomebrewPython() to check for versioned Python installations - Now searches for python3.13, python3.12, python3.11, python3.10 in addition to generic python3 - Validates each found Python to ensure it meets version requirements - Checks both Apple Silicon (/opt/homebrew/bin) and Intel Mac (/usr/local/bin) locations This ensures the app automatically finds and uses the latest compatible Python version instead of falling back to the potentially outdated system Python. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 * Update apps/frontend/src/main/python-detector.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Address PR review findings for Python detection enhancement Addresses all review findings from Auto Claude PR Review: 1. [HIGH] Align version ordering between python-detector.ts and cli-tool-manager.ts - Both now use consistent order: versioned first (3.13→3.10), then generic python3 - This ensures different parts of the app use the same Python version - Added validation in cli-tool-manager.ts (was missing before) 2. [MEDIUM] Add try/catch around validatePythonVersion calls - Wrapped validation in try/catch to handle timeouts and permission errors - Follows same pattern as findPythonCommand() - Ensures graceful fallback to next candidate on validation failure 3. [LOW] Add debug logging for Python detection - Added console.log for successful detection with version info - Added console.warn for rejected candidates with reason - Added logging when no valid Python found - Improves troubleshooting of user Python detection issues 4. [LOW] Document maintenance requirement for version list - Added JSDoc note about updating list for new Python releases - Added TODO comment for Python 3.14+ updates - Applied to both files for consistency Additional improvements: - Fixed bug in cli-tool-manager.ts that returned first found Python without validation - Both detection systems now validate Python version requirements (3.10+) - Consistent logging format between both detection systems 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 * Add Python 3.14 support to version detection Python 3.14 was released, so adding it to the detection lists: - Updated pythonNames arrays in both python-detector.ts and cli-tool-manager.ts - Added python3.14 to SAFE_PYTHON_COMMANDS set - Updated JSDoc comments to reflect Python 3.14 support - Removed TODO about Python 3.14 (now implemented) This ensures the app can detect and use Python 3.14 installations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 * Refactor: Extract shared Homebrew Python detection logic Eliminated code duplication by extracting shared Python detection logic into a reusable utility module. Changes: - Created apps/frontend/src/main/utils/homebrew-python.ts - Exported findHomebrewPython() utility function - Accepts validation function and log prefix as parameters - Contains all shared detection logic (version list, validation, logging) - Updated python-detector.ts - Removed duplicate findHomebrewPython() implementation (45 lines) - Now imports and delegates to shared utility - Maintains identical behavior and error semantics - Updated cli-tool-manager.ts - Removed duplicate findHomebrewPython() implementation (52 lines) - Now imports and delegates to shared utility - Maintains identical behavior and error semantics Benefits: - Single source of truth for Homebrew Python detection - Easier to maintain (update version list in one place) - Consistent behavior across the application - Reduced code duplication (~90 lines eliminated) The refactored code maintains 100% backward compatibility with identical return values, logging behavior, and error handling. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --------- Co-authored-by: Claude Sonnet 4.5 Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> --- apps/frontend/src/main/cli-tool-manager.ts | 33 ++------ apps/frontend/src/main/python-detector.ts | 18 ++--- .../src/main/utils/homebrew-python.ts | 77 +++++++++++++++++++ 3 files changed, 88 insertions(+), 40 deletions(-) create mode 100644 apps/frontend/src/main/utils/homebrew-python.ts diff --git a/apps/frontend/src/main/cli-tool-manager.ts b/apps/frontend/src/main/cli-tool-manager.ts index e54dd43b..4e0c6d0a 100644 --- a/apps/frontend/src/main/cli-tool-manager.ts +++ b/apps/frontend/src/main/cli-tool-manager.ts @@ -27,6 +27,7 @@ import os from 'os'; import { app } from 'electron'; import { findExecutable } from './env-utils'; import type { ToolDetectionResult } from '../shared/types'; +import { findHomebrewPython as findHomebrewPythonUtil } from './utils/homebrew-python'; /** * Supported CLI tools managed by this system @@ -731,37 +732,15 @@ class CLIToolManager { /** * Find Homebrew Python on macOS - * - * Checks both Apple Silicon and Intel Homebrew locations. - * Searches for python3, python3.13, python3.12, etc. in order. + * Delegates to shared utility function. * * @returns Path to Homebrew Python or null if not found */ private findHomebrewPython(): string | null { - const homebrewDirs = [ - '/opt/homebrew/bin', // Apple Silicon - '/usr/local/bin', // Intel Mac - ]; - - // Check for generic python3 first, then specific versions (newest first) - const pythonNames = [ - 'python3', - 'python3.13', - 'python3.12', - 'python3.11', - 'python3.10', - ]; - - for (const dir of homebrewDirs) { - for (const name of pythonNames) { - const pythonPath = path.join(dir, name); - if (existsSync(pythonPath)) { - return pythonPath; - } - } - } - - return null; + return findHomebrewPythonUtil( + (pythonPath) => this.validatePython(pythonPath), + '[CLI Tools]' + ); } /** diff --git a/apps/frontend/src/main/python-detector.ts b/apps/frontend/src/main/python-detector.ts index f8c80d20..e15bcd45 100644 --- a/apps/frontend/src/main/python-detector.ts +++ b/apps/frontend/src/main/python-detector.ts @@ -2,6 +2,7 @@ import { execSync, execFileSync } from 'child_process'; import { existsSync, accessSync, constants } from 'fs'; import path from 'path'; import { app } from 'electron'; +import { findHomebrewPython as findHomebrewPythonUtil } from './utils/homebrew-python'; /** * Get the path to the bundled Python executable. @@ -34,23 +35,12 @@ export function getBundledPythonPath(): string | null { /** * Find the first existing Homebrew Python installation. - * Checks common Homebrew paths for Python 3. + * Delegates to shared utility function. * * @returns The path to Homebrew Python, or null if not found */ function findHomebrewPython(): string | null { - const homebrewPaths = [ - '/opt/homebrew/bin/python3', // Apple Silicon (M1/M2/M3) - '/usr/local/bin/python3' // Intel Mac - ]; - - for (const pythonPath of homebrewPaths) { - if (existsSync(pythonPath)) { - return pythonPath; - } - } - - return null; + return findHomebrewPythonUtil(validatePythonVersion, '[Python]'); } /** @@ -308,6 +298,7 @@ const ALLOWED_PATH_PATTERNS: RegExp[] = [ /** * Known safe Python commands (not full paths). * These are resolved by the shell/OS and are safe. + * Note: Update this list when new Python versions are released. */ const SAFE_PYTHON_COMMANDS = new Set([ 'python', @@ -316,6 +307,7 @@ const SAFE_PYTHON_COMMANDS = new Set([ 'python3.11', 'python3.12', 'python3.13', + 'python3.14', 'py', 'py -3', ]); diff --git a/apps/frontend/src/main/utils/homebrew-python.ts b/apps/frontend/src/main/utils/homebrew-python.ts new file mode 100644 index 00000000..9891c123 --- /dev/null +++ b/apps/frontend/src/main/utils/homebrew-python.ts @@ -0,0 +1,77 @@ +/** + * Homebrew Python Detection Utility + * + * Shared logic for finding Python installations in Homebrew directories. + * Used by both python-detector.ts and cli-tool-manager.ts to ensure + * consistent Python detection across the application. + */ + +import { existsSync } from 'fs'; +import path from 'path'; + +/** + * Validation result for a Python installation. + */ +export interface PythonValidation { + valid: boolean; + version?: string; + message: string; +} + +/** + * Find the first valid Homebrew Python installation. + * Checks common Homebrew paths for Python 3, including versioned installations. + * Prioritizes newer Python versions (3.14, 3.13, 3.12, 3.11, 3.10). + * + * Note: This list should be updated when new Python versions are released. + * Check for specific versions first to ensure we find the latest available version. + * + * @param validateFn - Function to validate a Python path and return validation result + * @param logPrefix - Prefix for log messages (e.g., '[Python]', '[CLI Tools]') + * @returns The path to Homebrew Python, or null if not found + */ +export function findHomebrewPython( + validateFn: (pythonPath: string) => PythonValidation, + logPrefix: string +): string | null { + const homebrewDirs = [ + '/opt/homebrew/bin', // Apple Silicon (M1/M2/M3) + '/usr/local/bin' // Intel Mac + ]; + + // Check for specific Python versions first (newest to oldest), then fall back to generic python3. + // This ensures we find the latest available version that meets our requirements. + const pythonNames = [ + 'python3.14', + 'python3.13', + 'python3.12', + 'python3.11', + 'python3.10', + 'python3', + ]; + + for (const dir of homebrewDirs) { + for (const name of pythonNames) { + const pythonPath = path.join(dir, name); + if (existsSync(pythonPath)) { + try { + // Validate that this Python meets version requirements + const validation = validateFn(pythonPath); + if (validation.valid) { + console.log(`${logPrefix} Found valid Homebrew Python: ${pythonPath} (${validation.version})`); + return pythonPath; + } else { + console.warn(`${logPrefix} ${pythonPath} rejected: ${validation.message}`); + } + } catch (error) { + // Version check failed (e.g., timeout, permission issue), try next candidate + console.warn(`${logPrefix} Failed to validate ${pythonPath}: ${error}`); + continue; + } + } + } + } + + console.log(`${logPrefix} No valid Homebrew Python found in ${homebrewDirs.join(', ')}`); + return null; +}