Write

"""
Codebase Analyzer Service

Analyzes an existing codebase to extract project information such as:
- Technology stack (languages, frameworks, databases)
- Project structure
- Dependencies
- README content
"""

import os
import json
from pathlib import Path
from typing import Optional, Dict, List, Any

# Common file patterns to identify technologies
TECH_PATTERNS = {
    # Frontend
    'React': ['package.json:react', 'jsx', 'tsx', '.react'],
    'Vue': ['package.json:vue', '.vue'],
    'Angular': ['angular.json', 'package.json:@angular/core'],
    'Svelte': ['svelte.config.js', '.svelte'],
    'Next.js': ['next.config.js', 'next.config.mjs', 'package.json:next'],
    'HTML/CSS': ['.html', '.css'],

    # Backend
    'Python': ['.py', 'requirements.txt', 'pyproject.toml', 'setup.py'],
    'Node.js': ['package.json', '.js', '.ts'],
    'Go': ['go.mod', '.go'],
    'Rust': ['Cargo.toml', '.rs'],
    'Java': ['pom.xml', 'build.gradle', '.java'],
    'Ruby': ['Gemfile', '.rb'],
    'PHP': ['composer.json', '.php'],

    # Databases
    'PostgreSQL': ['pg', 'postgres', 'postgresql'],
    'MySQL': ['mysql', 'mariadb'],
    'SQLite': ['sqlite', '.sqlite', '.db'],
    'MongoDB': ['mongo', 'mongodb'],
    'Redis': ['redis'],
    'Firebase': ['firebase', 'firebaseConfig'],

    # Frameworks
    'FastAPI': ['fastapi'],
    'Flask': ['flask'],
    'Django': ['django', 'manage.py'],
    'Express': ['express'],
    'NestJS': ['@nestjs'],

    # Build tools
    'Vite': ['vite.config.js', 'vite.config.ts'],
    'Webpack': ['webpack.config.js'],
    'Tailwind CSS': ['tailwind.config.js', 'tailwind.config.ts'],
    'TypeScript': ['tsconfig.json', '.ts', '.tsx'],
}

# Folders to skip during analysis
SKIP_FOLDERS = {
    'node_modules', '.git', '__pycache__', '.venv', 'venv', 'env',
    '.idea', '.vscode', 'dist', 'build', '.next', '.cache',
    'coverage', '.pytest_cache', '.mypy_cache', 'target',
}

# File extensions to count
CODE_EXTENSIONS = {
    '.py', '.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte',
    '.go', '.rs', '.java', '.rb', '.php', '.html', '.css',
    '.scss', '.sass', '.less', '.json', '.yaml', '.yml',
    '.md', '.sql', '.sh', '.dockerfile',
}

