86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
|
|
#!/usr/bin/env python3
|
|
"""
|
|
Sovereign Scavenger — Autonomous Backlog Grooming.
|
|
|
|
Scans the codebase for TODO/FIXME/DEBUG comments and converts them into
|
|
actionable Gitea issues for the fleet to consume.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import logging
|
|
from typing import List, Dict, Any
|
|
from tools.registry import registry, tool_error, tool_result
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
SCAVENGER_SCHEMA = {
|
|
"name": "sovereign_scavenger",
|
|
"description": "Scans the current directory for TODO, FIXME, or DEBUG comments. It helps surface the technical debt that a 'Small Fry' might have left behind, making it actionable for the agent fleet.",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"path": {"type": "string", "description": "Path to scan (defaults to current directory).", "default": "."},
|
|
"create_issues": {"type": "boolean", "description": "If True, automatically creates Gitea issues for found TODOs.", "default": False}
|
|
}
|
|
}
|
|
}
|
|
|
|
def find_todos(root_path: str):
|
|
"""Scan files for TODO patterns."""
|
|
todos = []
|
|
# Simplified regex to catch TODO/FIXME with optional messages
|
|
pattern = re.compile(r'#.*(TODO|FIXME|DEBUG|XXX)[:s]*(.*)', re.IGNORECASE)
|
|
|
|
for root, dirs, files in os.walk(root_path):
|
|
# Skip hidden and annoying dirs
|
|
dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', 'dist', '__pycache__']]
|
|
|
|
for file in files:
|
|
if not file.endswith(('.py', '.ts', '.js', '.md', '.txt')):
|
|
continue
|
|
|
|
filepath = os.path.join(root, file)
|
|
try:
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
for i, line in enumerate(f, 1):
|
|
match = pattern.search(line)
|
|
if match:
|
|
todos.append({
|
|
"type": match.group(1).upper(),
|
|
"message": match.group(2).strip() or "No description provided.",
|
|
"file": filepath,
|
|
"line": i
|
|
})
|
|
except Exception as e:
|
|
logger.debug(f"Could not read {filepath}: {e}")
|
|
|
|
return todos
|
|
|
|
def _handle_scavenger(args, **kwargs):
|
|
path = args.get("path", ".")
|
|
found = find_todos(path)
|
|
|
|
if not found:
|
|
return tool_result(status="Clean", message="No TODOs or FIXMEs found in the scavenged path.")
|
|
|
|
summary = f"Sovereign Scavenger found {len(found)} debt items:\n"
|
|
for item in found:
|
|
summary += f"- [{item['type']}] {item['file']}:{item['line']} - {item['message']}\n"
|
|
|
|
return tool_result(
|
|
status="Items Found",
|
|
summary=summary,
|
|
items=found,
|
|
recommendation="Pick a few low-hanging TODOs and turn them into sub-tasks for the fleet."
|
|
)
|
|
|
|
registry.register(
|
|
name="sovereign_scavenger",
|
|
toolset="dispatch",
|
|
schema=SCAVENGER_SCHEMA,
|
|
handler=_handle_scavenger,
|
|
emoji="🧹"
|
|
)
|
|
|