Update a feature's details. Only features that are not yet completed (passes=False) can be edited. This allows users to provide corrections or additional instructions when the agent is stuck or implementing a feature incorrectly.
(project_name: str, feature_id: int, update: FeatureUpdate)
| 412 | |
| 413 | @router.patch("/{feature_id}", response_model=FeatureResponse) |
| 414 | async def update_feature(project_name: str, feature_id: int, update: FeatureUpdate): |
| 415 | """ |
| 416 | Update a feature's details. |
| 417 | |
| 418 | Only features that are not yet completed (passes=False) can be edited. |
| 419 | This allows users to provide corrections or additional instructions |
| 420 | when the agent is stuck or implementing a feature incorrectly. |
| 421 | """ |
| 422 | project_name = validate_project_name(project_name) |
| 423 | project_dir = _get_project_path(project_name) |
| 424 | |
| 425 | if not project_dir: |
| 426 | raise HTTPException(status_code=404, detail=f"Project '{project_name}' not found in registry") |
| 427 | |
| 428 | if not project_dir.exists(): |
| 429 | raise HTTPException(status_code=404, detail="Project directory not found") |
| 430 | |
| 431 | _, Feature = _get_db_classes() |
| 432 | |
| 433 | try: |
| 434 | with get_db_session(project_dir) as session: |
| 435 | feature = session.query(Feature).filter(Feature.id == feature_id).first() |
| 436 | |
| 437 | if not feature: |
| 438 | raise HTTPException(status_code=404, detail=f"Feature {feature_id} not found") |
| 439 | |
| 440 | # Prevent editing completed features |
| 441 | if feature.passes: |
| 442 | raise HTTPException( |
| 443 | status_code=400, |
| 444 | detail="Cannot edit a completed feature. Features marked as done are immutable." |
| 445 | ) |
| 446 | |
| 447 | # Apply updates for non-None fields |
| 448 | if update.category is not None: |
| 449 | feature.category = update.category |
| 450 | if update.name is not None: |
| 451 | feature.name = update.name |
| 452 | if update.description is not None: |
| 453 | feature.description = update.description |
| 454 | if update.steps is not None: |
| 455 | feature.steps = update.steps |
| 456 | if update.priority is not None: |
| 457 | feature.priority = update.priority |
| 458 | if update.dependencies is not None: |
| 459 | feature.dependencies = update.dependencies if update.dependencies else None |
| 460 | |
| 461 | session.commit() |
| 462 | session.refresh(feature) |
| 463 | |
| 464 | # Compute passing IDs for response |
| 465 | all_features = session.query(Feature).all() |
| 466 | passing_ids = {f.id for f in all_features if f.passes} |
| 467 | |
| 468 | return feature_to_response(feature, passing_ids) |
| 469 | except HTTPException: |
| 470 | raise |
| 471 | except Exception: |
nothing calls this directly
no test coverage detected