diff --git a/apps/backend/analysis/__init__.py b/apps/backend/analysis/__init__.py index c3d73619..49d59ee5 100644 --- a/apps/backend/analysis/__init__.py +++ b/apps/backend/analysis/__init__.py @@ -6,6 +6,9 @@ Code analysis and project scanning tools. """ # Import from analyzers subpackage (these are the modular analyzers) + +from __future__ import annotations + from .analyzers import ( ProjectAnalyzer as ModularProjectAnalyzer, ) diff --git a/apps/backend/analysis/analyzer.py b/apps/backend/analysis/analyzer.py index 46f07a23..23dea8a3 100644 --- a/apps/backend/analysis/analyzer.py +++ b/apps/backend/analysis/analyzer.py @@ -27,6 +27,8 @@ This module now serves as a facade to the modular analyzer system in the analyze All actual implementation is in focused submodules for better maintainability. """ +from __future__ import annotations + import json from pathlib import Path diff --git a/apps/backend/analysis/analyzers/__init__.py b/apps/backend/analysis/analyzers/__init__.py index b425b119..a04b2310 100644 --- a/apps/backend/analysis/analyzers/__init__.py +++ b/apps/backend/analysis/analyzers/__init__.py @@ -11,6 +11,8 @@ Main exports: - analyze_service: Convenience function for service analysis """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/base.py b/apps/backend/analysis/analyzers/base.py index 464c4a74..5bb604fc 100644 --- a/apps/backend/analysis/analyzers/base.py +++ b/apps/backend/analysis/analyzers/base.py @@ -5,6 +5,8 @@ Base Analyzer Module Provides common constants, utilities, and base functionality shared across all analyzers. """ +from __future__ import annotations + import json from pathlib import Path diff --git a/apps/backend/analysis/analyzers/context/__init__.py b/apps/backend/analysis/analyzers/context/__init__.py index bea71aad..ad7f441b 100644 --- a/apps/backend/analysis/analyzers/context/__init__.py +++ b/apps/backend/analysis/analyzers/context/__init__.py @@ -5,6 +5,8 @@ Context Analyzer Package Contains specialized detectors for comprehensive project context analysis. """ +from __future__ import annotations + from .api_docs_detector import ApiDocsDetector from .auth_detector import AuthDetector from .env_detector import EnvironmentDetector diff --git a/apps/backend/analysis/analyzers/context/api_docs_detector.py b/apps/backend/analysis/analyzers/context/api_docs_detector.py index fa334a9a..2d9929e6 100644 --- a/apps/backend/analysis/analyzers/context/api_docs_detector.py +++ b/apps/backend/analysis/analyzers/context/api_docs_detector.py @@ -8,6 +8,8 @@ Detects API documentation tools and configurations: - API documentation endpoints """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context/auth_detector.py b/apps/backend/analysis/analyzers/context/auth_detector.py index 74644007..65151764 100644 --- a/apps/backend/analysis/analyzers/context/auth_detector.py +++ b/apps/backend/analysis/analyzers/context/auth_detector.py @@ -11,6 +11,8 @@ Detects authentication and authorization patterns: - Auth middleware and decorators """ +from __future__ import annotations + import re from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context/env_detector.py b/apps/backend/analysis/analyzers/context/env_detector.py index aa0817a5..534cdfb7 100644 --- a/apps/backend/analysis/analyzers/context/env_detector.py +++ b/apps/backend/analysis/analyzers/context/env_detector.py @@ -9,6 +9,8 @@ Detects and analyzes environment variables from multiple sources: - Source code (os.getenv, process.env) """ +from __future__ import annotations + import re from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context/jobs_detector.py b/apps/backend/analysis/analyzers/context/jobs_detector.py index 0c27b8f0..05aba889 100644 --- a/apps/backend/analysis/analyzers/context/jobs_detector.py +++ b/apps/backend/analysis/analyzers/context/jobs_detector.py @@ -9,6 +9,8 @@ Detects background job and task queue systems: - Scheduled tasks and cron jobs """ +from __future__ import annotations + import re from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context/migrations_detector.py b/apps/backend/analysis/analyzers/context/migrations_detector.py index 328fa943..a5d7bf07 100644 --- a/apps/backend/analysis/analyzers/context/migrations_detector.py +++ b/apps/backend/analysis/analyzers/context/migrations_detector.py @@ -10,6 +10,8 @@ Detects database migration tools and configurations: - Prisma """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context/monitoring_detector.py b/apps/backend/analysis/analyzers/context/monitoring_detector.py index d4928918..0175547a 100644 --- a/apps/backend/analysis/analyzers/context/monitoring_detector.py +++ b/apps/backend/analysis/analyzers/context/monitoring_detector.py @@ -9,6 +9,8 @@ Detects monitoring and observability setup: - Logging infrastructure """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context/services_detector.py b/apps/backend/analysis/analyzers/context/services_detector.py index 80879bc6..6144c34e 100644 --- a/apps/backend/analysis/analyzers/context/services_detector.py +++ b/apps/backend/analysis/analyzers/context/services_detector.py @@ -13,6 +13,8 @@ Detects external service integrations based on dependencies: - Monitoring tools (Sentry, Datadog, New Relic) """ +from __future__ import annotations + import re from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/context_analyzer.py b/apps/backend/analysis/analyzers/context_analyzer.py index ad4c5c4b..9351e192 100644 --- a/apps/backend/analysis/analyzers/context_analyzer.py +++ b/apps/backend/analysis/analyzers/context_analyzer.py @@ -14,6 +14,8 @@ Orchestrates comprehensive project context analysis including: This module delegates to specialized detectors for clean separation of concerns. """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/database_detector.py b/apps/backend/analysis/analyzers/database_detector.py index 82f79ddc..f4380b9c 100644 --- a/apps/backend/analysis/analyzers/database_detector.py +++ b/apps/backend/analysis/analyzers/database_detector.py @@ -7,6 +7,8 @@ Detects database models and schemas across different ORMs: - JavaScript/TypeScript: Prisma, TypeORM, Drizzle, Mongoose """ +from __future__ import annotations + import re from pathlib import Path diff --git a/apps/backend/analysis/analyzers/framework_analyzer.py b/apps/backend/analysis/analyzers/framework_analyzer.py index ffb4131b..9dcab158 100644 --- a/apps/backend/analysis/analyzers/framework_analyzer.py +++ b/apps/backend/analysis/analyzers/framework_analyzer.py @@ -6,6 +6,8 @@ Detects programming languages, frameworks, and related technologies across diffe Supports Python, Node.js/TypeScript, Go, Rust, and Ruby frameworks. """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/port_detector.py b/apps/backend/analysis/analyzers/port_detector.py index 4235abbb..7e533b43 100644 --- a/apps/backend/analysis/analyzers/port_detector.py +++ b/apps/backend/analysis/analyzers/port_detector.py @@ -6,6 +6,8 @@ Detects application ports from multiple sources including entry points, environment files, Docker Compose, configuration files, and scripts. """ +from __future__ import annotations + import re from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/project_analyzer_module.py b/apps/backend/analysis/analyzers/project_analyzer_module.py index 4cb6a504..948d487a 100644 --- a/apps/backend/analysis/analyzers/project_analyzer_module.py +++ b/apps/backend/analysis/analyzers/project_analyzer_module.py @@ -5,6 +5,8 @@ Project Analyzer Module Analyzes entire projects, detecting monorepo structures, services, infrastructure, and conventions. """ +from __future__ import annotations + from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/analyzers/route_detector.py b/apps/backend/analysis/analyzers/route_detector.py index d3cd824b..5442a538 100644 --- a/apps/backend/analysis/analyzers/route_detector.py +++ b/apps/backend/analysis/analyzers/route_detector.py @@ -9,6 +9,8 @@ Detects API routes and endpoints across different frameworks: - Rust: Axum, Actix """ +from __future__ import annotations + import re from pathlib import Path diff --git a/apps/backend/analysis/analyzers/service_analyzer.py b/apps/backend/analysis/analyzers/service_analyzer.py index 44d98c22..cd7201b9 100644 --- a/apps/backend/analysis/analyzers/service_analyzer.py +++ b/apps/backend/analysis/analyzers/service_analyzer.py @@ -6,6 +6,8 @@ Main ServiceAnalyzer class that coordinates all analysis for a single service/pa Integrates framework detection, route analysis, database models, and context extraction. """ +from __future__ import annotations + import re from pathlib import Path from typing import Any diff --git a/apps/backend/analysis/ci_discovery.py b/apps/backend/analysis/ci_discovery.py index 347546c4..8aebd2e9 100644 --- a/apps/backend/analysis/ci_discovery.py +++ b/apps/backend/analysis/ci_discovery.py @@ -22,6 +22,8 @@ Usage: print(f"Test Commands: {result.test_commands}") """ +from __future__ import annotations + import json import re from dataclasses import dataclass, field diff --git a/apps/backend/analysis/insight_extractor.py b/apps/backend/analysis/insight_extractor.py index be1792f1..0abbc235 100644 --- a/apps/backend/analysis/insight_extractor.py +++ b/apps/backend/analysis/insight_extractor.py @@ -9,6 +9,8 @@ Uses the Claude Agent SDK (same as the rest of the system) for extraction. Falls back to generic insights if extraction fails (never blocks the build). """ +from __future__ import annotations + import json import logging import os diff --git a/apps/backend/analysis/project_analyzer.py b/apps/backend/analysis/project_analyzer.py index 74484684..f9e2e28d 100644 --- a/apps/backend/analysis/project_analyzer.py +++ b/apps/backend/analysis/project_analyzer.py @@ -28,6 +28,9 @@ needed for the detected tech stack, while blocking dangerous operations. """ # Re-export all public API from the project module + +from __future__ import annotations + from project import ( # Command registries BASE_COMMANDS, diff --git a/apps/backend/analysis/risk_classifier.py b/apps/backend/analysis/risk_classifier.py index 37488c08..285d37e7 100644 --- a/apps/backend/analysis/risk_classifier.py +++ b/apps/backend/analysis/risk_classifier.py @@ -21,6 +21,8 @@ Usage: test_types = classifier.get_required_test_types(spec_dir) """ +from __future__ import annotations + import json from dataclasses import dataclass, field from pathlib import Path diff --git a/apps/backend/analysis/security_scanner.py b/apps/backend/analysis/security_scanner.py index 3b1b8b42..ff99c0c7 100644 --- a/apps/backend/analysis/security_scanner.py +++ b/apps/backend/analysis/security_scanner.py @@ -21,6 +21,8 @@ Usage: print("Security issues found - blocking QA approval") """ +from __future__ import annotations + import json import subprocess from dataclasses import dataclass, field diff --git a/apps/backend/analysis/test_discovery.py b/apps/backend/analysis/test_discovery.py index 9cd1c689..031b0217 100644 --- a/apps/backend/analysis/test_discovery.py +++ b/apps/backend/analysis/test_discovery.py @@ -22,6 +22,8 @@ Usage: print(f"Test command: {result['test_command']}") """ +from __future__ import annotations + import json from dataclasses import dataclass, field from pathlib import Path diff --git a/apps/backend/spec/discovery.py b/apps/backend/spec/discovery.py index 06dd4e84..a5dd8f9d 100644 --- a/apps/backend/spec/discovery.py +++ b/apps/backend/spec/discovery.py @@ -69,8 +69,62 @@ def get_project_index_stats(spec_dir: Path) -> dict: try: with open(spec_index) as f: index_data = json.load(f) + + # Support both old and new analyzer formats + file_count = 0 + + # Old format: top-level "files" array + if "files" in index_data: + file_count = len(index_data["files"]) + # New format: count files in services + elif "services" in index_data: + services = index_data["services"] + + for service_data in services.values(): + if isinstance(service_data, dict): + # Config files + file_count += 3 # package.json, tsconfig.json, .env.example + + # Entry point + if service_data.get("entry_point"): + file_count += 1 + + # Dependencies indicate source files + deps = service_data.get("dependencies", []) + dev_deps = service_data.get("dev_dependencies", []) + file_count += len(deps) // 2 # Rough estimate: 1 file per 2 deps + file_count += len(dev_deps) // 4 # Fewer files for dev deps + + # Key directories (each represents multiple files) + key_dirs = service_data.get("key_directories", {}) + file_count += len(key_dirs) * 8 # Estimate 8 files per directory + + # Config files + if service_data.get("dockerfile"): + file_count += 1 + if service_data.get("test_directory"): + file_count += 3 # Test files + + # Infrastructure files + if "infrastructure" in index_data: + infra = index_data["infrastructure"] + if infra.get("docker_compose"): + file_count += len(infra["docker_compose"]) + if infra.get("dockerfiles"): + file_count += len(infra["dockerfiles"]) + + # Convention files + if "conventions" in index_data: + conv = index_data["conventions"] + if conv.get("linting"): + file_count += 1 # eslintrc or similar + if conv.get("formatting"): + file_count += 1 # prettier config + if conv.get("git_hooks"): + file_count += 1 # husky/hooks + return { - "file_count": len(index_data.get("files", [])), + "file_count": file_count, "project_type": index_data.get("project_type", "unknown"), } except Exception: diff --git a/apps/frontend/src/main/index.ts b/apps/frontend/src/main/index.ts index 11cb39b4..c445f016 100644 --- a/apps/frontend/src/main/index.ts +++ b/apps/frontend/src/main/index.ts @@ -1,5 +1,6 @@ import { app, BrowserWindow, shell, nativeImage } from 'electron'; import { join } from 'path'; +import { existsSync, readFileSync } from 'fs'; import { electronApp, optimizer, is } from '@electron-toolkit/utils'; import { setupIpcHandlers } from './ipc-setup'; import { AgentManager } from './agent'; @@ -120,6 +121,23 @@ app.whenReady().then(() => { // Initialize agent manager agentManager = new AgentManager(); + // Load settings and configure agent manager with Python and auto-claude paths + try { + const settingsPath = join(app.getPath('userData'), 'settings.json'); + if (existsSync(settingsPath)) { + const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); + if (settings.pythonPath || settings.autoBuildPath) { + console.warn('[main] Configuring AgentManager with settings:', { + pythonPath: settings.pythonPath, + autoBuildPath: settings.autoBuildPath + }); + agentManager.configure(settings.pythonPath, settings.autoBuildPath); + } + } + } catch (error) { + console.warn('[main] Failed to load settings for agent configuration:', error); + } + // Initialize terminal manager terminalManager = new TerminalManager(() => mainWindow); 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 38e5c90f..217566c0 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 @@ -1,4 +1,4 @@ -import { ipcMain } from 'electron'; +import { ipcMain, app } from 'electron'; import type { BrowserWindow } from 'electron'; import path from 'path'; import { existsSync, readFileSync } from 'fs'; @@ -21,6 +21,7 @@ import { buildMemoryStatus } from './memory-status-handlers'; import { loadFileBasedMemories } from './memory-data-handlers'; +import { parsePythonCommand } from '../../python-detector'; /** * Load project index from file @@ -157,9 +158,30 @@ export function registerProjectContextHandlers( const analyzerPath = path.join(autoBuildSource, 'analyzer.py'); 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'; + try { + const settingsPath = path.join(app.getPath('userData'), 'settings.json'); + if (existsSync(settingsPath)) { + const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); + if (settings.pythonPath && existsSync(settings.pythonPath)) { + pythonCmd = settings.pythonPath; + console.log('[project-context] Using Python from settings:', pythonCmd); + } + } + } catch (err) { + console.warn('[project-context] Could not read Python from settings:', err); + } + + const [pythonCommand, pythonBaseArgs] = parsePythonCommand(pythonCmd); + // Run analyzer await new Promise((resolve, reject) => { - const proc = spawn('python', [ + let stdout = ''; + let stderr = ''; + + const proc = spawn(pythonCommand, [ + ...pythonBaseArgs, analyzerPath, '--project-dir', project.path, '--output', indexOutputPath @@ -168,15 +190,30 @@ export function registerProjectContextHandlers( env: { ...process.env } }); + proc.stdout?.on('data', (data) => { + stdout += data.toString(); + }); + + proc.stderr?.on('data', (data) => { + stderr += data.toString(); + }); + proc.on('close', (code: number) => { if (code === 0) { + console.log('[project-context] Analyzer stdout:', stdout); resolve(); } else { - reject(new Error(`Analyzer exited with code ${code}`)); + console.error('[project-context] Analyzer failed with code', code); + console.error('[project-context] Analyzer stderr:', stderr); + console.error('[project-context] Analyzer stdout:', stdout); + reject(new Error(`Analyzer exited with code ${code}: ${stderr || stdout}`)); } }); - proc.on('error', reject); + proc.on('error', (err) => { + console.error('[project-context] Analyzer spawn error:', err); + reject(err); + }); }); // Read the new index diff --git a/apps/frontend/src/main/updater/path-resolver.ts b/apps/frontend/src/main/updater/path-resolver.ts index c9aecc79..94ebd34d 100644 --- a/apps/frontend/src/main/updater/path-resolver.ts +++ b/apps/frontend/src/main/updater/path-resolver.ts @@ -2,7 +2,7 @@ * Path resolution utilities for Auto Claude updater */ -import { existsSync } from 'fs'; +import { existsSync, readFileSync } from 'fs'; import path from 'path'; import { app } from 'electron'; @@ -43,9 +43,22 @@ export function getUpdateCachePath(): string { } /** - * Get the effective source path (considers override from updates) + * Get the effective source path (considers override from updates and settings) */ export function getEffectiveSourcePath(): string { + // First, check user settings for configured autoBuildPath + try { + const settingsPath = path.join(app.getPath('userData'), 'settings.json'); + if (existsSync(settingsPath)) { + const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); + if (settings.autoBuildPath && existsSync(settings.autoBuildPath)) { + return settings.autoBuildPath; + } + } + } catch { + // Ignore settings read errors + } + if (app.isPackaged) { // Check for user-updated source first const overridePath = path.join(app.getPath('userData'), 'backend-source'); diff --git a/apps/frontend/src/renderer/components/TaskCard.tsx b/apps/frontend/src/renderer/components/TaskCard.tsx index fb514816..d8808f51 100644 --- a/apps/frontend/src/renderer/components/TaskCard.tsx +++ b/apps/frontend/src/renderer/components/TaskCard.tsx @@ -231,12 +231,15 @@ export function TaskCard({ task, onClick }: TaskCardProps) { {EXECUTION_PHASE_LABELS[executionPhase]} )} - - {isStuck ? 'Needs Recovery' : isIncomplete ? 'Needs Resume' : getStatusLabel(task.status)} - + {/* Status badge - hide when execution phase badge is showing */} + {!hasActiveExecution && ( + + {isStuck ? 'Needs Recovery' : isIncomplete ? 'Needs Resume' : getStatusLabel(task.status)} + + )} {/* Review reason badge - explains why task needs human review */} {reviewReasonInfo && !isStuck && !isIncomplete && (