class CodebaseAnalyzer:
    """Analyzes codebases to extract project information."""

    def __init__(self, path: str):
        self.path = Path(path)
        self.detected_tech: Dict[str, List[str]] = {
            'frontend': [],
            'backend': [],
            'database': [],
            'frameworks': [],
            'tools': [],
        }
        self.file_stats: Dict[str, int] = {}
        self.file_count = 0
        self.total_lines = 0
        self.readme_content = ""
        self.package_info: Dict[str, Any] = {}

    def analyze(self) -> Dict[str, Any]:
        """
        Perform full codebase analysis.

        Returns:
            Dict containing analysis results including:
            - detected_tech: Technologies found in the codebase
            - file_stats: Count of files by extension
            - structure: Top-level directory structure
            - readme: README content if found
            - package_info: Package manager info (package.json, requirements.txt, etc.)
        """
        if not self.path.exists():
            return {
                'error': f'Path does not exist: {self.path}',
                'valid': False,
            }

        if not self.path.is_dir():
            return {
                'error': f'Path is not a directory: {self.path}',
                'valid': False,
            }

        # Analyze files
        self._scan_files()

        # Read README
        self._read_readme()

        # Read package info
        self._read_package_info()

        # Detect technologies
        self._detect_technologies()

        # Get directory structure
        structure = self._get_structure()

        return {
            'valid': True,
            'path': str(self.path),
            'name': self.path.name,
            'detected_tech': self.detected_tech,
            'file_stats': self.file_stats,
            'file_count': self.file_count,
            'total_lines': self.total_lines,
            'structure': structure,
            'readme': self.readme_content[:5000] if self.readme_content else None,  # Limit README size
            'package_info': self.package_info,
        }

    def _scan_files(self):
        """Scan all files in the codebase."""
        for root, dirs, files in os.walk(self.path):
            # Skip excluded directories
            dirs[:] = [d for d in dirs if d not in SKIP_FOLDERS]

            for file in files:
                self.file_count += 1
                ext = Path(file).suffix.lower()

                if ext:
                    self.file_stats[ext] = self.file_stats.get(ext, 0) + 1

                # Count lines for code files
                if ext in CODE_EXTENSIONS:
                    file_path = Path(root) / file
                    try:
                        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                            self.total_lines += sum(1 for _ in f)
                    except Exception:
                        pass

    def _read_readme(self):
        """Read README file if it exists."""
        readme_names = ['README.md', 'README.txt', 'README', 'readme.md', 'Readme.md']
        for readme_name in readme_names:
            readme_path = self.path / readme_name
            if readme_path.exists():
                try:
                    with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
                        self.readme_content = f.read()
                    break
                except Exception:
                    pass

    def _read_package_info(self):
        """Read package manager files."""
        # package.json (Node.js)
        package_json = self.path / 'package.json'
        if package_json.exists():
            try:
                with open(package_json, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    self.package_info['package_json'] = {
                        'name': data.get('name'),
                        'version': data.get('version'),
                        'description': data.get('description'),
                        'dependencies': list(data.get('dependencies', {}).keys()),
                        'devDependencies': list(data.get('devDependencies', {}).keys()),
                    }
            except Exception:
                pass

        # requirements.txt (Python)
        requirements = self.path / 'requirements.txt'
        if requirements.exists():
            try:
                with open(requirements, 'r', encoding='utf-8') as f:
                    deps = [line.strip().split('==')[0].split('>=')[0].split('<=')[0]
                            for line in f if line.strip() and not line.startswith('#')]
                    self.package_info['requirements'] = deps
            except Exception:
                pass

        # pyproject.toml (Python)
        pyproject = self.path / 'pyproject.toml'
        if pyproject.exists():
            try:
                with open(pyproject, 'r', encoding='utf-8') as f:
                    content = f.read()
                    self.package_info['pyproject'] = True
                    # Basic parsing - just note it exists
            except Exception:
                pass

    def _detect_technologies(self):
        """Detect technologies based on file patterns and package info."""
        detected = set()

        # Check file extensions
        for ext in self.file_stats:
            if ext in ['.py']:
                detected.add('Python')
            elif ext in ['.js', '.ts']:
                detected.add('Node.js')
            elif ext in ['.jsx', '.tsx']:
                detected.add('React')
                detected.add('Node.js')
            elif ext in ['.vue']:
                detected.add('Vue')
                detected.add('Node.js')
            elif ext in ['.svelte']:
                detected.add('Svelte')
                detected.add('Node.js')
            elif ext in ['.go']:
                detected.add('Go')
            elif ext in ['.rs']:
                detected.add('Rust')
            elif ext in ['.java']:
                detected.add('Java')
            elif ext in ['.rb']:
                detected.add('Ruby')
            elif ext in ['.php']:
                detected.add('PHP')

        # Check package.json dependencies
        if 'package_json' in self.package_info:
            deps = self.package_info['package_json'].get('dependencies', [])
            deps += self.package_info['package_json'].get('devDependencies', [])

            for dep in deps:
                if dep == 'react' or dep.startswith('@react'):
                    detected.add('React')
                elif dep == 'vue' or dep.startswith('@vue'):
                    detected.add('Vue')
                elif dep.startswith('@angular'):
                    detected.add('Angular')
                elif dep == 'svelte':
                    detected.add('Svelte')
                elif dep == 'next':
                    detected.add('Next.js')
                elif dep == 'express':
                    detected.add('Express')
                elif dep.startswith('@nestjs'):
                    detected.add('NestJS')
                elif dep == 'tailwindcss':
                    detected.add('Tailwind CSS')
                elif dep == 'typescript':
                    detected.add('TypeScript')
                elif dep == 'vite':
                    detected.add('Vite')

        # Check Python dependencies
        if 'requirements' in self.package_info:
            for dep in self.package_info['requirements']:
                dep_lower = dep.lower()
                if dep_lower == 'fastapi':
                    detected.add('FastAPI')
                elif dep_lower == 'flask':
                    detected.add('Flask')
                elif dep_lower == 'django':
                    detected.add('Django')
                elif dep_lower == 'sqlalchemy':
                    detected.add('SQLAlchemy')
                elif dep_lower in ['psycopg2', 'psycopg2-binary', 'asyncpg']:
                    detected.add('PostgreSQL')
                elif dep_lower in ['pymysql', 'mysqlclient']:
                    detected.add('MySQL')
                elif dep_lower == 'aiosqlite':
                    detected.add('SQLite')
                elif dep_lower == 'pymongo':
                    detected.add('MongoDB')
                elif dep_lower == 'redis':
                    detected.add('Redis')

        # Check for specific config files
        if (self.path / 'tailwind.config.js').exists() or (self.path / 'tailwind.config.ts').exists():
            detected.add('Tailwind CSS')
        if (self.path / 'vite.config.js').exists() or (self.path / 'vite.config.ts').exists():
            detected.add('Vite')
        if (self.path / 'tsconfig.json').exists():
            detected.add('TypeScript')
        if (self.path / 'next.config.js').exists() or (self.path / 'next.config.mjs').exists():
            detected.add('Next.js')
        if (self.path / 'angular.json').exists():
            detected.add('Angular')

        # Categorize detected technologies
        frontend_tech = {'React', 'Vue', 'Angular', 'Svelte', 'Next.js', 'HTML/CSS'}
        backend_tech = {'Python', 'Node.js', 'Go', 'Rust', 'Java', 'Ruby', 'PHP'}
        database_tech = {'PostgreSQL', 'MySQL', 'SQLite', 'MongoDB', 'Redis', 'Firebase'}
        framework_tech = {'FastAPI', 'Flask', 'Django', 'Express', 'NestJS'}
        tool_tech = {'Vite', 'Webpack', 'Tailwind CSS', 'TypeScript', 'SQLAlchemy'}

        for tech in detected:
            if tech in frontend_tech:
                self.detected_tech['frontend'].append(tech)
            elif tech in backend_tech:
                self.detected_tech['backend'].append(tech)
            elif tech in database_tech:
                self.detected_tech['database'].append(tech)
            elif tech in framework_tech:
                self.detected_tech['frameworks'].append(tech)
            elif tech in tool_tech:
                self.detected_tech['tools'].append(tech)

    def _get_structure(self) -> List[Dict[str, Any]]:
        """Get top-level directory structure."""
        structure = []

        try:
            for item in sorted(self.path.iterdir()):
                if item.name.startswith('.') or item.name in SKIP_FOLDERS:
                    continue

                entry = {
                    'name': item.name,
                    'type': 'directory' if item.is_dir() else 'file',
                }

                if item.is_dir():
                    # Count items in directory
                    try:
                        entry['count'] = sum(1 for _ in item.iterdir())
                    except Exception:
                        entry['count'] = 0

                structure.append(entry)
        except Exception:
            pass

        return structure[:20]  # Limit to 20 items

def analyze_codebase(path: str) -> Dict[str, Any]:
    """
    Convenience function to analyze a codebase.

    Args:
        path: Path to the codebase directory

    Returns:
        Analysis results dictionary
    """
    analyzer = CodebaseAnalyzer(path)
    return analyzer.analyze()


File created successfully at: C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend/services/codebase_analyzer.py

"""
Codebase Analyzer Service

Analyzes an existing codebase to extract project information such as:
- Technology stack (languages, frameworks, databases)
- Project structure
- Dependencies
- README content
"""

import os
import json
from pathlib import Path
from typing import Optional, Dict, List, Any

# Common file patterns to identify technologies
TECH_PATTERNS = {
    # Frontend
    'React': ['package.json:react', 'jsx', 'tsx', '.react'],
    'Vue': ['package.json:vue', '.vue'],
    'Angular': ['angular.json', 'package.json:@angular/core'],
    'Svelte': ['svelte.config.js', '.svelte'],
    'Next.js': ['next.config.js', 'next.config.mjs', 'package.json:next'],
    'HTML/CSS': ['.html', '.css'],

    # Backend
    'Python': ['.py', 'requirements.txt', 'pyproject.toml', 'setup.py'],
    'Node.js': ['package.json', '.js', '.ts'],
    'Go': ['go.mod', '.go'],
    'Rust': ['Cargo.toml', '.rs'],
    'Java': ['pom.xml', 'build.gradle', '.java'],
    'Ruby': ['Gemfile', '.rb'],
    'PHP': ['composer.json', '.php'],

    # Databases
    'PostgreSQL': ['pg', 'postgres', 'postgresql'],
    'MySQL': ['mysql', 'mariadb'],
    'SQLite': ['sqlite', '.sqlite', '.db'],
    'MongoDB': ['mongo', 'mongodb'],
    'Redis': ['redis'],
    'Firebase': ['firebase', 'firebaseConfig'],

    # Frameworks
    'FastAPI': ['fastapi'],
    'Flask': ['flask'],
    'Django': ['django', 'manage.py'],
    'Express': ['express'],
    'NestJS': ['@nestjs'],

    # Build tools
    'Vite': ['vite.config.js', 'vite.config.ts'],
    'Webpack': ['webpack.config.js'],
    'Tailwind CSS': ['tailwind.config.js', 'tailwind.config.ts'],
    'TypeScript': ['tsconfig.json', '.ts', '.tsx'],
}

# Folders to skip during analysis
SKIP_FOLDERS = {
    'node_modules', '.git', '__pycache__', '.venv', 'venv', 'env',
    '.idea', '.vscode', 'dist', 'build', '.next', '.cache',
    'coverage', '.pytest_cache', '.mypy_cache', 'target',
}

# File extensions to count
CODE_EXTENSIONS = {
    '.py', '.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte',
    '.go', '.rs', '.java', '.rb', '.php', '.html', '.css',
    '.scss', '.sass', '.less', '.json', '.yaml', '.yml',
    '.md', '.sql', '.sh', '.dockerfile',
}

class CodebaseAnalyzer:
    """Analyzes codebases to extract project information."""

    def __init__(self, path: str):
        self.path = Path(path)
        self.detected_tech: Dict[str, List[str]] = {
            'frontend': [],
            'backend': [],
            'database': [],
            'frameworks': [],
            'tools': [],
        }
        self.file_stats: Dict[str, int] = {}
        self.file_count = 0
        self.total_lines = 0
        self.readme_content = ""
        self.package_info: Dict[str, Any] = {}

    def analyze(self) -> Dict[str, Any]:
        """
        Perform full codebase analysis.

        Returns:
            Dict containing analysis results including:
            - detected_tech: Technologies found in the codebase
            - file_stats: Count of files by extension
            - structure: Top-level directory structure
            - readme: README content if found
            - package_info: Package manager info (package.json, requirements.txt, etc.)
        """
        if not self.path.exists():
            return {
                'error': f'Path does not exist: {self.path}',
                'valid': False,
            }

        if not self.path.is_dir():
            return {
                'error': f'Path is not a directory: {self.path}',
                'valid': False,
            }

        # Analyze files
        self._scan_files()

        # Read README
        self._read_readme()

        # Read package info
        self._read_package_info()

        # Detect technologies
        self._detect_technologies()

        # Get directory structure
        structure = self._get_structure()

        return {
            'valid': True,
            'path': str(self.path),
            'name': self.path.name,
            'detected_tech': self.detected_tech,
            'file_stats': self.file_stats,
            'file_count': self.file_count,
            'total_lines': self.total_lines,
            'structure': structure,
            'readme': self.readme_content[:5000] if self.readme_content else None,  # Limit README size
            'package_info': self.package_info,
        }

    def _scan_files(self):
        """Scan all files in the codebase."""
        for root, dirs, files in os.walk(self.path):
            # Skip excluded directories
            dirs[:] = [d for d in dirs if d not in SKIP_FOLDERS]

            for file in files:
                self.file_count += 1
                ext = Path(file).suffix.lower()

                if ext:
                    self.file_stats[ext] = self.file_stats.get(ext, 0) + 1

                # Count lines for code files
                if ext in CODE_EXTENSIONS:
                    file_path = Path(root) / file
                    try:
                        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                            self.total_lines += sum(1 for _ in f)
                    except Exception:
                        pass

    def _read_readme(self):
        """Read README file if it exists."""
        readme_names = ['README.md', 'README.txt', 'README', 'readme.md', 'Readme.md']
        for readme_name in readme_names:
            readme_path = self.path / readme_name
            if readme_path.exists():
                try:
                    with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
                        self.readme_content = f.read()
                    break
                except Exception:
                    pass

    def _read_package_info(self):
        """Read package manager files."""
        # package.json (Node.js)
        package_json = self.path / 'package.json'
        if package_json.exists():
            try:
                with open(package_json, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    self.package_info['package_json'] = {
                        'name': data.get('name'),
                        'version': data.get('version'),
                        'description': data.get('description'),
                        'dependencies': list(data.get('dependencies', {}).keys()),
                        'devDependencies': list(data.get('devDependencies', {}).keys()),
                    }
            except Exception:
                pass

        # requirements.txt (Python)
        requirements = self.path / 'requirements.txt'
        if requirements.exists():
            try:
                with open(requirements, 'r', encoding='utf-8') as f:
                    deps = [line.strip().split('==')[0].split('>=')[0].split('<=')[0]
                            for line in f if line.strip() and not line.startswith('#')]
                    self.package_info['requirements'] = deps
            except Exception:
                pass

        # pyproject.toml (Python)
        pyproject = self.path / 'pyproject.toml'
        if pyproject.exists():
            try:
                with open(pyproject, 'r', encoding='utf-8') as f:
                    content = f.read()
                    self.package_info['pyproject'] = True
                    # Basic parsing - just note it exists
            except Exception:
                pass

    def _detect_technologies(self):
        """Detect technologies based on file patterns and package info."""
        detected = set()

        # Check file extensions
        for ext in self.file_stats:
            if ext in ['.py']:
                detected.add('Python')
            elif ext in ['.js', '.ts']:
                detected.add('Node.js')
            elif ext in ['.jsx', '.tsx']:
                detected.add('React')
                detected.add('Node.js')
            elif ext in ['.vue']:
                detected.add('Vue')
                detected.add('Node.js')
            elif ext in ['.svelte']:
                detected.add('Svelte')
                detected.add('Node.js')
            elif ext in ['.go']:
                detected.add('Go')
            elif ext in ['.rs']:
                detected.add('Rust')
            elif ext in ['.java']:
                detected.add('Java')
            elif ext in ['.rb']:
                detected.add('Ruby')
            elif ext in ['.php']:
                detected.add('PHP')

        # Check package.json dependencies
        if 'package_json' in self.package_info:
            deps = self.package_info['package_json'].get('dependencies', [])
            deps += self.package_info['package_json'].get('devDependencies', [])

            for dep in deps:
                if dep == 'react' or dep.startswith('@react'):
                    detected.add('React')
                elif dep == 'vue' or dep.startswith('@vue'):
                    detected.add('Vue')
                elif dep.startswith('@angular'):
                    detected.add('Angular')
                elif dep == 'svelte':
                    detected.add('Svelte')
                elif dep == 'next':
                    detected.add('Next.js')
                elif dep == 'express':
                    detected.add('Express')
                elif dep.startswith('@nestjs'):
                    detected.add('NestJS')
                elif dep == 'tailwindcss':
                    detected.add('Tailwind CSS')
                elif dep == 'typescript':
                    detected.add('TypeScript')
                elif dep == 'vite':
                    detected.add('Vite')

        # Check Python dependencies
        if 'requirements' in self.package_info:
            for dep in self.package_info['requirements']:
                dep_lower = dep.lower()
                if dep_lower == 'fastapi':
                    detected.add('FastAPI')
                elif dep_lower == 'flask':
                    detected.add('Flask')
                elif dep_lower == 'django':
                    detected.add('Django')
                elif dep_lower == 'sqlalchemy':
                    detected.add('SQLAlchemy')
                elif dep_lower in ['psycopg2', 'psycopg2-binary', 'asyncpg']:
                    detected.add('PostgreSQL')
                elif dep_lower in ['pymysql', 'mysqlclient']:
                    detected.add('MySQL')
                elif dep_lower == 'aiosqlite':
                    detected.add('SQLite')
                elif dep_lower == 'pymongo':
                    detected.add('MongoDB')
                elif dep_lower == 'redis':
                    detected.add('Redis')

        # Check for specific config files
        if (self.path / 'tailwind.config.js').exists() or (self.path / 'tailwind.config.ts').exists():
            detected.add('Tailwind CSS')
        if (self.path / 'vite.config.js').exists() or (self.path / 'vite.config.ts').exists():
            detected.add('Vite')
        if (self.path / 'tsconfig.json').exists():
            detected.add('TypeScript')
        if (self.path / 'next.config.js').exists() or (self.path / 'next.config.mjs').exists():
            detected.add('Next.js')
        if (self.path / 'angular.json').exists():
            detected.add('Angular')

        # Categorize detected technologies
        frontend_tech = {'React', 'Vue', 'Angular', 'Svelte', 'Next.js', 'HTML/CSS'}
        backend_tech = {'Python', 'Node.js', 'Go', 'Rust', 'Java', 'Ruby', 'PHP'}
        database_tech = {'PostgreSQL', 'MySQL', 'SQLite', 'MongoDB', 'Redis', 'Firebase'}
        framework_tech = {'FastAPI', 'Flask', 'Django', 'Express', 'NestJS'}
        tool_tech = {'Vite', 'Webpack', 'Tailwind CSS', 'TypeScript', 'SQLAlchemy'}

        for tech in detected:
            if tech in frontend_tech:
                self.detected_tech['frontend'].append(tech)
            elif tech in backend_tech:
                self.detected_tech['backend'].append(tech)
            elif tech in database_tech:
                self.detected_tech['database'].append(tech)
            elif tech in framework_tech:
                self.detected_tech['frameworks'].append(tech)
            elif tech in tool_tech:
                self.detected_tech['tools'].append(tech)

    def _get_structure(self) -> List[Dict[str, Any]]:
        """Get top-level directory structure."""
        structure = []

        try:
            for item in sorted(self.path.iterdir()):
                if item.name.startswith('.') or item.name in SKIP_FOLDERS:
                    continue

                entry = {
                    'name': item.name,
                    'type': 'directory' if item.is_dir() else 'file',
                }

                if item.is_dir():
                    # Count items in directory
                    try:
                        entry['count'] = sum(1 for _ in item.iterdir())
                    except Exception:
                        entry['count'] = 0

                structure.append(entry)
        except Exception:
            pass

        return structure[:20]  # Limit to 20 items

def analyze_codebase(path: str) -> Dict[str, Any]:
    """
    Convenience function to analyze a codebase.

    Args:
        path: Path to the codebase directory

    Returns:
        Analysis results dictionary
    """
    analyzer = CodebaseAnalyzer(path)
    return analyzer.analyze()


Now let me create the API endpoint for adopting a codebase:


"""
Adopt Codebase API Router

Handles adopting existing codebases into Auto-Claude-Plus projects.
"""

from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel
from datetime import datetime

from services.database import get_db
from services.codebase_analyzer import analyze_codebase
from models.project import Project
from models.memory import MemoryProject

router = APIRouter()

class CodebaseAnalysisRequest(BaseModel):
    """Request to analyze a codebase."""
    path: str

class CodebaseAnalysisResponse(BaseModel):
    """Response from codebase analysis."""
    valid: bool
    path: Optional[str] = None
    name: Optional[str] = None
    error: Optional[str] = None
    detected_tech: Optional[dict] = None
    file_stats: Optional[dict] = None
    file_count: Optional[int] = None
    total_lines: Optional[int] = None
    structure: Optional[list] = None
    readme: Optional[str] = None
    package_info: Optional[dict] = None

class AdoptCodebaseRequest(BaseModel):
    """Request to adopt a codebase into a new project."""
    path: str
    name: str
    description: Optional[str] = None
    complexity: str = "medium"
    design_mode: str = "mvp"

class AdoptCodebaseResponse(BaseModel):
    """Response from adopting a codebase."""
    id: int
    name: str
    description: Optional[str]
    path: Optional[str]
    status: str
    complexity: str
    design_mode: str
    current_phase: int
    total_phases: int
    spec_version: int
    created_at: datetime
    updated_at: datetime
    analysis: dict

    class Config:
        from_attributes = True

@router.post("/analyze", response_model=CodebaseAnalysisResponse)
async def analyze_existing_codebase(request: CodebaseAnalysisRequest):
    """
    Analyze an existing codebase without creating a project.

    This endpoint scans a directory and returns information about:
    - Detected technologies (frontend, backend, database, etc.)
    - File statistics
    - Project structure
    - README content
    - Package dependencies
    """
    analysis = analyze_codebase(request.path)
    return CodebaseAnalysisResponse(**analysis)

@router.post("", response_model=AdoptCodebaseResponse, status_code=status.HTTP_201_CREATED)
async def adopt_codebase(
    request: AdoptCodebaseRequest,
    db: AsyncSession = Depends(get_db)
):
    """
    Adopt an existing codebase by creating a new project with analysis.

    This endpoint:
    1. Analyzes the codebase at the specified path
    2. Creates a new project with the codebase path
    3. Stores the analysis results in project memory
    """
    # First analyze the codebase
    analysis = analyze_codebase(request.path)

    if not analysis.get('valid', False):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=analysis.get('error', 'Invalid codebase path')
        )

    # Check for duplicate project name
    existing_project = await Project.get_by_name(db, request.name)
    if existing_project:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"A project named '{request.name}' already exists"
        )

    # Create the project with the codebase path
    new_project = await Project.create(
        db,
        name=request.name,
        description=request.description,
        path=request.path,
        complexity=request.complexity,
        design_mode=request.design_mode,
    )

    # Store codebase analysis in project memory
    # Store as codebase_map type
    codebase_map_content = {
        'detected_tech': analysis.get('detected_tech', {}),
        'file_stats': analysis.get('file_stats', {}),
        'file_count': analysis.get('file_count', 0),
        'total_lines': analysis.get('total_lines', 0),
        'structure': analysis.get('structure', []),
    }

    await MemoryProject.create(
        db,
        project_id=new_project.id,
        type='codebase_map',
        content=f"Codebase analysis for {request.path}",
        metadata=codebase_map_content,
    )

    # If there's a README, store it as project insight
    if analysis.get('readme'):
        await MemoryProject.create(
            db,
            project_id=new_project.id,
            type='insight',
            content=f"README content from adopted codebase:\n\n{analysis.get('readme', '')}",
            metadata={'source': 'adopted_codebase', 'file': 'README.md'},
        )

    # If there's package info, store it as insight
    if analysis.get('package_info'):
        package_summary = []
        if 'package_json' in analysis['package_info']:
            pkg = analysis['package_info']['package_json']
            if pkg.get('dependencies'):
                package_summary.append(f"Dependencies: {', '.join(pkg['dependencies'][:15])}")
            if pkg.get('devDependencies'):
                package_summary.append(f"Dev Dependencies: {', '.join(pkg['devDependencies'][:15])}")

        if 'requirements' in analysis['package_info']:
            package_summary.append(f"Python Requirements: {', '.join(analysis['package_info']['requirements'][:15])}")

        if package_summary:
            await MemoryProject.create(
                db,
                project_id=new_project.id,
                type='pattern',
                content=f"Package dependencies from adopted codebase:\n\n" + "\n".join(package_summary),
                metadata={'source': 'adopted_codebase', 'type': 'dependencies'},
            )

    return AdoptCodebaseResponse(
        id=new_project.id,
        name=new_project.name,
        description=new_project.description,
        path=new_project.path,
        status=new_project.status,
        complexity=new_project.complexity,
        design_mode=new_project.design_mode,
        current_phase=new_project.current_phase,
        total_phases=new_project.total_phases,
        spec_version=new_project.spec_version,
        created_at=new_project.created_at,
        updated_at=new_project.updated_at,
        analysis=analysis,
    )


