Ideen: zwei Bereiche, drei Karten — Durchdenken nach vorn
Ampel / ampel (push) Successful in 24s

User-Befund, und er trifft einen echten Modellierungsfehler von gestern: "Eine
durchgedachte Idee wird ja sowieso mit meinem Ja zu einem IDE-Repo." Stimmt —
/ideen/weiterfuehren macht aus der durchdachten Idee GENAU die IDE-Projekt-Karte,
die der Repo-Weg direkt anlegt. Es sind zwei Stufen EINES Weges, keine zwei Achsen.

Der Haken von gestern war deshalb falsch: "Die Box, allein" + "nur denken" war
anklickbar, submit() setzte dann aber still welt:"ide" und schob einen in die
Zed-Welt, ohne das zu sagen. Genau die versteckte Umschaltung, die anderswo in
diesem Repo als Fassade gilt.

Jetzt GENAU EINE Auswahl aus drei, in zwei Bereichen:
  Du baust selbst, in Zed   [Erst durchdenken] [Direkt ein Repo]
  Oder die Box macht es     [Die Box baut allein]
Die falsche Kombination ist damit strukturell unmoeglich, nicht nur unwahrscheinlich.

Nebengewinn: beim Durchdenken entfallen Tiefe und Ziel am Eingang. Die
Weiter-Leiste fragt beides ohnehin beim "gefaellt mir" — und dann weiss man, was
das Ding ueberhaupt wird. Vorher entschied man LXC-oder-Docker, bevor ein Konzept
existierte.

Ausgewaehlt ist immer eine KARTE, nie ein Bereich — der Bereich gruppiert nur, was
denselben Weg geht. Voreinstellung ist "Erst durchdenken": die Wahl, die am
wenigsten anlegt. Der Einordner ueberschreibt sie ohnehin in ~500 ms.

