Files
alfred/agent/commands.py

110 lines
3.3 KiB
Python

# agent/commands.py
from dataclasses import dataclass
from typing import Callable, Dict, List
import os
from .memory import Memory
@dataclass
class Command:
name: str
description: str
needs_project_root: bool
handler: Callable[[List[str], Memory], str]
class CommandRegistry:
def __init__(self, memory: Memory):
self.memory = memory
self.commands: Dict[str, Command] = {}
self._register_defaults()
def _register_defaults(self):
# /setroot <path>
def cmd_setroot(args: List[str], mem: Memory) -> str:
if not args:
return "Usage: `/setroot <chemin_absolu_vers_projet>`"
path = args[0]
if not os.path.isdir(path):
return f"Le chemin `{path}` n'existe pas ou n'est pas un dossier."
mem.set_project_root(path)
return f"✅ Chemin du projet défini sur `{path}`."
self.register(
Command(
name="setroot",
description="Définit le chemin racine du projet.",
needs_project_root=False,
handler=cmd_setroot,
)
)
# /scan [rel_path]
def cmd_scan(args: List[str], mem: Memory) -> str:
root = mem.get_project_root()
rel = args[0] if args else "."
full = os.path.abspath(os.path.join(root, rel))
# sécurité basique
if not full.startswith(os.path.abspath(root)):
return "❌ Tu ne peux pas sortir du project_root."
if not os.path.isdir(full):
return f"❌ `{rel}` n'est pas un dossier dans le projet."
entries = sorted(os.listdir(full))
if not entries:
return f"📁 `{rel}` est vide."
lines = [f"📁 Scan de `{rel}` (dans `{root}`):"]
for e in entries:
p = os.path.join(full, e)
if os.path.isdir(p):
lines.append(f" 📂 {e}/")
else:
lines.append(f" 📄 {e}")
return "\n".join(lines)
self.register(
Command(
name="scan",
description="Liste les fichiers/dossiers du projet.",
needs_project_root=True,
handler=cmd_scan,
)
)
def register(self, cmd: Command):
self.commands[cmd.name] = cmd
def handle(self, raw_input: str) -> str:
"""
Parse et exécute une commande du type `/scan src` ou `/setroot /chemin`.
"""
text = raw_input.strip()
if not text.startswith("/"):
return "Internal error: not a command."
parts = text[1:].split()
if not parts:
return "Commande vide."
name = parts[0]
args = parts[1:]
cmd = self.commands.get(name)
if not cmd:
return f"Commande inconnue: `/{name}`.\nCommandes disponibles: {', '.join('/'+n for n in self.commands.keys())}"
# dépendance project_root
if cmd.needs_project_root and not self.memory.get_project_root():
return (
"❗ Aucun `project_root` défini pour l'instant.\n"
"Commence par le définir avec:\n"
"`/setroot /chemin/vers/ton/projet`"
)
return cmd.handler(args, self.memory)