Start the dev server for a project. If a custom command is provided in the request, it will be used. Otherwise, the effective command from the project configuration is used. Args: project_name: Name of the project request: Optional start request with custom command
(
project_name: str,
request: DevServerStartRequest = DevServerStartRequest(),
)
| 269 | |
| 270 | @router.post("/start", response_model=DevServerActionResponse) |
| 271 | async def start_devserver( |
| 272 | project_name: str, |
| 273 | request: DevServerStartRequest = DevServerStartRequest(), |
| 274 | ) -> DevServerActionResponse: |
| 275 | """ |
| 276 | Start the dev server for a project. |
| 277 | |
| 278 | If a custom command is provided in the request, it will be used. |
| 279 | Otherwise, the effective command from the project configuration is used. |
| 280 | |
| 281 | Args: |
| 282 | project_name: Name of the project |
| 283 | request: Optional start request with custom command |
| 284 | |
| 285 | Returns: |
| 286 | Response indicating success/failure and current status |
| 287 | """ |
| 288 | manager = get_project_devserver_manager(project_name) |
| 289 | project_dir = get_project_dir(project_name) |
| 290 | |
| 291 | # Determine which command to use |
| 292 | command: str | None |
| 293 | if request.command: |
| 294 | raise HTTPException( |
| 295 | status_code=400, |
| 296 | detail="Direct command execution is disabled. Use /config to set a safe custom_command." |
| 297 | ) |
| 298 | |
| 299 | command = get_dev_command(project_dir) |
| 300 | |
| 301 | if not command: |
| 302 | raise HTTPException( |
| 303 | status_code=400, |
| 304 | detail="No dev command available. Configure a custom command or ensure project type can be detected." |
| 305 | ) |
| 306 | |
| 307 | # Validate command against security allowlist before execution |
| 308 | validate_dev_command(command, project_dir) |
| 309 | |
| 310 | # Defense-in-depth: also run strict structural validation at execution time |
| 311 | # (catches config file tampering that bypasses the /config endpoint) |
| 312 | try: |
| 313 | validate_custom_command_strict(command) |
| 314 | except ValueError as e: |
| 315 | raise HTTPException(status_code=400, detail=str(e)) |
| 316 | |
| 317 | # Now command is definitely str and validated |
| 318 | success, message = await manager.start(command) |
| 319 | |
| 320 | return DevServerActionResponse( |
| 321 | success=success, |
| 322 | status=manager.status, |
| 323 | message=message, |
| 324 | ) |
| 325 | |
| 326 | |
| 327 | @router.post("/stop", response_model=DevServerActionResponse) |
nothing calls this directly
no test coverage detected