Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/backend/agents/tools_pkg/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
TOOL_SEARCH_TEAM_DOCS = "mcp__auto-claude__search_team_docs"
TOOL_GET_TEAM_DOCS = "mcp__auto-claude__get_team_docs"

# Roadmap management tools
TOOL_REORDER_FEATURES = "mcp__auto-claude__reorder_features"

# Background task management tools
TOOL_START_BACKGROUND = "mcp__auto-claude__start_background_command"
TOOL_GET_TASK_STATUS = "mcp__auto-claude__get_task_status"
Expand Down
2 changes: 2 additions & 0 deletions apps/backend/agents/tools_pkg/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
create_memory_tools,
create_progress_tools,
create_qa_tools,
create_roadmap_tools,
create_statistics_tools,
create_subtask_tools,
)
Expand Down Expand Up @@ -52,6 +53,7 @@ def create_all_tools(spec_dir: Path, project_dir: Path) -> list:
all_tools.extend(create_background_task_tools(spec_dir, project_dir))
all_tools.extend(create_debugging_tools(spec_dir, project_dir))
all_tools.extend(create_knowledge_base_tools(spec_dir, project_dir))
all_tools.extend(create_roadmap_tools(spec_dir, project_dir))

return all_tools

Expand Down
2 changes: 2 additions & 0 deletions apps/backend/agents/tools_pkg/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .memory import create_memory_tools
from .progress import create_progress_tools
from .qa import create_qa_tools
from .roadmap import create_roadmap_tools
from .statistics import create_statistics_tools
from .subtask import create_subtask_tools

Expand All @@ -23,4 +24,5 @@
"create_background_task_tools",
"create_debugging_tools",
"create_knowledge_base_tools",
"create_roadmap_tools",
]
183 changes: 183 additions & 0 deletions apps/backend/agents/tools_pkg/tools/roadmap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
"""
Roadmap Tools
=============

Tools for managing roadmap features, including reordering within phases.
"""

import json
from pathlib import Path
from typing import Any

try:
from claude_agent_sdk import tool

SDK_TOOLS_AVAILABLE = True
except ImportError:
SDK_TOOLS_AVAILABLE = False
tool = None


def create_roadmap_tools(spec_dir: Path, project_dir: Path) -> list:

Check failure on line 21 in apps/backend/agents/tools_pkg/tools/roadmap.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 25 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0ZqmXTZn4SgT19h5T1&open=AZ0ZqmXTZn4SgT19h5T1&pullRequest=170

Check warning on line 21 in apps/backend/agents/tools_pkg/tools/roadmap.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the unused function parameter "spec_dir".

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0ZqmXTZn4SgT19h5T0&open=AZ0ZqmXTZn4SgT19h5T0&pullRequest=170
"""
Create roadmap management tools.

Args:
spec_dir: Path to the spec directory
project_dir: Path to the project root

Returns:
List of roadmap tool functions
"""
if not SDK_TOOLS_AVAILABLE:
return []

tools = []

# -------------------------------------------------------------------------
# Tool: reorder_features
# -------------------------------------------------------------------------
@tool(
"reorder_features",
"Reorder roadmap features within a specific phase. Updates the features array to reflect the new order.",
{
"type": "object",
"properties": {
"phase_id": {
"type": "string",
"description": "The ID of the phase containing the features to reorder",
},
"feature_ids": {
"type": "array",
"items": {"type": "string"},
"description": "Array of feature IDs in the desired new order",
},
},
"required": ["phase_id", "feature_ids"],
},
)
async def reorder_features(args: dict[str, Any]) -> dict[str, Any]:
"""Reorder features within a phase in the roadmap."""
roadmap_file = project_dir / ".auto-claude" / "roadmap" / "roadmap.json"

if not roadmap_file.exists():
return {
"content": [
{
"type": "text",
"text": "Error: Roadmap file not found. Generate a roadmap first.",
}
]
}

try:
phase_id = args.get("phase_id")
feature_ids = args.get("feature_ids", [])

if not phase_id:
return {
"content": [{"type": "text", "text": "Error: phase_id is required"}]
}

if not feature_ids:
return {
"content": [
{"type": "text", "text": "Error: feature_ids array is required"}
]
}

