From 0f7d6e0530f4e47f0d882a54657edb5eefe89636 Mon Sep 17 00:00:00 2001 From: HSSAINI Saad Date: Wed, 24 Dec 2025 14:03:49 +0100 Subject: [PATCH] fix: resolve Python detection and backend packaging issues (#241) * fix: resolve Python detection and backend packaging issues - Fix backend packaging path (auto-claude -> backend) to match path-resolver.ts expectations - Add future annotations import to config_parser.py for Python 3.9+ compatibility - Use findPythonCommand() in project-context-handlers to prioritize Homebrew Python - Improve Python detection to prefer Homebrew paths over system Python on macOS This resolves the following issues: - 'analyzer.py not found' error due to incorrect packaging destination - TypeError with 'dict | None' syntax on Python < 3.10 - Wrong Python interpreter being used (system Python instead of Homebrew Python 3.10+) Tested on macOS with packaged app - project index now loads successfully. * refactor: address PR review feedback - Extract findHomebrewPython() helper to eliminate code duplication between findPythonCommand() and getDefaultPythonCommand() - Remove hardcoded version-specific paths (python3.12) and rely only on generic Homebrew symlinks for better maintainability - Remove unnecessary 'from __future__ import annotations' from config_parser.py since backend requires Python 3.12+ where union types are native These changes make the code more maintainable, less fragile to Python version changes, and properly reflect the project's Python 3.12+ requirement. --- apps/frontend/package-lock.json | 2 +- apps/frontend/package.json | 2 +- .../context/project-context-handlers.ts | 4 +- apps/frontend/src/main/python-detector.ts | 46 ++++++++++++++++--- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/apps/frontend/package-lock.json b/apps/frontend/package-lock.json index d8a0c0e3..81c474c3 100644 --- a/apps/frontend/package-lock.json +++ b/apps/frontend/package-lock.json @@ -65,7 +65,7 @@ "@types/uuid": "^10.0.0", "@vitejs/plugin-react": "^5.1.2", "autoprefixer": "^10.4.22", - "electron": "^39.2.6", + "electron": "^39.2.7", "electron-builder": "^26.0.12", "electron-vite": "^5.0.0", "eslint": "^9.39.1", diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 77eb83d0..7ab47e33 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -149,7 +149,7 @@ }, { "from": "../backend", - "to": "auto-claude", + "to": "backend", "filter": [ "!**/.git", "!**/__pycache__", diff --git a/apps/frontend/src/main/ipc-handlers/context/project-context-handlers.ts b/apps/frontend/src/main/ipc-handlers/context/project-context-handlers.ts index 217566c0..162ce35f 100644 --- a/apps/frontend/src/main/ipc-handlers/context/project-context-handlers.ts +++ b/apps/frontend/src/main/ipc-handlers/context/project-context-handlers.ts @@ -21,7 +21,7 @@ import { buildMemoryStatus } from './memory-status-handlers'; import { loadFileBasedMemories } from './memory-data-handlers'; -import { parsePythonCommand } from '../../python-detector'; +import { findPythonCommand, parsePythonCommand } from '../../python-detector'; /** * Load project index from file @@ -159,7 +159,7 @@ export function registerProjectContextHandlers( const indexOutputPath = path.join(project.path, AUTO_BUILD_PATHS.PROJECT_INDEX); // Get Python command directly from settings file (not pythonEnvManager which creates NEW venv) - let pythonCmd = 'python3'; + let pythonCmd = findPythonCommand() || 'python3'; try { const settingsPath = path.join(app.getPath('userData'), 'settings.json'); if (existsSync(settingsPath)) { diff --git a/apps/frontend/src/main/python-detector.ts b/apps/frontend/src/main/python-detector.ts index 55cea55e..a9046c78 100644 --- a/apps/frontend/src/main/python-detector.ts +++ b/apps/frontend/src/main/python-detector.ts @@ -1,6 +1,27 @@ import { execSync } from 'child_process'; import { existsSync } from 'fs'; +/** + * Find the first existing Homebrew Python installation. + * Checks common Homebrew paths for Python 3. + * + * @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 path of homebrewPaths) { + if (existsSync(path)) { + return path; + } + } + + return null; +} + /** * Detect and return the best available Python command. * Tries multiple candidates and returns the first one that works with Python 3. @@ -10,11 +31,16 @@ import { existsSync } from 'fs'; export function findPythonCommand(): string | null { const isWindows = process.platform === 'win32'; - // On Windows, try py launcher first (most reliable), then python, then python3 - // On Unix, try python3 first, then python - const candidates = isWindows - ? ['py -3', 'python', 'python3', 'py'] - : ['python3', 'python']; + // Build candidate list prioritizing Homebrew Python on macOS + let candidates: string[]; + if (isWindows) { + candidates = ['py -3', 'python', 'python3', 'py']; + } else { + const homebrewPython = findHomebrewPython(); + candidates = homebrewPython + ? [homebrewPython, 'python3', 'python'] + : ['python3', 'python']; + } for (const cmd of candidates) { try { @@ -35,7 +61,10 @@ export function findPythonCommand(): string | null { } // Fallback to platform-specific default - return isWindows ? 'python' : 'python3'; + if (isWindows) { + return 'python'; + } + return findHomebrewPython() || 'python3'; } /** @@ -110,7 +139,10 @@ function validatePythonVersion(pythonCmd: string): { * @returns The default Python command for this platform */ export function getDefaultPythonCommand(): string { - return process.platform === 'win32' ? 'python' : 'python3'; + if (process.platform === 'win32') { + return 'python'; + } + return findHomebrewPython() || 'python3'; } /**