mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-01-31 14:43:35 +00:00
feat: Add GitHub Actions CI for PR protection
- Add CI workflow with Python (ruff lint, security tests) and UI (ESLint, TypeScript, build) jobs - Add ruff, mypy, pytest to requirements.txt - Add pyproject.toml with ruff configuration - Fix import sorting across Python files (ruff --fix) - Fix test_security.py expectations to match actual security policy - Remove invalid 'eof' command from ALLOWED_COMMANDS 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,17 +10,23 @@ import shutil
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Request, WebSocket, HTTPException
|
||||
from fastapi import FastAPI, HTTPException, Request, WebSocket
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from .routers import projects_router, features_router, agent_router, spec_creation_router, filesystem_router, assistant_chat_router
|
||||
from .websocket import project_websocket
|
||||
from .services.process_manager import cleanup_all_managers
|
||||
from .services.assistant_chat_session import cleanup_all_sessions as cleanup_assistant_sessions
|
||||
from .routers import (
|
||||
agent_router,
|
||||
assistant_chat_router,
|
||||
features_router,
|
||||
filesystem_router,
|
||||
projects_router,
|
||||
spec_creation_router,
|
||||
)
|
||||
from .schemas import SetupStatus
|
||||
|
||||
from .services.assistant_chat_session import cleanup_all_sessions as cleanup_assistant_sessions
|
||||
from .services.process_manager import cleanup_all_managers
|
||||
from .websocket import project_websocket
|
||||
|
||||
# Paths
|
||||
ROOT_DIR = Path(__file__).parent.parent
|
||||
|
||||
@@ -5,12 +5,12 @@ API Routers
|
||||
FastAPI routers for different API endpoints.
|
||||
"""
|
||||
|
||||
from .projects import router as projects_router
|
||||
from .features import router as features_router
|
||||
from .agent import router as agent_router
|
||||
from .spec_creation import router as spec_creation_router
|
||||
from .filesystem import router as filesystem_router
|
||||
from .assistant_chat import router as assistant_chat_router
|
||||
from .features import router as features_router
|
||||
from .filesystem import router as filesystem_router
|
||||
from .projects import router as projects_router
|
||||
from .spec_creation import router as spec_creation_router
|
||||
|
||||
__all__ = [
|
||||
"projects_router",
|
||||
|
||||
@@ -11,7 +11,7 @@ from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
|
||||
from ..schemas import AgentStatus, AgentActionResponse, AgentStartRequest
|
||||
from ..schemas import AgentActionResponse, AgentStartRequest, AgentStatus
|
||||
from ..services.process_manager import get_manager
|
||||
|
||||
|
||||
|
||||
@@ -11,21 +11,21 @@ import re
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, HTTPException
|
||||
from fastapi import APIRouter, HTTPException, WebSocket, WebSocketDisconnect
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..services.assistant_chat_session import (
|
||||
AssistantChatSession,
|
||||
get_session,
|
||||
create_session,
|
||||
remove_session,
|
||||
get_session,
|
||||
list_sessions,
|
||||
remove_session,
|
||||
)
|
||||
from ..services.assistant_database import (
|
||||
get_conversations,
|
||||
get_conversation,
|
||||
delete_conversation,
|
||||
create_conversation,
|
||||
delete_conversation,
|
||||
get_conversation,
|
||||
get_conversations,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -5,17 +5,17 @@ Features Router
|
||||
API endpoints for feature/test case management.
|
||||
"""
|
||||
|
||||
import re
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
|
||||
from ..schemas import (
|
||||
FeatureCreate,
|
||||
FeatureResponse,
|
||||
FeatureListResponse,
|
||||
FeatureResponse,
|
||||
)
|
||||
|
||||
# Lazy imports to avoid circular dependencies
|
||||
@@ -45,7 +45,7 @@ def _get_db_classes():
|
||||
root = Path(__file__).parent.parent.parent
|
||||
if str(root) not in sys.path:
|
||||
sys.path.insert(0, str(root))
|
||||
from api.database import create_database, Feature
|
||||
from api.database import Feature, create_database
|
||||
_create_database = create_database
|
||||
_Feature = Feature
|
||||
return _create_database, _Feature
|
||||
@@ -110,7 +110,7 @@ async def list_features(project_name: str):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{project_name}' not found in registry")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
db_file = project_dir / "features.db"
|
||||
if not db_file.exists():
|
||||
@@ -142,7 +142,7 @@ async def list_features(project_name: str):
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Database error in list_features")
|
||||
raise HTTPException(status_code=500, detail="Database error occurred")
|
||||
|
||||
@@ -157,7 +157,7 @@ async def create_feature(project_name: str, feature: FeatureCreate):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{project_name}' not found in registry")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
_, Feature = _get_db_classes()
|
||||
|
||||
@@ -187,7 +187,7 @@ async def create_feature(project_name: str, feature: FeatureCreate):
|
||||
return feature_to_response(db_feature)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Failed to create feature")
|
||||
raise HTTPException(status_code=500, detail="Failed to create feature")
|
||||
|
||||
@@ -202,7 +202,7 @@ async def get_feature(project_name: str, feature_id: int):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{project_name}' not found in registry")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
db_file = project_dir / "features.db"
|
||||
if not db_file.exists():
|
||||
@@ -220,7 +220,7 @@ async def get_feature(project_name: str, feature_id: int):
|
||||
return feature_to_response(feature)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Database error in get_feature")
|
||||
raise HTTPException(status_code=500, detail="Database error occurred")
|
||||
|
||||
@@ -235,7 +235,7 @@ async def delete_feature(project_name: str, feature_id: int):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{project_name}' not found in registry")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
_, Feature = _get_db_classes()
|
||||
|
||||
@@ -252,7 +252,7 @@ async def delete_feature(project_name: str, feature_id: int):
|
||||
return {"success": True, "message": f"Feature {feature_id} deleted"}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Failed to delete feature")
|
||||
raise HTTPException(status_code=500, detail="Failed to delete feature")
|
||||
|
||||
@@ -272,7 +272,7 @@ async def skip_feature(project_name: str, feature_id: int):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{project_name}' not found in registry")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
_, Feature = _get_db_classes()
|
||||
|
||||
@@ -292,6 +292,6 @@ async def skip_feature(project_name: str, feature_id: int):
|
||||
return {"success": True, "message": f"Feature {feature_id} moved to end of queue"}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Failed to skip feature")
|
||||
raise HTTPException(status_code=500, detail="Failed to skip feature")
|
||||
|
||||
@@ -18,14 +18,13 @@ from fastapi import APIRouter, HTTPException, Query
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from ..schemas import (
|
||||
CreateDirectoryRequest,
|
||||
DirectoryEntry,
|
||||
DirectoryListResponse,
|
||||
DriveInfo,
|
||||
PathValidationResponse,
|
||||
CreateDirectoryRequest,
|
||||
)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/filesystem", tags=["filesystem"])
|
||||
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ from fastapi import APIRouter, HTTPException
|
||||
|
||||
from ..schemas import (
|
||||
ProjectCreate,
|
||||
ProjectSummary,
|
||||
ProjectDetail,
|
||||
ProjectPrompts,
|
||||
ProjectPromptsUpdate,
|
||||
ProjectStats,
|
||||
ProjectSummary,
|
||||
)
|
||||
|
||||
# Lazy imports to avoid circular dependencies
|
||||
@@ -43,8 +43,8 @@ def _init_imports():
|
||||
if str(root) not in sys.path:
|
||||
sys.path.insert(0, str(root))
|
||||
|
||||
from prompts import scaffold_project_prompts, get_project_prompts_dir
|
||||
from progress import count_passing_tests
|
||||
from prompts import get_project_prompts_dir, scaffold_project_prompts
|
||||
from start import check_spec_exists
|
||||
|
||||
_check_spec_exists = check_spec_exists
|
||||
@@ -62,10 +62,10 @@ def _get_registry_functions():
|
||||
sys.path.insert(0, str(root))
|
||||
|
||||
from registry import (
|
||||
register_project,
|
||||
unregister_project,
|
||||
get_project_path,
|
||||
list_registered_projects,
|
||||
register_project,
|
||||
unregister_project,
|
||||
validate_project_path,
|
||||
)
|
||||
return register_project, unregister_project, get_project_path, list_registered_projects, validate_project_path
|
||||
@@ -272,7 +272,7 @@ async def get_project_prompts(name: str):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{name}' not found")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
prompts_dir = _get_project_prompts_dir(project_dir)
|
||||
|
||||
@@ -305,7 +305,7 @@ async def update_project_prompts(name: str, prompts: ProjectPromptsUpdate):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{name}' not found")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
prompts_dir = _get_project_prompts_dir(project_dir)
|
||||
prompts_dir.mkdir(parents=True, exist_ok=True)
|
||||
@@ -335,6 +335,6 @@ async def get_project_stats_endpoint(name: str):
|
||||
raise HTTPException(status_code=404, detail=f"Project '{name}' not found")
|
||||
|
||||
if not project_dir.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Project directory not found")
|
||||
raise HTTPException(status_code=404, detail="Project directory not found")
|
||||
|
||||
return get_project_stats(project_dir)
|
||||
|
||||
@@ -5,23 +5,22 @@ Spec Creation Router
|
||||
WebSocket and REST endpoints for interactive spec creation with Claude.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, HTTPException
|
||||
from fastapi import APIRouter, HTTPException, WebSocket, WebSocketDisconnect
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
from ..schemas import ImageAttachment
|
||||
from ..services.spec_chat_session import (
|
||||
SpecChatSession,
|
||||
get_session,
|
||||
create_session,
|
||||
remove_session,
|
||||
get_session,
|
||||
list_sessions,
|
||||
remove_session,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -8,8 +8,8 @@ Request/Response models for the API endpoints.
|
||||
import base64
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
# ============================================================================
|
||||
# Project Schemas
|
||||
|
||||
@@ -20,9 +20,8 @@ from typing import AsyncGenerator, Optional
|
||||
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient
|
||||
|
||||
from .assistant_database import (
|
||||
create_conversation,
|
||||
add_message,
|
||||
get_conversation,
|
||||
create_conversation,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -11,8 +11,8 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, ForeignKey
|
||||
from sqlalchemy.orm import sessionmaker, relationship, declarative_base
|
||||
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Text, create_engine
|
||||
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -14,11 +14,10 @@ import sys
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Literal, Callable, Awaitable, Set
|
||||
from typing import Awaitable, Callable, Literal, Set
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Patterns for sensitive data that should be redacted from output
|
||||
|
||||
@@ -6,7 +6,6 @@ Manages interactive spec creation conversation with Claude.
|
||||
Uses the create-spec.md skill to guide users through app spec creation.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
|
||||
Reference in New Issue
Block a user