File created successfully at: C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend/api/adopt.py

"""
Adopt Codebase API Router

Handles adopting existing codebases into Auto-Claude-Plus projects.
"""

from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel
from datetime import datetime

from services.database import get_db
from services.codebase_analyzer import analyze_codebase
from models.project import Project
from models.memory import MemoryProject

router = APIRouter()

class CodebaseAnalysisRequest(BaseModel):
    """Request to analyze a codebase."""
    path: str

class CodebaseAnalysisResponse(BaseModel):
    """Response from codebase analysis."""
    valid: bool
    path: Optional[str] = None
    name: Optional[str] = None
    error: Optional[str] = None
    detected_tech: Optional[dict] = None
    file_stats: Optional[dict] = None
    file_count: Optional[int] = None
    total_lines: Optional[int] = None
    structure: Optional[list] = None
    readme: Optional[str] = None
    package_info: Optional[dict] = None

class AdoptCodebaseRequest(BaseModel):
    """Request to adopt a codebase into a new project."""
    path: str
    name: str
    description: Optional[str] = None
    complexity: str = "medium"
    design_mode: str = "mvp"

class AdoptCodebaseResponse(BaseModel):
    """Response from adopting a codebase."""
    id: int
    name: str
    description: Optional[str]
    path: Optional[str]
    status: str
    complexity: str
    design_mode: str
    current_phase: int
    total_phases: int
    spec_version: int
    created_at: datetime
    updated_at: datetime
    analysis: dict

    class Config:
        from_attributes = True

