Konzept nachschaerfen: Rueckmeldung statt nur annehmen-oder-wegwerfen
Nach dem Lesen eines Konzepts gab es bisher nur zwei Wege: "Gefaellt mir" oder archivieren. Der haeufige Fall fehlte komplett — EIN Punkt passt nicht und der Commander hat einen besseren Vorschlag. - POST /api/ideen/nachschaerfen -> konzept_ueberarbeiten(): legt eine neue Idee-Karte an (kein Bau), verkettet an die Quell-Karte, mit dem Wortlaut der Rueckmeldung. Auftrag: bestehendes Konzept lesen, genannte Punkte UND deren Folgewirkungen aendern, Rest stehen lassen, kurzer Haertetest nur auf die geaenderten Teile. Schafft der Vorschlag ein Problem: einbauen UND die Folge sichtbar in die Risiken schreiben — nicht uebergehen, nicht schoenreden. Die neue Fassung geht an DIESELBE Stelle (Repo-Commit bzw. Datei + .bak), so zeigt "Konzept" ueberall den frischen Stand. Beliebig oft wiederholbar, weil die Ueberarbeitung selbst wieder eine Idee-Karte ist. - UI: Rueckmeldefeld direkt unter dem gelesenen Konzept, ueber dem Gefaellt-mir-Weg (der haeufigere Fall gehoert nach oben und offen sichtbar). - SOUL: neuer Sonderfall UEBERARBEITUNG (Schritt 2 entfaellt, kein zweites Repo). Zwei Fehler nebenbei gefunden und behoben: - _wo_liegt(): der Auftrag verwechselte "Repo bekannt" mit "Konzept kommt aus dem Repo". Faellt MC2 auf die lokale Datei zurueck, stand vorher "liegt im Repo als <lokaler Dateiname>" im Auftrag — eine Datei, die es dort nie gab. - SOUL-Regel 4: der Push gilt erst als erledigt, wenn `git ls-remote` ihn BEWEIST. Ein Worker hat am 21.07. genau hier abgekuerzt, Erfolg gemeldet, und das Repo war nachher nicht auffindbar. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,20 @@ def weiterfuehren(body: WeiterIn) -> dict:
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class NachschaerfenIn(BaseModel):
|
||||||
|
id: str
|
||||||
|
hinweis: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/ideen/nachschaerfen")
|
||||||
|
def nachschaerfen(body: NachschaerfenIn) -> dict:
|
||||||
|
"""„Punkt X passt nicht" → Überarbeitungs-Runde am bestehenden Konzept."""
|
||||||
|
res = ideen.konzept_ueberarbeiten(body.id, body.hinweis)
|
||||||
|
if not res.get("ok"):
|
||||||
|
raise HTTPException(400, res.get("error", "Überarbeitung konnte nicht gestartet werden."))
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
@router.post("/ideen/archivieren")
|
@router.post("/ideen/archivieren")
|
||||||
def archive(body: TaskIn) -> dict:
|
def archive(body: TaskIn) -> dict:
|
||||||
res = ideen.archive_task(body.id)
|
res = ideen.archive_task(body.id)
|
||||||
|
|||||||
+136
-27
@@ -885,6 +885,52 @@ _AUS_IDEE_FUSS = (
|
|||||||
"· Uebergabe wie ueblich: Repo-URL nennen, damit der Commander in Zed loslegen kann.")
|
"· Uebergabe wie ueblich: Repo-URL nennen, damit der Commander in Zed loslegen kann.")
|
||||||
|
|
||||||
|
|
||||||
|
def _wo_liegt(konz: dict) -> str:
|
||||||
|
"""Eine Zeile: WO das Konzept wirklich liegt — für den Auftrag an den Worker.
|
||||||
|
|
||||||
|
Wichtig ist der Unterschied zwischen „Repo bekannt" und „Konzept KOMMT aus dem Repo":
|
||||||
|
findet die Repo-Datei nicht statt (Push verpufft, Datei anders benannt), liest MC2 die
|
||||||
|
lokale Fassung. Wer dann trotzdem „liegt im Repo als <lokaler Dateiname>" in den Auftrag
|
||||||
|
schreibt, schickt den Worker auf eine Datei, die es dort nie gab.
|
||||||
|
"""
|
||||||
|
repo, pfad = konz.get("repo"), konz.get("pfad")
|
||||||
|
url = konz.get("clone_url") or (f"https://{_GITEA_HOST}/{repo}.git" if repo else "")
|
||||||
|
if konz.get("quelle") == "repo":
|
||||||
|
return (f"Das gepruefte Konzept liegt im Gitea-Repo `{repo}` ({url}) "
|
||||||
|
f"als `{konz.get('datei') or 'KONZEPT.md'}`.")
|
||||||
|
if repo:
|
||||||
|
return (f"Das gepruefte Konzept liegt als Datei `{pfad}` auf dieser Box. Zur Idee gehoert "
|
||||||
|
f"bereits das Gitea-Repo `{repo}` ({url}) — dort ist das Konzept aber NICHT (mehr) "
|
||||||
|
"abrufbar. Pruefe das Repo, bevor du etwas anlegst.")
|
||||||
|
return f"Das gepruefte Konzept liegt als Datei `{pfad}` auf dieser Box."
|
||||||
|
|
||||||
|
|
||||||
|
def _konzept_und_name(task_id: str) -> tuple:
|
||||||
|
"""(Konzept-Daten, kurzer Anzeige-Name, Fehlertext) einer Idee-Karte.
|
||||||
|
|
||||||
|
Der Kartentitel ist der ROHE Zuruf des Commanders („Recherchiere zu … Lass ma…") —
|
||||||
|
als Name unbrauchbar. Die Ueberschrift des Konzepts ist die aufgeraeumte Fassung
|
||||||
|
derselben Sache; nur wenn es keine gibt, den Zuruf kappen.
|
||||||
|
"""
|
||||||
|
konz = konzept_of(task_id)
|
||||||
|
if not konz.get("konzept"):
|
||||||
|
return {}, "", (konz.get("error")
|
||||||
|
or "Zu dieser Idee gibt es noch kein Konzept — erst durchdenken lassen.")
|
||||||
|
try:
|
||||||
|
r = _hermes(["show", task_id, "--json"], timeout=30)
|
||||||
|
d = _parse_json(r.stdout)
|
||||||
|
except Exception as exc:
|
||||||
|
return {}, "", f"Karte nicht lesbar: {exc}"
|
||||||
|
t = (d.get("task") if isinstance(d, dict) and isinstance(d.get("task"), dict)
|
||||||
|
else d if isinstance(d, dict) else {})
|
||||||
|
quell_titel = _TITEL_PRAEFIX_RX.sub("", str(t.get("title") or "").strip())
|
||||||
|
if not quell_titel:
|
||||||
|
return {}, "", "Quell-Karte hat keinen Titel."
|
||||||
|
h1 = re.search(r"^#\s+(.+)$", konz["konzept"], re.M)
|
||||||
|
kurz = h1.group(1).strip() if h1 else re.split(r"(?<=[.!?])\s", quell_titel)[0]
|
||||||
|
return konz, _kurz(kurz, 85), ""
|
||||||
|
|
||||||
|
|
||||||
def projekt_aus_idee(task_id: str, ziel: str = "", tiefe: str = "") -> dict:
|
def projekt_aus_idee(task_id: str, ziel: str = "", tiefe: str = "") -> dict:
|
||||||
"""Aus einer fertig durchdachten Idee eine IDE-Projekt-Karte machen.
|
"""Aus einer fertig durchdachten Idee eine IDE-Projekt-Karte machen.
|
||||||
|
|
||||||
@@ -897,39 +943,20 @@ def projekt_aus_idee(task_id: str, ziel: str = "", tiefe: str = "") -> dict:
|
|||||||
if not _TASK_ID_RX.match(task_id or ""):
|
if not _TASK_ID_RX.match(task_id or ""):
|
||||||
return {"ok": False, "error": f"Keine gültige Aufgaben-Nummer: {task_id!r}"}
|
return {"ok": False, "error": f"Keine gültige Aufgaben-Nummer: {task_id!r}"}
|
||||||
|
|
||||||
konz = konzept_of(task_id)
|
konz, kurz, fehler = _konzept_und_name(task_id)
|
||||||
if not konz.get("konzept"):
|
if fehler:
|
||||||
return {"ok": False, "error": konz.get("error")
|
return {"ok": False, "error": fehler}
|
||||||
or "Zu dieser Idee gibt es noch kein Konzept — erst durchdenken lassen."}
|
|
||||||
|
|
||||||
try:
|
|
||||||
r = _hermes(["show", task_id, "--json"], timeout=30)
|
|
||||||
d = _parse_json(r.stdout)
|
|
||||||
except Exception as exc:
|
|
||||||
return {"ok": False, "error": f"Karte nicht lesbar: {exc}"}
|
|
||||||
t = (d.get("task") if isinstance(d, dict) and isinstance(d.get("task"), dict)
|
|
||||||
else d if isinstance(d, dict) else {})
|
|
||||||
quell_titel = re.sub(r"^\s*Idee\s*[:\-–]\s*", "", str(t.get("title") or "").strip())
|
|
||||||
if not quell_titel:
|
|
||||||
return {"ok": False, "error": "Quell-Karte hat keinen Titel."}
|
|
||||||
# Der Kartentitel ist der ROHE Zuruf des Commanders („Recherchiere zu … Lass ma…") —
|
|
||||||
# als Projektname unbrauchbar. Die Ueberschrift des Konzepts ist die aufgeraeumte
|
|
||||||
# Fassung derselben Sache; nur wenn es keine gibt, den Zuruf kappen.
|
|
||||||
h1 = re.search(r"^#\s+(.+)$", konz["konzept"], re.M)
|
|
||||||
kurz = h1.group(1).strip() if h1 else re.split(r"(?<=[.!?])\s", quell_titel)[0]
|
|
||||||
kurz = (kurz[:85].rstrip() + "…") if len(kurz) > 86 else kurz
|
|
||||||
titel = f"Projekt: {kurz}"[:200]
|
titel = f"Projekt: {kurz}"[:200]
|
||||||
|
|
||||||
if konz.get("repo"):
|
if konz.get("repo"):
|
||||||
# Liegt das Konzept schon in einem Gitea-Repo, ist DAS das Projekt-Repo —
|
# Liegt das Konzept schon in einem Gitea-Repo, ist DAS das Projekt-Repo —
|
||||||
# ein zweites anzulegen wuerde den Commander nur mit Dubletten beschenken.
|
# ein zweites anzulegen wuerde den Commander nur mit Dubletten beschenken.
|
||||||
quelle = (f"· Das gepruefte Konzept liegt bereits im Gitea-Repo `{konz['repo']}` "
|
quelle = (f"· {_wo_liegt(konz)}\n"
|
||||||
f"({konz.get('clone_url') or ''}) als `{konz.get('datei') or 'KONZEPT.md'}`. "
|
f"· NUTZE GENAU DIESES REPO als Projekt-Repo — lege KEIN neues an (Schritt 2 "
|
||||||
"NUTZE GENAU DIESES REPO als Projekt-Repo — lege KEIN neues an (Schritt 2 "
|
|
||||||
"entfaellt). Klone es voll, ergaenze die fehlenden Doku-Dateien und pushe auf main.")
|
"entfaellt). Klone es voll, ergaenze die fehlenden Doku-Dateien und pushe auf main.")
|
||||||
else:
|
else:
|
||||||
quelle = (f"· Das gepruefte Konzept liegt als Datei `{konz.get('pfad')}` auf dieser Box. "
|
quelle = (f"· {_wo_liegt(konz)}\n"
|
||||||
"Lies sie vollstaendig, lege dann wie in Schritt 2 ein frisches Repo an und "
|
"· Lies es vollstaendig, lege dann wie in Schritt 2 ein frisches Repo an und "
|
||||||
"uebernimm den Inhalt als `KONZEPT.md`.")
|
"uebernimm den Inhalt als `KONZEPT.md`.")
|
||||||
|
|
||||||
zielwahl = _ZIEL.get(str(ziel).lower())
|
zielwahl = _ZIEL.get(str(ziel).lower())
|
||||||
@@ -955,7 +982,7 @@ def projekt_aus_idee(task_id: str, ziel: str = "", tiefe: str = "") -> dict:
|
|||||||
_list_cache["ts"] = 0.0
|
_list_cache["ts"] = 0.0
|
||||||
try:
|
try:
|
||||||
from services import announce
|
from services import announce
|
||||||
announce.add(f"Aus der Idee „{_kurz(quell_titel, 60)}“ wird ein Projekt: {task['id']} — die Box "
|
announce.add(f"Aus der Idee „{_kurz(kurz, 60)}“ wird ein Projekt: {task['id']} — die Box "
|
||||||
"bereitet das Repo vor, gebaut wird in Zed.",
|
"bereitet das Repo vor, gebaut wird in Zed.",
|
||||||
"[Ideen-Queue]", "ideen-queue", "silent")
|
"[Ideen-Queue]", "ideen-queue", "silent")
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -963,6 +990,88 @@ def projekt_aus_idee(task_id: str, ziel: str = "", tiefe: str = "") -> dict:
|
|||||||
return {"ok": True, "id": task["id"], "titel": titel}
|
return {"ok": True, "id": task["id"], "titel": titel}
|
||||||
|
|
||||||
|
|
||||||
|
# ── „So nicht" — Konzept mit Rueckmeldung ueberarbeiten lassen (21.07.) ──────
|
||||||
|
# Vorher gab es nach dem Lesen nur annehmen oder wegwerfen. Ein Konzept wird aber
|
||||||
|
# selten beim ersten Wurf richtig: der Commander sieht EINEN Punkt, der nicht passt.
|
||||||
|
# Die Ueberarbeitung ist wieder eine Idee-Karte (kein Bau) und schreibt die neue
|
||||||
|
# Fassung an DIESELBE Stelle — so zeigt „Konzept" ueberall den frischen Stand.
|
||||||
|
_UEBERARBEITEN_KOPF = (
|
||||||
|
"AUFTRAGS-ART: IDEE PRUEFEN — UEBERARBEITUNG. Es gibt bereits ein durchdachtes, "
|
||||||
|
"gehaertetes Konzept. Der Commander hat es GELESEN und will gezielte Aenderungen. "
|
||||||
|
"KEIN Projektstart, KEIN Bau, KEIN Geruest.")
|
||||||
|
_UEBERARBEITEN_FUSS = (
|
||||||
|
"· Arbeite die Rueckmeldung EIN: lies das bestehende Konzept vollstaendig, aendere die "
|
||||||
|
"genannten Punkte und alles, was dadurch nicht mehr stimmt (Folgewirkungen!). Denk das "
|
||||||
|
"Ganze NICHT von vorn — was er nicht angesprochen hat, bleibt.\n"
|
||||||
|
"· Nimm seinen Vorschlag ernst, aber sei ehrlich: schafft er ein Problem, dann bau ihn ein "
|
||||||
|
"UND schreib die Folge sichtbar ins Konzept (Abschnitt Risiken/offene Punkte). Setz dich "
|
||||||
|
"nicht stillschweigend darueber hinweg und rede es auch nicht schoen.\n"
|
||||||
|
"· Ein KURZER Haertetest (Advocatus Diaboli) NUR auf die geaenderten Teile reicht — die "
|
||||||
|
"volle Kaskade ist Verschwendung, der Rest ist bereits geprueft.\n"
|
||||||
|
"· Uebergabe: was du geaendert hast, was daraus folgte und was du bewusst gelassen hast.")
|
||||||
|
|
||||||
|
|
||||||
|
def konzept_ueberarbeiten(task_id: str, hinweis: str) -> dict:
|
||||||
|
"""Rueckmeldung zum Konzept → neue Idee-Karte, die das Konzept ueberarbeitet.
|
||||||
|
|
||||||
|
Haengt als Kind an der Quell-Karte (Kette im Auftragsbuch) und schreibt die neue
|
||||||
|
Fassung an dieselbe Stelle wie die alte (Repo bzw. Datei).
|
||||||
|
"""
|
||||||
|
if not _available():
|
||||||
|
return {"ok": False, "error": "Die Ideen-Queue lebt auf der Box."}
|
||||||
|
if not _TASK_ID_RX.match(task_id or ""):
|
||||||
|
return {"ok": False, "error": f"Keine gültige Aufgaben-Nummer: {task_id!r}"}
|
||||||
|
hinweis = (hinweis or "").strip()
|
||||||
|
if not (3 <= len(hinweis) <= 2000):
|
||||||
|
return {"ok": False, "error": "Bitte schreib zwischen 3 und 2000 Zeichen, was anders werden soll."}
|
||||||
|
|
||||||
|
konz, kurz, fehler = _konzept_und_name(task_id)
|
||||||
|
if fehler:
|
||||||
|
return {"ok": False, "error": fehler}
|
||||||
|
|
||||||
|
if konz.get("quelle") == "repo":
|
||||||
|
quelle = (f"· {_wo_liegt(konz)}\n"
|
||||||
|
"· Die NEUE FASSUNG gehoert an dieselbe Stelle: Repo voll klonen, die Datei "
|
||||||
|
"ueberschreiben, committen und auf main pushen (Push mit `git ls-remote origin main` "
|
||||||
|
"BEWEISEN, nicht annehmen). KEIN neues Repo anlegen — der Commander vergleicht die "
|
||||||
|
"Fassungen ueber die Git-Historie.")
|
||||||
|
else:
|
||||||
|
quelle = (f"· {_wo_liegt(konz)}\n"
|
||||||
|
"· Die NEUE FASSUNG gehoert an dieselbe Stelle. Sichere die alte Fassung vorher "
|
||||||
|
"als `<datei>.bak`, dann schreib die ueberarbeitete Fassung in die Originaldatei."
|
||||||
|
+ (" Gibt es das genannte Repo wirklich, gehoert die neue Fassung ZUSAETZLICH "
|
||||||
|
"als `KONZEPT.md` hinein (klonen, schreiben, pushen, Push beweisen)."
|
||||||
|
if konz.get("repo") else ""))
|
||||||
|
|
||||||
|
teile = [f"{_UEBERARBEITEN_KOPF}\n{quelle}\n"
|
||||||
|
f"· SO SOLL ES ANDERS WERDEN — Wortlaut des Commanders:\n „{hinweis}“\n"
|
||||||
|
f"{_UEBERARBEITEN_FUSS}",
|
||||||
|
_INFRA_LXC]
|
||||||
|
titel = f"Konzept nachschärfen: {kurz}"[:200]
|
||||||
|
args = ["create", titel, "--body", "\n\n".join(teile)[:4000], "--assignee", "projektstart",
|
||||||
|
"--parent", task_id, "--created-by", "mc2-ui", "--json"]
|
||||||
|
try:
|
||||||
|
r = _hermes(args)
|
||||||
|
except Exception as exc:
|
||||||
|
return {"ok": False, "error": f"Queue nicht erreichbar: {exc}"}
|
||||||
|
task = _parse_json(r.stdout)
|
||||||
|
if r.returncode != 0 or not isinstance(task, dict) or not task.get("id"):
|
||||||
|
return {"ok": False,
|
||||||
|
"error": (r.stderr or r.stdout or "kanban create fehlgeschlagen").strip()[:300]}
|
||||||
|
# Die alte Fassung wird ueberschrieben → gecachtes Konzept der Quell-Karte verwerfen,
|
||||||
|
# sonst zeigt die alte Karte nach der Ueberarbeitung noch tagelang den alten Stand.
|
||||||
|
_konzept_cache.pop(task_id, None)
|
||||||
|
_list_cache["ts"] = 0.0
|
||||||
|
try:
|
||||||
|
from services import announce
|
||||||
|
announce.add(f"Konzept „{_kurz(kurz, 60)}“ wird nachgeschärft ({task['id']}): "
|
||||||
|
f"„{_kurz(hinweis, 120)}“",
|
||||||
|
"[Ideen-Queue]", "ideen-queue", "silent")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return {"ok": True, "id": task["id"], "titel": titel}
|
||||||
|
|
||||||
|
|
||||||
def log_of(task_id: str) -> dict:
|
def log_of(task_id: str) -> dict:
|
||||||
"""Worker-Log einer Idee (hermes kanban log <id>), ANSI entfernt, letzte ~120 Zeilen."""
|
"""Worker-Log einer Idee (hermes kanban log <id>), ANSI entfernt, letzte ~120 Zeilen."""
|
||||||
if not _available():
|
if not _available():
|
||||||
|
|||||||
@@ -81,6 +81,19 @@ DURCHDACHT haben — er hat sich NICHT entschieden, sie zu bauen. Dann gilt abwe
|
|||||||
- Schritt 4 (Uebergabe) NICHT als Bau-Aufforderung: sag, was die Idee waere, was sie braeuchte und
|
- Schritt 4 (Uebergabe) NICHT als Bau-Aufforderung: sag, was die Idee waere, was sie braeuchte und
|
||||||
was dagegen spricht — und dass die Entscheidung bei ihm liegt. Kein „oeffne in Zed und bau".
|
was dagegen spricht — und dass die Entscheidung bei ihm liegt. Kein „oeffne in Zed und bau".
|
||||||
|
|
||||||
|
## Sonderfall: „UEBERARBEITUNG" (der Commander hat das Konzept gelesen)
|
||||||
|
Steht im Auftrag **`AUFTRAGS-ART: IDEE PRUEFEN — UEBERARBEITUNG`**, existiert das Konzept schon
|
||||||
|
und der Commander will gezielte Änderungen. Dann gilt abweichend:
|
||||||
|
- **Schritt 2 entfällt — lege KEIN neues Repo an.** Der Auftrag nennt die Stelle, an der das
|
||||||
|
Konzept liegt (Repo oder Datei); die neue Fassung gehört an **genau dieselbe Stelle**. Ein
|
||||||
|
zweites Repo für dieselbe Idee ist ein Fehlschlag.
|
||||||
|
- Schritt 1 schrumpft: lies das bestehende Konzept, ändere die genannten Punkte **und deren
|
||||||
|
Folgewirkungen**, lass den Rest stehen. Ein kurzer Härtetest nur auf die geänderten Teile.
|
||||||
|
- Sein Vorschlag hat Vorrang, aber nicht blind: schafft er ein Problem, bau ihn ein **und**
|
||||||
|
schreib die Folge sichtbar in den Abschnitt Risiken/offene Punkte. Nicht stillschweigend
|
||||||
|
übergehen, nicht schönreden.
|
||||||
|
- Übergabe: was geändert wurde, was daraus folgte, was du bewusst gelassen hast.
|
||||||
|
|
||||||
## Eiserne Regeln (nicht verhandelbar)
|
## Eiserne Regeln (nicht verhandelbar)
|
||||||
1. **Du baust KEINEN Code.** Kein Gerüst, keine `package.json`, keine Quelldateien. Nur die
|
1. **Du baust KEINEN Code.** Kein Gerüst, keine `package.json`, keine Quelldateien. Nur die
|
||||||
Doku-Dateien aus Schritt 3. Wer Code schreibt, hat die Aufgabe verfehlt.
|
Doku-Dateien aus Schritt 3. Wer Code schreibt, hat die Aufgabe verfehlt.
|
||||||
@@ -89,6 +102,11 @@ DURCHDACHT haben — er hat sich NICHT entschieden, sie zu bauen. Dann gilt abwe
|
|||||||
Auftrag ein bestehendes Repo als Vorbild genannt ist, nur LESEN, nie hineinschreiben.)
|
Auftrag ein bestehendes Repo als Vorbild genannt ist, nur LESEN, nie hineinschreiben.)
|
||||||
3. **Jede Rollen-Stimme des Konzepts kommt aus `worker.sh` an heavy** — nie selbst ausgedacht.
|
3. **Jede Rollen-Stimme des Konzepts kommt aus `worker.sh` an heavy** — nie selbst ausgedacht.
|
||||||
4. **Kein `git init`, kein Shallow-Clone.** Immer voll klonen (Credentials in `~/.git-credentials`).
|
4. **Kein `git init`, kein Shallow-Clone.** Immer voll klonen (Credentials in `~/.git-credentials`).
|
||||||
|
**Der Push gilt erst als erledigt, wenn `git ls-remote origin main` ihn BEWEIST** — ein Exit-Code
|
||||||
|
0 und „main -> main" auf dem Bildschirm reichen nicht. Ohne diesen Beleg kein `kanban_complete`;
|
||||||
|
melde stattdessen ehrlich, dass der Push unbestätigt ist. (Am 21.07. hat ein Worker genau hier
|
||||||
|
abgekürzt, „Push erfolgreich" gemeldet — und das Repo war nachher nicht auffindbar. Der
|
||||||
|
Commander stand vor einer Übergabe ins Leere.)
|
||||||
5. **TABU-Zonen:** approvals/Tokens/ufw/Security-Configs, `~/.hermes/config.yaml`, systemd-Units.
|
5. **TABU-Zonen:** approvals/Tokens/ufw/Security-Configs, `~/.hermes/config.yaml`, systemd-Units.
|
||||||
Braucht der Auftrag so etwas → `kanban_block` mit Begründung.
|
Braucht der Auftrag so etwas → `kanban_block` mit Begründung.
|
||||||
6. **Festfahren-Stopp:** Bleibt das Konzept nach den Runden mit echten Blockern offen (widersprüchliche
|
6. **Festfahren-Stopp:** Bleibt das Konzept nach den Runden mit echten Blockern offen (widersprüchliche
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as A,Y as P,l as B,b as M,u as D,r as z,j as e,Z as T,e as a,$ as g,a0 as b,a1 as W,x as f,a2 as j,W as G,X as I,C as N,g as y,q as i}from"./index-BIxEIVk4.js";/**
|
import{c as A,Y as P,l as B,b as M,u as D,r as z,j as e,Z as T,e as a,$ as g,a0 as b,a1 as W,x as f,a2 as j,W as G,X as I,C as N,g as y,q as i}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* 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
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as m,ag as S,r as c,j as e,ah as z,L as g,U as M,ai as C,ad as D,aj as A,ak as B,al as Z,e as E,am as L,u as R,b as q,g as k,q as T}from"./index-BIxEIVk4.js";import{R as j}from"./rotate-ccw-BUzBp8lK.js";/**
|
import{c as m,ag as S,r as c,j as e,ah as z,L as g,U as M,ai as C,ad as D,aj as A,ak as B,al as Z,e as E,am as L,u as R,b as q,g as k,q as T}from"./index-DZ34eLRy.js";import{R as j}from"./rotate-ccw-DRxIaGHA.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as v,r as c,I,J as A,j as e,K as h,x as B,B as H,D as E,M as z,e as M,L as T,N as F,C as K}from"./index-BIxEIVk4.js";import{F as O}from"./folder-open-BNUNFCZC.js";import{C as R}from"./circle-x-CoImx1bc.js";import{C as W}from"./copy-KeB1XKMX.js";/**
|
import{c as v,r as c,I,J as A,j as e,K as h,x as B,B as H,D as E,M as z,e as M,L as T,N as F,C as K}from"./index-DZ34eLRy.js";import{F as O}from"./folder-open-Bb3HvkQd.js";import{C as R}from"./circle-x-Cw3-1mKp.js";import{C as W}from"./copy-aWlMWseD.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as h,an as b,r as i,j as e,L as g,ao as f,a2 as j,U as k,e as o,D as N,M as v,N as w,g as y}from"./index-BIxEIVk4.js";import{B as S}from"./book-open-ypkLMas8.js";import{C as z}from"./circle-x-CoImx1bc.js";/**
|
import{c as h,an as b,r as i,j as e,L as g,ao as f,a2 as j,U as k,e as o,D as N,M as v,N as w,g as y}from"./index-DZ34eLRy.js";import{B as S}from"./book-open-C27V5HRN.js";import{C as z}from"./circle-x-Cw3-1mKp.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+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,x as C,a6 as z,a7 as k,a8 as y,a0 as v,W as L,a9 as G,a2 as T,e as f,U as D}from"./index-BIxEIVk4.js";import{B as w}from"./book-open-ypkLMas8.js";import{a as N,L as B,C as P,Z as E}from"./zap-Yspf4acb.js";import{L as R}from"./layers-DKhggjLr.js";import{L as I}from"./lightbulb-DoLJF3FP.js";/**
|
import{c as p,j as e,r as M,x as C,a6 as z,a7 as k,a8 as y,a0 as v,W as L,a9 as G,a2 as T,e as f,U as D}from"./index-DZ34eLRy.js";import{B as w}from"./book-open-C27V5HRN.js";import{a as N,L as B,C as P,Z as E}from"./zap-BXgwt99q.js";import{L as R}from"./layers-a89ag0RB.js";import{L as I}from"./lightbulb-CUD1a5ov.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
import{Y as b,u as f,$ as h,r as d,j as e,e as c,Z as g,T as p,a3 as j,a4 as N,g as v,a5 as w,q as x}from"./index-BIxEIVk4.js";function y(){const{data:s}=b(),m=f(),r=s!=null&&s.box_console_url?h(s.box_console_url):void 0,a=s==null?void 0:s.box_console_reachable,[l,o]=d.useState(!1),[i,n]=d.useState("");async function u(){o(!0),n("");try{const t=await v("/api/maintenance/restart",{method:"POST",body:JSON.stringify({service:"box-console"})});n(t.ok?"Neu gestartet — einen Moment, dann lädt das Terminal.":`Fehlgeschlagen: ${t.err||"Unbekannter Fehler"}`),w(m,x.agentStatus,x.services)}catch(t){n(`Fehlgeschlagen: ${(t==null?void 0:t.message)||t}`)}finally{o(!1)}}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:c("h-2 w-2 rounded-full",a?"bg-emerald-500 animate-pulse":"bg-amber-500")}),a?"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(g,{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:[a===!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(p,{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 Terminal-Dienst (",e.jsx("code",{className:"font-mono text-primary",children:"box-console"}),") läuft gerade nicht."]}),e.jsxs("button",{onClick:u,disabled:l,className:"flex h-9 items-center gap-1.5 rounded-lg border border-amber-500/40 bg-amber-500/10 px-4 text-[11px] font-bold uppercase tracking-wide text-amber-300 transition-all hover:bg-amber-500/20 cursor-pointer disabled:opacity-50",children:[e.jsx(j,{className:c("h-3.5 w-3.5",l&&"animate-spin")})," Dienst neu starten"]}),i&&e.jsx("p",{className:"max-w-sm text-[11px] text-muted-foreground",children:i})]}),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(N,{className:"mr-2 h-4 w-4"})," Lade Konsole…"]})]})}export{y as KonsoleView};
|
import{Y as b,u as f,$ as h,r as d,j as e,e as c,Z as g,T as p,a3 as j,a4 as N,g as v,a5 as w,q as x}from"./index-DZ34eLRy.js";function y(){const{data:s}=b(),m=f(),r=s!=null&&s.box_console_url?h(s.box_console_url):void 0,a=s==null?void 0:s.box_console_reachable,[l,o]=d.useState(!1),[i,n]=d.useState("");async function u(){o(!0),n("");try{const t=await v("/api/maintenance/restart",{method:"POST",body:JSON.stringify({service:"box-console"})});n(t.ok?"Neu gestartet — einen Moment, dann lädt das Terminal.":`Fehlgeschlagen: ${t.err||"Unbekannter Fehler"}`),w(m,x.agentStatus,x.services)}catch(t){n(`Fehlgeschlagen: ${(t==null?void 0:t.message)||t}`)}finally{o(!1)}}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:c("h-2 w-2 rounded-full",a?"bg-emerald-500 animate-pulse":"bg-amber-500")}),a?"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(g,{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:[a===!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(p,{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 Terminal-Dienst (",e.jsx("code",{className:"font-mono text-primary",children:"box-console"}),") läuft gerade nicht."]}),e.jsxs("button",{onClick:u,disabled:l,className:"flex h-9 items-center gap-1.5 rounded-lg border border-amber-500/40 bg-amber-500/10 px-4 text-[11px] font-bold uppercase tracking-wide text-amber-300 transition-all hover:bg-amber-500/20 cursor-pointer disabled:opacity-50",children:[e.jsx(j,{className:c("h-3.5 w-3.5",l&&"animate-spin")})," Dienst neu starten"]}),i&&e.jsx("p",{className:"max-w-sm text-[11px] text-muted-foreground",children:i})]}),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(N,{className:"mr-2 h-4 w-4"})," Lade Konsole…"]})]})}export{y as KonsoleView};
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GraphView-WCSGAm2M.js","assets/index-BIxEIVk4.js","assets/index-DvvQb_PK.css"])))=>i.map(i=>d[i]);
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GraphView-CfWXNn-Z.js","assets/index-DZ34eLRy.js","assets/index-CYYdYGeg.css"])))=>i.map(i=>d[i]);
|
||||||
var je=Object.defineProperty;var ke=(d,i,c)=>i in d?je(d,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[i]=c;var J=(d,i,c)=>ke(d,typeof i!="symbol"?i+"":i,c);import{c as h,r as s,j as e,u as ve,b as Ne,O as W,Q as Se,C as X,R as Ce,S as Ee,P as Me,U as O,e as x,V as ze,W as De,X as Z,A as Y,_ as Oe,g as j}from"./index-BIxEIVk4.js";import{C as ee}from"./copy-KeB1XKMX.js";import{S as _e}from"./send-Dl36sWcQ.js";import{B as Ge}from"./book-open-ypkLMas8.js";/**
|
var je=Object.defineProperty;var ke=(d,i,c)=>i in d?je(d,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[i]=c;var J=(d,i,c)=>ke(d,typeof i!="symbol"?i+"":i,c);import{c as h,r as s,j as e,u as ve,b as Ne,O as W,Q as Se,C as X,R as Ce,S as Ee,P as Me,U as O,e as x,V as ze,W as De,X as Z,A as Y,_ as Oe,g as j}from"./index-DZ34eLRy.js";import{C as ee}from"./copy-aWlMWseD.js";import{S as _e}from"./send-DrbIxJOY.js";import{B as Ge}from"./book-open-C27V5HRN.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
@@ -34,7 +34,7 @@ var je=Object.defineProperty;var ke=(d,i,c)=>i in d?je(d,i,{enumerable:!0,config
|
|||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
* See the LICENSE file in the root directory of this source tree.
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
*/const Pe=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 te extends s.Component{constructor(){super(...arguments);J(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 se=s.lazy(()=>Oe(()=>import("./GraphView-WCSGAm2M.js"),__vite__mapDeps([0,1,2])).then(d=>({default:d.GraphView}))),k=["identity","knowledge","rules","events"],v=new Set(["auto","agent","hermes"]),N={identity:{label:"Identität",icon:Pe,bg:"bg-cyan-500/10",text:"text-cyan-400"},knowledge:{label:"Wissen",icon:De,bg:"bg-indigo-500/10",text:"text-indigo-400"},rules:{label:"Regeln",icon:Le,bg:"bg-violet-500/10",text:"text-violet-400"},events:{label:"Ereignisse",icon:ze,bg:"bg-amber-500/10",text:"text-amber-400"}},ne={label:"Gedächtnis",icon:Ge,text:"text-muted-foreground"},Re={identity:"border-l-cyan-500/80",knowledge:"border-l-indigo-500/80",rules:"border-l-violet-500/80",events:"border-l-amber-500/80"},_={identity:"#00f5ff",knowledge:"#3b82f6",rules:"#d946ef",events:"#fbbf24"},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 Pe=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 te extends s.Component{constructor(){super(...arguments);J(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 se=s.lazy(()=>Oe(()=>import("./GraphView-CfWXNn-Z.js"),__vite__mapDeps([0,1,2])).then(d=>({default:d.GraphView}))),k=["identity","knowledge","rules","events"],v=new Set(["auto","agent","hermes"]),N={identity:{label:"Identität",icon:Pe,bg:"bg-cyan-500/10",text:"text-cyan-400"},knowledge:{label:"Wissen",icon:De,bg:"bg-indigo-500/10",text:"text-indigo-400"},rules:{label:"Regeln",icon:Le,bg:"bg-violet-500/10",text:"text-violet-400"},events:{label:"Ereignisse",icon:ze,bg:"bg-amber-500/10",text:"text-amber-400"}},ne={label:"Gedächtnis",icon:Ge,text:"text-muted-foreground"},Re={identity:"border-l-cyan-500/80",knowledge:"border-l-indigo-500/80",rules:"border-l-violet-500/80",events:"border-l-amber-500/80"},_={identity:"#00f5ff",knowledge:"#3b82f6",rules:"#d946ef",events:"#fbbf24"},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,
|
1) wer ich bin und woran ich gerade arbeite,
|
||||||
2) wie ich angesprochen werden möchte,
|
2) wie ich angesprochen werden möchte,
|
||||||
3) meine bevorzugten Tools, Sprachen und Arbeitsweise,
|
3) meine bevorzugten Tools, Sprachen und Arbeitsweise,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as E,u as oe,a as Fe,b as ge,j as e,f as ue,d as Re,e as w,g as K,q as P,h as Ie,r as N,C as Y,L as Oe,i as Pe,B as le,k as Te,E as Be,l as de,m as Ge,n as $e,o as He,p as ee,X as pe,P as Qe,H as fe,T as re,s as Ue,t as Ve,v as V,w as We,S as ye,x as Ze,y as Je,z as Xe,A as Ye,D as De,F as et,G as tt}from"./index-BIxEIVk4.js";import{C as rt}from"./code-xml-CGKbbFs2.js";import{R as st}from"./rotate-ccw-BUzBp8lK.js";import{C as he,Z as ie,L as nt,a as at}from"./zap-Yspf4acb.js";import{L as ot}from"./layers-DKhggjLr.js";/**
|
import{c as E,u as oe,a as Fe,b as ge,j as e,f as ue,d as Re,e as w,g as K,q as P,h as Ie,r as N,C as Y,L as Oe,i as Pe,B as le,k as Te,E as Be,l as de,m as Ge,n as $e,o as He,p as ee,X as pe,P as Qe,H as fe,T as re,s as Ue,t as Ve,v as V,w as We,S as ye,x as Ze,y as Je,z as Xe,A as Ye,D as De,F as et,G as tt}from"./index-DZ34eLRy.js";import{C as rt}from"./code-xml-CCSjVAVc.js";import{R as st}from"./rotate-ccw-DRxIaGHA.js";import{C as he,Z as ie,L as nt,a as at}from"./zap-BXgwt99q.js";import{L as ot}from"./layers-a89ag0RB.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{ap as y,r as x,g as L,j as e,L as v,S,ae as W,U as C,e as w,aq as E}from"./index-BIxEIVk4.js";import{F as M}from"./folder-open-BNUNFCZC.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{ap as y,r as x,g as L,j as e,L as v,S,ae as W,U as C,e as w,aq as E}from"./index-DZ34eLRy.js";import{F as M}from"./folder-open-Bb3HvkQd.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(`
|
`),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(`
|
`)},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};
|
`)},"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-BIxEIVk4.js";/**
|
import{c as a}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c}from"./index-BIxEIVk4.js";/**
|
import{c}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as e}from"./index-BIxEIVk4.js";/**
|
import{c as e}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c}from"./index-BIxEIVk4.js";/**
|
import{c}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as a}from"./index-BIxEIVk4.js";/**
|
import{c as a}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as a}from"./index-BIxEIVk4.js";/**
|
import{c as a}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as t}from"./index-BIxEIVk4.js";/**
|
import{c as t}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as t}from"./index-BIxEIVk4.js";/**
|
import{c as t}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as a}from"./index-BIxEIVk4.js";/**
|
import{c as a}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{c as a}from"./index-BIxEIVk4.js";/**
|
import{c as a}from"./index-DZ34eLRy.js";/**
|
||||||
* @license lucide-react v0.460.0 - ISC
|
* @license lucide-react v0.460.0 - ISC
|
||||||
*
|
*
|
||||||
* This source code is licensed under the ISC license.
|
* This source code is licensed under the ISC license.
|
||||||
Vendored
+2
-2
@@ -7,8 +7,8 @@
|
|||||||
<link rel="manifest" href="/manifest.webmanifest" />
|
<link rel="manifest" href="/manifest.webmanifest" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<title>Mission Control 2.0</title>
|
<title>Mission Control 2.0</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BIxEIVk4.js"></script>
|
<script type="module" crossorigin src="/assets/index-DZ34eLRy.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-DvvQb_PK.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CYYdYGeg.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -734,22 +734,20 @@ function KonzeptPanel({ id, istIdee, onWeiter }: {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// „Gefällt mir" — aus der geprüften Idee ein IDE-Projekt machen. Ohne das war die Idee
|
// Was nach dem Lesen passieren kann. Zwei Wege, bewusst nebeneinander statt hintereinander:
|
||||||
// eine Sackgasse (Titel neu eintippen, Konzept von vorn denken lassen). Die neue Karte
|
// nachschärfen (ein Punkt passt nicht — häufiger Fall, darum oben und offen) oder annehmen.
|
||||||
// bekommt das fertige Konzept als Vorlage und hängt als Kette an der Idee.
|
|
||||||
function WeiterLeiste({ id, onFertig }: { id: string; onFertig?: () => void }) {
|
function WeiterLeiste({ id, onFertig }: { id: string; onFertig?: () => void }) {
|
||||||
const [ziel, setZiel] = useState<"lxc" | "docker">("lxc")
|
const [ziel, setZiel] = useState<"lxc" | "docker">("lxc")
|
||||||
const [tiefe, setTiefe] = useState<"simpel" | "gruendlich">("simpel")
|
const [tiefe, setTiefe] = useState<"simpel" | "gruendlich">("simpel")
|
||||||
const [busy, setBusy] = useState(false)
|
const [busy, setBusy] = useState(false)
|
||||||
const [neu, setNeu] = useState<string | null>(null)
|
const [neu, setNeu] = useState<{ id: string; art: "projekt" | "runde" } | null>(null)
|
||||||
const [fehler, setFehler] = useState("")
|
const [fehler, setFehler] = useState("")
|
||||||
const los = async () => {
|
const [hinweis, setHinweis] = useState("")
|
||||||
|
const ruf = async (pfad: string, rumpf: object, art: "projekt" | "runde") => {
|
||||||
setBusy(true); setFehler("")
|
setBusy(true); setFehler("")
|
||||||
try {
|
try {
|
||||||
const r = await api<{ id: string }>("/api/ideen/weiterfuehren", {
|
const r = await api<{ id: string }>(pfad, { method: "POST", body: JSON.stringify(rumpf) })
|
||||||
method: "POST", body: JSON.stringify({ id, ziel, tiefe }),
|
setNeu({ id: r.id, art })
|
||||||
})
|
|
||||||
setNeu(r.id)
|
|
||||||
onFertig?.()
|
onFertig?.()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
setFehler(String(e?.message || e))
|
setFehler(String(e?.message || e))
|
||||||
@@ -760,16 +758,45 @@ function WeiterLeiste({ id, onFertig }: { id: string; onFertig?: () => void }) {
|
|||||||
if (neu) {
|
if (neu) {
|
||||||
return (
|
return (
|
||||||
<p className="mt-3 border-t border-violet-500/20 pt-2 text-[11px] text-emerald-300">
|
<p className="mt-3 border-t border-violet-500/20 pt-2 text-[11px] text-emerald-300">
|
||||||
Projekt-Karte <span className="font-mono">{neu}</span> ist angelegt — die Box bereitet das
|
{neu.art === "projekt" ? (
|
||||||
Repo vor (Konzept übernimmt sie, sie denkt es nicht neu). Danach öffnest du es in Zed.
|
<>Projekt-Karte <span className="font-mono">{neu.id}</span> ist angelegt — die Box bereitet
|
||||||
|
das Repo vor (Konzept übernimmt sie, sie denkt es nicht neu). Danach öffnest du es in Zed.</>
|
||||||
|
) : (
|
||||||
|
<>Überarbeitung <span className="font-mono">{neu.id}</span> läuft — die Box arbeitet deine
|
||||||
|
Rückmeldung ein und schreibt die neue Fassung an dieselbe Stelle. Danach hier wieder
|
||||||
|
„Konzept" öffnen.</>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="mt-3 space-y-2 border-t border-violet-500/20 pt-2.5">
|
<div className="mt-3 space-y-3 border-t border-violet-500/20 pt-2.5">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<p className="text-[11px] text-muted-foreground">
|
||||||
|
<b className="text-sky-300/90">Passt etwas nicht?</b> Schreib hin, was anders werden soll —
|
||||||
|
die Box arbeitet es ein und lässt den Rest stehen. Beliebig oft wiederholbar.
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input
|
||||||
|
value={hinweis}
|
||||||
|
onChange={(e) => setHinweis(e.target.value)}
|
||||||
|
onKeyDown={(e) => { if (e.key === "Enter" && hinweis.trim().length >= 3 && !busy) ruf("/api/ideen/nachschaerfen", { id, hinweis }, "runde") }}
|
||||||
|
placeholder="z. B. „Punkt 3: kein WebSocket, das ist mir zu fragil — nimm Polling“"
|
||||||
|
maxLength={2000}
|
||||||
|
className="h-8 min-w-0 flex-1 rounded-lg border border-border/60 bg-background/60 px-2.5 text-xs text-foreground placeholder:text-muted-foreground/50 focus:border-sky-400/50 focus:outline-none"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => ruf("/api/ideen/nachschaerfen", { id, hinweis }, "runde")}
|
||||||
|
disabled={busy || hinweis.trim().length < 3}
|
||||||
|
className="flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-sky-500/40 bg-sky-500/10 px-3 text-[10px] font-bold uppercase tracking-wide text-sky-300 transition-all hover:bg-sky-500/20 cursor-pointer disabled:opacity-50">
|
||||||
|
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <RefreshCw className="h-3.5 w-3.5" />}
|
||||||
|
Nachschärfen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<p className="text-[11px] text-muted-foreground">
|
<p className="text-[11px] text-muted-foreground">
|
||||||
Gefällt dir das? Dann macht die Box daraus ein <b className="text-violet-300/90">startklares
|
<b className="text-violet-300/90">Passt es so?</b> Dann macht die Box daraus ein startklares
|
||||||
Repo</b> — Konzept wird übernommen (nicht neu gedacht), dazu Roadmap, AGENTS.md & Co.
|
Repo — Konzept wird übernommen (nicht neu gedacht), dazu Roadmap, AGENTS.md & Co.
|
||||||
Gebaut wird danach von dir in Zed.
|
Gebaut wird danach von dir in Zed.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-2">
|
<div className="flex flex-wrap items-center gap-x-3 gap-y-2">
|
||||||
@@ -798,7 +825,7 @@ function WeiterLeiste({ id, onFertig }: { id: string; onFertig?: () => void }) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={los}
|
onClick={() => ruf("/api/ideen/weiterfuehren", { id, ziel, tiefe }, "projekt")}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
className="ml-auto flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-violet-500/40 bg-violet-500/10 px-3 text-[10px] font-bold uppercase tracking-wide text-violet-300 transition-all hover:bg-violet-500/20 cursor-pointer disabled:opacity-50">
|
className="ml-auto flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-violet-500/40 bg-violet-500/10 px-3 text-[10px] font-bold uppercase tracking-wide text-violet-300 transition-all hover:bg-violet-500/20 cursor-pointer disabled:opacity-50">
|
||||||
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Code2 className="h-3.5 w-3.5" />}
|
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Code2 className="h-3.5 w-3.5" />}
|
||||||
|
|||||||
Reference in New Issue
Block a user