mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-01-30 06:12:06 +00:00
Add in-progress status tracking for features
Implements feature locking to prevent multiple agent sessions from working on the same feature simultaneously. This is essential for parallel agent execution. Database changes: - Add `in_progress` boolean column to Feature model - Add migration function to handle existing databases MCP Server tools: - Add `feature_mark_in_progress` - lock feature when starting work - Add `feature_clear_in_progress` - unlock feature when abandoning - Update `feature_get_next` to skip in-progress features - Update `feature_get_stats` to include in_progress count - Update `feature_mark_passing` and `feature_skip` to clear in_progress Backend updates: - Update progress.py to track and display in_progress count - Update features router to properly categorize in-progress features - Update WebSocket to broadcast in_progress in progress updates - Add in_progress to FeatureResponse schema Frontend updates: - Add in_progress to TypeScript types (Feature, ProjectStats, WSProgressMessage) - Update useWebSocket hook to track in_progress state Prompt template: - Add instructions for agents to mark features in-progress immediately - Document new MCP tools in allowed tools section Also fixes spec_chat_session.py to use absolute project path instead of relative path for consistency with CLI behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,7 @@ def feature_to_response(f) -> FeatureResponse:
|
||||
description=f.description,
|
||||
steps=f.steps if isinstance(f.steps, list) else [],
|
||||
passes=f.passes,
|
||||
in_progress=f.in_progress,
|
||||
)
|
||||
|
||||
|
||||
@@ -123,18 +124,21 @@ async def list_features(project_name: str):
|
||||
all_features = session.query(Feature).order_by(Feature.priority).all()
|
||||
|
||||
pending = []
|
||||
in_progress = []
|
||||
done = []
|
||||
|
||||
for f in all_features:
|
||||
feature_response = feature_to_response(f)
|
||||
if f.passes:
|
||||
done.append(feature_response)
|
||||
elif f.in_progress:
|
||||
in_progress.append(feature_response)
|
||||
else:
|
||||
pending.append(feature_response)
|
||||
|
||||
return FeatureListResponse(
|
||||
pending=pending,
|
||||
in_progress=[],
|
||||
in_progress=in_progress,
|
||||
done=done,
|
||||
)
|
||||
except HTTPException:
|
||||
|
||||
@@ -73,7 +73,7 @@ def validate_project_name(name: str) -> str:
|
||||
def get_project_stats(project_dir: Path) -> ProjectStats:
|
||||
"""Get statistics for a project."""
|
||||
_init_imports()
|
||||
passing, total = _count_passing_tests(project_dir)
|
||||
passing, _, total = _count_passing_tests(project_dir)
|
||||
percentage = (passing / total * 100) if total > 0 else 0.0
|
||||
return ProjectStats(passing=passing, total=total, percentage=round(percentage, 1))
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ class FeatureResponse(FeatureBase):
|
||||
id: int
|
||||
priority: int
|
||||
passes: bool
|
||||
in_progress: bool
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
@@ -83,8 +83,12 @@ class SpecChatSession:
|
||||
except UnicodeDecodeError:
|
||||
skill_content = skill_path.read_text(encoding="utf-8", errors="replace")
|
||||
|
||||
# Replace $ARGUMENTS with the project path (use forward slashes for consistency)
|
||||
project_path = f"generations/{self.project_name}"
|
||||
# Ensure project directory exists (like CLI does in start.py)
|
||||
self.project_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Replace $ARGUMENTS with absolute project path (like CLI does in start.py:184)
|
||||
# Using absolute path avoids confusion when project folder name differs from app name
|
||||
project_path = str(self.project_dir.resolve())
|
||||
system_prompt = skill_content.replace("$ARGUMENTS", project_path)
|
||||
|
||||
# Create Claude SDK client with limited tools for spec creation
|
||||
|
||||
@@ -117,21 +117,24 @@ async def poll_progress(websocket: WebSocket, project_name: str):
|
||||
project_dir = _get_generations_dir() / project_name
|
||||
count_passing_tests = _get_count_passing_tests()
|
||||
last_passing = -1
|
||||
last_in_progress = -1
|
||||
last_total = -1
|
||||
|
||||
while True:
|
||||
try:
|
||||
passing, total = count_passing_tests(project_dir)
|
||||
passing, in_progress, total = count_passing_tests(project_dir)
|
||||
|
||||
# Only send if changed
|
||||
if passing != last_passing or total != last_total:
|
||||
if passing != last_passing or in_progress != last_in_progress or total != last_total:
|
||||
last_passing = passing
|
||||
last_in_progress = in_progress
|
||||
last_total = total
|
||||
percentage = (passing / total * 100) if total > 0 else 0
|
||||
|
||||
await websocket.send_json({
|
||||
"type": "progress",
|
||||
"passing": passing,
|
||||
"in_progress": in_progress,
|
||||
"total": total,
|
||||
"percentage": round(percentage, 1),
|
||||
})
|
||||
@@ -204,11 +207,12 @@ async def project_websocket(websocket: WebSocket, project_name: str):
|
||||
|
||||
# Send initial progress
|
||||
count_passing_tests = _get_count_passing_tests()
|
||||
passing, total = count_passing_tests(project_dir)
|
||||
passing, in_progress, total = count_passing_tests(project_dir)
|
||||
percentage = (passing / total * 100) if total > 0 else 0
|
||||
await websocket.send_json({
|
||||
"type": "progress",
|
||||
"passing": passing,
|
||||
"in_progress": in_progress,
|
||||
"total": total,
|
||||
"percentage": round(percentage, 1),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user