@router.post("/analyze", response_model=CodebaseAnalysisResponse)
async def analyze_existing_codebase(request: CodebaseAnalysisRequest):
    """
    Analyze an existing codebase without creating a project.

    This endpoint scans a directory and returns information about:
    - Detected technologies (frontend, backend, database, etc.)
    - File statistics
    - Project structure
    - README content
    - Package dependencies
    """
    analysis = analyze_codebase(request.path)
    return CodebaseAnalysisResponse(**analysis)

@router.post("", response_model=AdoptCodebaseResponse, status_code=status.HTTP_201_CREATED)
async def adopt_codebase(
    request: AdoptCodebaseRequest,
    db: AsyncSession = Depends(get_db)
):
    """
    Adopt an existing codebase by creating a new project with analysis.

    This endpoint:
    1. Analyzes the codebase at the specified path
    2. Creates a new project with the codebase path
    3. Stores the analysis results in project memory
    """
    # First analyze the codebase
    analysis = analyze_codebase(request.path)

    if not analysis.get('valid', False):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=analysis.get('error', 'Invalid codebase path')
        )

    # Check for duplicate project name
    existing_project = await Project.get_by_name(db, request.name)
    if existing_project:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"A project named '{request.name}' already exists"
        )

    # Create the project with the codebase path
    new_project = await Project.create(
        db,
        name=request.name,
        description=request.description,
        path=request.path,
        complexity=request.complexity,
        design_mode=request.design_mode,
    )

    # Store codebase analysis in project memory
    # Store as codebase_map type
    codebase_map_content = {
        'detected_tech': analysis.get('detected_tech', {}),
        'file_stats': analysis.get('file_stats', {}),
        'file_count': analysis.get('file_count', 0),
        'total_lines': analysis.get('total_lines', 0),
        'structure': analysis.get('structure', []),
    }

    await MemoryProject.create(
        db,
        project_id=new_project.id,
        type='codebase_map',
        content=f"Codebase analysis for {request.path}",
        metadata=codebase_map_content,
    )

    # If there's a README, store it as project insight
    if analysis.get('readme'):
        await MemoryProject.create(
            db,
            project_id=new_project.id,
            type='insight',
            content=f"README content from adopted codebase:\n\n{analysis.get('readme', '')}",
            metadata={'source': 'adopted_codebase', 'file': 'README.md'},
        )

    # If there's package info, store it as insight
    if analysis.get('package_info'):
        package_summary = []
        if 'package_json' in analysis['package_info']:
            pkg = analysis['package_info']['package_json']
            if pkg.get('dependencies'):
                package_summary.append(f"Dependencies: {', '.join(pkg['dependencies'][:15])}")
            if pkg.get('devDependencies'):
                package_summary.append(f"Dev Dependencies: {', '.join(pkg['devDependencies'][:15])}")

        if 'requirements' in analysis['package_info']:
            package_summary.append(f"Python Requirements: {', '.join(analysis['package_info']['requirements'][:15])}")

        if package_summary:
            await MemoryProject.create(
                db,
                project_id=new_project.id,
                type='pattern',
                content=f"Package dependencies from adopted codebase:\n\n" + "\n".join(package_summary),
                metadata={'source': 'adopted_codebase', 'type': 'dependencies'},
            )

    return AdoptCodebaseResponse(
        id=new_project.id,
        name=new_project.name,
        description=new_project.description,
        path=new_project.path,
        status=new_project.status,
        complexity=new_project.complexity,
        design_mode=new_project.design_mode,
        current_phase=new_project.current_phase,
        total_phases=new_project.total_phases,
        spec_version=new_project.spec_version,
        created_at=new_project.created_at,
        updated_at=new_project.updated_at,
        analysis=analysis,
    )


Now let me register the adopt API router in main.py:


     1→"""
     2→Auto-Claude-Plus Backend - Main Application Entry Point
     3→
     4→FastAPI application that provides:
     5→- REST API for project, task, and memory management
     6→- WebSocket endpoints for real-time agent output streaming
     7→- IPC bridge for Electron frontend communication
     8→- Changelog generation from completed tasks
     9→"""
    10→
    11→from contextlib import asynccontextmanager
    12→from fastapi import FastAPI
    13→from fastapi.middleware.cors import CORSMiddleware
    14→
    15→from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog
    16→from services.database import init_db, get_db
    17→
    18→
    19→@asynccontextmanager
    20→async def lifespan(app: FastAPI):
    21→    """Application lifecycle management."""
    22→    # Startup: Initialize database
    23→    await init_db()
    24→    print("Database initialized")
    25→    yield
    26→    # Shutdown: Cleanup
    27→    print("Application shutting down")
    28→
    29→
    30→# Create FastAPI application
    31→app = FastAPI(
    32→    title="Auto-Claude-Plus API",
    33→    description="Backend API for the Auto-Claude-Plus autonomous coding framework",
    34→    version="0.1.0",
    35→    lifespan=lifespan,
    36→)
    37→
    38→# Configure CORS for Electron frontend
    39→app.add_middleware(
    40→    CORSMiddleware,
    41→    allow_origins=["*"],  # Electron app runs locally
    42→    allow_credentials=True,
    43→    allow_methods=["*"],
    44→    allow_headers=["*"],
    45→)
    46→
    47→# Include routers
    48→app.include_router(projects.router, prefix="/api/projects", tags=["Projects"])
    49→app.include_router(specs.router, prefix="/api", tags=["Specs"])
    50→app.include_router(tasks.router, prefix="/api", tags=["Tasks"])
    51→app.include_router(agents.router, prefix="/api/agents", tags=["Agents"])
    52→app.include_router(memory.router, prefix="/api/memory", tags=["Memory"])
    53→app.include_router(notifications.router, prefix="/api/notifications", tags=["Notifications"])
    54→app.include_router(settings.router, prefix="/api/settings", tags=["Settings"])
    55→app.include_router(phases.router, prefix="/api/projects", tags=["Phases"])
    56→app.include_router(changelog.router, prefix="/api", tags=["Changelog"])
    57→
    58→
    59→@app.get("/")
    60→async def root():
    61→    """Root endpoint - health check."""
    62→    return {
    63→        "name": "Auto-Claude-Plus API",
    64→        "version": "0.1.0",
    65→        "status": "running",
    66→    }
    67→
    68→
    69→@app.get("/health")
    70→async def health_check():
    71→    """Health check endpoint."""
    72→    return {"status": "healthy"}
    73→
    74→
    75→if __name__ == "__main__":
    76→    import uvicorn
    77→    uvicorn.run(app, host="0.0.0.0", port=8000)
    78→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

"""
Auto-Claude-Plus Backend - Main Application Entry Point

FastAPI application that provides:
- REST API for project, task, and memory management
- WebSocket endpoints for real-time agent output streaming
- IPC bridge for Electron frontend communication
- Changelog generation from completed tasks
"""

