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:
@@ -55,3 +55,8 @@ def archive(body: TaskIn) -> dict:
|
||||
@router.get("/ideen/{id}/log")
|
||||
def get_log(id: str) -> dict:
|
||||
return ideen.log_of(id)
|
||||
|
||||
|
||||
@router.get("/ideen/{id}/ergebnis")
|
||||
def get_ergebnis(id: str) -> dict:
|
||||
return ideen.ergebnis_of(id)
|
||||
|
||||
@@ -18,11 +18,15 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
SKILLS_DIR = Path.home() / ".hermes" / "skills"
|
||||
BUNDLED_DIR = Path.home() / ".hermes" / "hermes-agent" / "skills"
|
||||
REPO_DIR = Path.home() / "mission-control-v2" / "deploy" / "skills"
|
||||
HERMES_SRC = Path.home() / ".hermes" / "hermes-agent"
|
||||
HERMES_PY = HERMES_SRC / "venv" / "bin" / "python"
|
||||
USAGE_FILE = SKILLS_DIR / ".usage.json"
|
||||
AUFTRAGSBUCH_FILE = Path("/srv/models/mc2-auftragsbuch.json")
|
||||
ABLEHNUNGEN_FILE = Path("/srv/models/mc2-ablehnungen.jsonl")
|
||||
@@ -56,6 +60,35 @@ def _norm(s: str) -> str:
|
||||
return re.sub(r"[\s_-]+", "", (s or "").lower())
|
||||
|
||||
|
||||
# aktiv/inaktiv: dieselbe Wahrheit wie Hermes selbst (und sein eingebautes WebUI) —
|
||||
# hermes_cli.banner.get_available_skills() prüft Plattform/Voraussetzungen/Config und
|
||||
# liefert, was der Agent WIRKLICH laden kann. Wir rufen sie im Hermes-venv auf (MC2
|
||||
# läuft in eigenem Python) und cachen großzügig — der Skill-Satz ändert sich selten.
|
||||
_aktiv_cache: dict = {"ts": 0.0, "namen": None}
|
||||
_AKTIV_EVERY = 600.0 # s
|
||||
|
||||
|
||||
def _aktive_namen() -> set[str] | None:
|
||||
"""Normalisierte Namen aller ladbaren Skills; None = nicht ermittelbar (Dev-Modus)."""
|
||||
if not HERMES_PY.is_file():
|
||||
return None
|
||||
now = time.time()
|
||||
if _aktiv_cache["namen"] is not None and now - _aktiv_cache["ts"] < _AKTIV_EVERY:
|
||||
return _aktiv_cache["namen"]
|
||||
code = ("from hermes_cli.banner import get_available_skills;import json;"
|
||||
"print(json.dumps(get_available_skills()))")
|
||||
try:
|
||||
r = subprocess.run([str(HERMES_PY), "-c", code], capture_output=True,
|
||||
text=True, timeout=60, cwd=str(HERMES_SRC))
|
||||
idx = r.stdout.find("{")
|
||||
kategorien = json.loads(r.stdout[idx:]) if idx >= 0 else {}
|
||||
namen = {_norm(n) for liste in kategorien.values() for n in liste}
|
||||
except Exception:
|
||||
return _aktiv_cache["namen"] # alter Stand ist besser als flackerndes None
|
||||
_aktiv_cache.update(ts=now, namen=namen)
|
||||
return namen
|
||||
|
||||
|
||||
def list_skills() -> list[dict]:
|
||||
"""Alle Skills mit Beschreibung, Herkunft und Nutzungszahlen (leer im Dev-Modus)."""
|
||||
if not SKILLS_DIR.is_dir():
|
||||
@@ -65,6 +98,7 @@ def list_skills() -> list[dict]:
|
||||
except Exception:
|
||||
usage_raw = {}
|
||||
usage = {_norm(k): v for k, v in usage_raw.items()}
|
||||
aktive = _aktive_namen()
|
||||
|
||||
def eintrag(md: Path, rel: str, kategorie: str | None) -> dict:
|
||||
try:
|
||||
@@ -79,10 +113,14 @@ def list_skills() -> list[dict]:
|
||||
herkunft = "selbst"
|
||||
kurz = rel.split("/")[-1]
|
||||
u = usage.get(_norm(kurz)) or usage.get(_norm(fm.get("name", ""))) or {}
|
||||
aktiv = None
|
||||
if aktive is not None:
|
||||
aktiv = _norm(kurz) in aktive or _norm(fm.get("name", "")) in aktive
|
||||
return {
|
||||
"id": rel,
|
||||
"name": fm.get("name") or kurz,
|
||||
"kategorie": kategorie,
|
||||
"aktiv": aktiv,
|
||||
"beschreibung": fm.get("description") or "",
|
||||
"version": fm.get("version") or "",
|
||||
"autor": fm.get("author") or "",
|
||||
|
||||
@@ -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():
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as k,R as _,m as S,b as C,u as H,r as E,j as e,U as A,e as a,V as u,W as p,Y as B,s as h,Z as D,Q as P,X as M,C as g,g as b,q as i}from"./index-CDslgvwS.js";/**
|
||||
import{c as k,R as _,m as S,b as C,u as H,r as E,j as e,U as A,e as a,V as u,W as p,Y as B,s as h,Z as D,Q as P,X as M,C as g,g as b,q as i}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
+13
-8
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as h,aa as S,r as c,j as e,ab as z,L as g,N as M,ac as C,a9 as D,ad as A,ae as B,af as Z,e as E,ag as L,u as q,b as R,g as k,q as T}from"./index-CDslgvwS.js";/**
|
||||
import{c as h,aa as S,r as c,j as e,ab as z,L as g,N as M,ac as C,a9 as D,ad as A,ae as B,af as Z,e as E,ag as L,u as q,b as R,g as k,q as T}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as v,r as c,z as D,A as I,j as e,D as h,s as B,B as H,w as z,F as E,e as M,L as F,G as T,C as K}from"./index-CDslgvwS.js";import{F as O}from"./folder-open-D9Tf3AHU.js";import{C as R}from"./circle-x-D-XzMNyu.js";import{C as V}from"./copy-B32DycGg.js";/**
|
||||
import{c as v,r as c,z as D,A as I,j as e,D as h,s as B,B as H,w as z,F as E,e as M,L as F,G as T,C as K}from"./index-ClYatDZT.js";import{F as O}from"./folder-open-Birisrv_.js";import{C as R}from"./circle-x-BVoF4hpT.js";import{C as V}from"./copy-DTtK5aX-.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as p,j as e,r as M,s as C,a0 as z,a1 as k,a2 as y,W as v,Q as L,a3 as G,Z as T,e as f,N as D}from"./index-CDslgvwS.js";import{B as w}from"./book-open-kUtGvGMW.js";import{a as N,b as B,L as P,C as E,Z as R}from"./zap-BFGxSGSP.js";import{L as I}from"./lightbulb-Cfb98djJ.js";/**
|
||||
import{c as p,j as e,r as M,s as C,a0 as z,a1 as k,a2 as y,W as v,Q as L,a3 as G,Z as T,e as f,N as D}from"./index-ClYatDZT.js";import{B as w}from"./book-open-CdFvbc2z.js";import{a as N,b as B,L as P,C as E,Z as R}from"./zap-raGIywOo.js";import{L as I}from"./lightbulb-ETwYqnI4.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{R as l,V as o,j as e,e as a,U as n,T as d,$ as i}from"./index-CDslgvwS.js";function c(){const{data:s}=l(),r=s!=null&&s.box_console_url?o(s.box_console_url):void 0,t=s==null?void 0:s.box_console_reachable;return e.jsxs("div",{className:"flex h-full flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-end justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text font-space text-2xl font-bold tracking-tight text-transparent",children:"Konsole"}),e.jsx("p",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:"Direkte Shell auf der Box — wie ein SSH-Fenster, mitten im Browser."})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] font-medium text-muted-foreground",children:[e.jsx("span",{className:a("h-2 w-2 rounded-full",t?"bg-emerald-500 animate-pulse":"bg-amber-500")}),t?"online":"offline"]}),r&&e.jsxs("a",{href:r,target:"_blank",rel:"noopener",className:"flex h-8 items-center gap-1.5 rounded-lg border border-border/60 bg-background/20 px-3 text-xs font-semibold text-muted-foreground transition-all hover:border-primary/50 hover:text-foreground",children:[e.jsx(n,{className:"h-3.5 w-3.5"})," In neuem Tab"]})]})]}),r?e.jsxs("div",{className:"relative min-h-[58vh] flex-1 overflow-hidden rounded-2xl border border-border/60 bg-black/50 shadow-lg shadow-black/25",children:[t===!1&&e.jsxs("div",{className:"absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 bg-black/70 text-center",children:[e.jsx(d,{className:"h-8 w-8 text-amber-400"}),e.jsx("div",{className:"text-sm font-semibold text-amber-300",children:"Konsole nicht erreichbar"}),e.jsxs("p",{className:"max-w-sm text-[11px] leading-normal text-muted-foreground",children:["Der ",e.jsx("code",{className:"font-mono text-primary",children:"box-console"}),"-Dienst (ttyd) läuft nicht. Auf der Box: ",e.jsx("code",{className:"font-mono",children:"systemctl --user restart box-console"}),"."]})]}),e.jsx("iframe",{src:r,title:"Box-Konsole",className:"h-full w-full border-0",style:{minHeight:"58vh"}})]}):e.jsxs("div",{className:"flex min-h-[58vh] flex-1 items-center justify-center rounded-2xl border border-border/60 bg-background/20 text-xs text-muted-foreground",children:[e.jsx(i,{className:"mr-2 h-4 w-4"})," Lade Konsole…"]})]})}export{c as KonsoleView};
|
||||
import{R as l,V as o,j as e,e as a,U as n,T as d,$ as i}from"./index-ClYatDZT.js";function c(){const{data:s}=l(),r=s!=null&&s.box_console_url?o(s.box_console_url):void 0,t=s==null?void 0:s.box_console_reachable;return e.jsxs("div",{className:"flex h-full flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-end justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text font-space text-2xl font-bold tracking-tight text-transparent",children:"Konsole"}),e.jsx("p",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:"Direkte Shell auf der Box — wie ein SSH-Fenster, mitten im Browser."})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] font-medium text-muted-foreground",children:[e.jsx("span",{className:a("h-2 w-2 rounded-full",t?"bg-emerald-500 animate-pulse":"bg-amber-500")}),t?"online":"offline"]}),r&&e.jsxs("a",{href:r,target:"_blank",rel:"noopener",className:"flex h-8 items-center gap-1.5 rounded-lg border border-border/60 bg-background/20 px-3 text-xs font-semibold text-muted-foreground transition-all hover:border-primary/50 hover:text-foreground",children:[e.jsx(n,{className:"h-3.5 w-3.5"})," In neuem Tab"]})]})]}),r?e.jsxs("div",{className:"relative min-h-[58vh] flex-1 overflow-hidden rounded-2xl border border-border/60 bg-black/50 shadow-lg shadow-black/25",children:[t===!1&&e.jsxs("div",{className:"absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 bg-black/70 text-center",children:[e.jsx(d,{className:"h-8 w-8 text-amber-400"}),e.jsx("div",{className:"text-sm font-semibold text-amber-300",children:"Konsole nicht erreichbar"}),e.jsxs("p",{className:"max-w-sm text-[11px] leading-normal text-muted-foreground",children:["Der ",e.jsx("code",{className:"font-mono text-primary",children:"box-console"}),"-Dienst (ttyd) läuft nicht. Auf der Box: ",e.jsx("code",{className:"font-mono",children:"systemctl --user restart box-console"}),"."]})]}),e.jsx("iframe",{src:r,title:"Box-Konsole",className:"h-full w-full border-0",style:{minHeight:"58vh"}})]}):e.jsxs("div",{className:"flex min-h-[58vh] flex-1 items-center justify-center rounded-2xl border border-border/60 bg-background/20 text-xs text-muted-foreground",children:[e.jsx(i,{className:"mr-2 h-4 w-4"})," Lade Konsole…"]})]})}export{c as KonsoleView};
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GraphView-BPfxMmZZ.js","assets/index-CDslgvwS.js","assets/index-Bhpy_OBa.css"])))=>i.map(i=>d[i]);
|
||||
var ke=Object.defineProperty;var ve=(d,i,c)=>i in d?ke(d,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[i]=c;var U=(d,i,c)=>ve(d,typeof i!="symbol"?i+"":i,c);import{c as h,r as s,j as e,u as Ne,b as Se,I as J,J as Ce,C as W,K as Ee,S as Me,M as ze,N as _,e as x,O as _e,Q as Oe,X,v as Z,_ as Te,g as j}from"./index-CDslgvwS.js";import{C as Y}from"./copy-B32DycGg.js";import{S as Ae}from"./send-BuNKVXpO.js";import{B as De}from"./book-open-kUtGvGMW.js";/**
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GraphView-DGCqAmwL.js","assets/index-ClYatDZT.js","assets/index-Cq_BqGQa.css"])))=>i.map(i=>d[i]);
|
||||
var ke=Object.defineProperty;var ve=(d,i,c)=>i in d?ke(d,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[i]=c;var U=(d,i,c)=>ve(d,typeof i!="symbol"?i+"":i,c);import{c as h,r as s,j as e,u as Ne,b as Se,I as J,J as Ce,C as W,K as Ee,S as Me,M as ze,N as _,e as x,O as _e,Q as Oe,X,v as Z,_ as Te,g as j}from"./index-ClYatDZT.js";import{C as Y}from"./copy-DTtK5aX-.js";import{S as Ae}from"./send-D-g9GbnJ.js";import{B as De}from"./book-open-CdFvbc2z.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
@@ -34,7 +34,7 @@ var ke=Object.defineProperty;var ve=(d,i,c)=>i in d?ke(d,i,{enumerable:!0,config
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const Re=h("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);class re extends s.Component{constructor(){super(...arguments);U(this,"state",{error:null})}static getDerivedStateFromError(c){return{error:c}}render(){return this.state.error?e.jsxs("div",{className:"h-[480px] rounded-2xl border border-red-500/20 bg-red-500/5 p-6 text-xs text-red-400 overflow-auto",children:[e.jsx("div",{className:"font-semibold mb-2",children:"Graph konnte nicht gerendert werden"}),e.jsx("pre",{className:"whitespace-pre-wrap break-words text-[11px] leading-relaxed",children:this.state.error.message})]}):this.props.children}}const te=s.lazy(()=>Te(()=>import("./GraphView-BPfxMmZZ.js"),__vite__mapDeps([0,1,2])).then(d=>({default:d.GraphView}))),k=["identity","knowledge","rules","events"],se=new Set(["auto","agent","hermes"]),O={identity:{label:"Identität",icon:Re,bg:"bg-cyan-500/10",text:"text-cyan-400"},knowledge:{label:"Wissen",icon:Oe,bg:"bg-indigo-500/10",text:"text-indigo-400"},rules:{label:"Regeln",icon:Pe,bg:"bg-violet-500/10",text:"text-violet-400"},events:{label:"Ereignisse",icon:_e,bg:"bg-amber-500/10",text:"text-amber-400"}},ne={label:"Gedächtnis",icon:De,text:"text-muted-foreground"},Ve={identity:"border-l-cyan-500/80",knowledge:"border-l-indigo-500/80",rules:"border-l-violet-500/80",events:"border-l-amber-500/80"},ae=`Hi Hermes! Lass uns ein kurzes Onboarding machen, damit du dich künftig an mich erinnerst. Stell mir nacheinander ein paar kurze Fragen zu:
|
||||
*/const Re=h("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);class re extends s.Component{constructor(){super(...arguments);U(this,"state",{error:null})}static getDerivedStateFromError(c){return{error:c}}render(){return this.state.error?e.jsxs("div",{className:"h-[480px] rounded-2xl border border-red-500/20 bg-red-500/5 p-6 text-xs text-red-400 overflow-auto",children:[e.jsx("div",{className:"font-semibold mb-2",children:"Graph konnte nicht gerendert werden"}),e.jsx("pre",{className:"whitespace-pre-wrap break-words text-[11px] leading-relaxed",children:this.state.error.message})]}):this.props.children}}const te=s.lazy(()=>Te(()=>import("./GraphView-DGCqAmwL.js"),__vite__mapDeps([0,1,2])).then(d=>({default:d.GraphView}))),k=["identity","knowledge","rules","events"],se=new Set(["auto","agent","hermes"]),O={identity:{label:"Identität",icon:Re,bg:"bg-cyan-500/10",text:"text-cyan-400"},knowledge:{label:"Wissen",icon:Oe,bg:"bg-indigo-500/10",text:"text-indigo-400"},rules:{label:"Regeln",icon:Pe,bg:"bg-violet-500/10",text:"text-violet-400"},events:{label:"Ereignisse",icon:_e,bg:"bg-amber-500/10",text:"text-amber-400"}},ne={label:"Gedächtnis",icon:De,text:"text-muted-foreground"},Ve={identity:"border-l-cyan-500/80",knowledge:"border-l-indigo-500/80",rules:"border-l-violet-500/80",events:"border-l-amber-500/80"},ae=`Hi Hermes! Lass uns ein kurzes Onboarding machen, damit du dich künftig an mich erinnerst. Stell mir nacheinander ein paar kurze Fragen zu:
|
||||
1) wer ich bin und woran ich gerade arbeite,
|
||||
2) wie ich angesprochen werden möchte,
|
||||
3) meine bevorzugten Tools, Sprachen und Arbeitsweise,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as D,u as Ce,a as Ee,b as Se,j as e,f as ce,d as De,e as g,g as B,q as te,B as ae,h as qe,E as _e,i as Ge,r as y,X as Re,C as J,T as re,k as Z,H as Ae,l as P,m as me,n as Fe,o as Ke,p as Oe,S as pe,s as Ie,P as Te,t as Ue,v as He,w as Le,x as Pe,y as Qe}from"./index-CDslgvwS.js";import{C as xe,Z as ue,L as Ve,a as We,b as Je}from"./zap-BFGxSGSP.js";/**
|
||||
import{c as D,u as Ce,a as Ee,b as Se,j as e,f as ce,d as De,e as g,g as B,q as te,B as ae,h as qe,E as _e,i as Ge,r as y,X as Re,C as J,T as re,k as Z,H as Ae,l as P,m as me,n as Fe,o as Ke,p as Oe,S as pe,s as Ie,P as Te,t as Ue,v as He,w as Le,x as Pe,y as Qe}from"./index-ClYatDZT.js";import{C as xe,Z as ue,L as Ve,a as We,b as Je}from"./zap-raGIywOo.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{aj as y,r as x,g as L,j as e,L as v,S,ak as W,N as C,e as w,al as E}from"./index-CDslgvwS.js";import{F as M}from"./folder-open-D9Tf3AHU.js";const D={"":"Allgemein",traeume:"Träume",muster:"Muster","skill-kandidaten":"Skill-Kandidaten","skill-kandidaten/beauftragt":"Skill-Kandidaten · beauftragt","skill-kandidaten/verworfen":"Skill-Kandidaten · verworfen"};function T(){const{data:o,isLoading:h}=y(),[l,f]=x.useState(null),[d,r]=x.useState(null),[u,i]=x.useState(!1),[a,p]=x.useState(""),t=x.useMemo(()=>(o==null?void 0:o.files)??[],[o]),m=x.useMemo(()=>{const s=new Map;for(const n of t)s.set(n.name.toLowerCase(),n.path);return s},[t]),g=x.useMemo(()=>{if(!a.trim())return t;const s=a.toLowerCase();return t.filter(n=>n.title.toLowerCase().includes(s)||n.path.toLowerCase().includes(s))},[t,a]),b=x.useMemo(()=>{const s=[];for(const n of g){const c=s.find(k=>k.dir===n.dir);c?c.files.push(n):s.push({dir:n.dir,files:[n]})}return s.sort((n,c)=>n.dir===""?-1:c.dir===""?1:n.dir.localeCompare(c.dir))},[g]);x.useEffect(()=>{if(!l&&t.length){const s=t.find(n=>n.path.toLowerCase()==="index.md");f((s==null?void 0:s.path)??t[0].path)}},[t,l]),x.useEffect(()=>{l&&(i(!0),L(`/api/wissen/datei?pfad=${encodeURIComponent(l)}`).then(r).catch(()=>r({path:l,content:"*(Notiz nicht ladbar)*",mtime:0})).finally(()=>i(!1)))},[l]);const j=s=>{const n=m.get(s.toLowerCase());n&&f(n)};return e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text font-space text-2xl font-bold tracking-tight text-transparent",children:"Wissen"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Was sich die Box nachts erschließt — Traum-Notizen, Muster und Skill-Ideen aus dem Wissens-Vault, verlinkt wie ein Wiki."})]}),o&&!o.available&&e.jsx("div",{className:"rounded-2xl border border-amber-500/30 bg-amber-500/5 p-4 text-xs text-amber-300",children:"Der Wissens-Vault liegt auf der Box (~/wissens-vault) — im lokalen Dev-Modus nicht verfügbar."}),h&&e.jsxs("div",{className:"flex items-center gap-2 rounded-2xl border border-border/60 bg-card/30 p-6 text-xs text-muted-foreground",children:[e.jsx(v,{className:"h-4 w-4 animate-spin"})," Vault wird geladen …"]}),(o==null?void 0:o.available)&&t.length===0&&e.jsx("div",{className:"rounded-2xl border border-dashed border-border/60 bg-card/20 p-8 text-center text-xs text-muted-foreground",children:"Noch keine Notizen. Der nächtliche Traum (03:15) legt sie an — morgen früh steht hier die erste."}),t.length>0&&e.jsxs("div",{className:"flex flex-col gap-4 lg:flex-row",children:[e.jsxs("aside",{className:"w-full shrink-0 space-y-3 lg:w-72",children:[e.jsxs("div",{className:"relative",children:[e.jsx("input",{value:a,onChange:s=>p(s.target.value),type:"search",placeholder:"Notizen durchsuchen…","aria-label":"Notizen durchsuchen",className:"h-9 w-full rounded-lg border border-border/60 bg-card/45 pl-8 pr-3 text-xs text-foreground outline-none focus:ring-1 focus:ring-primary/50"}),e.jsx(S,{className:"absolute left-2.5 top-2.5 h-3.5 w-3.5 text-muted-foreground"})]}),e.jsx("div",{className:"max-h-[70vh] space-y-3 overflow-y-auto pr-1 scrollbar-thin",children:b.map(({dir:s,files:n})=>e.jsxs("div",{children:[e.jsxs("p",{className:"mb-1 flex items-center gap-1 text-[10px] font-bold uppercase tracking-wider text-muted-foreground/60",children:[e.jsx(M,{className:"h-3 w-3"})," ",D[s]??s]}),e.jsx("div",{className:"space-y-0.5",children:n.map(c=>e.jsxs("button",{onClick:()=>f(c.path),className:w("flex w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left text-xs transition-all cursor-pointer",l===c.path?"bg-primary/15 text-primary":"text-muted-foreground hover:bg-accent hover:text-foreground"),children:[e.jsx(W,{className:"h-3.5 w-3.5 shrink-0"}),e.jsx("span",{className:"truncate",title:c.title,children:c.name}),c.neu&&e.jsxs("span",{className:"ml-auto flex items-center gap-0.5 rounded bg-violet-500/15 px-1 py-0.5 text-[8px] font-bold uppercase text-violet-300",children:[e.jsx(C,{className:"h-2.5 w-2.5"}),"neu"]})]},c.path))})]},s||"__root"))})]}),e.jsx("div",{className:"min-w-0 flex-1 mc-card p-5",children:u?e.jsxs("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[e.jsx(v,{className:"h-4 w-4 animate-spin"})," Notiz wird geladen …"]}):d?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between border-b border-border/40 pb-2",children:[e.jsxs("span",{className:"flex items-center gap-1.5 font-mono text-[11px] text-muted-foreground",children:[e.jsx(E,{className:"h-3.5 w-3.5"})," ",d.path]}),d.mtime>0&&e.jsxs("span",{className:"text-[10px] text-muted-foreground/60",children:["Stand ",new Date(d.mtime*1e3).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",hour:"2-digit",minute:"2-digit"})]})]}),e.jsx(z,{text:d.content,onWikiLink:j,known:m})]}):null})]})]})}function z({text:o,onWikiLink:h,known:l}){const f=o.split(`
|
||||
import{aj as y,r as x,g as L,j as e,L as v,S,ak as W,N as C,e as w,al as E}from"./index-ClYatDZT.js";import{F as M}from"./folder-open-Birisrv_.js";const D={"":"Allgemein",traeume:"Träume",muster:"Muster","skill-kandidaten":"Skill-Kandidaten","skill-kandidaten/beauftragt":"Skill-Kandidaten · beauftragt","skill-kandidaten/verworfen":"Skill-Kandidaten · verworfen"};function T(){const{data:o,isLoading:h}=y(),[l,f]=x.useState(null),[d,r]=x.useState(null),[u,i]=x.useState(!1),[a,p]=x.useState(""),t=x.useMemo(()=>(o==null?void 0:o.files)??[],[o]),m=x.useMemo(()=>{const s=new Map;for(const n of t)s.set(n.name.toLowerCase(),n.path);return s},[t]),g=x.useMemo(()=>{if(!a.trim())return t;const s=a.toLowerCase();return t.filter(n=>n.title.toLowerCase().includes(s)||n.path.toLowerCase().includes(s))},[t,a]),b=x.useMemo(()=>{const s=[];for(const n of g){const c=s.find(k=>k.dir===n.dir);c?c.files.push(n):s.push({dir:n.dir,files:[n]})}return s.sort((n,c)=>n.dir===""?-1:c.dir===""?1:n.dir.localeCompare(c.dir))},[g]);x.useEffect(()=>{if(!l&&t.length){const s=t.find(n=>n.path.toLowerCase()==="index.md");f((s==null?void 0:s.path)??t[0].path)}},[t,l]),x.useEffect(()=>{l&&(i(!0),L(`/api/wissen/datei?pfad=${encodeURIComponent(l)}`).then(r).catch(()=>r({path:l,content:"*(Notiz nicht ladbar)*",mtime:0})).finally(()=>i(!1)))},[l]);const j=s=>{const n=m.get(s.toLowerCase());n&&f(n)};return e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text font-space text-2xl font-bold tracking-tight text-transparent",children:"Wissen"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Was sich die Box nachts erschließt — Traum-Notizen, Muster und Skill-Ideen aus dem Wissens-Vault, verlinkt wie ein Wiki."})]}),o&&!o.available&&e.jsx("div",{className:"rounded-2xl border border-amber-500/30 bg-amber-500/5 p-4 text-xs text-amber-300",children:"Der Wissens-Vault liegt auf der Box (~/wissens-vault) — im lokalen Dev-Modus nicht verfügbar."}),h&&e.jsxs("div",{className:"flex items-center gap-2 rounded-2xl border border-border/60 bg-card/30 p-6 text-xs text-muted-foreground",children:[e.jsx(v,{className:"h-4 w-4 animate-spin"})," Vault wird geladen …"]}),(o==null?void 0:o.available)&&t.length===0&&e.jsx("div",{className:"rounded-2xl border border-dashed border-border/60 bg-card/20 p-8 text-center text-xs text-muted-foreground",children:"Noch keine Notizen. Der nächtliche Traum (03:15) legt sie an — morgen früh steht hier die erste."}),t.length>0&&e.jsxs("div",{className:"flex flex-col gap-4 lg:flex-row",children:[e.jsxs("aside",{className:"w-full shrink-0 space-y-3 lg:w-72",children:[e.jsxs("div",{className:"relative",children:[e.jsx("input",{value:a,onChange:s=>p(s.target.value),type:"search",placeholder:"Notizen durchsuchen…","aria-label":"Notizen durchsuchen",className:"h-9 w-full rounded-lg border border-border/60 bg-card/45 pl-8 pr-3 text-xs text-foreground outline-none focus:ring-1 focus:ring-primary/50"}),e.jsx(S,{className:"absolute left-2.5 top-2.5 h-3.5 w-3.5 text-muted-foreground"})]}),e.jsx("div",{className:"max-h-[70vh] space-y-3 overflow-y-auto pr-1 scrollbar-thin",children:b.map(({dir:s,files:n})=>e.jsxs("div",{children:[e.jsxs("p",{className:"mb-1 flex items-center gap-1 text-[10px] font-bold uppercase tracking-wider text-muted-foreground/60",children:[e.jsx(M,{className:"h-3 w-3"})," ",D[s]??s]}),e.jsx("div",{className:"space-y-0.5",children:n.map(c=>e.jsxs("button",{onClick:()=>f(c.path),className:w("flex w-full items-center gap-1.5 rounded-lg px-2 py-1.5 text-left text-xs transition-all cursor-pointer",l===c.path?"bg-primary/15 text-primary":"text-muted-foreground hover:bg-accent hover:text-foreground"),children:[e.jsx(W,{className:"h-3.5 w-3.5 shrink-0"}),e.jsx("span",{className:"truncate",title:c.title,children:c.name}),c.neu&&e.jsxs("span",{className:"ml-auto flex items-center gap-0.5 rounded bg-violet-500/15 px-1 py-0.5 text-[8px] font-bold uppercase text-violet-300",children:[e.jsx(C,{className:"h-2.5 w-2.5"}),"neu"]})]},c.path))})]},s||"__root"))})]}),e.jsx("div",{className:"min-w-0 flex-1 mc-card p-5",children:u?e.jsxs("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[e.jsx(v,{className:"h-4 w-4 animate-spin"})," Notiz wird geladen …"]}):d?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between border-b border-border/40 pb-2",children:[e.jsxs("span",{className:"flex items-center gap-1.5 font-mono text-[11px] text-muted-foreground",children:[e.jsx(E,{className:"h-3.5 w-3.5"})," ",d.path]}),d.mtime>0&&e.jsxs("span",{className:"text-[10px] text-muted-foreground/60",children:["Stand ",new Date(d.mtime*1e3).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",hour:"2-digit",minute:"2-digit"})]})]}),e.jsx(z,{text:d.content,onWikiLink:j,known:m})]}):null})]})]})}function z({text:o,onWikiLink:h,known:l}){const f=o.split(`
|
||||
`),d=[];let r=[],u=null;const i=a=>{r.length&&(d.push(e.jsx("ul",{className:"mb-3 ml-4 list-disc space-y-1",children:r},a)),r=[])};return f.forEach((a,p)=>{const t=`l${p}`;if(u!==null){a.trimEnd()==="```"?(d.push(e.jsx("pre",{className:"mb-3 overflow-x-auto rounded-xl border border-border/50 bg-background/50 p-3 font-mono text-[11px] leading-relaxed text-foreground/85",children:u.join(`
|
||||
`)},t)),u=null):u.push(a);return}if(a.trimStart().startsWith("```")){i(t),u=[];return}const m=a.trimEnd();if(!m.trim()){i(t);return}const g=m.match(/^(#{1,4})\s+(.*)$/);if(g){i(t);const j=g[1].length,s=j===1?"text-lg font-bold mt-1 mb-3":j===2?"text-base font-bold mt-4 mb-2":"text-sm font-bold mt-3 mb-1.5";d.push(e.jsx("p",{className:w(s,"font-space text-foreground"),children:N(g[2],h,l,t)},t));return}const b=m.match(/^\s*[-*•]\s+(.*)$/);if(b){r.push(e.jsx("li",{className:"text-xs leading-relaxed text-foreground/85",children:N(b[1],h,l,t)},t));return}i(t),d.push(e.jsx("p",{className:"mb-2 text-xs leading-relaxed text-foreground/85",children:N(m,h,l,t)},t))}),i("end"),u!==null&&d.push(e.jsx("pre",{className:"mb-3 overflow-x-auto rounded-xl border border-border/50 bg-background/50 p-3 font-mono text-[11px]",children:u.join(`
|
||||
`)},"code-end")),e.jsx("div",{className:"max-w-3xl",children:d})}function N(o,h,l,f){return o.split(/(\[\[[^\]]+\]\]|\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)/g).map((r,u)=>{const i=`${f}-${u}`,a=r.match(/^\[\[([^\]|]+)(?:\|([^\]]+))?\]\]$/);if(a){const p=a[1].trim(),t=(a[2]??a[1]).trim();return l.has(p.toLowerCase())?e.jsx("button",{onClick:()=>h(p),className:"rounded bg-primary/10 px-1 text-primary underline decoration-primary/40 underline-offset-2 hover:bg-primary/20 cursor-pointer",children:t},i):e.jsx("span",{className:"rounded bg-background/40 px-1 text-muted-foreground",title:"Notiz existiert (noch) nicht",children:t},i)}return r.startsWith("**")&&r.endsWith("**")?e.jsx("b",{className:"font-semibold text-foreground",children:r.slice(2,-2)},i):r.startsWith("*")&&r.endsWith("*")&&r.length>2?e.jsx("i",{children:r.slice(1,-1)},i):r.startsWith("`")&&r.endsWith("`")?e.jsx("code",{className:"rounded bg-background/50 px-1 font-mono text-[11px] text-teal-300",children:r.slice(1,-1)},i):e.jsx("span",{children:r},i)})}export{T as WissenView};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as a}from"./index-CDslgvwS.js";/**
|
||||
import{c as a}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c}from"./index-CDslgvwS.js";/**
|
||||
import{c}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c}from"./index-CDslgvwS.js";/**
|
||||
import{c}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as a}from"./index-CDslgvwS.js";/**
|
||||
import{c as a}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
-1
File diff suppressed because one or more lines are too long
+3
-3
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as t}from"./index-CDslgvwS.js";/**
|
||||
import{c as t}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as a}from"./index-CDslgvwS.js";/**
|
||||
import{c as a}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import{c as a}from"./index-CDslgvwS.js";/**
|
||||
import{c as a}from"./index-ClYatDZT.js";/**
|
||||
* @license lucide-react v0.460.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
Vendored
+2
-2
@@ -7,8 +7,8 @@
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<title>Mission Control 2.0</title>
|
||||
<script type="module" crossorigin src="/assets/index-CDslgvwS.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Bhpy_OBa.css">
|
||||
<script type="module" crossorigin src="/assets/index-ClYatDZT.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Cq_BqGQa.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -507,6 +507,13 @@ export interface IdeenResp {
|
||||
fehler?: string
|
||||
}
|
||||
|
||||
// Ergebnis einer fertigen Queue-Aufgabe (Abschluss-Zusammenfassung des Workers)
|
||||
export interface IdeenErgebnis {
|
||||
available: boolean
|
||||
summary: string
|
||||
result: string
|
||||
}
|
||||
|
||||
// ── Chronik (Timeline aus dem Melde-Briefkasten) ─────────────────────────────
|
||||
export interface ChronikItem {
|
||||
id: number
|
||||
@@ -525,6 +532,7 @@ export interface EigenlebenSkill {
|
||||
id: string
|
||||
name: string
|
||||
kategorie: string | null
|
||||
aktiv: boolean | null // null = nicht ermittelbar (Dev-Modus)
|
||||
beschreibung: string
|
||||
version: string
|
||||
autor: string
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ export interface NavItem {
|
||||
export const NAV: NavItem[] = [
|
||||
{ id: "dashboard", label: "Cockpit", hint: "Deine Box auf einen Blick", icon: LayoutDashboard, group: "Operativ" },
|
||||
{ id: "auftraege", label: "Auftragsbuch", hint: "Vorschläge der Box — annehmen oder ablehnen", icon: Inbox, group: "Operativ" },
|
||||
{ id: "eigenleben", label: "Von allein", hint: "Was die Box selbst gebaut hat — Skills & Bilanz", icon: Sparkles, group: "Operativ" },
|
||||
{ id: "eigenleben", label: "Skills", hint: "Fähigkeiten der Box — aktiv/inaktiv, Herkunft & Vorschlags-Bilanz", icon: Sparkles, group: "Operativ" },
|
||||
{ id: "chronik", label: "Chronik", hint: "Was die Box von allein getan hat + Zeitmaschine", icon: History, group: "Operativ" },
|
||||
{ id: "memory", label: "Gedächtnis", hint: "Geteiltes Memory verwalten", icon: Brain, group: "Wissen" },
|
||||
{ id: "wissen", label: "Wissen", hint: "Lucys Wissens-Vault (Traum-Notizen)", icon: Library, group: "Wissen" },
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useState } from "react"
|
||||
import { useEffect, useState } from "react"
|
||||
import {
|
||||
Inbox, Check, X, GitBranch, FileDiff, Loader2, AlertTriangle, Sparkles,
|
||||
ChevronDown, ChevronRight, Clock, Hammer, RefreshCw, Lightbulb, Send, HelpCircle,
|
||||
ChevronDown, ChevronRight, Clock, ClipboardCheck, Hammer, RefreshCw, Lightbulb, Send, HelpCircle,
|
||||
} from "lucide-react"
|
||||
import { api, type AuftragItem, type IdeenItem, type SkillKandidat } from "@/lib/api"
|
||||
import { api, type AuftragItem, type IdeenErgebnis, type IdeenItem, type SkillKandidat } from "@/lib/api"
|
||||
import { useAuftragsbuch, useIdeen, useIdeenLog, useQueryClient, qk } from "@/lib/queries"
|
||||
import { useDialog } from "@/lib/useDialog"
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -259,7 +259,9 @@ function IdeenSection() {
|
||||
{items.map((it: IdeenItem) => {
|
||||
const ui = IDEEN_STATE[it.status] ?? { label: it.status, cls: "text-muted-foreground border-border/60 bg-background/30" }
|
||||
const isOpen = openLog === it.id
|
||||
const canOpen = it.status === "triage" || it.status === "running"
|
||||
// Aufklappbar: laufende Karten zeigen das Live-Log, FERTIGE das Ergebnis
|
||||
// (User-Wunsch 15.07.: „Dinge werden getestet, ich sehe das Ergebnis nicht").
|
||||
const canOpen = it.status === "triage" || it.status === "running" || it.status === "done"
|
||||
const blocked = it.status === "blocked"
|
||||
const answering = !!busy["ans:" + it.id]
|
||||
return (
|
||||
@@ -283,7 +285,7 @@ function IdeenSection() {
|
||||
{canOpen && (
|
||||
<button
|
||||
onClick={() => setOpenLog(isOpen ? null : it.id)}
|
||||
title="Worker-Log anzeigen"
|
||||
title={it.status === "done" ? "Ergebnis anzeigen" : "Worker-Log anzeigen"}
|
||||
className="shrink-0 rounded-md p-1 text-muted-foreground/60 transition-colors hover:text-foreground cursor-pointer">
|
||||
{isOpen ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronRight className="h-3.5 w-3.5" />}
|
||||
</button>
|
||||
@@ -320,7 +322,7 @@ function IdeenSection() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isOpen && canOpen && (
|
||||
{isOpen && canOpen && it.status !== "done" && (
|
||||
<div className="ml-2 -mt-1">
|
||||
<div className="rounded-lg border border-border/50 bg-background/50 p-2">
|
||||
{logEnabled && logData.isLoading ? (
|
||||
@@ -337,6 +339,8 @@ function IdeenSection() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isOpen && it.status === "done" && <ErgebnisPanel id={it.id} />}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
@@ -351,6 +355,41 @@ function IdeenSection() {
|
||||
)
|
||||
}
|
||||
|
||||
// Ergebnis einer FERTIGEN Queue-Aufgabe: die Abschluss-Zusammenfassung des Workers
|
||||
// (kanban_complete). Lazy — wird erst beim Aufklappen geladen, ändert sich nie mehr.
|
||||
function ErgebnisPanel({ id }: { id: string }) {
|
||||
const [erg, setErg] = useState<IdeenErgebnis | null>(null)
|
||||
const [fehler, setFehler] = useState(false)
|
||||
useEffect(() => {
|
||||
let weg = false
|
||||
api<IdeenErgebnis>(`/api/ideen/${id}/ergebnis`)
|
||||
.then((r) => { if (!weg) setErg(r) })
|
||||
.catch(() => { if (!weg) setFehler(true) })
|
||||
return () => { weg = true }
|
||||
}, [id])
|
||||
const text = erg ? (erg.summary || erg.result) : ""
|
||||
return (
|
||||
<div className="ml-2 -mt-1">
|
||||
<div className="rounded-lg border border-emerald-500/25 bg-emerald-500/5 p-2.5">
|
||||
<p className="mb-1 flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wide text-emerald-300">
|
||||
<ClipboardCheck className="h-3 w-3" /> Ergebnis des Workers
|
||||
</p>
|
||||
{fehler ? (
|
||||
<p className="text-[10px] text-red-400">Ergebnis nicht ladbar</p>
|
||||
) : erg === null ? (
|
||||
<p className="text-[10px] text-muted-foreground animate-pulse">Wird geladen …</p>
|
||||
) : text ? (
|
||||
<p className="max-h-64 overflow-y-auto whitespace-pre-wrap text-xs leading-relaxed text-foreground/85">{text}</p>
|
||||
) : (
|
||||
<p className="text-[10px] text-muted-foreground italic">
|
||||
Der Worker hat keine Abschluss-Zusammenfassung hinterlassen (ältere Karte oder Protokollverstoß).
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function StateBadge({ item }: { item: AuftragItem }) {
|
||||
const st = item.status
|
||||
if (!st) return null
|
||||
|
||||
@@ -53,11 +53,12 @@ export function EigenlebenView() {
|
||||
<div className="space-y-7">
|
||||
<div>
|
||||
<h1 className="bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text font-space text-2xl font-bold tracking-tight text-transparent">
|
||||
Von allein
|
||||
Skills
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Was deine Box selbst geleistet hat: ihre Fähigkeiten (Skills) und was aus ihren Vorschlägen wurde.
|
||||
Das ist derselbe Skill-Satz, mit dem Lucy spricht und die Nacht-Worker arbeiten.
|
||||
Die Fähigkeiten deiner Box — mit Herkunft, Nutzung und ob der Agent sie gerade laden kann
|
||||
(aktiv/inaktiv). Das ist derselbe Skill-Satz, mit dem Lucy spricht und die Nacht-Worker
|
||||
arbeiten. Darunter: was aus den Vorschlägen der Box wurde.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -147,6 +148,18 @@ function SkillKarte({ skill }: { skill: EigenlebenSkill }) {
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="text-sm font-semibold text-foreground">{skill.name}</span>
|
||||
{skill.aktiv === true && (
|
||||
<span className="flex items-center gap-1 rounded bg-emerald-500/10 px-1.5 py-0.5 text-[9px] font-bold text-emerald-300"
|
||||
title="Der Agent kann diesen Skill laden und nutzen.">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400" /> aktiv
|
||||
</span>
|
||||
)}
|
||||
{skill.aktiv === false && (
|
||||
<span className="flex items-center gap-1 rounded bg-zinc-500/10 px-1.5 py-0.5 text-[9px] font-bold text-zinc-400"
|
||||
title="Der Agent kann diesen Skill gerade NICHT laden — Plattform passt nicht (z. B. Apple-Skills auf Linux), Voraussetzungen fehlen oder per Config abgeschaltet.">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-zinc-500" /> inaktiv
|
||||
</span>
|
||||
)}
|
||||
{skill.kategorie && (
|
||||
<span className="rounded bg-background/60 px-1.5 py-0.5 text-[9px] font-semibold text-muted-foreground/80">{skill.kategorie}</span>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user