Skills-Ansicht: Umbenennung + aktiv/inaktiv + Karten-Ergebnisse im Auftragsbuch

User-Feedback 15.07.:
1) 'Von allein' heisst jetzt 'Skills' (id #eigenleben bleibt, Links halten).
2) Jeder Skill traegt aktiv/inaktiv - Quelle ist Hermes' EIGENE Wahrheit
   (hermes_cli.banner.get_available_skills via Hermes-venv, dieselbe Logik
   wie das eingebaute WebUI: Plattform/Voraussetzungen/Config). Bewusst NUR
   die Datenquelle wiederverwendet, nicht deren UI - Skill-VERWALTUNG bleibt
   im Hermes-GUI-Tab, alles andere waere Bloat/Doppelbau.
3) Auftragsbuch: fertige Queue-Karten sind aufklappbar und zeigen das
   ERGEBNIS des Workers (kanban_complete-Summary, lazy via
   GET /api/ideen/{id}/ergebnis) - 'Dinge werden getestet, ich sehe aber
   das Ergebnis nicht' ist damit zu.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-15 14:21:46 +02:00
parent bf9fd808d8
commit fdabe1768e
30 changed files with 197 additions and 48 deletions
+41
View File
@@ -35,6 +35,10 @@ _LIST_EVERY = 15.0 # s
_log_cache: dict = {"ts": 0.0, "task_id": None, "data": None}
_LOG_EVERY = 4.0 # s
# Cache für Ergebnis (Abschluss-Zusammenfassung) — ändert sich nach done nie mehr
_erg_cache: dict = {}
_ERG_MAX = 40 # simple Deckelung gegen unbegrenztes Wachsen
def _available() -> bool:
return os.name == "posix" and HERMES.is_file()
@@ -213,6 +217,43 @@ def archive_task(task_id: str) -> dict:
return {"ok": True}
def ergebnis_of(task_id: str) -> dict:
"""Das ERGEBNIS einer fertigen Aufgabe — die Abschluss-Zusammenfassung des Workers.
User-Wunsch 15.07.: „im Auftragsbuch werden Dinge getestet, ich sehe aber das
Ergebnis nicht." Die Wahrheit liegt beim kanban_complete-Aufruf (summary/result)
im jüngsten `completed`-Event; `list --json` trägt sie nicht → lazy per `show`,
nur wenn der User die Karte aufklappt. Fertige Ergebnisse ändern sich nie → Cache.
"""
if not _available():
return {"available": False, "summary": "", "result": ""}
if not _TASK_ID_RX.match(task_id or ""):
return {"available": True, "summary": "", "result": ""}
if task_id in _erg_cache:
return _erg_cache[task_id]
try:
r = _hermes(["show", task_id, "--json"], timeout=30)
d = _parse_json(r.stdout)
except Exception:
log.warning("ideen: kanban show %s (ergebnis) fehlgeschlagen", task_id, exc_info=True)
return {"available": True, "summary": "", "result": ""}
summary, result = "", ""
if isinstance(d, dict):
if isinstance(d.get("result"), str):
result = d["result"].strip()
for ev in d.get("events") or []: # chronologisch → letztes completed gewinnt
if isinstance(ev, dict) and ev.get("kind") == "completed":
s = ((ev.get("payload") or {}).get("summary") or "").strip()
if s:
summary = s
data = {"available": True, "summary": summary[:4000], "result": result[:4000]}
if len(_erg_cache) >= _ERG_MAX:
_erg_cache.pop(next(iter(_erg_cache)))
_erg_cache[task_id] = data
return data
def log_of(task_id: str) -> dict:
"""Worker-Log einer Idee (hermes kanban log <id>), ANSI entfernt, letzte ~120 Zeilen."""
if not _available():