from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog
from services.database import init_db, get_db

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifecycle management."""
    # Startup: Initialize database
    await init_db()
    print("Database initialized")
    yield
    # Shutdown: Cleanup
    print("Application shutting down")

# Create FastAPI application
app = FastAPI(
    title="Auto-Claude-Plus API",
    description="Backend API for the Auto-Claude-Plus autonomous coding framework",
    version="0.1.0",
    lifespan=lifespan,
)

# Configure CORS for Electron frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Electron app runs locally
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers
app.include_router(projects.router, prefix="/api/projects", tags=["Projects"])
app.include_router(specs.router, prefix="/api", tags=["Specs"])
app.include_router(tasks.router, prefix="/api", tags=["Tasks"])
app.include_router(agents.router, prefix="/api/agents", tags=["Agents"])
app.include_router(memory.router, prefix="/api/memory", tags=["Memory"])
app.include_router(notifications.router, prefix="/api/notifications", tags=["Notifications"])
app.include_router(settings.router, prefix="/api/settings", tags=["Settings"])
app.include_router(phases.router, prefix="/api/projects", tags=["Phases"])
app.include_router(changelog.router, prefix="/api", tags=["Changelog"])

@app.get("/")
async def root():
    """Root endpoint - health check."""
    return {
        "name": "Auto-Claude-Plus API",
        "version": "0.1.0",
        "status": "running",
    }

@app.get("/health")
async def health_check():
    """Health check endpoint."""
    return {"status": "healthy"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)


Edit

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt


Error: File has been unexpectedly modified. Read it again before attempting to write it.


from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt


Bash

Read main.py using cat


"""
Auto-Claude-Plus Backend - Main Application Entry Point

FastAPI application that provides:
- REST API for project, task, and memory management
- WebSocket endpoints for real-time agent output streaming
- IPC bridge for Electron frontend communication
- Changelog generation from completed tasks
"""

from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog
from services.database import init_db, get_db

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifecycle management."""
    # Startup: Initialize database
    await init_db()
    print("Database initialized")
    yield
    # Shutdown: Cleanup
    print("Application shutting down")

# Create FastAPI application
app = FastAPI(
    title="Auto-Claude-Plus API",
    description="Backend API for the Auto-Claude-Plus autonomous coding framework",
    version="0.1.0",
    lifespan=lifespan,
)

# Configure CORS for Electron frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Electron app runs locally
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers
app.include_router(projects.router, prefix="/api/projects", tags=["Projects"])
app.include_router(specs.router, prefix="/api", tags=["Specs"])
app.include_router(tasks.router, prefix="/api", tags=["Tasks"])
app.include_router(agents.router, prefix="/api/agents", tags=["Agents"])
app.include_router(memory.router, prefix="/api/memory", tags=["Memory"])
app.include_router(notifications.router, prefix="/api/notifications", tags=["Notifications"])
app.include_router(settings.router, prefix="/api/settings", tags=["Settings"])
app.include_router(phases.router, prefix="/api/projects", tags=["Phases"])
app.include_router(changelog.router, prefix="/api", tags=["Changelog"])

@app.get("/")
async def root():
    """Root endpoint - health check."""
    return {
        "name": "Auto-Claude-Plus API",
        "version": "0.1.0",
        "status": "running",
    }

@app.get("/health")
async def health_check():
    """Health check endpoint."""
    return {"status": "healthy"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)


Write

"""
Auto-Claude-Plus Backend - Main Application Entry Point

FastAPI application that provides:
- REST API for project, task, and memory management
- WebSocket endpoints for real-time agent output streaming
- IPC bridge for Electron frontend communication
- Changelog generation from completed tasks
"""

from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt
from services.database import init_db, get_db

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifecycle management."""
    # Startup: Initialize database
    await init_db()
    print("Database initialized")
    yield
    # Shutdown: Cleanup
    print("Application shutting down")

# Create FastAPI application
app = FastAPI(
    title="Auto-Claude-Plus API",
    description="Backend API for the Auto-Claude-Plus autonomous coding framework",
    version="0.1.0",
    lifespan=lifespan,
)

# Configure CORS for Electron frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Electron app runs locally
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers
app.include_router(projects.router, prefix="/api/projects", tags=["Projects"])
app.include_router(specs.router, prefix="/api", tags=["Specs"])
app.include_router(tasks.router, prefix="/api", tags=["Tasks"])
app.include_router(agents.router, prefix="/api/agents", tags=["Agents"])
app.include_router(memory.router, prefix="/api/memory", tags=["Memory"])
app.include_router(notifications.router, prefix="/api/notifications", tags=["Notifications"])
app.include_router(settings.router, prefix="/api/settings", tags=["Settings"])
app.include_router(phases.router, prefix="/api/projects", tags=["Phases"])
app.include_router(changelog.router, prefix="/api", tags=["Changelog"])
app.include_router(adopt.router, prefix="/api/adopt", tags=["Adopt"])

@app.get("/")
async def root():
    """Root endpoint - health check."""
    return {
        "name": "Auto-Claude-Plus API",
        "version": "0.1.0",
        "status": "running",
    }

@app.get("/health")
async def health_check():
    """Health check endpoint."""
    return {"status": "healthy"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)


<tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>

Error: File has not been read yet. Read it first before writing to it.


Edit

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog
from services.database import init_db, get_db

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt
from services.database import init_db, get_db


There seems to be another process modifying this file. Let me try a different approach:


Bash

cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && sed -i 's/from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog$/from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt/' main.py

Add adopt import using sed


     1→"""
     2→Auto-Claude-Plus Backend - Main Application Entry Point
     3→
     4→FastAPI application that provides:
     5→- REST API for project, task, and memory management
     6→- WebSocket endpoints for real-time agent output streaming
     7→- IPC bridge for Electron frontend communication
     8→- Changelog generation from completed tasks
     9→"""
    10→
    11→from contextlib import asynccontextmanager
    12→from fastapi import FastAPI
    13→from fastapi.middleware.cors import CORSMiddleware
    14→
    15→from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt
    16→from services.database import init_db, get_db
    17→
    18→
    19→@asynccontextmanager
    20→async def lifespan(app: FastAPI):
    21→    """Application lifecycle management."""
    22→    # Startup: Initialize database
    23→    await init_db()
    24→    print("Database initialized")
    25→    yield
    26→    # Shutdown: Cleanup
    27→    print("Application shutting down")
    28→
    29→
    30→# Create FastAPI application
    31→app = FastAPI(
    32→    title="Auto-Claude-Plus API",
    33→    description="Backend API for the Auto-Claude-Plus autonomous coding framework",
    34→    version="0.1.0",
    35→    lifespan=lifespan,
    36→)
    37→
    38→# Configure CORS for Electron frontend
    39→app.add_middleware(
    40→    CORSMiddleware,
    41→    allow_origins=["*"],  # Electron app runs locally
    42→    allow_credentials=True,
    43→    allow_methods=["*"],
    44→    allow_headers=["*"],
    45→)
    46→
    47→# Include routers
    48→app.include_router(projects.router, prefix="/api/projects", tags=["Projects"])
    49→app.include_router(specs.router, prefix="/api", tags=["Specs"])
    50→app.include_router(tasks.router, prefix="/api", tags=["Tasks"])
    51→app.include_router(agents.router, prefix="/api/agents", tags=["Agents"])
    52→app.include_router(memory.router, prefix="/api/memory", tags=["Memory"])
    53→app.include_router(notifications.router, prefix="/api/notifications", tags=["Notifications"])
    54→app.include_router(settings.router, prefix="/api/settings", tags=["Settings"])
    55→app.include_router(phases.router, prefix="/api/projects", tags=["Phases"])
    56→app.include_router(changelog.router, prefix="/api", tags=["Changelog"])
    57→
    58→
    59→@app.get("/")
    60→async def root():
    61→    """Root endpoint - health check."""
    62→    return {
    63→        "name": "Auto-Claude-Plus API",
    64→        "version": "0.1.0",
    65→        "status": "running",
    66→    }
    67→
    68→
    69→@app.get("/health")
    70→async def health_check():
    71→    """Health check endpoint."""
    72→    return {"status": "healthy"}
    73→
    74→
    75→if __name__ == "__main__":
    76→    import uvicorn
    77→    uvicorn.run(app, host="0.0.0.0", port=8000)
    78→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

"""
Auto-Claude-Plus Backend - Main Application Entry Point

FastAPI application that provides:
- REST API for project, task, and memory management
- WebSocket endpoints for real-time agent output streaming
- IPC bridge for Electron frontend communication
- Changelog generation from completed tasks
"""

from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt
from services.database import init_db, get_db

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifecycle management."""
    # Startup: Initialize database
    await init_db()
    print("Database initialized")
    yield
    # Shutdown: Cleanup
    print("Application shutting down")

# Create FastAPI application
app = FastAPI(
    title="Auto-Claude-Plus API",
    description="Backend API for the Auto-Claude-Plus autonomous coding framework",
    version="0.1.0",
    lifespan=lifespan,
)

# Configure CORS for Electron frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Electron app runs locally
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers
app.include_router(projects.router, prefix="/api/projects", tags=["Projects"])
app.include_router(specs.router, prefix="/api", tags=["Specs"])
app.include_router(tasks.router, prefix="/api", tags=["Tasks"])
app.include_router(agents.router, prefix="/api/agents", tags=["Agents"])
app.include_router(memory.router, prefix="/api/memory", tags=["Memory"])
app.include_router(notifications.router, prefix="/api/notifications", tags=["Notifications"])
app.include_router(settings.router, prefix="/api/settings", tags=["Settings"])
app.include_router(phases.router, prefix="/api/projects", tags=["Phases"])
app.include_router(changelog.router, prefix="/api", tags=["Changelog"])

