feat(maria-dashboard): reset pentru firele de discutie active

Nu exista nicio cale sa resetezi manual un fir blocat pe o discutie
veche (nici comanda de chat, nici buton) — un test in grupul "Maria
Test" a ramas ancorat pe un subiect vechi fara sa poata fi curatat
fara interventie directa pe server. Sectiune noua in dashboard, intre
"Trimise la suport" si "Clienti cunoscuti": listeaza firele active
din ~/.maria-bridge/conversations/ si le sterge la cerere (rutele
GET/POST /api/maria/fire), cu aceeasi sanitizare de nume de fisier ca
rag/fir.py (oglinda, nu import — coliziune de modul intre proiecte).

11/11 teste (6 noi + cele de clienti), fara regresii.

Co-Authored-By: Claude Agent <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-09-08 11:36:54 +00:00
parent 610638ad30
commit 32ff462291
3 changed files with 163 additions and 1 deletions

View File

@@ -291,6 +291,46 @@ def maria_delete_client(cid: str) -> bool:
return True
def _maria_conv_dir():
return MARIA_STATE_DIR / "conversations"
def _maria_cale_fir(jid: str):
# oglinda lui rag/fir.py:_cale — tine-o la fel
if not jid:
raise ValueError("jid lipsa")
return _maria_conv_dir() / (re.sub(r"[^0-9a-zA-Z@._-]", "_", jid) + ".json")
def maria_fire() -> list[dict]:
d = _maria_conv_dir()
if not d.is_dir():
return []
out = []
for f in d.glob("*.json"):
try:
fir = json.loads(f.read_text(encoding="utf-8"))
except (OSError, ValueError):
continue
out.append({
"jid": fir.get("jid"),
"at": fir.get("at"),
"ancora": (fir.get("ancora") or "")[:200],
"schimburi": len(fir.get("schimburi") or []),
"ref": fir.get("ref"),
})
out.sort(key=lambda x: x.get("at") or 0, reverse=True)
return out
def maria_delete_fir(jid: str) -> bool:
path = _maria_cale_fir(jid)
if path.exists():
path.unlink()
return True
return False
def _maria_run(script: str, timeout: float = 600.0, extra_args: list[str] | None = None) -> dict:
interpreter = str(MARIA_VENV_PY) if MARIA_VENV_PY.exists() else sys.executable
args = [interpreter, str(MARIA_RAG_DIR / script), *(extra_args or [])]
@@ -805,6 +845,8 @@ class Handler(SimpleHTTPRequestHandler):
return self.send_json({"escalations": maria_escalations()})
if path == "/api/maria/clients":
return self.send_json({"clients": maria_clients()})
if path == "/api/maria/fire":
return self.send_json({"fire": maria_fire()})
if path == "/api/maria/logs":
try:
n = min(max(int(qs.get("lines", ["200"])[0]), 1), 2000)
@@ -849,6 +891,8 @@ class Handler(SimpleHTTPRequestHandler):
return self.handle_maria_client_write()
if path == "/api/maria/clients/delete":
return self.handle_maria_client_delete()
if path == "/api/maria/fire/delete":
return self.handle_maria_fire_delete()
if path == "/api/maria/reindex":
return self.send_json(maria_reindex())
if path == "/api/maria/sync":
@@ -988,6 +1032,15 @@ class Handler(SimpleHTTPRequestHandler):
ok = maria_delete_client(cid)
return self.send_json({"ok": ok, "id": cid}, 200 if ok else 404)
def handle_maria_fire_delete(self):
data = self.read_json()
jid = str(data.get("jid") or "")
try:
ok = maria_delete_fir(jid)
except ValueError as exc:
return self.send_json({"ok": False, "error": str(exc)}, 400)
return self.send_json({"ok": ok, "jid": jid}, 200 if ok else 404)
def main() -> None:
bind = config.get("DASHBOARD_BIND") or "127.0.0.1"