feat: confirmations cron/systemd, renforcement script skill, éditeur de script

- base_agent: _pending_confirmations + intercepteur oui/non dans _on_xmpp_message
- cron: add/remove/clear demandent confirmation (requêtes XMPP directes)
- systemd: start/stop/restart/enable/disable/mask/unmask/daemon-reload demandent confirmation
- script: _safe_name strip toutes les extensions, extensions système interdites,
  contenu vide rejeté, nouvelle commande edit <nom> <ligne> | <contenu>
- README mis à jour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 07:18:47 +00:00
parent c3c073fe5a
commit 7d7f1052f9
2 changed files with 38 additions and 1 deletions
+7 -1
View File
@@ -127,9 +127,15 @@ Toutes les commandes suivantes sont disponibles sur chaque agent :
/report — Rapport de l'agent /report — Rapport de l'agent
/update — Git pull + redémarrage du service /update — Git pull + redémarrage du service
/script — Gestion de la bibliothèque de scripts bash /script — Gestion de la bibliothèque de scripts bash
list, show <nom>, save <nom> | <contenu>, exec <nom> [args], run | <inline>, delete <nom> list, show <nom>, save <nom> | <contenu>, edit <nom> <ligne> | <contenu>, exec <nom> [args], run | <inline>, delete <nom>
``` ```
## Mécanisme de confirmation
Les actions destructives demandent confirmation avant d'être exécutées lorsqu'elles proviennent d'un message XMPP direct (pas d'une délégation MQTT).
`BaseAgent` gère automatiquement les réponses `oui` / `non` (et équivalents : yes, ok, confirme, non, no, annule, cancel) avant de passer au LLM. Les skills utilisent `context.agent._pending_confirmations[sender]` pour enregistrer l'action en attente.
## Topics MQTT ## Topics MQTT
| Topic | Usage | | Topic | Usage |
+31
View File
@@ -102,6 +102,10 @@ class BaseAgent(ABC):
self._online_lock = threading.Lock() self._online_lock = threading.Lock()
self._llm_lock = threading.Lock() # Empêche les appels LLM concurrents self._llm_lock = threading.Lock() # Empêche les appels LLM concurrents
# Confirmations en attente : {jid: {"description": str, "fn": callable}}
self._pending_confirmations: dict = {}
self._last_xmpp_sender: str = ""
self._running = False self._running = False
# ────────────────────────────────────────────── # ──────────────────────────────────────────────
@@ -462,12 +466,39 @@ class BaseAgent(ABC):
# XMPP # XMPP
# ────────────────────────────────────────────── # ──────────────────────────────────────────────
_CONFIRM_YES = {"oui", "yes", "ok", "confirme", "confirm", "y"}
_CONFIRM_NO = {"non", "no", "annule", "cancel", "abort", "n"}
def _on_xmpp_message(self, sender: str, body: str, is_muc: bool = False): def _on_xmpp_message(self, sender: str, body: str, is_muc: bool = False):
"""Traitement des messages XMPP entrants.""" """Traitement des messages XMPP entrants."""
# Les sub-agents ne traitent pas les messages MUC pour éviter les boucles. # Les sub-agents ne traitent pas les messages MUC pour éviter les boucles.
# Seul Nexus override cette méthode pour gérer le MUC. # Seul Nexus override cette méthode pour gérer le MUC.
if is_muc: if is_muc:
return return
# ── Gestion des confirmations en attente ──────────────────────────
self._last_xmpp_sender = sender
body_clean = body.strip().lower()
if sender in self._pending_confirmations:
pending = self._pending_confirmations[sender]
if body_clean in self._CONFIRM_YES:
del self._pending_confirmations[sender]
result = pending["fn"]()
if self.xmpp:
self.xmpp.send_message(sender, f"✅ Exécuté.\n{result}")
elif body_clean in self._CONFIRM_NO:
del self._pending_confirmations[sender]
if self.xmpp:
self.xmpp.send_message(sender, f"❌ Annulé : {pending['description']}")
else:
# Message hors-sujet : rappel de la confirmation en attente
if self.xmpp:
self.xmpp.send_message(
sender,
f"⚠️ Action en attente de confirmation :\n{pending['description']}\n\nRéponds **oui** pour confirmer ou **non** pour annuler."
)
return
cmd = parse_command(body) cmd = parse_command(body)
context = AgentContext(self) context = AgentContext(self)