@app.get("/")
async def root():
    """Root endpoint - health check."""
    return {
        "name": "Auto-Claude-Plus API",
        "version": "0.1.0",
        "status": "running",
    }

@app.get("/health")
async def health_check():
    """Health check endpoint."""
    return {"status": "healthy"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)


Now let me add the router registration:


Edit

app.include_router(changelog.router, prefix="/api", tags=["Changelog"])

@app.get("/")

app.include_router(changelog.router, prefix="/api", tags=["Changelog"])
app.include_router(adopt.router, prefix="/api/adopt", tags=["Adopt"])

@app.get("/")


Bash

cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && sed -i '/app.include_router(changelog.router, prefix="\/api", tags=\["Changelog"\])/a app.include_router(adopt.router, prefix="/api/adopt", tags=["Adopt"])' main.py

Add adopt router registration using sed


grep -n "adopt" "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend/main.py"

Verify adopt router is registered


15:from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog, adopt
57:app.include_router(adopt.router, prefix="/api/adopt", tags=["Adopt"])


Backend is set up. Now let me restart the backend server to load the new endpoints:


cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && taskkill //F //IM python.exe 2>/dev/null; sleep 1; source venv/Scripts/activate && python -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload &

Restart backend server


Error: Command 'taskkill' is not in the allowed commands list


Let me just test if the backend is working with the new endpoint by calling the API:


curl -s http://localhost:8000/api/adopt/analyze -X POST -H "Content-Type: application/json" -d '{"path": "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder"}' 2>/dev/null | head -50

Test codebase analysis endpoint


The backend needs to be restarted to load the new module. Let me check what process is running and try a different approach:


curl -s http://localhost:8000/api/projects | head -5

Check if backend is responding


This is a test description with special chars: @#$%^&*() and numbers 12345.

A

Final test for feedback

Project created to test multi-tab handling

This is a long description to test form preservation during network errors. If this text is still here after an error, the feature works correctly.

Final test for feedback


The backend is running with --reload flag, which should hot-reload the new module. Let me wait a moment and try again:


Bash

sleep 2 && curl -s http://localhost:8000/api/adopt/analyze -X POST -H "Content-Type: application/json" -d '{"path": "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder"}'

Test codebase analysis endpoint after delay


The backend might not be using --reload mode. Let me check what endpoints exist:


curl -s http://localhost:8000/openapi.json | grep -o '"paths":{[^}]*' | head -10

Check OpenAPI spec for available endpoints


The adopt endpoint isn't registered yet. The backend likely needs a manual restart. Let me check init.sh to understand how the backend is started:


     1→#!/bin/bash
     2→
     3→# Auto-Claude-Plus Development Environment Setup Script
     4→# This script sets up and runs the complete development environment
     5→
     6→set -e
     7→
     8→echo "============================================"
     9→echo "  Auto-Claude-Plus - Development Setup"
    10→echo "============================================"
    11→echo ""
    12→
    13→# Colors for output
    14→RED='\033[0;31m'
    15→GREEN='\033[0;32m'
    16→YELLOW='\033[1;33m'
    17→BLUE='\033[0;34m'
    18→NC='\033[0m' # No Color
    19→
    20→# Function to check if a command exists
    21→check_command() {
    22→    if command -v "$1" &> /dev/null; then
    23→        echo -e "${GREEN}[OK]${NC} $1 found"
    24→        return 0
    25→    else
    26→        echo -e "${RED}[MISSING]${NC} $1 not found"
    27→        return 1
    28→    fi
    29→}
    30→
    31→# Function to print section headers
    32→section() {
    33→    echo ""
    34→    echo -e "${BLUE}>>> $1${NC}"
    35→    echo "--------------------------------------------"
    36→}
    37→
    38→# Check prerequisites
    39→section "Checking Prerequisites"
    40→
    41→MISSING_DEPS=0
    42→
    43→check_command "python" || MISSING_DEPS=1
    44→check_command "node" || MISSING_DEPS=1
    45→check_command "npm" || MISSING_DEPS=1
    46→check_command "git" || MISSING_DEPS=1
    47→
    48→# Check Python version
    49→if command -v python &> /dev/null; then
    50→    PYTHON_VERSION=$(python --version 2>&1 | grep -oP '\d+\.\d+' | head -1)
    51→    PYTHON_MAJOR=$(echo $PYTHON_VERSION | cut -d. -f1)
    52→    PYTHON_MINOR=$(echo $PYTHON_VERSION | cut -d. -f2)
    53→    if [ "$PYTHON_MAJOR" -ge 3 ] && [ "$PYTHON_MINOR" -ge 12 ]; then
    54→        echo -e "${GREEN}[OK]${NC} Python version $PYTHON_VERSION (>=3.12 required)"
    55→    else
    56→        echo -e "${YELLOW}[WARN]${NC} Python version $PYTHON_VERSION (3.12+ recommended)"
    57→    fi
    58→fi
    59→
    60→# Check Node version
    61→if command -v node &> /dev/null; then
    62→    NODE_VERSION=$(node --version | grep -oP '\d+' | head -1)
    63→    if [ "$NODE_VERSION" -ge 20 ]; then
    64→        echo -e "${GREEN}[OK]${NC} Node.js version $(node --version) (>=20 required)"
    65→    else
    66→        echo -e "${YELLOW}[WARN]${NC} Node.js version $(node --version) (20+ recommended)"
    67→    fi
    68→fi
    69→
    70→# Check for uv (Python package manager)
    71→if command -v uv &> /dev/null; then
    72→    echo -e "${GREEN}[OK]${NC} uv package manager found"
    73→    USE_UV=1
    74→else
    75→    echo -e "${YELLOW}[INFO]${NC} uv not found, will use pip"
    76→    USE_UV=0
    77→fi
    78→
    79→# Check for Docker (optional)
    80→if command -v docker &> /dev/null; then
    81→    echo -e "${GREEN}[OK]${NC} Docker found (optional)"
    82→else
    83→    echo -e "${YELLOW}[INFO]${NC} Docker not found (optional for containerized deployment)"
    84→fi
    85→
    86→if [ $MISSING_DEPS -eq 1 ]; then
    87→    echo ""
    88→    echo -e "${RED}ERROR: Missing required dependencies. Please install them and try again.${NC}"
    89→    exit 1
    90→fi
    91→
    92→# Setup Backend
    93→section "Setting up Python Backend"
    94→
    95→cd backend
    96→
    97→if [ ! -d "venv" ]; then
    98→    echo "Creating Python virtual environment..."
    99→    python -m venv venv
   100→fi
   101→
   102→# Activate virtual environment
   103→if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
   104→    source venv/Scripts/activate
   105→else
   106→    source venv/bin/activate
   107→fi
   108→
   109→echo "Installing Python dependencies..."
   110→if [ $USE_UV -eq 1 ]; then
   111→    uv pip install -r requirements.txt
   112→else
   113→    pip install -r requirements.txt
   114→fi
   115→
   116→cd ..
   117→
   118→# Setup Frontend
   119→section "Setting up Electron/React Frontend"
   120→
   121→cd frontend
   122→
   123→echo "Installing Node.js dependencies..."
   124→npm install
   125→
   126→cd ..
   127→
   128→# Initialize database if needed
   129→section "Initializing Database"
   130→
   131→if [ ! -f "data/auto-claude-plus.db" ]; then
   132→    echo "Creating database directory..."
   133→    mkdir -p data
   134→    echo "Database will be initialized on first run"
   135→else
   136→    echo "Database already exists"
   137→fi
   138→
   139→# Build frontend for production (optional)
   140→section "Build Status"
   141→
   142→echo -e "${YELLOW}[INFO]${NC} To build for production, run:"
   143→echo "  cd frontend && npm run build"
   144→echo ""
   145→
   146→# Start instructions
   147→section "Starting the Application"
   148→
   149→echo "To start the development environment, run the following commands in separate terminals:"
   150→echo ""
   151→echo -e "${GREEN}Terminal 1 - Backend:${NC}"
   152→echo "  cd backend"
   153→if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
   154→    echo "  source venv/Scripts/activate"
   155→else
   156→    echo "  source venv/bin/activate"
   157→fi
   158→echo "  python -m uvicorn main:app --reload --port 8000"
   159→echo ""
   160→echo -e "${GREEN}Terminal 2 - Frontend (Electron):${NC}"
   161→echo "  cd frontend"
   162→echo "  npm run dev"
   163→echo ""
   164→echo "Or use the combined start script:"
   165→echo "  ./start.sh"
   166→echo ""
   167→
   168→echo "============================================"
   169→echo -e "${GREEN}  Setup Complete!${NC}"
   170→echo "============================================"
   171→echo ""
   172→echo "Access Points:"
   173→echo "  - Electron App: Will launch automatically"
   174→echo "  - Backend API: http://localhost:8000"
   175→echo "  - API Docs: http://localhost:8000/docs"
   176→echo ""
   177→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

#!/bin/bash

# Auto-Claude-Plus Development Environment Setup Script
# This script sets up and runs the complete development environment

set -e

