"""Tool: manage next steps for a project (DB-backed, replaces .a0/next_steps.md).""" from __future__ import annotations import os from helpers.tool import Tool, Response from usr.plugins.a0_software_orchestrator.helpers.db_state_store import ( get_project_id, add_next_step, complete_next_step, list_next_steps, ) from usr.plugins.a0_software_orchestrator.helpers.exceptions import PluginDBError def _resolve_name(project_name: str = "", project_root: str = "") -> str: """Ermittelt den Projektnamen: explizit → aus project_root → aus cwd.""" if project_name: return project_name.strip() if project_root: return os.path.basename(project_root.rstrip("/")) return os.path.basename(os.getcwd()) class NextStep(Tool): """Add, list, or complete next steps for a project. Args (kwargs): project_name (str): Projektname (bevorzugt). project_root (str): Legacy – wird zu basename() aufgelöst. next_step (str): Inhalt des neuen Steps (bei action=add). step_id (int): ID des Steps (bei action=complete). action (str): "add" (default), "list", "complete". """ async def execute( self, project_name: str = "", project_root: str = "", next_step: str = "", step_id: int = 0, action: str = "", **kwargs, ): if not action: return Response(message="ERROR: 'action' required. Supported: add, list, complete", break_loop=False) name = _resolve_name(project_name, project_root) try: pid = get_project_id(name) if pid is None: raise LookupError(f"project '{name}' is not registered") except (ValueError, LookupError) as e: return Response(message=f"ERROR: {e}", break_loop=False) except PluginDBError as e: return Response(message=f"Database error: {e}", break_loop=False) if action == "add": if not next_step and kwargs.get("content"): next_step = str(kwargs.get("content")) if not next_step or not next_step.strip(): return Response( message="ERROR: 'next_step' content required for action=add", break_loop=False, ) new_id = add_next_step(pid, next_step.strip()) return Response( message=f"Next step added (id={new_id}, project={name}): {next_step.strip()}", break_loop=False, ) if action == "list": steps = list_next_steps(pid, status="pending") if not steps: return Response( message=f"No pending next steps for project '{name}'.", break_loop=False, ) lines = [f"Pending next steps for '{name}':"] for s in steps: lines.append(f" - [id={s['id']}] {s['content']}") return Response(message="\n".join(lines), break_loop=False) if action == "complete": if not step_id: return Response( message="ERROR: 'step_id' required for action=complete", break_loop=False, ) ok = complete_next_step(int(step_id)) if ok: return Response( message=f"Next step id={step_id} marked as done.", break_loop=False, ) return Response( message=f"No next step with id={step_id} found.", break_loop=False, ) return Response( message=f"Unknown action {action!r}. Supported: add, list, complete", break_loop=False, )