Create a new project at the specified path.
(project: ProjectCreate)
| 147 | |
| 148 | @router.post("", response_model=ProjectSummary) |
| 149 | async def create_project(project: ProjectCreate): |
| 150 | """Create a new project at the specified path.""" |
| 151 | _init_imports() |
| 152 | assert _scaffold_project_prompts is not None # guaranteed by _init_imports() |
| 153 | (register_project, _, get_project_path, list_registered_projects, |
| 154 | _, _, _) = _get_registry_functions() |
| 155 | |
| 156 | name = validate_project_name(project.name) |
| 157 | project_path = Path(project.path).resolve() |
| 158 | |
| 159 | # Check if project name already registered |
| 160 | existing = get_project_path(name) |
| 161 | if existing: |
| 162 | raise HTTPException( |
| 163 | status_code=409, |
| 164 | detail=f"Project '{name}' already exists at {existing}" |
| 165 | ) |
| 166 | |
| 167 | # Check if path already registered under a different name |
| 168 | all_projects = list_registered_projects() |
| 169 | for existing_name, info in all_projects.items(): |
| 170 | existing_path = Path(info["path"]).resolve() |
| 171 | # Case-insensitive comparison on Windows |
| 172 | if sys.platform == "win32": |
| 173 | paths_match = str(existing_path).lower() == str(project_path).lower() |
| 174 | else: |
| 175 | paths_match = existing_path == project_path |
| 176 | |
| 177 | if paths_match: |
| 178 | raise HTTPException( |
| 179 | status_code=409, |
| 180 | detail=f"Path '{project_path}' is already registered as project '{existing_name}'" |
| 181 | ) |
| 182 | |
| 183 | # Security: Check if path is in a blocked location |
| 184 | from .filesystem import is_path_blocked |
| 185 | if is_path_blocked(project_path): |
| 186 | raise HTTPException( |
| 187 | status_code=403, |
| 188 | detail="Cannot create project in system or sensitive directory" |
| 189 | ) |
| 190 | |
| 191 | # Validate the path is usable |
| 192 | if project_path.exists(): |
| 193 | if not project_path.is_dir(): |
| 194 | raise HTTPException( |
| 195 | status_code=400, |
| 196 | detail="Path exists but is not a directory" |
| 197 | ) |
| 198 | else: |
| 199 | # Create the directory |
| 200 | try: |
| 201 | project_path.mkdir(parents=True, exist_ok=True) |
| 202 | except OSError as e: |
| 203 | raise HTTPException( |
| 204 | status_code=500, |
| 205 | detail=f"Failed to create directory: {e}" |
| 206 | ) |
nothing calls this directly
no test coverage detected