echo "============================================"
echo "  Auto-Claude-Plus - Development Setup"
echo "============================================"
echo ""

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Function to check if a command exists
check_command() {
    if command -v "$1" &> /dev/null; then
        echo -e "${GREEN}[OK]${NC} $1 found"
        return 0
    else
        echo -e "${RED}[MISSING]${NC} $1 not found"
        return 1
    fi
}

# Function to print section headers
section() {
    echo ""
    echo -e "${BLUE}>>> $1${NC}"
    echo "--------------------------------------------"
}

# Check prerequisites
section "Checking Prerequisites"

MISSING_DEPS=0

check_command "python" || MISSING_DEPS=1
check_command "node" || MISSING_DEPS=1
check_command "npm" || MISSING_DEPS=1
check_command "git" || MISSING_DEPS=1

# Check Python version
if command -v python &> /dev/null; then
    PYTHON_VERSION=$(python --version 2>&1 | grep -oP '\d+\.\d+' | head -1)
    PYTHON_MAJOR=$(echo $PYTHON_VERSION | cut -d. -f1)
    PYTHON_MINOR=$(echo $PYTHON_VERSION | cut -d. -f2)
    if [ "$PYTHON_MAJOR" -ge 3 ] && [ "$PYTHON_MINOR" -ge 12 ]; then
        echo -e "${GREEN}[OK]${NC} Python version $PYTHON_VERSION (>=3.12 required)"
    else
        echo -e "${YELLOW}[WARN]${NC} Python version $PYTHON_VERSION (3.12+ recommended)"
    fi
fi

# Check Node version
if command -v node &> /dev/null; then
    NODE_VERSION=$(node --version | grep -oP '\d+' | head -1)
    if [ "$NODE_VERSION" -ge 20 ]; then
        echo -e "${GREEN}[OK]${NC} Node.js version $(node --version) (>=20 required)"
    else
        echo -e "${YELLOW}[WARN]${NC} Node.js version $(node --version) (20+ recommended)"
    fi
fi

# Check for uv (Python package manager)
if command -v uv &> /dev/null; then
    echo -e "${GREEN}[OK]${NC} uv package manager found"
    USE_UV=1
else
    echo -e "${YELLOW}[INFO]${NC} uv not found, will use pip"
    USE_UV=0
fi

# Check for Docker (optional)
if command -v docker &> /dev/null; then
    echo -e "${GREEN}[OK]${NC} Docker found (optional)"
else
    echo -e "${YELLOW}[INFO]${NC} Docker not found (optional for containerized deployment)"
fi

if [ $MISSING_DEPS -eq 1 ]; then
    echo ""
    echo -e "${RED}ERROR: Missing required dependencies. Please install them and try again.${NC}"
    exit 1
fi

# Setup Backend
section "Setting up Python Backend"

cd backend

if [ ! -d "venv" ]; then
    echo "Creating Python virtual environment..."
    python -m venv venv
fi

# Activate virtual environment
if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
    source venv/Scripts/activate
else
    source venv/bin/activate
fi

echo "Installing Python dependencies..."
if [ $USE_UV -eq 1 ]; then
    uv pip install -r requirements.txt
else
    pip install -r requirements.txt
fi

cd ..

# Setup Frontend
section "Setting up Electron/React Frontend"

cd frontend

echo "Installing Node.js dependencies..."
npm install

cd ..

# Initialize database if needed
section "Initializing Database"

if [ ! -f "data/auto-claude-plus.db" ]; then
    echo "Creating database directory..."
    mkdir -p data
    echo "Database will be initialized on first run"
else
    echo "Database already exists"
fi

# Build frontend for production (optional)
section "Build Status"

echo -e "${YELLOW}[INFO]${NC} To build for production, run:"
echo "  cd frontend && npm run build"
echo ""

# Start instructions
section "Starting the Application"

echo "To start the development environment, run the following commands in separate terminals:"
echo ""
echo -e "${GREEN}Terminal 1 - Backend:${NC}"
echo "  cd backend"
if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
    echo "  source venv/Scripts/activate"
else
    echo "  source venv/bin/activate"
fi
echo "  python -m uvicorn main:app --reload --port 8000"
echo ""
echo -e "${GREEN}Terminal 2 - Frontend (Electron):${NC}"
echo "  cd frontend"
echo "  npm run dev"
echo ""
echo "Or use the combined start script:"
echo "  ./start.sh"
echo ""

echo "============================================"
echo -e "${GREEN}  Setup Complete!${NC}"
echo "============================================"
echo ""
echo "Access Points:"
echo "  - Electron App: Will launch automatically"
echo "  - Backend API: http://localhost:8000"
echo "  - API Docs: http://localhost:8000/docs"
echo ""


The backend is supposed to run with `--reload` flag. Let me check if perhaps there's an issue with the import or the code. Let me verify the adopt.py syntax:


cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && source venv/Scripts/activate && python -c "from api import adopt; print('adopt module imported successfully')"

Test if adopt module can be imported


Error: Could not parse command for security validation: cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && source venv/Scripts/activate && python -c "from api import adopt; print('adopt module imported successfully')"


cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && python -c "import sys; sys.path.insert(0, '.'); from api import adopt; print('OK')"

Test if adopt module can be imported


Error: Could not parse command for security validation: cd "C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend" && python -c "import sys; sys.path.insert(0, '.'); from api import adopt; print('OK')"


Test python command


hello


cd C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend && python -m py_compile api/adopt.py

Check adopt.py syntax


The syntax is valid. Let me check if the uvicorn process is running with --reload:


ps aux 2>/dev/null | grep -i uvicorn || wmic process where "name like '%python%'" get processid,commandline 2>/dev/null | head -10

Check for uvicorn process


Error: Command 'wmic' is not in the allowed commands list


Let me try a different approach - I'll check if the backend might need to be restarted by looking at the backend log file:


tail -30 C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend.log 2>/dev/null || tail -30 C:/Users/MikeSwanson/AutoBuilder/My-Auto-Builder/backend_new.log 2>/dev/null || echo "No log file found"

Check backend logs


Traceback (most recent call last):
  File "C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\backend\main.py", line 15, in <module>
    from api import projects, specs, tasks, agents, memory, notifications, settings, phases, changelog
  File "C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\backend\api\projects.py", line 14, in <module>
    from services.database import get_db
  File "C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\backend\services\database.py", line 18, in <module>
    engine = create_async_engine(
        DATABASE_URL,
        echo=False,  # Set to True for SQL debugging
        future=True,
    )
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\ext\asyncio\engine.py", line 120, in create_async_engine
    sync_engine = _create_engine(url, **kw)
  File "<string>", line 2, in create_engine
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\util\deprecations.py", line 281, in warned
    return fn(*args, **kwargs)  # type: ignore[no-any-return]
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\create.py", line 617, in create_engine
    dbapi = dbapi_meth(**dbapi_args)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\dialects\sqlite\aiosqlite.py", line 416, in import_dbapi
    __import__("aiosqlite"), __import__("sqlite3")
    ~~~~~~~~~~^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'aiosqlite'


I see - there's an error in the backend log from a previous run with a wrong virtual environment. The current backend must be running fine since it's responding. The issue is likely that the current running backend process predates my changes and needs to be restarted.

Since I can't directly restart the backend, let me proceed with implementing the frontend UI. The user will need to restart the backend to test the new endpoint. Let me now create the frontend component for adopting codebases:


TodoWrite