API unveraendert; alle drei Abbildungen gegen den alten Vertrag geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-26 00:08:23 +02:00
parent cb649aac34
commit 20d4f40ed9
28 changed files with 187 additions and 159 deletions
@@ -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-DI19YZ2i.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-BITRSHQi.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,4 +1,4 @@
import{c as W,ab as H,ac as T,u as F,b as G,r as b,j as e,a3 as O,e as y,L as p,C as z,a9 as P,K as q,U as I,V,ad as K,X as E,T as C,D as M,M as R,g as $,ae as _,q as U}from"./index-DI19YZ2i.js";import{S,H as Q}from"./SectionLabel-DJ0JNfWI.js";/** import{c as W,ab as H,ac as T,u as F,b as G,r as b,j as e,a3 as O,e as y,L as p,C as z,a9 as P,K as q,U as I,V,ad as K,X as E,T as C,D as M,M as R,g as $,ae as _,q as U}from"./index-BITRSHQi.js";import{S,H as Q}from"./SectionLabel-CxnAJzn3.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,4 +1,4 @@
import{c as m,ai as S,r as c,j as e,aj as z,L as g,U as M,ak as C,ae as D,al as A,am as B,an as Z,e as E,ao as L,u as R,b as q,g as k,q as T}from"./index-DI19YZ2i.js";import{R as j}from"./rotate-ccw-CBUivZG3.js";/** import{c as m,ai as S,r as c,j as e,aj as z,L as g,U as M,ak as C,ae as D,al as A,am as B,an as Z,e as E,ao as L,u as R,b as q,g as k,q as T}from"./index-BITRSHQi.js";import{R as j}from"./rotate-ccw-Bqk2RuMY.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,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-DI19YZ2i.js";import{F as O}from"./folder-open-DKNPWUub.js";import{C as R}from"./circle-x-5Vi9Kek6.js";import{C as W}from"./copy-CsXXFqkj.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-BITRSHQi.js";import{F as O}from"./folder-open-Cf0PzlLv.js";import{C as R}from"./circle-x-BCNcRD6W.js";import{C as W}from"./copy-CxQj3NkO.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,4 +1,4 @@
import{c as h,ap as b,r as i,j as e,L as g,aq 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-DI19YZ2i.js";import{B as S}from"./book-open-CqxVgaj6.js";import{C as z}from"./circle-x-5Vi9Kek6.js";/** import{c as h,ap as b,r as i,j as e,L as g,aq 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-BITRSHQi.js";import{B as S}from"./book-open-DbieW73t.js";import{C as z}from"./circle-x-BCNcRD6W.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
@@ -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,a9 as L,W as G,aa as T,a2 as D,e as f,U as B}from"./index-DI19YZ2i.js";import{B as w}from"./book-open-CqxVgaj6.js";import{a as N,L as P,C as E,Z as R}from"./zap-CVKHAOl9.js";import{L as I}from"./layers-DQdxWFgI.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,a9 as L,W as G,aa as T,a2 as D,e as f,U as B}from"./index-BITRSHQi.js";import{B as w}from"./book-open-DbieW73t.js";import{a as N,L as P,C as E,Z as R}from"./zap-Bie21ltg.js";import{L as I}from"./layers-C0bwoJh5.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
@@ -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-DI19YZ2i.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-BITRSHQi.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};
@@ -1,5 +1,5 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GraphView-JdSE2NmA.js","assets/index-DI19YZ2i.js","assets/index-DLBMFIff.css"])))=>i.map(i=>d[i]); const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GraphView-BroxK768.js","assets/index-BITRSHQi.js","assets/index-DCSDaWJZ.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-DI19YZ2i.js";import{C as ee}from"./copy-CsXXFqkj.js";import{S as _e}from"./send-CpIJWZ5L.js";import{B as Ge}from"./book-open-CqxVgaj6.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-BITRSHQi.js";import{C as ee}from"./copy-CxQj3NkO.js";import{S as _e}from"./send-ByEkObSZ.js";import{B as Ge}from"./book-open-DbieW73t.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-JdSE2NmA.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-BroxK768.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,4 +1,4 @@
import{c as q,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-DI19YZ2i.js";import{C as rt}from"./code-xml-C9b7xGyM.js";import{R as st}from"./rotate-ccw-CBUivZG3.js";import{C as be,Z as ie,L as nt,a as at}from"./zap-CVKHAOl9.js";import{L as ot}from"./layers-DQdxWFgI.js";/** import{c as q,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-BITRSHQi.js";import{C as rt}from"./code-xml-B8Mgduyw.js";import{R as st}from"./rotate-ccw-Bqk2RuMY.js";import{C as be,Z as ie,L as nt,a as at}from"./zap-Bie21ltg.js";import{L as ot}from"./layers-C0bwoJh5.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,4 +1,4 @@
import{c as s,j as e}from"./index-DI19YZ2i.js";/** import{c as s,j as e}from"./index-BITRSHQi.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,4 +1,4 @@
import{ar as y,r as x,g as L,j as e,L as v,S,ag as W,U as C,e as w,as as E}from"./index-DI19YZ2i.js";import{F as M}from"./folder-open-DKNPWUub.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{ar as y,r as x,g as L,j as e,L as v,S,ah as W,U as C,e as w,as as E}from"./index-BITRSHQi.js";import{F as M}from"./folder-open-Cf0PzlLv.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,4 +1,4 @@
import{c as a}from"./index-DI19YZ2i.js";/** import{c as a}from"./index-BITRSHQi.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,4 +1,4 @@
import{c}from"./index-DI19YZ2i.js";/** import{c}from"./index-BITRSHQi.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,4 +1,4 @@
import{c as e}from"./index-DI19YZ2i.js";/** import{c as e}from"./index-BITRSHQi.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,4 +1,4 @@
import{c}from"./index-DI19YZ2i.js";/** import{c}from"./index-BITRSHQi.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,4 +1,4 @@
import{c as a}from"./index-DI19YZ2i.js";/** import{c as a}from"./index-BITRSHQi.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
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
import{c as a}from"./index-DI19YZ2i.js";/** import{c as a}from"./index-BITRSHQi.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,4 +1,4 @@
import{c as t}from"./index-DI19YZ2i.js";/** import{c as t}from"./index-BITRSHQi.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,4 +1,4 @@
import{c as a}from"./index-DI19YZ2i.js";/** import{c as a}from"./index-BITRSHQi.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,4 +1,4 @@
import{c as a}from"./index-DI19YZ2i.js";/** import{c as a}from"./index-BITRSHQi.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.
+2 -2
View File
@@ -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-DI19YZ2i.js"></script> <script type="module" crossorigin src="/assets/index-BITRSHQi.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DLBMFIff.css"> <link rel="stylesheet" crossorigin href="/assets/index-DCSDaWJZ.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
+129 -101
View File
@@ -67,20 +67,23 @@ function IdeenSection() {
const qc = useQueryClient() const qc = useQueryClient()
const { showAlert, showConfirm, dialogElement } = useDialog() const { showAlert, showConfirm, dialogElement } = useDialog()
const [text, setText] = useState("") const [text, setText] = useState("")
// Zwei UNABHÄNGIGE Entscheidungen statt vier sich ausschliessender Modi (25.07.2026): // GENAU EINE Auswahl aus drei, in zwei Bereichen (26.07.2026):
// wer — baut die Box selbst, oder bekommst du ein Repo für Zed? // denken → du baust selbst, aber erst ein Konzept. Auf „gefällt mir" wird daraus ein Repo.
// nurDenken — soll erst nur ein Konzept entstehen? (passt zu beidem) // repo → du baust selbst, Konzept + Gitea-Repo sofort.
// Vorher hiessen die Knöpfe BOX/IDEE/IDE:SIMPEL/IDE:GRÜNDLICH und pressten beides in eine // box → die Box baut, Ergebnis kommt als Patch-Vorschlag.
// Reihe — das brauchte 116 Wörter Beipackzettel darunter. Die Abbildung auf die //
// unveränderte API passiert in submit(). // Vorher (25.07.) waren das zwei angeblich unabhängige Dimensionen: „wer baut" plus ein
const [wer, setWer] = useState<"box" | "zed">("box") // Haken „nur denken". Das war FALSCH modelliert — `weiterfuehren` macht aus einer
// durchdachten Idee genau die IDE-Projekt-Karte, die `repo` direkt anlegt. Es sind also
// zwei Stufen EINES Weges, nicht zwei Achsen. Und die Kombination box+denken schob einen
// still in die IDE-Welt (submit setzte welt:"ide"), ohne das irgendwo zu sagen.
const [modus, setModus] = useState<"denken" | "repo" | "box">("denken")
const [tiefe, setTiefe] = useState<"schlank" | "gruendlich">("schlank") const [tiefe, setTiefe] = useState<"schlank" | "gruendlich">("schlank")
const [nurDenken, setNurDenken] = useState(false)
// Kam die aktuelle Auswahl von der Box? Nur fürs Etikett „Vorschlag" — sobald du selbst // Kam die aktuelle Auswahl von der Box? Nur fürs Etikett „Vorschlag" — sobald du selbst
// klickst, verschwindet es, damit nie unklar ist, wessen Entscheidung da steht. // klickst, verschwindet es, damit nie unklar ist, wessen Entscheidung da steht.
const [vorgeschlagen, setVorgeschlagen] = useState(false) const [vorgeschlagen, setVorgeschlagen] = useState(false)
const isIde = wer === "zed" || nurDenken // beides läuft über das projektstart-Profil const isIde = modus !== "box" // denken UND repo laufen über das projektstart-Profil
const isProjekt = wer === "zed" && !nurDenken // nur DANN sind Tiefe und Ziel wirksam const isProjekt = modus === "repo" // nur DANN sind Tiefe und Ziel jetzt schon nötig
// Ziel-Plattform des Projekts (nur IDE-Welt): läuft es als LXC-Dienst oder in Docker? // Ziel-Plattform des Projekts (nur IDE-Welt): läuft es als LXC-Dienst oder in Docker?
const [ziel, setZiel] = useState<"lxc" | "docker">("lxc") const [ziel, setZiel] = useState<"lxc" | "docker">("lxc")
const [sending, setSending] = useState(false) const [sending, setSending] = useState(false)
@@ -105,9 +108,10 @@ function IdeenSection() {
const r = await api<{ ok: boolean; wer?: "box" | "zed"; tiefe?: "schlank" | "gruendlich"; nur_denken?: boolean }>( const r = await api<{ ok: boolean; wer?: "box" | "zed"; tiefe?: "schlank" | "gruendlich"; nur_denken?: boolean }>(
"/api/ideen/einordnen", { method: "POST", body: JSON.stringify({ text: t }) }) "/api/ideen/einordnen", { method: "POST", body: JSON.stringify({ text: t }) })
if (verworfen || !r?.ok) return if (verworfen || !r?.ok) return
if (r.wer) setWer(r.wer) // Die drei Karten aus der Einordnung ableiten: eine Frage („lohnt sich…?") wird zum
// Durchdenken, ein eigenständiges Programm zum Repo, alles am Heimlabor zur Box.
setModus(r.nur_denken ? "denken" : r.wer === "zed" ? "repo" : "box")
if (r.tiefe) setTiefe(r.tiefe) if (r.tiefe) setTiefe(r.tiefe)
setNurDenken(!!r.nur_denken)
setVorgeschlagen(true) setVorgeschlagen(true)
} catch { /* stumm — die Voreinstellung bleibt einfach stehen */ } } catch { /* stumm — die Voreinstellung bleibt einfach stehen */ }
}, 700) }, 700)
@@ -128,12 +132,13 @@ function IdeenSection() {
const titel = t.length > 160 ? t.slice(0, 157) + "…" : t const titel = t.length > 160 ? t.slice(0, 157) + "…" : t
await api("/api/ideen", { method: "POST", body: JSON.stringify({ await api("/api/ideen", { method: "POST", body: JSON.stringify({
titel, notiz: t.length > 160 ? t : "", titel, notiz: t.length > 160 ? t : "",
// Abbildung auf die unveränderte API: „nur denken" läuft immer über die IDE-Welt, // Abbildung auf die unveränderte API. Tiefe und Ziel gehen NUR beim Repo-Weg mit —
// weil dort das Profil sitzt, das denkt statt baut. // beim Durchdenken fragt die Weiter-Leiste sie später beim „gefällt mir", und dann
// weiss man mehr als jetzt.
welt: isIde ? "ide" : "box", welt: isIde ? "ide" : "box",
tiefe: isProjekt ? (tiefe === "gruendlich" ? "gruendlich" : "simpel") : "", tiefe: isProjekt ? (tiefe === "gruendlich" ? "gruendlich" : "simpel") : "",
ziel: isProjekt ? ziel : "", // eine Idee braucht noch keine Plattform ziel: isProjekt ? ziel : "",
art: nurDenken ? "idee" : "projekt", art: modus === "denken" ? "idee" : "projekt",
}) }) }) })
setText("") setText("")
setVorgeschlagen(false) setVorgeschlagen(false)
@@ -466,96 +471,90 @@ function IdeenSection() {
</button> </button>
</div> </div>
{/* Wer baut das? Zwei Karten statt vier Kürzel — jede sagt, was DU danach bekommst. */} {/* ZWEI BEREICHE, drei Karten — ausgewaehlt ist immer genau EINE Karte, nie ein
ganzer Bereich. Der Bereich gruppiert nur, was denselben Weg geht: „durchdenken"
und „Repo" sind zwei Stufen desselben Wegs (weiterfuehren macht aus der einen die
andere), waehrend die Box-Welt etwas voellig anderes tut. */}
<div> <div>
<p className="mb-1.5 text-[11px] text-muted-foreground/70">Wer baut das?</p> <p className="mb-2 text-[11px] text-muted-foreground/70">Was soll damit passieren?</p>
<div className="grid gap-2 sm:grid-cols-2">
{([
{ id: "box" as const, icon: Hammer, titel: "Die Box, allein",
text: "Sie baut es und legt dir das Ergebnis als Vorschlag hin — nichts geht ohne deinen Klick live." },
{ id: "zed" as const, icon: Code2, titel: "Ich, in Zed",
text: "Du bekommst ein fertiges Repo mit Konzept und Doku. Den Code schreibst du selbst." },
]).map((k) => {
const aktiv = wer === k.id
return (
<button key={k.id}
onClick={() => { setWer(k.id); setVorgeschlagen(false) }}
disabled={nurDenken}
className={cn("rounded-xl border p-3 text-left transition-all cursor-pointer disabled:cursor-default",
nurDenken ? "border-border/30 opacity-40"
: aktiv ? "border-primary/60 bg-primary/5" : "border-border/50 hover:border-border")}>
<div className="flex items-center gap-2">
<k.icon className={cn("h-4 w-4 shrink-0", aktiv && !nurDenken ? "text-primary" : "text-muted-foreground")} />
<span className="text-xs font-semibold text-foreground">{k.titel}</span>
{aktiv && vorgeschlagen && !nurDenken && (
<span className="ml-auto shrink-0 rounded border border-primary/40 bg-primary/10 px-1.5 py-0.5 text-[10px] font-bold text-primary">
Vorschlag
</span>
)}
</div>
<p className="mt-1 text-[11px] leading-relaxed text-muted-foreground">{k.text}</p>
</button>
)
})}
</div>
{nurDenken && (
<p className="mt-1.5 text-[10px] text-muted-foreground/60">
Wer baut, entscheidest du, wenn das Konzept da ist.
</p>
)}
</div>
{/* Tiefe und Ziel wirken NUR beim Repo-Weg — deshalb erscheinen sie auch nur dort. <div className="rounded-xl border border-border/40 bg-background/20 p-3">
Ein Schalter, der nichts tut, ist schlimmer als keiner. */} <div className="mb-2 flex items-center gap-2">
{isProjekt && ( <Code2 className="h-4 w-4 shrink-0 text-muted-foreground" />
<div className="flex flex-wrap items-center gap-x-3 gap-y-2"> <span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
<span className="text-[11px] text-muted-foreground/70">Wie gründlich?</span> Du baust selbst, in Zed
<div className="flex rounded-lg border border-border/60 p-0.5"> </span>
{([["schlank", "schlank"], ["gruendlich", "gründlich"]] as const).map(([id, label]) => ( </div>
<button key={id} onClick={() => { setTiefe(id); setVorgeschlagen(false) }} <div className="grid gap-2 sm:grid-cols-2">
className={cn("rounded px-2.5 py-1 text-[10px] font-bold uppercase tracking-wide transition-all cursor-pointer", {([
tiefe === id ? "bg-primary/15 text-primary" : "text-muted-foreground/60 hover:text-foreground")}> { id: "denken" as const, icon: Lightbulb, titel: "Erst durchdenken",
{label} text: "Du bekommst ein Konzept. Gefällt es dir, wird auf Klick ein Repo daraus." },
</button> { id: "repo" as const, icon: GitFork, titel: "Direkt ein Repo",
text: "Konzept und Gitea-Repo in einem Zug — wenn du es ohnehin bauen willst." },
]).map((k) => (
<Wahl key={k.id} k={k} aktiv={modus === k.id} vorgeschlagen={vorgeschlagen}
onWahl={() => { setModus(k.id); setVorgeschlagen(false) }} />
))} ))}
</div> </div>
<span className="text-[10px] text-muted-foreground/60">
{tiefe === "gruendlich"
? "mehrere Fach-Rollen, bis zu 3 Denk-Runden, mehrfacher Härtetest — dauert entsprechend"
: "2 Rollen, eine Denk-Runde — ein paar Minuten"}
</span>
<span className="ml-auto flex items-center gap-1.5">
<span className="text-[11px] text-muted-foreground/70">Läuft als</span>
<div className="flex rounded-lg border border-border/40 p-0.5">
{([["lxc", "LXC"], ["docker", "Docker"]] as const).map(([id, label]) => (
<button key={id} onClick={() => setZiel(id)}
title={id === "lxc"
? "Dienst in einem eigenen Proxmox-LXC (systemd, kein Docker). Wird vom Backup-Server automatisch mitgesichert."
: "Natives Docker: Dockerfile + compose, portabel und pipeline-tauglich."}
className={cn("rounded px-2 py-0.5 text-[10px] font-semibold transition-all cursor-pointer",
ziel === id ? "bg-foreground/10 text-foreground" : "text-muted-foreground/50 hover:text-foreground/80")}>
{label}
</button>
))}
</div>
</span>
</div>
)}
{/* Orthogonal zu allem darüber: erst denken, bauen später entscheiden. */} {/* Tiefe und Ziel nur beim Repo-Weg: beim Durchdenken fragt die Weiter-Leiste
<label className="flex cursor-pointer items-start gap-2 border-t border-border/30 pt-3"> sie spaeter — dann weisst du, was das Ding ueberhaupt wird. */}
<input type="checkbox" checked={nurDenken} {modus === "repo" && (
onChange={(e) => { setNurDenken(e.target.checked); setVorgeschlagen(false) }} <div className="mt-3 flex flex-wrap items-center gap-x-3 gap-y-2 border-t border-border/30 pt-3">
className="mt-0.5 h-3.5 w-3.5 shrink-0 accent-sky-400 cursor-pointer" /> <span className="text-[11px] text-muted-foreground/70">Wie gründlich?</span>
<span className="min-w-0"> <div className="flex rounded-lg border border-border/60 p-0.5">
<span className="text-xs font-semibold text-foreground">Erst nur durchdenken, noch nichts anlegen</span> {([["schlank", "schlank"], ["gruendlich", "gründlich"]] as const).map(([id, label]) => (
<span className="mt-0.5 block text-[11px] leading-relaxed text-muted-foreground"> <button key={id} onClick={() => { setTiefe(id); setVorgeschlagen(false) }}
Die Box arbeitet die Idee mit Produkt-Blick aus was ist es, für wen, was gibt es className={cn("rounded px-2.5 py-1 text-[10px] font-bold uppercase tracking-wide transition-all cursor-pointer",
schon, was wäre der kleinste sinnvolle Wurf, was spricht dagegen. Ergebnis ist ein tiefe === id ? "bg-primary/15 text-primary" : "text-muted-foreground/60 hover:text-foreground")}>
Konzept: kein Repo, kein Code, kein Bau-Druck. {label}
</span> </button>
</span> ))}
</label> </div>
<span className="text-[10px] text-muted-foreground/60">
{tiefe === "gruendlich"
? "mehrere Fach-Rollen, bis zu 3 Denk-Runden, mehrfacher Härtetest"
: "2 Rollen, eine Denk-Runde — ein paar Minuten"}
</span>
<span className="ml-auto flex items-center gap-1.5">
<span className="text-[11px] text-muted-foreground/70">Läuft als</span>
<div className="flex rounded-lg border border-border/40 p-0.5">
{([["lxc", "LXC"], ["docker", "Docker"]] as const).map(([id, label]) => (
<button key={id} onClick={() => setZiel(id)}
title={id === "lxc"
? "Dienst in einem eigenen Proxmox-LXC (systemd, kein Docker). Wird vom Backup-Server automatisch mitgesichert."
: "Natives Docker: Dockerfile + compose, portabel und pipeline-tauglich."}
className={cn("rounded px-2 py-0.5 text-[10px] font-semibold transition-all cursor-pointer",
ziel === id ? "bg-foreground/10 text-foreground" : "text-muted-foreground/50 hover:text-foreground/80")}>
{label}
</button>
))}
</div>
</span>
</div>
)}
{modus === "denken" && (
<p className="mt-2.5 flex items-start gap-1.5 border-t border-border/30 pt-2.5 text-[10px] leading-relaxed text-muted-foreground/60">
<HelpCircle className="mt-px h-3 w-3 shrink-0" />
Wie gründlich und wo es läuft, fragt die Box erst beim gefällt mir" — dann weißt du mehr.
</p>
)}
</div>
<div className="mt-2 rounded-xl border border-border/40 bg-background/20 p-3">
<div className="mb-2 flex items-center gap-2">
<Hammer className="h-4 w-4 shrink-0 text-muted-foreground" />
<span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
Oder die Box macht es
</span>
</div>
<Wahl
k={{ id: "box", icon: Hammer, titel: "Die Box baut allein",
text: "Für dein Heimlabor Mission Control, Lucy, Rippy, Wartung, Doku. Das Ergebnis kommt als Patch-Vorschlag ins Auftragsbuch; nichts geht ohne deinen Klick live." }}
aktiv={modus === "box"} vorgeschlagen={vorgeschlagen}
onWahl={() => { setModus("box"); setVorgeschlagen(false) }} />
</div>
</div>
{isLoading && ( {isLoading && (
<p className="flex items-center gap-2 text-xs text-muted-foreground"><Loader2 className="h-3.5 w-3.5 animate-spin" /> Queue wird geladen …</p> <p className="flex items-center gap-2 text-xs text-muted-foreground"><Loader2 className="h-3.5 w-3.5 animate-spin" /> Queue wird geladen …</p>
)} )}
@@ -633,6 +632,35 @@ function IdeenSection() {
) )
} }
// Eine der drei Auswahl-Karten. Der Text steht AN der Option, nicht in einer Legende
// darunter — man liest nur, was zu dem gehört, was man gerade anschaut.
function Wahl({ k, aktiv, vorgeschlagen, onWahl }: {
k: { id: string; icon: typeof Hammer; titel: string; text: string }
aktiv: boolean
vorgeschlagen: boolean
onWahl: () => void
}) {
return (
<button
onClick={onWahl}
className={cn("rounded-xl border p-3 text-left transition-all cursor-pointer",
aktiv ? "border-primary/60 bg-primary/5" : "border-border/50 hover:border-border")}>
<div className="flex items-center gap-2">
<k.icon className={cn("h-4 w-4 shrink-0", aktiv ? "text-primary" : "text-muted-foreground")} />
<span className="text-xs font-semibold text-foreground">{k.titel}</span>
{/* Etikett nur an der AUSGEWÄHLTEN Karte und nur solange der Vorschlag unberührt
ist — sonst wäre nie klar, wessen Entscheidung gerade dasteht. */}
{aktiv && vorgeschlagen && (
<span className="ml-auto shrink-0 rounded border border-primary/40 bg-primary/10 px-1.5 py-0.5 text-[10px] font-bold text-primary">
Vorschlag
</span>
)}
</div>
<p className="mt-1 text-[11px] leading-relaxed text-muted-foreground">{k.text}</p>
</button>
)
}
// Karten-Familie (verkettete Karten = ein Projekt) als Block: Fortschritt oben, dann die // Karten-Familie (verkettete Karten = ein Projekt) als Block: Fortschritt oben, dann die
// AKTIVEN Karten in Ausführungs-Reihenfolge, Wartende und Fertige zusammengeklappt. // AKTIVEN Karten in Ausführungs-Reihenfolge, Wartende und Fertige zusammengeklappt.
// Ersetzt für Ketten die flache Erstellzeit-Liste (User: „Reihenfolge komplett durcheinander"). // Ersetzt für Ketten die flache Erstellzeit-Liste (User: „Reihenfolge komplett durcheinander").