# Read roadmap
with open(roadmap_file, encoding="utf-8") as f:

Check failure on line 90 in apps/backend/agents/tools_pkg/tools/roadmap.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an asynchronous file API instead of synchronous open() in this async function.

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0ZqmXTZn4SgT19h5T2&open=AZ0ZqmXTZn4SgT19h5T2&pullRequest=170
roadmap = json.load(f)

# Validate phase exists
phases = roadmap.get("phases", [])
phase_exists = any(p.get("id") == phase_id for p in phases)
if not phase_exists:
return {
"content": [
{
"type": "text",
"text": f"Error: Phase '{phase_id}' not found in roadmap",
}
]
}

# Get all features
all_features = roadmap.get("features", [])

# Separate features by phase
phase_features = [f for f in all_features if f.get("phase_id") == phase_id]
other_features = [f for f in all_features if f.get("phase_id") != phase_id]

# Validate all feature IDs exist in the phase
existing_feature_ids = {f.get("id") for f in phase_features}
for fid in feature_ids:
if fid not in existing_feature_ids:
return {
"content": [
{
"type": "text",
"text": f"Error: Feature '{fid}' not found in phase '{phase_id}'",
}
]
}

# Create feature lookup
feature_map = {f.get("id"): f for f in phase_features}

# Reorder phase features according to feature_ids
reordered_phase_features = []
for fid in feature_ids:
if fid in feature_map:
reordered_phase_features.append(feature_map[fid])

# Combine: other phases first, then reordered phase features
updated_features = other_features + reordered_phase_features

# Update roadmap
roadmap["features"] = updated_features

# Update timestamp if metadata exists
if "metadata" in roadmap:
from datetime import datetime

roadmap["metadata"]["updated_at"] = datetime.utcnow().isoformat() + "Z"

Check failure on line 145 in apps/backend/agents/tools_pkg/tools/roadmap.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Don't use `datetime.datetime.utcnow` to create this datetime object.

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0ZqmXTZn4SgT19h5T3&open=AZ0ZqmXTZn4SgT19h5T3&pullRequest=170

# Write back to file
with open(roadmap_file, "w", encoding="utf-8") as f:

Check failure on line 148 in apps/backend/agents/tools_pkg/tools/roadmap.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use an asynchronous file API instead of synchronous open() in this async function.

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0ZqmXTZn4SgT19h5T4&open=AZ0ZqmXTZn4SgT19h5T4&pullRequest=170
json.dump(roadmap, f, indent=2)

# Build success message
feature_titles = [
f"{fid}: {feature_map[fid].get('title', 'Unknown')}"
for fid in feature_ids
if fid in feature_map
]

result = f"""Successfully reordered {len(feature_ids)} features in phase '{phase_id}'

New order:
{chr(10).join(f" {i + 1}. {title}" for i, title in enumerate(feature_titles))}

Roadmap file updated: {roadmap_file.relative_to(project_dir)}"""

return {"content": [{"type": "text", "text": result}]}

except json.JSONDecodeError as e:
return {
"content": [
{
"type": "text",
"text": f"Error: Failed to parse roadmap JSON: {e}",
}
]
}
except Exception as e:
return {
"content": [{"type": "text", "text": f"Error reordering features: {e}"}]
}

tools.append(reorder_features)

return tools
2 changes: 2 additions & 0 deletions apps/backend/auto_claude_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
TOOL_GET_SPEC_STATISTICS,
TOOL_RECORD_DISCOVERY,
TOOL_RECORD_GOTCHA,
TOOL_REORDER_FEATURES,
TOOL_UPDATE_QA_STATUS,
TOOL_UPDATE_SUBTASK_STATUS,
is_electron_mcp_enabled,
Expand All @@ -35,6 +36,7 @@
"TOOL_GET_BUILD_PROGRESS",
"TOOL_RECORD_DISCOVERY",
"TOOL_RECORD_GOTCHA",
"TOOL_REORDER_FEATURES",
"TOOL_GET_SESSION_CONTEXT",
"TOOL_GET_SPEC_STATISTICS",
"TOOL_UPDATE_QA_STATUS",
Expand Down
Loading