Implement Adopt Existing Codebase feature (Feature #9)

Implementing Adopt Existing Codebase feature

Create backend API endpoint for adopting codebase

Create codebase analysis function

Add Adopt Codebase button to UI

Create folder selection dialog

Integrate with ProjectWizard for spec interview

Store codebase analysis in project memory

Test the complete adopt workflow


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

Implement Adopt Existing Codebase feature (Feature #9)

Implementing Adopt Existing Codebase feature

Create backend API endpoint for adopting codebase

Create codebase analysis function

Add Adopt Codebase button to UI

Create folder selection dialog

Integrate with ProjectWizard for spec interview

Store codebase analysis in project memory

Test the complete adopt workflow

Create codebase analysis function

Add Adopt Codebase button to UI

Create folder selection dialog

Test the complete adopt workflow


Now let me create the AdoptCodebase page/wizard component:


Write

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useProjectStore } from '../stores/projectStore'
import { useToastStore } from '../components/Toast'
import {
  ArrowLeft,
  ArrowRight,
  Check,
  Loader2,
  FolderSearch,
  FileCode,
  Folder,
  AlertCircle,
} from 'lucide-react'

interface CodebaseAnalysis {
  valid: boolean
  path?: string
  name?: string
  error?: string
  detected_tech?: {
    frontend: string[]
    backend: string[]
    database: string[]
    frameworks: string[]
    tools: string[]
  }
  file_stats?: Record<string, number>
  file_count?: number
  total_lines?: number
  structure?: Array<{ name: string; type: string; count?: number }>
  readme?: string
  package_info?: Record<string, any>
}

interface DesignPreferences {
  designMode: 'mvp' | 'finished'
}

export default function AdoptCodebase() {
  const navigate = useNavigate()
  const { fetchProjects } = useProjectStore()
  const { addToast } = useToastStore()

  const [step, setStep] = useState(1)
  const [isAnalyzing, setIsAnalyzing] = useState(false)
  const [isCreating, setIsCreating] = useState(false)

  // Form data
  const [path, setPath] = useState('')
  const [analysis, setAnalysis] = useState<CodebaseAnalysis | null>(null)
  const [projectName, setProjectName] = useState('')
  const [description, setDescription] = useState('')
  const [designPreferences, setDesignPreferences] = useState<DesignPreferences>({
    designMode: 'mvp',
  })

  const [errors, setErrors] = useState<{ path?: string; name?: string }>({})

  const totalSteps = 4

  const handleAnalyze = async () => {
    if (!path.trim()) {
      setErrors({ ...errors, path: 'Please enter a codebase path' })
      return
    }

    setIsAnalyzing(true)
    setErrors({})

    try {
      const response = await fetch('http://localhost:8000/api/adopt/analyze', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ path: path.trim() }),
      })

      const data = await response.json()

      if (!response.ok) {
        throw new Error(data.detail || 'Failed to analyze codebase')
      }

      if (!data.valid) {
        setErrors({ path: data.error || 'Invalid codebase path' })
        return
      }

      setAnalysis(data)
      // Auto-populate project name from codebase name
      if (data.name && !projectName) {
        setProjectName(data.name)
      }
      // Auto-populate description from README
      if (data.readme && !description) {
        // Extract first paragraph or first 200 chars from README
        const firstParagraph = data.readme.split('\n\n')[0]?.replace(/^#.*\n?/, '').trim()
        if (firstParagraph) {
          setDescription(firstParagraph.substring(0, 200))
        }
      }
      setStep(2)
    } catch (error) {
      console.error('Analysis error:', error)
      const message = error instanceof Error ? error.message : 'Failed to analyze codebase'
      setErrors({ path: message })
      addToast('error', 'Analysis Failed', message)
    } finally {
      setIsAnalyzing(false)
    }
  }

  const handleNext = () => {
    if (step === 2) {
      // Validate project name
      if (!projectName.trim()) {
        setErrors({ name: 'Project name is required' })
        return
      }
      if (projectName.trim().length < 2) {
        setErrors({ name: 'Project name must be at least 2 characters' })
        return
      }
    }
    setErrors({})
    if (step < totalSteps) {
      setStep(step + 1)
    }
  }

  const handleBack = () => {
    if (step > 1) {
      setStep(step - 1)
    }
  }

  const handleCreate = async () => {
    setIsCreating(true)

    try {
      const response = await fetch('http://localhost:8000/api/adopt', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          path: path.trim(),
          name: projectName.trim(),
          description: description.trim() || undefined,
          design_mode: designPreferences.designMode,
        }),
      })

      const data = await response.json()

      if (!response.ok) {
        throw new Error(data.detail || 'Failed to adopt codebase')
      }

      addToast('success', 'Project Created', `Successfully adopted "${projectName}" codebase`)
      await fetchProjects()
      navigate(`/?project=${data.id}`)
    } catch (error) {
      console.error('Create error:', error)
      const message = error instanceof Error ? error.message : 'Failed to adopt codebase'
      addToast('error', 'Creation Failed', message)
    } finally {
      setIsCreating(false)
    }
  }

  const getTechBadges = () => {
    if (!analysis?.detected_tech) return []
    const badges: string[] = []
    Object.values(analysis.detected_tech).forEach((techs) => {
      badges.push(...techs)
    })
    return badges
  }

  return (

      {/* Progress */}

            Step {step} of {totalSteps}

            {Math.round((step / totalSteps) * 100)}% complete

          <div
            className="h-full bg-accent transition-all duration-300"
            style={{ width: `${(step / totalSteps) * 100}%` }}
          />

      {/* Step Content */}

        {step === 1 && (

Select Codebase

              Enter the path to an existing codebase you want to adopt. The system will analyze it
              to detect technologies, dependencies, and structure.

                  Codebase Path *

                    <FolderSearch
                      size={18}
                      className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
                    />
                    <input
                      id="codebase-path"
                      type="text"
                      value={path}
                      onChange={(e) => setPath(e.target.value)}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter' && path.trim()) {
                          handleAnalyze()
                        }
                      }}
                      placeholder="C:\Users\you\projects\my-app"
                      className={`w-full pl-10 pr-4 py-2 bg-secondary border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 ${
                        errors.path
                          ? 'border-red-500 focus:ring-red-500'
                          : 'border-border focus:ring-accent'
                      }`}
                    />

                {errors.path &&
{errors.path}
}

                  Enter the full path to your project folder. The analyzer will scan files and
                  detect technologies.

        )}

        {step === 2 && analysis && (

Analysis Results

              {/* Codebase Info */}

                  <Folder className="text-accent mt-1" size={20} />

{analysis.name}

{analysis.path}

                        {analysis.file_count?.toLocaleString()} files

                        {analysis.total_lines?.toLocaleString()} lines

              {/* Detected Technologies */}
              {getTechBadges().length > 0 && (

Detected Technologies

                    {getTechBadges().map((tech, i) => (

                        {tech}

                    ))}

              )}

              {/* Project Structure */}
              {analysis.structure && analysis.structure.length > 0 && (

Project Structure

                    {analysis.structure.slice(0, 10).map((item, i) => (

                        {item.type === 'directory' ? (
                          <Folder size={14} className="text-accent" />
                        ) : (
                          <FileCode size={14} className="text-muted-foreground" />
                        )}
                        {item.name}
                        {item.type === 'directory' && item.count !== undefined && (
                          ({item.count} items)
                        )}

                    ))}

              )}

              {/* Project Name */}

                  Project Name *

                <input
                  id="project-name"
                  type="text"
                  value={projectName}
                  onChange={(e) => {
                    setProjectName(e.target.value)
                    if (errors.name) setErrors({ ...errors, name: undefined })
                  }}
                  placeholder="My Project"
                  className={`w-full px-4 py-2 bg-secondary border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 ${
                    errors.name
                      ? 'border-red-500 focus:ring-red-500'
                      : 'border-border focus:ring-accent'
                  }`}
                />
                {errors.name &&
{errors.name}
}

              {/* Description */}

                  Description

                <textarea
                  id="project-description"
                  value={description}
                  onChange={(e) => setDescription(e.target.value)}
                  placeholder="A brief description of the project..."
                  rows={3}
                  className="w-full px-4 py-2 bg-secondary border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-accent"
                />

        )}

        {step === 3 && (

Design Mode

              Choose how strictly design requirements should be applied when working on this codebase.

              <button
                onClick={() => setDesignPreferences({ ...designPreferences, designMode: 'mvp' })}
                className={`w-full p-4 rounded-lg border text-left transition-colors ${
                  designPreferences.designMode === 'mvp'
                    ? 'border-accent bg-accent/10'
                    : 'border-border hover:border-muted-foreground'
                }`}
              >

MVP Mode

                  {designPreferences.designMode === 'mvp' && (

                      Selected

                  )}

                  Functional drafts are acceptable. Focus on getting features working first, with
                  polished design coming later. Best for rapid prototyping and early development.

              </button>
              <button
                onClick={() =>
                  setDesignPreferences({ ...designPreferences, designMode: 'finished' })
                }
                className={`w-full p-4 rounded-lg border text-left transition-colors ${
                  designPreferences.designMode === 'finished'
                    ? 'border-accent bg-accent/10'
                    : 'border-border hover:border-muted-foreground'
                }`}
              >

Finished Mode

                  {designPreferences.designMode === 'finished' && (

                      Selected

                  )}

                  Stricter design requirements apply. All frontend work must meet polish standards
                  with proper typography, color, motion, and spatial composition.

              </button>

        )}

        {step === 4 && analysis && (

Review & Create

              {/* Summary */}

Project Name

{projectName}

Codebase Path

{analysis.path}

              {description && (

Description

{description}

              )}

Detected Technologies

                  {getTechBadges().length > 0 ? (
                    getTechBadges().map((tech, i) => (

                        {tech}

                    ))
                  ) : (
                    No technologies detected
                  )}

Design Mode

                  {designPreferences.designMode === 'mvp'
                    ? 'MVP (Functional Drafts)'
                    : 'Finished (Polished)'}

              {/* What will happen */}

What happens next?

- A new project will be created with the codebase path

- Analysis results will be stored in project memory

- You can start defining tasks and working with agents

        )}

      {/* Navigation */}

        <button
          onClick={step === 1 ? () => navigate('/') : handleBack}
          className="btn-secondary flex items-center gap-2"
        >
          <ArrowLeft size={18} />
          {step === 1 ? 'Cancel' : 'Back'}
        </button>

        {step === 1 ? (
          <button
            onClick={handleAnalyze}
            disabled={isAnalyzing || !path.trim()}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            {isAnalyzing ? (
              <>
                <Loader2 size={18} className="animate-spin" />
                Analyzing...
              </>
            ) : (
              <>
                Analyze
                <ArrowRight size={18} />
              </>
            )}
          </button>
        ) : step < totalSteps ? (
          <button
            onClick={handleNext}
            disabled={step === 2 && !projectName.trim()}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            Next
            <ArrowRight size={18} />
          </button>
        ) : (
          <button
            onClick={handleCreate}
            disabled={isCreating}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            {isCreating ? (
              <>
                <Loader2 size={18} className="animate-spin" />
                Creating...
              </>
            ) : (
              <>
                <Check size={18} />
                Adopt Codebase
              </>
            )}
          </button>
        )}

  )
}