5881a21d9a
Gilt fuer alle Tools (Hermes, Cline, OpenCode) via MCP-Server. - user: wer der User ist, Praeferenzen, Arbeitsweise - instruction: Verhaltensregeln fuer alle KI-Tools Hermes-Agent speichert aktiv in diese Kategorien wenn er Neues lernt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
669 lines
210 KiB
JavaScript
669 lines
210 KiB
JavaScript
var rl=Object.defineProperty;var Dr=e=>{throw TypeError(e)};var sl=(e,n,a)=>n in e?rl(e,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):e[n]=a;var ln=(e,n,a)=>sl(e,typeof n!="symbol"?n+"":n,a),Ui=(e,n,a)=>n.has(e)||Dr("Cannot "+a);var h=(e,n,a)=>(Ui(e,n,"read from private field"),a?a.call(e):n.get(e)),Oe=(e,n,a)=>n.has(e)?Dr("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(e):n.set(e,a),Pe=(e,n,a,s)=>(Ui(e,n,"write to private field"),s?s.call(e,a):n.set(e,a),a),it=(e,n,a)=>(Ui(e,n,"access private method"),a);var _r=Array.isArray,ll=Array.prototype.indexOf,zi=Array.prototype.includes,Fi=Array.from,ol=Object.defineProperty,ni=Object.getOwnPropertyDescriptor,dl=Object.getOwnPropertyDescriptors,cl=Object.prototype,vl=Array.prototype,ds=Object.getPrototypeOf,$r=Object.isExtensible;const ul=()=>{};function pl(e){for(var n=0;n<e.length;n++)e[n]()}function cs(){var e,n,a=new Promise((s,l)=>{e=s,n=l});return{promise:a,resolve:e,reject:n}}function ta(e,n){if(Array.isArray(e))return e;if(n===void 0||!(Symbol.iterator in e))return Array.from(e);const a=[];for(const s of e)if(a.push(s),a.length===n)break;return a}const Yt=2,Fa=4,Ki=8,vs=1<<24,Sn=16,En=32,ra=64,rr=128,bn=512,Vt=1024,Qt=2048,Ln=4096,en=8192,_n=16384,ja=32768,sr=1<<25,Ka=65536,Pi=1<<17,fl=1<<18,Ua=1<<19,hl=1<<20,Pn=1<<25,wa=65536,Di=1<<21,za=1<<22,ia=1<<23,Pa=Symbol("$state"),gl=Symbol(""),Si=Symbol("attributes"),lr=Symbol("class"),or=Symbol("style"),Za=Symbol("text"),Mi=Symbol("form reset"),Ni=new class extends Error{constructor(){super(...arguments);ln(this,"name","StaleReactionError");ln(this,"message","The reaction that called `getAbortSignal()` was re-run or destroyed")}};var rs;const ml=!!((rs=globalThis.document)!=null&&rs.contentType)&&globalThis.document.contentType.includes("xml");function us(e){throw new Error("https://svelte.dev/e/lifecycle_outside_component")}function bl(){throw new Error("https://svelte.dev/e/async_derived_orphan")}function _l(e,n,a){throw new Error("https://svelte.dev/e/each_key_duplicate")}function yl(e){throw new Error("https://svelte.dev/e/effect_in_teardown")}function kl(){throw new Error("https://svelte.dev/e/effect_in_unowned_derived")}function xl(e){throw new Error("https://svelte.dev/e/effect_orphan")}function wl(){throw new Error("https://svelte.dev/e/effect_update_depth_exceeded")}function Sl(){throw new Error("https://svelte.dev/e/state_descriptors_fixed")}function Ml(){throw new Error("https://svelte.dev/e/state_prototype_fixed")}function El(){throw new Error("https://svelte.dev/e/state_unsafe_mutation")}function Al(){throw new Error("https://svelte.dev/e/svelte_boundary_reset_onerror")}const Cl=1,Tl=2,ps=4,zl=8,Pl=16,Dl=1,$l=2,Gt=Symbol("uninitialized"),fs="http://www.w3.org/1999/xhtml",Ll="http://www.w3.org/2000/svg",Il="http://www.w3.org/1998/Math/MathML";function Ol(){console.warn("https://svelte.dev/e/derived_inert")}function Bl(){console.warn("https://svelte.dev/e/select_multiple_invalid_value")}function Rl(){console.warn("https://svelte.dev/e/svelte_boundary_reset_noop")}function hs(e){return e===this.v}function Fl(e,n){return e!=e?n==n:e!==n||e!==null&&typeof e=="object"||typeof e=="function"}function gs(e){return!Fl(e,this.v)}let Zt=null;function Na(e){Zt=e}function On(e,n=!1,a){Zt={p:Zt,i:!1,c:null,e:null,s:e,x:null,r:Ue,l:null}}function Bn(e){var n=Zt,a=n.e;if(a!==null){n.e=null;for(var s of a)Rs(s)}return n.i=!0,Zt=n.p,{}}function ms(){return!0}let da=[];function bs(){var e=da;da=[],pl(e)}function ba(e){if(da.length===0&&!ii){var n=da;queueMicrotask(()=>{n===da&&bs()})}da.push(e)}function Kl(){for(;da.length>0;)bs()}function _s(e){var n=Ue;if(n===null)return Ve.f|=ia,e;if((n.f&ja)===0&&(n.f&Fa)===0)throw e;na(e,n)}function na(e,n){if(!(n!==null&&(n.f&_n)!==0)){for(;n!==null;){if((n.f&rr)!==0){if((n.f&ja)===0)throw e;try{n.b.error(e);return}catch(a){e=a}}n=n.parent}throw e}}const Nl=-7169;function Nt(e,n){e.f=e.f&Nl|n}function yr(e){(e.f&bn)!==0||e.deps===null?Nt(e,Vt):Nt(e,Ln)}function ys(e){if(e!==null)for(const n of e)(n.f&Yt)===0||(n.f&wa)===0||(n.f^=wa,ys(n.deps))}function ks(e,n,a){(e.f&Qt)!==0?n.add(e):(e.f&Ln)!==0&&a.add(e),ys(e.deps),Nt(e,Vt)}function ql(e){let n=0,a=Ma(0),s;return()=>{Ar()&&(t(a),qi(()=>(n===0&&(s=Ha(()=>e(()=>ri(a)))),n+=1,()=>{ba(()=>{n-=1,n===0&&(s==null||s(),s=void 0,ri(a))})})))}}var Wl=Ka|Ua;function Gl(e,n,a,s){new Vl(e,n,a,s)}var pn,br,fn,pa,nn,hn,Xt,dn,Kn,fa,Xn,Da,vi,ui,Nn,Oi,Bt,jl,Ul,Hl,dr,Ei,Ai,cr,vr;class Vl{constructor(n,a,s,l){Oe(this,Bt);ln(this,"parent");ln(this,"is_pending",!1);ln(this,"transform_error");Oe(this,pn);Oe(this,br,null);Oe(this,fn);Oe(this,pa);Oe(this,nn);Oe(this,hn,null);Oe(this,Xt,null);Oe(this,dn,null);Oe(this,Kn,null);Oe(this,fa,0);Oe(this,Xn,0);Oe(this,Da,!1);Oe(this,vi,new Set);Oe(this,ui,new Set);Oe(this,Nn,null);Oe(this,Oi,ql(()=>(Pe(this,Nn,Ma(h(this,fa))),()=>{Pe(this,Nn,null)})));var o;Pe(this,pn,n),Pe(this,fn,a),Pe(this,pa,c=>{var d=Ue;d.b=this,d.f|=rr,s(c)}),this.parent=Ue.b,this.transform_error=l??((o=this.parent)==null?void 0:o.transform_error)??(c=>c),Pe(this,nn,Cr(()=>{it(this,Bt,dr).call(this)},Wl))}defer_effect(n){ks(n,h(this,vi),h(this,ui))}is_rendered(){return!this.is_pending&&(!this.parent||this.parent.is_rendered())}has_pending_snippet(){return!!h(this,fn).pending}update_pending_count(n,a){it(this,Bt,cr).call(this,n,a),Pe(this,fa,h(this,fa)+n),!(!h(this,Nn)||h(this,Da))&&(Pe(this,Da,!0),ba(()=>{Pe(this,Da,!1),h(this,Nn)&&qa(h(this,Nn),h(this,fa))}))}get_effect_pending(){return h(this,Oi).call(this),t(h(this,Nn))}error(n){if(!h(this,fn).onerror&&!h(this,fn).failed)throw n;ce!=null&&ce.is_fork?(h(this,hn)&&ce.skip_effect(h(this,hn)),h(this,Xt)&&ce.skip_effect(h(this,Xt)),h(this,dn)&&ce.skip_effect(h(this,dn)),ce.oncommit(()=>{it(this,Bt,vr).call(this,n)})):it(this,Bt,vr).call(this,n)}}pn=new WeakMap,br=new WeakMap,fn=new WeakMap,pa=new WeakMap,nn=new WeakMap,hn=new WeakMap,Xt=new WeakMap,dn=new WeakMap,Kn=new WeakMap,fa=new WeakMap,Xn=new WeakMap,Da=new WeakMap,vi=new WeakMap,ui=new WeakMap,Nn=new WeakMap,Oi=new WeakMap,Bt=new WeakSet,jl=function(){try{Pe(this,hn,gn(()=>h(this,pa).call(this,h(this,pn))))}catch(n){this.error(n)}},Ul=function(n){const a=h(this,fn).failed;a&&Pe(this,dn,gn(()=>{a(h(this,pn),()=>n,()=>()=>{})}))},Hl=function(){const n=h(this,fn).pending;n&&(this.is_pending=!0,Pe(this,Xt,gn(()=>n(h(this,pn)))),ba(()=>{var a=Pe(this,Kn,document.createDocumentFragment()),s=Gn();a.append(s),Pe(this,hn,it(this,Bt,Ai).call(this,()=>gn(()=>h(this,pa).call(this,s)))),h(this,Xn)===0&&(h(this,pn).before(a),Pe(this,Kn,null),ya(h(this,Xt),()=>{Pe(this,Xt,null)}),it(this,Bt,Ei).call(this,ce))}))},dr=function(){try{if(this.is_pending=this.has_pending_snippet(),Pe(this,Xn,0),Pe(this,fa,0),Pe(this,hn,gn(()=>{h(this,pa).call(this,h(this,pn))})),h(this,Xn)>0){var n=Pe(this,Kn,document.createDocumentFragment());zr(h(this,hn),n);const a=h(this,fn).pending;Pe(this,Xt,gn(()=>a(h(this,pn))))}else it(this,Bt,Ei).call(this,ce)}catch(a){this.error(a)}},Ei=function(n){this.is_pending=!1,n.transfer_effects(h(this,vi),h(this,ui))},Ai=function(n){var a=Ue,s=Ve,l=Zt;In(h(this,nn)),yn(h(this,nn)),Na(h(this,nn).ctx);try{return Sa.ensure(),n()}catch(o){return _s(o),null}finally{In(a),yn(s),Na(l)}},cr=function(n,a){var s;if(!this.has_pending_snippet()){this.parent&&it(s=this.parent,Bt,cr).call(s,n,a);return}Pe(this,Xn,h(this,Xn)+n),h(this,Xn)===0&&(it(this,Bt,Ei).call(this,a),h(this,Xt)&&ya(h(this,Xt),()=>{Pe(this,Xt,null)}),h(this,Kn)&&(h(this,pn).before(h(this,Kn)),Pe(this,Kn,null)))},vr=function(n){h(this,hn)&&(sn(h(this,hn)),Pe(this,hn,null)),h(this,Xt)&&(sn(h(this,Xt)),Pe(this,Xt,null)),h(this,dn)&&(sn(h(this,dn)),Pe(this,dn,null));var a=h(this,fn).onerror;let s=h(this,fn).failed;var l=!1,o=!1;const c=()=>{if(l){Rl();return}l=!0,o&&Al(),h(this,dn)!==null&&ya(h(this,dn),()=>{Pe(this,dn,null)}),it(this,Bt,Ai).call(this,()=>{it(this,Bt,dr).call(this)})},d=v=>{try{o=!0,a==null||a(v,c),o=!1}catch(p){na(p,h(this,nn)&&h(this,nn).parent)}s&&Pe(this,dn,it(this,Bt,Ai).call(this,()=>{try{return gn(()=>{var p=Ue;p.b=this,p.f|=rr,s(h(this,pn),()=>v,()=>c)})}catch(p){return na(p,h(this,nn).parent),null}}))};ba(()=>{var v;try{v=this.transform_error(n)}catch(p){na(p,h(this,nn)&&h(this,nn).parent);return}v!==null&&typeof v=="object"&&typeof v.then=="function"?v.then(d,p=>na(p,h(this,nn)&&h(this,nn).parent)):d(v)})};function Jl(e,n,a,s){const l=kr;var o=e.filter(x=>!x.settled),c=n.map(l);if(a.length===0&&o.length===0){s(c);return}var d=Ue,v=Ql(),p=o.length===1?o[0].promise:o.length>1?Promise.all(o.map(x=>x.promise)):null;function _(x){if((d.f&_n)===0){v();try{s([...c,...x])}catch(A){na(A,d)}$i()}}var T=xs();if(a.length===0){p.then(()=>_([])).finally(T);return}function y(){Promise.all(a.map(x=>Zl(x))).then(_).catch(x=>na(x,d)).finally(T)}p?p.then(()=>{v(),y(),$i()}):y()}function Ql(){var e=Ue,n=Ve,a=Zt,s=ce;return function(o=!0){In(e),yn(n),Na(a),o&&(e.f&_n)===0&&(s==null||s.activate(),s==null||s.apply())}}function $i(e=!0){In(null),yn(null),Na(null),e&&(ce==null||ce.deactivate())}function xs(){var e=Ue,n=e.b,a=ce,s=!!(n!=null&&n.is_rendered());return n==null||n.update_pending_count(1,a),a.increment(s,e),()=>{n==null||n.update_pending_count(-1,a),a.decrement(s,e)}}function kr(e){var n=Yt|Qt;return Ue!==null&&(Ue.f|=Ua),{ctx:Zt,deps:null,effects:null,equals:hs,f:n,fn:e,reactions:null,rv:0,v:Gt,wv:0,parent:Ue,ac:null}}const Ya=Symbol("obsolete");function Zl(e,n,a){let s=Ue;s===null&&bl();var l=void 0,o=Ma(Gt),c=!Ve,d=new Set;return ho(()=>{var x,A;var v=Ue,p=cs();l=p.promise;try{Promise.resolve(e()).then(p.resolve,D=>{D!==Ni&&p.reject(D)}).finally($i)}catch(D){p.reject(D),$i()}var _=ce;if(c){if((v.f&ja)!==0)var T=xs();if((x=s.b)!=null&&x.is_rendered())(A=_.async_deriveds.get(v))==null||A.reject(Ya);else for(const D of d.values())D.reject(Ya);d.add(p),_.async_deriveds.set(v,p)}const y=(D,M=void 0)=>{T==null||T(),d.delete(p),M!==Ya&&(_.activate(),M?(o.f|=ia,qa(o,M)):((o.f&ia)!==0&&(o.f^=ia),qa(o,D)),_.deactivate())};p.promise.then(y,D=>y(null,D||"unknown"))}),Bs(()=>{for(const v of d)v.reject(Ya)}),new Promise(v=>{function p(_){function T(){_===l?v(o):p(l)}_.then(T,T)}p(l)})}function N(e){const n=kr(e);return Vs(n),n}function Yl(e){const n=kr(e);return n.equals=gs,n}function Xl(e){var n=e.effects;if(n!==null){e.effects=null;for(var a=0;a<n.length;a+=1)sn(n[a])}}function xr(e){var n,a=Ue,s=e.parent;if(!sa&&s!==null&&e.v!==Gt&&(s.f&(_n|en))!==0)return Ol(),e.v;In(s);try{e.f&=~wa,Xl(e),n=Js(e)}finally{In(a)}return n}function ws(e){var n=xr(e);if(!e.equals(n)&&(e.wv=Us(),(!(ce!=null&&ce.is_fork)||e.deps===null)&&(ce!==null?(ce.capture(e,n,!0),ai==null||ai.capture(e,n,!0)):e.v=n,e.deps===null))){Nt(e,Vt);return}sa||(Jt!==null?(Ar()||ce!=null&&ce.is_fork)&&Jt.set(e,n):yr(e))}function eo(e){var n,a;if(e.effects!==null)for(const s of e.effects)(s.teardown||s.ac)&&((n=s.teardown)==null||n.call(s),(a=s.ac)==null||a.abort(Ni),s.fn!==null&&(s.teardown=ul),s.ac=null,di(s,0),Tr(s))}function Ss(e){if(e.effects!==null)for(const n of e.effects)n.teardown&&n.fn!==null&&Wa(n)}let Hi=null,Aa=null,ce=null,ai=null,Jt=null,ur=null,ii=!1,Ji=!1,Ta=null,Ci=null;var Lr=0;let to=1;var $a,ea,ha,La,Ia,Oa,qn,Ba,an,pi,Wn,xn,Tn,Ra,ga,ht,pr,Xa,fr,Ms,Es,Ca,no,ei;const Bi=class Bi{constructor(){Oe(this,ht);ln(this,"id",to++);Oe(this,$a,!1);ln(this,"linked",!0);Oe(this,ea,null);Oe(this,ha,null);ln(this,"async_deriveds",new Map);ln(this,"current",new Map);ln(this,"previous",new Map);Oe(this,La,new Set);Oe(this,Ia,new Set);Oe(this,Oa,0);Oe(this,qn,new Map);Oe(this,Ba,null);Oe(this,an,[]);Oe(this,pi,[]);Oe(this,Wn,new Set);Oe(this,xn,new Set);Oe(this,Tn,new Map);Oe(this,Ra,new Set);ln(this,"is_fork",!1);Oe(this,ga,!1);Aa===null?Hi=Aa=this:(Pe(Aa,ha,this),Pe(this,ea,Aa)),Aa=this}skip_effect(n){h(this,Tn).has(n)||h(this,Tn).set(n,{d:[],m:[]}),h(this,Ra).delete(n)}unskip_effect(n,a=s=>this.schedule(s)){var s=h(this,Tn).get(n);if(s){h(this,Tn).delete(n);for(var l of s.d)Nt(l,Qt),a(l);for(l of s.m)Nt(l,Ln),a(l)}h(this,Ra).add(n)}capture(n,a,s=!1){n.v!==Gt&&!this.previous.has(n)&&this.previous.set(n,n.v),(n.f&ia)===0&&(this.current.set(n,[a,s]),Jt==null||Jt.set(n,a)),this.is_fork||(n.v=a)}activate(){ce=this}deactivate(){ce=null,Jt=null}flush(){try{Ji=!0,ce=this,it(this,ht,Xa).call(this)}finally{Lr=0,ur=null,Ta=null,Ci=null,Ji=!1,ce=null,Jt=null,_a.clear()}}discard(){var n;for(const a of h(this,Ia))a(this);h(this,Ia).clear();for(const a of this.async_deriveds.values())a.reject(Ya);it(this,ht,ei).call(this),(n=h(this,Ba))==null||n.resolve()}register_created_effect(n){h(this,pi).push(n)}increment(n,a){if(Pe(this,Oa,h(this,Oa)+1),n){let s=h(this,qn).get(a)??0;h(this,qn).set(a,s+1)}}decrement(n,a){if(Pe(this,Oa,h(this,Oa)-1),n){let s=h(this,qn).get(a)??0;s===1?h(this,qn).delete(a):h(this,qn).set(a,s-1)}h(this,ga)||(Pe(this,ga,!0),ba(()=>{Pe(this,ga,!1),this.linked&&this.flush()}))}transfer_effects(n,a){for(const s of n)h(this,Wn).add(s);for(const s of a)h(this,xn).add(s);n.clear(),a.clear()}oncommit(n){h(this,La).add(n)}ondiscard(n){h(this,Ia).add(n)}settled(){return(h(this,Ba)??Pe(this,Ba,cs())).promise}static ensure(){if(ce===null){const n=ce=new Bi;!Ji&&!ii&&ba(()=>{h(n,$a)||n.flush()})}return ce}apply(){{Jt=null;return}}schedule(n){var l;if(ur=n,(l=n.b)!=null&&l.is_pending&&(n.f&(Fa|Ki|vs))!==0&&(n.f&ja)===0){n.b.defer_effect(n);return}for(var a=n;a.parent!==null;){a=a.parent;var s=a.f;if(Ta!==null&&a===Ue&&(Ve===null||(Ve.f&Yt)===0))return;if((s&(ra|En))!==0){if((s&Vt)===0)return;a.f^=Vt}}h(this,an).push(a)}};$a=new WeakMap,ea=new WeakMap,ha=new WeakMap,La=new WeakMap,Ia=new WeakMap,Oa=new WeakMap,qn=new WeakMap,Ba=new WeakMap,an=new WeakMap,pi=new WeakMap,Wn=new WeakMap,xn=new WeakMap,Tn=new WeakMap,Ra=new WeakMap,ga=new WeakMap,ht=new WeakSet,pr=function(){if(this.is_fork)return!0;for(const s of h(this,qn).keys()){for(var n=s,a=!1;n.parent!==null;){if(h(this,Tn).has(n)){a=!0;break}n=n.parent}if(!a)return!0}return!1},Xa=function(){var v,p,_,T;Pe(this,$a,!0),Lr++>1e3&&(it(this,ht,ei).call(this),io());for(const y of h(this,Wn))h(this,xn).delete(y),Nt(y,Qt),this.schedule(y);for(const y of h(this,xn))Nt(y,Ln),this.schedule(y);const n=h(this,an);Pe(this,an,[]),this.apply();var a=Ta=[],s=[],l=Ci=[];for(const y of n)try{it(this,ht,fr).call(this,y,a,s)}catch(x){throw Ts(y),it(this,ht,pr).call(this)||this.discard(),x}if(ce=null,l.length>0){var o=Bi.ensure();for(const y of l)o.schedule(y)}if(Ta=null,Ci=null,it(this,ht,pr).call(this)){it(this,ht,Ca).call(this,s),it(this,ht,Ca).call(this,a);for(const[y,x]of h(this,Tn))Cs(y,x);l.length>0&&it(v=ce,ht,Xa).call(v);return}const c=it(this,ht,Ms).call(this);if(c){it(this,ht,Ca).call(this,s),it(this,ht,Ca).call(this,a),it(p=c,ht,Es).call(p,this);return}h(this,Wn).clear(),h(this,xn).clear();for(const y of h(this,La))y(this);h(this,La).clear(),ai=this,Ir(s),Ir(a),ai=null,(_=h(this,Ba))==null||_.resolve();var d=ce;if(h(this,Oa)===0&&(h(this,an).length===0||d!==null)&&it(this,ht,ei).call(this),h(this,an).length>0)if(d!==null){const y=d;h(y,an).push(...h(this,an).filter(x=>!h(y,an).includes(x)))}else d=this;d!==null&&it(T=d,ht,Xa).call(T)},fr=function(n,a,s){n.f^=Vt;for(var l=n.first;l!==null;){var o=l.f,c=(o&(En|ra))!==0,d=c&&(o&Vt)!==0,v=d||(o&en)!==0||h(this,Tn).has(l);if(!v&&l.fn!==null){c?l.f^=Vt:(o&Fa)!==0?a.push(l):bi(l)&&((o&Sn)!==0&&h(this,xn).add(l),Wa(l));var p=l.first;if(p!==null){l=p;continue}}for(;l!==null;){var _=l.next;if(_!==null){l=_;break}l=l.parent}}},Ms=function(){for(var n=h(this,ea);n!==null;){if(!n.is_fork){for(const[a,[,s]]of this.current)if(n.current.has(a)&&!s)return n}n=h(n,ea)}return null},Es=function(n){var s;for(const[l,o]of n.current)!this.previous.has(l)&&n.previous.has(l)&&this.previous.set(l,n.previous.get(l)),this.current.set(l,o);for(const[l,o]of n.async_deriveds){const c=this.async_deriveds.get(l);c&&o.promise.then(c.resolve).catch(c.reject)}n.async_deriveds.clear(),this.transfer_effects(h(n,Wn),h(n,xn));const a=l=>{var o=l.reactions;if(o!==null)for(const v of o){var c=v.f;if((c&Yt)!==0)a(v);else{var d=v;c&(za|Sn)&&!this.async_deriveds.has(d)&&(h(this,xn).delete(d),Nt(d,Qt),this.schedule(d))}}};for(const l of this.current.keys())a(l);this.oncommit(()=>n.discard()),it(s=n,ht,ei).call(s),ce=this,it(this,ht,Xa).call(this)},Ca=function(n){for(var a=0;a<n.length;a+=1)ks(n[a],h(this,Wn),h(this,xn))},no=function(){var T;for(let y=Hi;y!==null;y=h(y,ha)){var n=y.id<this.id,a=[];for(const[x,[A,D]]of this.current){if(y.current.has(x)){var s=y.current.get(x)[0];if(n&&A!==s)y.current.set(x,[A,D]);else continue}a.push(x)}if(n)for(const[x,A]of this.async_deriveds){const D=y.async_deriveds.get(x);D&&A.promise.then(D.resolve).catch(D.reject)}var l=[...y.current.keys()].filter(x=>!y.current.get(x)[1]);if(!(!h(y,$a)||l.length===0)){var o=l.filter(x=>!this.current.has(x));if(o.length===0)n&&y.discard();else if(a.length>0){if(n)for(const x of h(this,Ra))y.unskip_effect(x,A=>{var D;(A.f&(Sn|za))!==0?y.schedule(A):it(D=y,ht,Ca).call(D,[A])});y.activate();var c=new Set,d=new Map;for(var v of a)As(v,o,c,d);d=new Map;var p=[...y.current].filter(([x,A])=>{const D=this.current.get(x);return D?D[0]!==A[0]||D[1]!==A[1]:!0}).map(([x])=>x);if(p.length>0)for(const x of h(this,pi))(x.f&(_n|en|Pi))===0&&wr(x,p,d)&&((x.f&(za|Sn))!==0?(Nt(x,Qt),y.schedule(x)):h(y,Wn).add(x));if(h(y,an).length>0&&!h(y,ga)){y.apply();for(var _ of h(y,an))it(T=y,ht,fr).call(T,_,[],[]);Pe(y,an,[])}y.deactivate()}}}},ei=function(){if(this.linked){var n=h(this,ea),a=h(this,ha);n===null?Hi=a:Pe(n,ha,a),a===null?Aa=n:Pe(a,ea,n),this.linked=!1}};let Sa=Bi;function ao(e){var n=ii;ii=!0;try{for(var a;;){if(Kl(),ce===null)return a;ce.flush()}}finally{ii=n}}function io(){try{wl()}catch(e){na(e,ur)}}let kn=null;function Ir(e){var n=e.length;if(n!==0){for(var a=0;a<n;){var s=e[a++];if((s.f&(_n|en))===0&&bi(s)&&(kn=new Set,Wa(s),s.deps===null&&s.first===null&&s.nodes===null&&s.teardown===null&&s.ac===null&&qs(s),(kn==null?void 0:kn.size)>0)){_a.clear();for(const l of kn){if((l.f&(_n|en))!==0)continue;const o=[l];let c=l.parent;for(;c!==null;)kn.has(c)&&(kn.delete(c),o.push(c)),c=c.parent;for(let d=o.length-1;d>=0;d--){const v=o[d];(v.f&(_n|en))===0&&Wa(v)}}kn.clear()}}kn=null}}function As(e,n,a,s){if(!a.has(e)&&(a.add(e),e.reactions!==null))for(const l of e.reactions){const o=l.f;(o&Yt)!==0?As(l,n,a,s):(o&(za|Sn))!==0&&(o&Qt)===0&&wr(l,n,s)&&(Nt(l,Qt),Sr(l))}}function wr(e,n,a){const s=a.get(e);if(s!==void 0)return s;if(e.deps!==null)for(const l of e.deps){if(zi.call(n,l))return!0;if((l.f&Yt)!==0&&wr(l,n,a))return a.set(l,!0),!0}return a.set(e,!1),!1}function Sr(e){ce.schedule(e)}function Cs(e,n){if(!((e.f&En)!==0&&(e.f&Vt)!==0)){(e.f&Qt)!==0?n.d.push(e):(e.f&Ln)!==0&&n.m.push(e),Nt(e,Vt);for(var a=e.first;a!==null;)Cs(a,n),a=a.next}}function Ts(e){Nt(e,Vt);for(var n=e.first;n!==null;)Ts(n),n=n.next}let Li=new Set;const _a=new Map;let zs=!1;function Ma(e,n){var a={f:0,v:e,reactions:null,equals:hs,rv:0,wv:0};return a}function O(e,n){const a=Ma(e);return Vs(a),a}function ro(e,n=!1,a=!0){const s=Ma(e);return n||(s.equals=gs),s}function u(e,n,a=!1){Ve!==null&&(!Mn||(Ve.f&Pi)!==0)&&ms()&&(Ve.f&(Yt|Sn|za|Pi))!==0&&(Dn===null||!Dn.has(e))&&El();let s=a?jt(n):n;return qa(e,s,Ci)}function qa(e,n,a=null){if(!e.equals(n)){_a.set(e,sa?n:e.v);var s=Sa.ensure();if(s.capture(e,n),(e.f&Yt)!==0){const l=e;(e.f&Qt)!==0&&xr(l),Jt===null&&yr(l)}e.wv=Us(),Ps(e,Qt,a),Ue!==null&&(Ue.f&Vt)!==0&&(Ue.f&(En|ra))===0&&(un===null?mo([e]):un.push(e)),!s.is_fork&&Li.size>0&&!zs&&so()}return n}function so(){zs=!1;for(const e of Li){(e.f&Vt)!==0&&Nt(e,Ln);let n;try{n=bi(e)}catch{n=!0}n&&Wa(e)}Li.clear()}function ri(e){u(e,e.v+1)}function Ps(e,n,a){var s=e.reactions;if(s!==null)for(var l=s.length,o=0;o<l;o++){var c=s[o],d=c.f,v=(d&Qt)===0;if(v&&Nt(c,n),(d&Pi)!==0)Li.add(c);else if((d&Yt)!==0){var p=c;Jt==null||Jt.delete(p),(d&wa)===0&&(d&bn&&(Ue===null||(Ue.f&Di)===0)&&(c.f|=wa),Ps(p,Ln,a))}else if(v){var _=c;(d&Sn)!==0&&kn!==null&&kn.add(_),a!==null?a.push(_):Sr(_)}}}function jt(e){if(typeof e!="object"||e===null||Pa in e)return e;const n=ds(e);if(n!==cl&&n!==vl)return e;var a=new Map,s=_r(e),l=O(0),o=ka,c=d=>{if(ka===o)return d();var v=Ve,p=ka;yn(null),Kr(o);var _=d();return yn(v),Kr(p),_};return s&&a.set("length",O(e.length)),new Proxy(e,{defineProperty(d,v,p){(!("value"in p)||p.configurable===!1||p.enumerable===!1||p.writable===!1)&&Sl();var _=a.get(v);return _===void 0?c(()=>{var T=O(p.value);return a.set(v,T),T}):u(_,p.value,!0),!0},deleteProperty(d,v){var p=a.get(v);if(p===void 0){if(v in d){const _=c(()=>O(Gt));a.set(v,_),ri(l)}}else u(p,Gt),ri(l);return!0},get(d,v,p){var x;if(v===Pa)return e;var _=a.get(v),T=v in d;if(_===void 0&&(!T||(x=ni(d,v))!=null&&x.writable)&&(_=c(()=>{var A=jt(T?d[v]:Gt),D=O(A);return D}),a.set(v,_)),_!==void 0){var y=t(_);return y===Gt?void 0:y}return Reflect.get(d,v,p)},getOwnPropertyDescriptor(d,v){var p=Reflect.getOwnPropertyDescriptor(d,v);if(p&&"value"in p){var _=a.get(v);_&&(p.value=t(_))}else if(p===void 0){var T=a.get(v),y=T==null?void 0:T.v;if(T!==void 0&&y!==Gt)return{enumerable:!0,configurable:!0,value:y,writable:!0}}return p},has(d,v){var y;if(v===Pa)return!0;var p=a.get(v),_=p!==void 0&&p.v!==Gt||Reflect.has(d,v);if(p!==void 0||Ue!==null&&(!_||(y=ni(d,v))!=null&&y.writable)){p===void 0&&(p=c(()=>{var x=_?jt(d[v]):Gt,A=O(x);return A}),a.set(v,p));var T=t(p);if(T===Gt)return!1}return _},set(d,v,p,_){var ke;var T=a.get(v),y=v in d;if(s&&v==="length")for(var x=p;x<T.v;x+=1){var A=a.get(x+"");A!==void 0?u(A,Gt):x in d&&(A=c(()=>O(Gt)),a.set(x+"",A))}if(T===void 0)(!y||(ke=ni(d,v))!=null&&ke.writable)&&(T=c(()=>O(void 0)),u(T,jt(p)),a.set(v,T));else{y=T.v!==Gt;var D=c(()=>jt(p));u(T,D)}var M=Reflect.getOwnPropertyDescriptor(d,v);if(M!=null&&M.set&&M.set.call(_,p),!y){if(s&&typeof v=="string"){var B=a.get("length"),qe=Number(v);Number.isInteger(qe)&&qe>=B.v&&u(B,qe+1)}ri(l)}return!0},ownKeys(d){t(l);var v=Reflect.ownKeys(d).filter(T=>{var y=a.get(T);return y===void 0||y.v!==Gt});for(var[p,_]of a)_.v!==Gt&&!(p in d)&&v.push(p);return v},setPrototypeOf(){Ml()}})}function Or(e){try{if(e!==null&&typeof e=="object"&&Pa in e)return e[Pa]}catch{}return e}function lo(e,n){return Object.is(Or(e),Or(n))}var Br,Ds,$s,Ls;function oo(){if(Br===void 0){Br=window,Ds=/Firefox/.test(navigator.userAgent);var e=Element.prototype,n=Node.prototype,a=Text.prototype;$s=ni(n,"firstChild").get,Ls=ni(n,"nextSibling").get,$r(e)&&(e[lr]=void 0,e[Si]=null,e[or]=void 0,e.__e=void 0),$r(a)&&(a[Za]=void 0)}}function Gn(e=""){return document.createTextNode(e)}function aa(e){return $s.call(e)}function gi(e){return Ls.call(e)}function r(e,n){return aa(e)}function et(e,n=!1){{var a=aa(e);return a instanceof Comment&&a.data===""?gi(a):a}}function i(e,n=1,a=!1){let s=e;for(;n--;)s=gi(s);return s}function co(e){e.textContent=""}function Is(){return!1}function Os(e,n,a){return n==null||n===fs?a?document.createElement(e,{is:a}):document.createElement(e):a?document.createElementNS(n,e,{is:a}):document.createElementNS(n,e)}let Rr=!1;function vo(){Rr||(Rr=!0,document.addEventListener("reset",e=>{Promise.resolve().then(()=>{var n;if(!e.defaultPrevented)for(const a of e.target.elements)(n=a[Mi])==null||n.call(a)})},{capture:!0}))}function Mr(e){var n=Ve,a=Ue;yn(null),In(null);try{return e()}finally{yn(n),In(a)}}function Er(e,n,a,s=a){e.addEventListener(n,()=>Mr(a));const l=e[Mi];l?e[Mi]=()=>{l(),s(!0)}:e[Mi]=()=>s(!0),vo()}function uo(e){Ue===null&&(Ve===null&&xl(),kl()),sa&&yl()}function po(e,n){var a=n.last;a===null?n.last=n.first=e:(a.next=e,e.prev=a,n.last=e)}function Vn(e,n){var a=Ue;a!==null&&(a.f&en)!==0&&(e|=en);var s={ctx:Zt,deps:null,nodes:null,f:e|Qt|bn,first:null,fn:n,last:null,next:null,parent:a,b:a&&a.b,prev:null,teardown:null,wv:0,ac:null};ce==null||ce.register_created_effect(s);var l=s;if((e&Fa)!==0)Ta!==null?Ta.push(s):Sa.ensure().schedule(s);else if(n!==null){try{Wa(s)}catch(c){throw sn(s),c}l.deps===null&&l.teardown===null&&l.nodes===null&&l.first===l.last&&(l.f&Ua)===0&&(l=l.first,(e&Sn)!==0&&(e&Ka)!==0&&l!==null&&(l.f|=Ka))}if(l!==null&&(l.parent=a,a!==null&&po(l,a),Ve!==null&&(Ve.f&Yt)!==0&&(e&ra)===0)){var o=Ve;(o.effects??(o.effects=[])).push(l)}return s}function Ar(){return Ve!==null&&!Mn}function Bs(e){const n=Vn(Ki,null);return Nt(n,Vt),n.teardown=e,n}function mi(e){uo();var n=Ue.f,a=!Ve&&(n&En)!==0&&Zt!==null&&!Zt.i;if(a){var s=Zt;(s.e??(s.e=[])).push(e)}else return Rs(e)}function Rs(e){return Vn(Fa|hl,e)}function fo(e){Sa.ensure();const n=Vn(ra|Ua,e);return(a={})=>new Promise(s=>{a.outro?ya(n,()=>{sn(n),s(void 0)}):(sn(n),s(void 0))})}function Fs(e){return Vn(Fa,e)}function ho(e){return Vn(za|Ua,e)}function qi(e,n=0){return Vn(Ki|n,e)}function P(e,n=[],a=[],s=[]){Jl(s,n,a,l=>{Vn(Ki,()=>{e(...l.map(t))})})}function Cr(e,n=0){var a=Vn(Sn|n,e);return a}function gn(e){return Vn(En|Ua,e)}function Ks(e){var n=e.teardown;if(n!==null){const a=sa,s=Ve;Fr(!0),yn(null);try{n.call(null)}finally{Fr(a),yn(s)}}}function Tr(e,n=!1){var a=e.first;for(e.first=e.last=null;a!==null;){const l=a.ac;l!==null&&Mr(()=>{l.abort(Ni)});var s=a.next;(a.f&ra)!==0?a.parent=null:sn(a,n),a=s}}function go(e){for(var n=e.first;n!==null;){var a=n.next;(n.f&En)===0&&sn(n),n=a}}function sn(e,n=!0){var a=!1;(n||(e.f&fl)!==0)&&e.nodes!==null&&e.nodes.end!==null&&(Ns(e.nodes.start,e.nodes.end),a=!0),e.f|=sr,Tr(e,n&&!a),di(e,0);var s=e.nodes&&e.nodes.t;if(s!==null)for(const o of s)o.stop();Ks(e),e.f^=sr,e.f|=_n;var l=e.parent;l!==null&&l.first!==null&&qs(e),e.next=e.prev=e.teardown=e.ctx=e.deps=e.fn=e.nodes=e.ac=e.b=null}function Ns(e,n){for(;e!==null;){var a=e===n?null:gi(e);e.remove(),e=a}}function qs(e){var n=e.parent,a=e.prev,s=e.next;a!==null&&(a.next=s),s!==null&&(s.prev=a),n!==null&&(n.first===e&&(n.first=s),n.last===e&&(n.last=a))}function ya(e,n,a=!0){var s=[];Ws(e,s,!0);var l=()=>{a&&sn(e),n&&n()},o=s.length;if(o>0){var c=()=>--o||l();for(var d of s)d.out(c)}else l()}function Ws(e,n,a){if((e.f&en)===0){e.f^=en;var s=e.nodes&&e.nodes.t;if(s!==null)for(const d of s)(d.is_global||a)&&n.push(d);for(var l=e.first;l!==null;){var o=l.next;if((l.f&ra)===0){var c=(l.f&Ka)!==0||(l.f&En)!==0&&(e.f&Sn)!==0;Ws(l,n,c?a:!1)}l=o}}}function Ii(e){Gs(e,!0)}function Gs(e,n){if((e.f&en)!==0){e.f^=en,(e.f&Vt)===0&&(Nt(e,Qt),Sa.ensure().schedule(e));for(var a=e.first;a!==null;){var s=a.next,l=(a.f&Ka)!==0||(a.f&En)!==0;Gs(a,l?n:!1),a=s}var o=e.nodes&&e.nodes.t;if(o!==null)for(const c of o)(c.is_global||n)&&c.in()}}function zr(e,n){if(e.nodes)for(var a=e.nodes.start,s=e.nodes.end;a!==null;){var l=a===s?null:gi(a);n.append(a),a=l}}let Ti=!1,sa=!1;function Fr(e){sa=e}let Ve=null,Mn=!1;function yn(e){Ve=e}let Ue=null;function In(e){Ue=e}let Dn=null;function Vs(e){Ve!==null&&(Dn??(Dn=new Set)).add(e)}let rn=null,on=0,un=null;function mo(e){un=e}let js=1,ca=0,ka=ca;function Kr(e){ka=e}function Us(){return++js}function bi(e){var n=e.f;if((n&Qt)!==0)return!0;if(n&Yt&&(e.f&=~wa),(n&Ln)!==0){for(var a=e.deps,s=a.length,l=0;l<s;l++){var o=a[l];if(bi(o)&&ws(o),o.wv>e.wv)return!0}(n&bn)!==0&&Jt===null&&Nt(e,Vt)}return!1}function Hs(e,n,a=!0){var s=e.reactions;if(s!==null&&!(Dn!==null&&Dn.has(e)))for(var l=0;l<s.length;l++){var o=s[l];(o.f&Yt)!==0?Hs(o,n,!1):n===o&&(a?Nt(o,Qt):(o.f&Vt)!==0&&Nt(o,Ln),Sr(o))}}function Js(e){var D;var n=rn,a=on,s=un,l=Ve,o=Dn,c=Zt,d=Mn,v=ka,p=e.f;rn=null,on=0,un=null,Ve=(p&(En|ra))===0?e:null,Dn=null,Na(e.ctx),Mn=!1,ka=++ca,e.ac!==null&&(Mr(()=>{e.ac.abort(Ni)}),e.ac=null);try{e.f|=Di;var _=e.fn,T=_();e.f|=ja;var y=e.deps,x=ce==null?void 0:ce.is_fork;if(rn!==null){var A;if(x||di(e,on),y!==null&&on>0)for(y.length=on+rn.length,A=0;A<rn.length;A++)y[on+A]=rn[A];else e.deps=y=rn;if(Ar()&&(e.f&bn)!==0)for(A=on;A<y.length;A++)((D=y[A]).reactions??(D.reactions=[])).push(e)}else!x&&y!==null&&on<y.length&&(di(e,on),y.length=on);if(ms()&&un!==null&&!Mn&&y!==null&&(e.f&(Yt|Ln|Qt))===0)for(A=0;A<un.length;A++)Hs(un[A],e);if(l!==null&&l!==e){if(ca++,l.deps!==null)for(let M=0;M<a;M+=1)l.deps[M].rv=ca;if(n!==null)for(const M of n)M.rv=ca;un!==null&&(s===null?s=un:s.push(...un))}return(e.f&ia)!==0&&(e.f^=ia),T}catch(M){return _s(M)}finally{e.f^=Di,rn=n,on=a,un=s,Ve=l,Dn=o,Na(c),Mn=d,ka=v}}function bo(e,n){let a=n.reactions;if(a!==null){var s=ll.call(a,e);if(s!==-1){var l=a.length-1;l===0?a=n.reactions=null:(a[s]=a[l],a.pop())}}if(a===null&&(n.f&Yt)!==0&&(rn===null||!zi.call(rn,n))){var o=n;(o.f&bn)!==0&&(o.f^=bn,o.f&=~wa),o.v!==Gt&&yr(o),eo(o),di(o,0)}}function di(e,n){var a=e.deps;if(a!==null)for(var s=n;s<a.length;s++)bo(e,a[s])}function Wa(e){var n=e.f;if((n&_n)===0){Nt(e,Vt);var a=Ue,s=Ti;Ue=e,Ti=!0;try{(n&(Sn|vs))!==0?go(e):Tr(e),Ks(e);var l=Js(e);e.teardown=typeof l=="function"?l:null,e.wv=js;var o}finally{Ti=s,Ue=a}}}async function _o(){await Promise.resolve(),ao()}function t(e){var n=e.f,a=(n&Yt)!==0;if(Ve!==null&&!Mn){var s=Ue!==null&&(Ue.f&_n)!==0;if(!s&&(Dn===null||!Dn.has(e))){var l=Ve.deps;if((Ve.f&Di)!==0)e.rv<ca&&(e.rv=ca,rn===null&&l!==null&&l[on]===e?on++:rn===null?rn=[e]:rn.push(e));else{Ve.deps??(Ve.deps=[]),zi.call(Ve.deps,e)||Ve.deps.push(e);var o=e.reactions;o===null?e.reactions=[Ve]:zi.call(o,Ve)||o.push(Ve)}}}if(sa&&_a.has(e))return _a.get(e);if(a){var c=e;if(sa){var d=c.v;return((c.f&Vt)===0&&c.reactions!==null||Zs(c))&&(d=xr(c)),_a.set(c,d),d}var v=(c.f&bn)===0&&!Mn&&Ve!==null&&(Ti||(Ve.f&bn)!==0),p=(c.f&ja)===0;bi(c)&&(v&&(c.f|=bn),ws(c)),v&&!p&&(Ss(c),Qs(c))}if(Jt!=null&&Jt.has(e))return Jt.get(e);if((e.f&ia)!==0)throw e.v;return e.v}function Qs(e){if(e.f|=bn,e.deps!==null)for(const n of e.deps)(n.reactions??(n.reactions=[])).push(e),(n.f&Yt)!==0&&(n.f&bn)===0&&(Ss(n),Qs(n))}function Zs(e){if(e.v===Gt)return!0;if(e.deps===null)return!1;for(const n of e.deps)if(_a.has(n)||(n.f&Yt)!==0&&Zs(n))return!0;return!1}function Ha(e){var n=Mn;try{return Mn=!0,e()}finally{Mn=n}}const yo=["touchstart","touchmove"];function ko(e){return yo.includes(e)}const va=Symbol("events"),Ys=new Set,hr=new Set;function S(e,n,a){(n[va]??(n[va]={}))[e]=a}function jn(e){for(var n=0;n<e.length;n++)Ys.add(e[n]);for(var a of hr)a(e)}let Nr=null;function qr(e){var D,M;var n=this,a=n.ownerDocument,s=e.type,l=((D=e.composedPath)==null?void 0:D.call(e))||[],o=l[0]||e.target;Nr=e;var c=0,d=Nr===e&&e[va];if(d){var v=l.indexOf(d);if(v!==-1&&(n===document||n===window)){e[va]=n;return}var p=l.indexOf(n);if(p===-1)return;v<=p&&(c=v)}if(o=l[c]||e.target,o!==n){ol(e,"currentTarget",{configurable:!0,get(){return o||a}});var _=Ve,T=Ue;yn(null),In(null);try{for(var y,x=[];o!==null&&o!==n;){try{var A=(M=o[va])==null?void 0:M[s];A!=null&&(!o.disabled||e.target===o)&&A.call(o,e)}catch(B){y?x.push(B):y=B}if(e.cancelBubble)break;c++,o=c<l.length?l[c]:null}if(y){for(let B of x)queueMicrotask(()=>{throw B});throw y}}finally{e[va]=n,delete e.currentTarget,yn(_),In(T)}}}var ss;const Qi=((ss=globalThis==null?void 0:globalThis.window)==null?void 0:ss.trustedTypes)&&globalThis.window.trustedTypes.createPolicy("svelte-trusted-html",{createHTML:e=>e});function xo(e){return(Qi==null?void 0:Qi.createHTML(e))??e}function wo(e){var n=Os("template");return n.innerHTML=xo(e.replaceAll("<!>","<!---->")),n.content}function Ga(e,n){var a=Ue;a.nodes===null&&(a.nodes={start:e,end:n,a:null,t:null})}function b(e,n){var a=(n&Dl)!==0,s=(n&$l)!==0,l,o=!e.startsWith("<!>");return()=>{l===void 0&&(l=wo(o?e:"<!>"+e),a||(l=aa(l)));var c=s||Ds?document.importNode(l,!0):l.cloneNode(!0);if(a){var d=aa(c),v=c.lastChild;Ga(d,v)}else Ga(c,c);return c}}function si(e=""){{var n=Gn(e+"");return Ga(n,n),n}}function Va(){var e=document.createDocumentFragment(),n=document.createComment(""),a=Gn();return e.append(n,a),Ga(n,a),e}function f(e,n){e!==null&&e.before(n)}function g(e,n){var a=n==null?"":typeof n=="object"?`${n}`:n;a!==(e[Za]??(e[Za]=e.nodeValue))&&(e[Za]=a,e.nodeValue=`${a}`)}function So(e,n){return Mo(e,n)}const wi=new Map;function Mo(e,{target:n,anchor:a,props:s={},events:l,context:o,intro:c=!0,transformError:d}){oo();var v=void 0,p=fo(()=>{var _=a??n.appendChild(Gn());Gl(_,{pending:()=>{}},x=>{On({});var A=Zt;o&&(A.c=o),l&&(s.$$events=l),v=e(x,s)||{},Bn()},d);var T=new Set,y=x=>{for(var A=0;A<x.length;A++){var D=x[A];if(!T.has(D)){T.add(D);var M=ko(D);for(const ke of[n,document]){var B=wi.get(ke);B===void 0&&(B=new Map,wi.set(ke,B));var qe=B.get(D);qe===void 0?(ke.addEventListener(D,qr,{passive:M}),B.set(D,1)):B.set(D,qe+1)}}}};return y(Fi(Ys)),hr.add(y),()=>{var M;for(var x of T)for(const B of[n,document]){var A=wi.get(B),D=A.get(x);--D==0?(B.removeEventListener(x,qr),A.delete(x),A.size===0&&wi.delete(B)):A.set(x,D)}hr.delete(y),_!==a&&((M=_.parentNode)==null||M.removeChild(_))}});return Eo.set(v,p),v}let Eo=new WeakMap;var wn,zn,cn,ma,fi,hi,Ri;class Ao{constructor(n,a=!0){ln(this,"anchor");Oe(this,wn,new Map);Oe(this,zn,new Map);Oe(this,cn,new Map);Oe(this,ma,new Set);Oe(this,fi,!0);Oe(this,hi,n=>{if(h(this,wn).has(n)){var a=h(this,wn).get(n),s=h(this,zn).get(a);if(s)Ii(s),h(this,ma).delete(a);else{var l=h(this,cn).get(a);l&&(Ii(l.effect),h(this,zn).set(a,l.effect),h(this,cn).delete(a),l.fragment.lastChild.remove(),this.anchor.before(l.fragment),s=l.effect)}for(const[o,c]of h(this,wn)){if(h(this,wn).delete(o),o===n)break;const d=h(this,cn).get(c);d&&(sn(d.effect),h(this,cn).delete(c))}for(const[o,c]of h(this,zn)){if(o===a||h(this,ma).has(o))continue;const d=()=>{if(Array.from(h(this,wn).values()).includes(o)){var p=document.createDocumentFragment();zr(c,p),p.append(Gn()),h(this,cn).set(o,{effect:c,fragment:p})}else sn(c);h(this,ma).delete(o),h(this,zn).delete(o)};h(this,fi)||!s?(h(this,ma).add(o),ya(c,d,!1)):d()}}});Oe(this,Ri,n=>{h(this,wn).delete(n);const a=Array.from(h(this,wn).values());for(const[s,l]of h(this,cn))a.includes(s)||(sn(l.effect),h(this,cn).delete(s))});this.anchor=n,Pe(this,fi,a)}ensure(n,a){var s=ce,l=Is();if(a&&!h(this,zn).has(n)&&!h(this,cn).has(n))if(l){var o=document.createDocumentFragment(),c=Gn();o.append(c),h(this,cn).set(n,{effect:gn(()=>a(c)),fragment:o})}else h(this,zn).set(n,gn(()=>a(this.anchor)));if(h(this,wn).set(s,n),l){for(const[d,v]of h(this,zn))d===n?s.unskip_effect(v):s.skip_effect(v);for(const[d,v]of h(this,cn))d===n?s.unskip_effect(v.effect):s.skip_effect(v.effect);s.oncommit(h(this,hi)),s.ondiscard(h(this,Ri))}else h(this,hi).call(this,s)}}wn=new WeakMap,zn=new WeakMap,cn=new WeakMap,ma=new WeakMap,fi=new WeakMap,hi=new WeakMap,Ri=new WeakMap;function K(e,n,a=!1){var s=new Ao(e),l=a?Ka:0;function o(c,d){s.ensure(c,d)}Cr(()=>{var c=!1;n((d,v=0)=>{c=!0,o(v,d)}),c||o(-1,null)},l)}function dt(e,n){return n}function Co(e,n,a){for(var s=[],l=n.length,o,c=n.length,d=0;d<l;d++){let T=n[d];ya(T,()=>{if(o){if(o.pending.delete(T),o.done.add(T),o.pending.size===0){var y=e.outrogroups;gr(e,Fi(o.done)),y.delete(o),y.size===0&&(e.outrogroups=null)}}else c-=1},!1)}if(c===0){var v=s.length===0&&a!==null;if(v){var p=a,_=p.parentNode;co(_),_.append(p),e.items.clear()}gr(e,n,!v)}else o={pending:new Set(n),done:new Set},(e.outrogroups??(e.outrogroups=new Set)).add(o)}function gr(e,n,a=!0){var s;if(e.pending.size>0){s=new Set;for(const c of e.pending.values())for(const d of c)s.add(e.items.get(d).e)}for(var l=0;l<n.length;l++){var o=n[l];if(s!=null&&s.has(o)){o.f|=Pn;const c=document.createDocumentFragment();zr(o,c)}else sn(n[l],a)}}var Wr;function rt(e,n,a,s,l,o=null){var c=e,d=new Map,v=(n&ps)!==0;if(v){var p=e;c=p.appendChild(Gn())}var _=null,T=Yl(()=>{var ke=a();return _r(ke)?ke:ke==null?[]:Fi(ke)}),y,x=new Map,A=!0;function D(ke){(qe.effect.f&_n)===0&&(qe.pending.delete(ke),qe.fallback=_,To(qe,y,c,n,s),_!==null&&(y.length===0?(_.f&Pn)===0?Ii(_):(_.f^=Pn,ti(_,null,c)):ya(_,()=>{_=null})))}function M(ke){qe.pending.delete(ke)}var B=Cr(()=>{y=t(T);for(var ke=y.length,xe=new Set,Ae=ce,W=Is(),ae=0;ae<ke;ae+=1){var we=y[ae],Ce=s(we,ae),Be=A?null:d.get(Ce);Be?(Be.v&&qa(Be.v,we),Be.i&&qa(Be.i,ae),W&&Ae.unskip_effect(Be.e)):(Be=zo(d,A?c:Wr??(Wr=Gn()),we,Ce,ae,l,n,a),A||(Be.e.f|=Pn),d.set(Ce,Be)),xe.add(Ce)}if(ke===0&&o&&!_&&(A?_=gn(()=>o(c)):(_=gn(()=>o(Wr??(Wr=Gn()))),_.f|=Pn)),ke>xe.size&&_l(),!A)if(x.set(Ae,xe),W){for(const[je,bt]of d)xe.has(je)||Ae.skip_effect(bt.e);Ae.oncommit(D),Ae.ondiscard(M)}else D(Ae);t(T)}),qe={effect:B,items:d,pending:x,outrogroups:null,fallback:_};A=!1}function Qa(e){for(;e!==null&&(e.f&En)===0;)e=e.next;return e}function To(e,n,a,s,l){var Be,je,bt,z,re,ge,tt,oe,Fe;var o=(s&zl)!==0,c=n.length,d=e.items,v=Qa(e.effect.first),p,_=null,T,y=[],x=[],A,D,M,B;if(o)for(B=0;B<c;B+=1)A=n[B],D=l(A,B),M=d.get(D).e,(M.f&Pn)===0&&((je=(Be=M.nodes)==null?void 0:Be.a)==null||je.measure(),(T??(T=new Set)).add(M));for(B=0;B<c;B+=1){if(A=n[B],D=l(A,B),M=d.get(D).e,e.outrogroups!==null)for(const ue of e.outrogroups)ue.pending.delete(M),ue.done.delete(M);if((M.f&en)!==0&&(Ii(M),o&&((z=(bt=M.nodes)==null?void 0:bt.a)==null||z.unfix(),(T??(T=new Set)).delete(M))),(M.f&Pn)!==0)if(M.f^=Pn,M===v)ti(M,null,a);else{var qe=_?_.next:v;M===e.effect.last&&(e.effect.last=M.prev),M.prev&&(M.prev.next=M.next),M.next&&(M.next.prev=M.prev),Qn(e,_,M),Qn(e,M,qe),ti(M,qe,a),_=M,y=[],x=[],v=Qa(_.next);continue}if(M!==v){if(p!==void 0&&p.has(M)){if(y.length<x.length){var ke=x[0],xe;_=ke.prev;var Ae=y[0],W=y[y.length-1];for(xe=0;xe<y.length;xe+=1)ti(y[xe],ke,a);for(xe=0;xe<x.length;xe+=1)p.delete(x[xe]);Qn(e,Ae.prev,W.next),Qn(e,_,Ae),Qn(e,W,ke),v=ke,_=W,B-=1,y=[],x=[]}else p.delete(M),ti(M,v,a),Qn(e,M.prev,M.next),Qn(e,M,_===null?e.effect.first:_.next),Qn(e,_,M),_=M;continue}for(y=[],x=[];v!==null&&v!==M;)(p??(p=new Set)).add(v),x.push(v),v=Qa(v.next);if(v===null)continue}(M.f&Pn)===0&&y.push(M),_=M,v=Qa(M.next)}if(e.outrogroups!==null){for(const ue of e.outrogroups)ue.pending.size===0&&(gr(e,Fi(ue.done)),(re=e.outrogroups)==null||re.delete(ue));e.outrogroups.size===0&&(e.outrogroups=null)}if(v!==null||p!==void 0){var ae=[];if(p!==void 0)for(M of p)(M.f&en)===0&&ae.push(M);for(;v!==null;)(v.f&en)===0&&v!==e.fallback&&ae.push(v),v=Qa(v.next);var we=ae.length;if(we>0){var Ce=(s&ps)!==0&&c===0?a:null;if(o){for(B=0;B<we;B+=1)(tt=(ge=ae[B].nodes)==null?void 0:ge.a)==null||tt.measure();for(B=0;B<we;B+=1)(Fe=(oe=ae[B].nodes)==null?void 0:oe.a)==null||Fe.fix()}Co(e,ae,Ce)}}o&&ba(()=>{var ue,q;if(T!==void 0)for(M of T)(q=(ue=M.nodes)==null?void 0:ue.a)==null||q.apply()})}function zo(e,n,a,s,l,o,c,d){var v=(c&Cl)!==0?(c&Pl)===0?ro(a,!1,!1):Ma(a):null,p=(c&Tl)!==0?Ma(l):null;return{v,i:p,e:gn(()=>(o(n,v??a,p??l,d),()=>{e.delete(s)}))}}function ti(e,n,a){if(e.nodes)for(var s=e.nodes.start,l=e.nodes.end,o=n&&(n.f&Pn)===0?n.nodes.start:a;s!==null;){var c=gi(s);if(o.before(s),s===l)return;s=c}}function Qn(e,n,a){n===null?e.effect.first=a:n.next=a,a===null?e.effect.last=n:a.prev=n}function He(e,n,a=!1,s=!1,l=!1,o=!1){var c=e,d="";if(a)var v=e;P(()=>{var p=Ue;if(d!==(d=n()??"")){if(a){p.nodes=null,v.innerHTML=d,d!==""&&Ga(aa(v),v.lastChild);return}if(p.nodes!==null&&(Ns(p.nodes.start,p.nodes.end),p.nodes=null),d!==""){var _=s?Ll:l?Il:void 0,T=Os(s?"svg":l?"math":"template",_);T.innerHTML=d;var y=s||l?T:T.content;if(Ga(aa(y),y.lastChild),s||l)for(;aa(y);)c.before(aa(y));else c.before(y)}}})}function Po(e,n,a){var s=e==null?"":""+e;return s===""?null:s}function Do(e,n){return e==null?null:String(e)}function Dt(e,n,a,s,l,o){var c=e[lr];if(c!==a||c===void 0){var d=Po(a);d==null?e.removeAttribute("class"):e.className=d,e[lr]=a}return o}function Ot(e,n,a,s){var l=e[or];if(l!==n){var o=Do(n);o==null?e.removeAttribute("style"):e.style.cssText=o,e[or]=n}return s}function Xs(e,n,a=!1){if(e.multiple){if(n==null)return;if(!_r(n))return Bl();for(var s of e.options)s.selected=n.includes(li(s));return}for(s of e.options){var l=li(s);if(lo(l,n)){s.selected=!0;return}}(!a||n!==void 0)&&(e.selectedIndex=-1)}function $o(e){var n=new MutationObserver(()=>{Xs(e,e.__value)});n.observe(e,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["value"]}),Bs(()=>{n.disconnect()})}function xa(e,n,a=n){var s=new WeakSet,l=!0;Er(e,"change",o=>{var c=o?"[selected]":":checked",d;if(e.multiple)d=[].map.call(e.querySelectorAll(c),li);else{var v=e.querySelector(c)??e.querySelector("option:not([disabled])");d=v&&li(v)}a(d),e.__value=d,ce!==null&&s.add(ce)}),Fs(()=>{var o=n();if(e===document.activeElement){var c=ce;if(s.has(c))return}if(Xs(e,o,l),l&&o===void 0){var d=e.querySelector(":checked");d!==null&&(o=li(d),a(o))}e.__value=o,l=!1}),$o(e)}function li(e){return"__value"in e?e.__value:e.value}const Lo=Symbol("is custom element"),Io=Symbol("is html"),Oo=ml?"progress":"PROGRESS";function Zn(e,n){var a=el(e);a.value===(a.value=n??void 0)||e.value===n&&(n!==0||e.nodeName!==Oo)||(e.value=n??"")}function _i(e,n,a,s){var l=el(e);l[n]!==(l[n]=a)&&(n==="loading"&&(e[gl]=a),a==null?e.removeAttribute(n):typeof a!="string"&&Bo(e).includes(n)?e[n]=a:e.setAttribute(n,a))}function el(e){return e[Si]??(e[Si]={[Lo]:e.nodeName.includes("-"),[Io]:e.namespaceURI===fs})}var Gr=new Map;function Bo(e){var n=e.getAttribute("is")||e.nodeName,a=Gr.get(n);if(a)return a;Gr.set(n,a=[]);for(var s,l=e,o=Element.prototype;o!==l;){s=dl(l);for(var c in s)s[c].set&&c!=="innerHTML"&&c!=="textContent"&&c!=="innerText"&&a.push(c);l=ds(l)}return a}function vn(e,n,a=n){var s=new WeakSet;Er(e,"input",async l=>{var o=l?e.defaultValue:e.value;if(o=Zi(e)?Yi(o):o,a(o),ce!==null&&s.add(ce),await _o(),o!==(o=n())){var c=e.selectionStart,d=e.selectionEnd,v=e.value.length;if(e.value=o??"",d!==null){var p=e.value.length;c===d&&d===v&&p>v?(e.selectionStart=p,e.selectionEnd=p):(e.selectionStart=c,e.selectionEnd=Math.min(d,p))}}}),Ha(n)==null&&e.value&&(a(Zi(e)?Yi(e.value):e.value),ce!==null&&s.add(ce)),qi(()=>{var l=n();if(e===document.activeElement){var o=ce;if(s.has(o))return}Zi(e)&&l===Yi(e.value)||e.type==="date"&&!l&&!e.value||l!==e.value&&(e.value=l??"")})}function Ro(e,n,a=n){Er(e,"change",s=>{var l=s?e.defaultChecked:e.checked;a(l)}),Ha(n)==null&&a(e.checked),qi(()=>{var s=n();e.checked=!!s})}function Zi(e){var n=e.type;return n==="number"||n==="range"}function Yi(e){return e===""?null:+e}function Xi(e,n){return e===n||(e==null?void 0:e[Pa])===n}function Fo(e={},n,a,s){var l=Zt.r,o=Ue;return Fs(()=>{var c,d;return qi(()=>{c=d,d=[],Ha(()=>{Xi(a(...d),e)||(n(e,...d),c&&Xi(a(...c),e)&&n(null,...c))})}),()=>{let v=o;for(;v!==l&&v.parent!==null&&v.parent.f&sr;)v=v.parent;const p=()=>{d&&Xi(a(...d),e)&&n(null,...d)},_=v.teardown;v.teardown=()=>{p(),_==null||_()}}}),e}function yi(e){Zt===null&&us(),mi(()=>{const n=Ha(e);if(typeof n=="function")return n})}function Ko(e){Zt===null&&us(),yi(()=>()=>Ha(e))}let ci=localStorage.getItem("mc_token")||"";function tl(){return ci}function No(e){ci=(e||"").trim(),localStorage.setItem("mc_token",ci)}function qo(){const e={"Content-Type":"application/json"};return ci&&(e["X-MC-Token"]=ci),e}function oi(){return localStorage.getItem("mc_hf_token")||""}function Wo(e){localStorage.setItem("mc_hf_token",(e||"").trim())}async function $e(e,n={}){const a=await fetch(e,{headers:qo(),...n}),s=await a.json().catch(()=>({}));if(!a.ok)throw new Error(s.error||"HTTP "+a.status);return s}const Go=(e,n=document)=>n.querySelector(e),Vr=(e,n=document)=>[...n.querySelectorAll(e)];function $n(e){return String(e??"").replace(/[&<>]/g,n=>({"&":"&","<":"<",">":">"})[n])}let jr;function ie(e,n=!1){const a=Go("#toast");a&&(a.textContent=e,a.className="toast show"+(n?" err":""),clearTimeout(jr),jr=setTimeout(()=>a.className="toast",3200))}function Vo(e,n){return e==="running"||e==="ready"?'<span class="badge b-run">geladen</span>':e==="loading"||e==="starting"?'<span class="badge b-load">lädt…</span>':e==="downloading"?`<span class="badge b-load">↓ Download${n!=null?` ${Math.round(n)}%`:""}</span>`:'<span class="badge b-run">bereit</span>'}const ft=e=>`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">${e}</svg>`,Wi={logo:ft('<circle cx="12" cy="12" r="3.2"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M19 5l-2 2M7 17l-2 2"/>'),grid:ft('<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/>'),cpu:ft('<rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M1 9h3M1 15h3M20 9h3M20 15h3"/>'),pulse:ft('<path d="M3 12h4l2 6 4-14 2 8h6"/>'),server:ft('<rect x="3" y="4" width="18" height="7" rx="2"/><rect x="3" y="13" width="18" height="7" rx="2"/><path d="M7 7.5h.01M7 16.5h.01"/>'),book:ft('<path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M19 19H6a2 2 0 0 0-2 2"/>'),help:ft('<circle cx="12" cy="12" r="9"/><path d="M9.5 9.2a2.5 2.5 0 0 1 4.8 1c0 1.7-2.3 2-2.3 3.4"/><path d="M12 17h.01"/>'),settings:ft('<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-2.7 1.1V21a2 2 0 1 1-4 0v-.1A1.6 1.6 0 0 0 6.6 19l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.6 1.6 0 0 0-1.1-2.7H2a2 2 0 1 1 0-4h.1A1.6 1.6 0 0 0 4 6.6l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1A1.6 1.6 0 0 0 9 4.6V4a2 2 0 1 1 4 0v.1A1.6 1.6 0 0 0 17.4 6l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.6 1.6 0 0 0 1.1 2.7H21a2 2 0 1 1 0 4h-.1a1.6 1.6 0 0 0-1.5 1z"/>'),swap:ft('<path d="M7 4 3 8l4 4"/><path d="M3 8h12a4 4 0 0 1 0 8h-1"/><path d="m17 20 4-4-4-4"/>'),monitor:ft('<rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/>'),layers:ft('<path d="m12 2 9 5-9 5-9-5z"/><path d="m3 12 9 5 9-5M3 17l9 5 9-5"/>'),alert:ft('<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/>'),gauge:ft('<path d="M12 14 16 9"/><circle cx="12" cy="13" r="9"/><path d="M12 4v2M21 13h-2M5 13H3"/>'),search:ft('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),compass:ft('<circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/>'),code:ft('<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>'),eye:ft('<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>'),refresh:ft('<path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/>'),file:ft('<path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M9 13h6M9 17h5"/>'),database:ft('<ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.7 3.6 3 8 3s8-1.3 8-3V5"/><path d="M4 11v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"/>'),thermo:ft('<path d="M14 14.76V5a2 2 0 0 0-4 0v9.76a4 4 0 1 0 4 0z"/>'),shield:ft('<path d="M12 3l8 4v5c0 5-3.5 8-8 9-4.5-1-8-4-8-9V7z"/><path d="m9 12 2 2 4-4"/>'),info:ft('<circle cx="12" cy="12" r="9"/><path d="M12 16v-4M12 8h.01"/>'),chevron:ft('<path d="m9 6 6 6-6 6"/>'),bolt:ft('<path d="M13 2 3 14h7l-1 8 10-12h-7z"/>'),x:ft('<path d="M18 6 6 18M6 6l12 12"/>'),check:ft('<path d="M20 6 9 17l-5-5"/>'),download:ft('<path d="M12 3v12M7 10l5 5 5-5"/><path d="M5 21h14"/>'),clock:ft('<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>')};function Wt(e){return Wi[e]||""}function mr(e){return`<span class="info-dot" tabindex="0" title="${$n(e)}" aria-label="${$n(e)}">${Wi.info}</span>`}function oa(e){if(!e&&e!==0)return"–";const n=e/1024/1024/1024;return n>=1?n.toFixed(1)+" GB":Math.round(e/1024/1024)+" MB"}function mn({title:e,body:n,confirmLabel:a="Bestätigen",cancelLabel:s="Abbrechen",danger:l=!1}){return new Promise(o=>{const c=document.createElement("div");c.className="modal-overlay",c.innerHTML=`<div class="modal-card" role="dialog" aria-modal="true">
|
||
<h3>${$n(e)}</h3>
|
||
<p>${n}</p>
|
||
<div class="modal-actions">
|
||
<button data-x="0">${$n(s)}</button>
|
||
<button class="${l?"danger":"primary"}" data-x="1">${$n(a)}</button>
|
||
</div></div>`;const d=v=>{c.remove(),o(v)};c.addEventListener("click",v=>{if(v.target===c)return d(!1);const p=v.target.closest("[data-x]");p&&d(p.getAttribute("data-x")==="1")}),document.body.appendChild(c),c.querySelector('[data-x="1"]').focus()})}function Ur({title:e,body:n="",placeholder:a="",password:s=!1,confirmLabel:l="Weiter",danger:o=!1}){return new Promise(c=>{const d=document.createElement("div");d.className="modal-overlay",d.innerHTML=`<div class="modal-card" role="dialog" aria-modal="true">
|
||
<h3>${$n(e)}</h3>
|
||
${n?`<p>${n}</p>`:""}
|
||
<input type="${s?"password":"text"}" placeholder="${$n(a)}" autocomplete="off" style="margin-bottom:18px">
|
||
<div class="modal-actions">
|
||
<button data-x="0">Abbrechen</button>
|
||
<button class="${o?"danger":"primary"}" data-x="1">${$n(l)}</button>
|
||
</div></div>`;const v=d.querySelector("input"),p=_=>{d.remove(),c(_)};d.addEventListener("click",_=>{if(_.target===d)return p(null);const T=_.target.closest("[data-x]");T&&p(T.getAttribute("data-x")==="1"?v.value||"":null)}),v.addEventListener("keydown",_=>{_.key==="Enter"&&p(v.value||""),_.key==="Escape"&&p(null)}),document.body.appendChild(d),v.focus()})}function jo(e="overview"){const n=Vr(".nav-item[data-view]:not(.disabled)"),a=Vr(".view[data-view]"),s=new Set(a.map(o=>o.dataset.view));function l(o){s.has(o)||(o=e),a.forEach(c=>c.hidden=c.dataset.view!==o),n.forEach(c=>c.classList.toggle("active",c.dataset.view===o)),location.hash!=="#/"+o&&(location.hash="#/"+o)}return n.forEach(o=>o.addEventListener("click",c=>{c.preventDefault(),l(o.dataset.view)})),window.addEventListener("hashchange",()=>l(location.hash.replace("#/",""))),l(location.hash.replace("#/","")||e),{show:l}}let Hr=O(null);const ki={get value(){return t(Hr)},set(e){u(Hr,e,!0)}};let Jr=O(jt([])),Yn=O(jt([]));const ua={get value(){return t(Jr)},set(e){u(Jr,e||[],!0)},get tracked(){return t(Yn)},track(e){t(Yn).includes(e)||u(Yn,[...t(Yn),e],!0)},toggle(e){u(Yn,t(Yn).includes(e)?t(Yn).filter(n=>n!==e):[...t(Yn),e],!0)}};let Qr=O(null);const Pr={get value(){return t(Qr)},set(e){u(Qr,e,!0)}},Uo="5";var ls;typeof window<"u"&&((ls=window.__svelte??(window.__svelte={})).v??(ls.v=new Set)).add(Uo);var Ho=b('<span style="font-size:13px;font-weight:400;color:var(--mut)">— bereit für Anfragen</span>'),Jo=b('<div><div class="k-h"><span class="k-t">Temperatur (GPU)</span><span class="k-ic"></span></div> <div class="k-v"> </div> <div class="k-s"> </div></div> <div><div class="k-h"><span class="k-t">Freier Speicher</span><span class="k-ic"></span></div> <div class="k-v"> <small>GB</small></div> <div class="k-s"> </div></div>',1),Qo=b('<div class="kpi muted"><div class="k-h"><span class="k-t">Temperatur</span></div><div class="k-v">–</div><div class="k-s">messe…</div></div> <div class="kpi muted"><div class="k-h"><span class="k-t">Freier Speicher</span></div><div class="k-v">–</div><div class="k-s">messe…</div></div>',1),Zo=b('<div class="meter"><div class="meter-h"><span class="mk"> </span><span class="mv"> </span></div> <div><i></i></div></div>'),Yo=b('<div class="empty">Warte auf Messwerte…</div>'),Xo=b('<div class="card-sub">Noch kein Modell eingerichtet — starte hier:</div> <button class="qa"><span class="qa-ic teal"></span> <span class="qa-main"><span class="qa-t">Schritt 1 · Modell holen</span><span class="qa-s">Cookbook → passendes Setup installieren</span></span> <span class="qa-arrow"></span></button> <button class="qa" style="opacity:.55;pointer-events:none"><span class="qa-ic teal"></span> <span class="qa-main"><span class="qa-t">Schritt 2 · Tools verbinden</span><span class="qa-s">Erst nach dem Download verfügbar</span></span> <span class="qa-arrow"></span></button> <button class="qa"><span class="qa-ic blue"></span> <span class="qa-main"><span class="qa-t">Einsteiger-Guide lesen</span><span class="qa-s">Alle Begriffe erklärt, ohne Vorwissen</span></span> <span class="qa-arrow"></span></button>',1),ed=b('<div class="card-sub">Die häufigsten Aufgaben — ein Klick.</div> <button class="qa"><span class="qa-ic teal"></span> <span class="qa-main"><span class="qa-t">Modell finden</span><span class="qa-s">Passend zu deiner Hardware</span></span> <span class="qa-arrow"></span></button> <button class="qa"><span class="qa-ic amber"></span> <span class="qa-main"><span class="qa-t">Speicher freigeben</span><span class="qa-s">Alle Modelle entladen</span></span> <span class="qa-arrow"></span></button> <button class="qa"><span class="qa-ic blue"></span> <span class="qa-main"><span class="qa-t">Logs ansehen</span><span class="qa-s">Live mitlesen, was läuft</span></span> <span class="qa-arrow"></span></button> <button class="qa"><span class="qa-ic teal"></span> <span class="qa-main"><span class="qa-t">Tools verbinden</span><span class="qa-s">Zed, OpenCode, Cline einrichten</span></span> <span class="qa-arrow"></span></button>',1),td=b('<span class="tag img">Bild</span>'),nd=b('<span class="tag code">Code</span>'),ad=b('<span class="tag text">Text</span>'),id=b('<span class="chip" style="padding:2px 7px;font-size:11px">∞ aktiv</span>'),rd=b('<button class="ghost"> </button>'),sd=b('<div class="li" style="padding:10px 4px"><span></span> <div class="li-main"><div class="flex items-center gap-2" style="flex-wrap:wrap"><span class="li-id"> </span> <!> <!></div> <div class="li-sub mono-sm"> </div></div> <div class="flex items-center gap-2"><span class="li-meta"> </span> <!></div></div>'),Zr=b('<div class="list"></div>'),ld=b('<div class="empty-c"><div class="e-t">Noch keine Modelle</div> <div class="e-s">Hol dir unter „Cookbook" ein Modell, das auf deine Hardware passt.</div> <button class="primary" style="margin-top:12px">Zum Cookbook →</button></div>'),od=b('<a class="li" target="_blank" rel="noopener" style="text-decoration:none;color:inherit"><div class="li-main"><div style="font-size:13px;line-height:1.4"> </div> <div class="li-sub"> </div></div></a>'),dd=b('<div class="empty">News gerade nicht ladbar.</div>'),cd=b('<div class="pagehead" style="margin-bottom:10px"><div><h1 style="display:flex;align-items:center;gap:10px"> <!></h1> <div class="sub"> </div></div></div> <div class="tiles"><div><div class="k-h"><span class="k-t">LLM-Engine</span> <span class="k-ic"></span></div> <div class="k-v"> </div> <div class="k-s"> </div></div> <div><div class="k-h"><span class="k-t">Aktives Modell</span> <span class="k-ic"></span></div> <div class="k-v" style="font-size:16px;word-break:break-word"> </div> <div class="k-s"><!></div></div> <!></div> <div class="split"><div class="card"><div class="card-h"><h3>System-Gesundheit</h3></div> <div class="card-sub">Auslastung in Echtzeit.</div> <!></div> <div class="card"><div class="card-h"><h3>Schnellstart</h3></div> <!></div></div> <div class="grid grid-2"><div class="card"><div class="card-h"><h3>Dein Stack</h3> <span class="meta"> </span></div> <!></div> <div class="card"><div class="card-h"><h3>Top-News</h3> <span class="meta" style="cursor:pointer" role="button" tabindex="0">Alle →</span></div> <!></div></div>',1);function vd(e,n){On(n,!0);const a=N(()=>ki.value),s=N(()=>Pr.value),l=N(()=>{var C;return((C=t(a))==null?void 0:C.models)||[]}),o=N(()=>{var C;return((C=t(a))==null?void 0:C.swap_ok)??!1}),c=["running","ready","loading","starting"],d=N(()=>t(l).find(C=>c.includes(C.state))),v=N(()=>t(l).filter(C=>!C.incomplete)),p=N(()=>t(a)?t(o)?t(s)&&t(s).ram.percent>=90?"Achtung: Speicher wird knapp.":"Alles läuft rund.":"LLM-Engine offline":"Verbinde…"),_=N(()=>t(a)?t(o)?t(s)&&t(s).ram.percent>=90?`Arbeitsspeicher bei ${Math.round(t(s).ram.percent)} % — eventuell Speicher freigeben.`:`${t(v).length} ${t(v).length===1?"Modell":"Modelle"} konfiguriert · ${t(d)?`„${t(d).name}" geladen`:"keines geladen"} · keine Warnungen.`:"Der llama-swap-Dienst antwortet gerade nicht.":""),T=N(()=>()=>{var Z;const C=(Z=t(s))==null?void 0:Z.gpu;return C&&C.vram.total+C.gtt.total>0?(C.vram.used+C.gtt.used)/(C.vram.total+C.gtt.total)*100:0});let y=O(jt([])),x=O(null);yi(async()=>{try{u(y,((await $e("/api/news")).items||[]).slice(0,4),!0)}catch{}});async function A(){await mn({title:"Speicher freigeben?",body:"Alle aktuell geladenen Modelle werden aus dem Grafikspeicher geworfen. Sie laden beim nächsten Aufruf automatisch neu.",confirmLabel:"Speicher freigeben"})&&(await $e("/api/unload",{method:"POST"}),M())}async function D(C){u(x,C,!0);try{await $e("/api/preload?model="+encodeURIComponent(C),{method:"POST"})}catch(Z){ie("Laden fehlgeschlagen: "+(Z.message||"Engine nicht erreichbar?"),!0)}u(x,null),M()}function M(){document.dispatchEvent(new Event("mc:refresh"))}function B(C){var Z;(Z=document.querySelector(`.nav-item[data-view="${C}"]`))==null||Z.dispatchEvent(new MouseEvent("click"))}function qe(C){return C>=90?"red":C>=75?"":"green"}function ke(C){return C==null?"":C>=75?"red":C>=55?"":"green"}function xe(C){return C>=90?"red":C>=70?"":"green"}var Ae=cd(),W=et(Ae),ae=r(W),we=r(ae),Ce=r(we),Be=i(Ce);{var je=C=>{var Z=Ho();f(C,Z)};K(Be,C=>{t(o)&&!t(d)&&C(je)})}var bt=i(we,2),z=r(bt),re=i(W,2),ge=r(re),tt=r(ge),oe=i(r(tt),2);He(oe,()=>Wt("server"),!0);var Fe=i(tt,2),ue=r(Fe),q=i(Fe,2),Y=r(q),pe=i(ge,2),fe=r(pe),Ke=i(r(fe),2);He(Ke,()=>Wt("cpu"),!0);var Ye=i(fe,2),ct=r(Ye),st=i(Ye,2),lt=r(st);{var Re=C=>{var Z=si();P(Ge=>g(Z,`${Ge??""} · ${t(d).state??""}`),[()=>{var Ge;return(Ge=t(d).meta)!=null&&Ge.ctx?Math.round(t(d).meta.ctx/1024)+"k ctx":""}]),f(C,Z)},Je=C=>{var Z=si("lädt bei erster Anfrage");f(C,Z)};K(lt,C=>{t(d)?C(Re):C(Je,-1)})}var vt=i(pe,2);{var F=C=>{const Z=N(()=>{var Hn;return t(s).gpu_temp??((Hn=t(s).cpu)==null?void 0:Hn.temp)??null}),Ge=N(()=>ke(t(Z))),he=N(()=>t(s).ram.total-t(s).ram.used),G=N(()=>100-t(s).ram.percent);var Q=Jo(),V=et(Q),R=r(V),H=i(r(R));He(H,()=>Wt("thermo"),!0);var te=i(R,2),ve=r(te),Ie=i(te,2),Ee=r(Ie),ut=i(V,2),Et=r(ut),De=i(r(Et));He(De,()=>Wt("database"),!0);var xt=i(Et,2),Rn=r(xt),Un=i(xt,2),la=r(Un);P((Hn,Ja,w,k)=>{Dt(V,1,`kpi ${t(Ge)??""}`),g(ve,Hn),g(Ee,t(Z)==null?"messe…":t(Z)<55?"kühl":t(Z)<75?"normal":"⚠ heiß"),Dt(ut,1,`kpi ${t(G)<15?"red":t(G)<30?"":"green"}`),g(Rn,Ja),g(la,`von ${w??""} GB · ${k??""} % frei`)},[()=>t(Z)!=null?`${Math.round(t(Z))}°C`:"–",()=>Math.round(t(he)/1073741824),()=>Math.round(t(s).ram.total/1073741824),()=>Math.round(t(G))]),f(C,Q)},X=C=>{var Z=Qo();f(C,Z)};K(vt,C=>{t(s)?C(F):C(X,-1)})}var E=i(re,2),I=r(E),se=i(r(I),4);{var le=C=>{const Z=N(()=>t(T)());var Ge=Va(),he=et(Ge);rt(he,17,()=>{var G;return[["Prozessor (CPU)",((G=t(s).cpu)==null?void 0:G.percent)??0,""],["Arbeitsspeicher (RAM)",t(s).ram.percent,qe(t(s).ram.percent)],["Grafikspeicher (VRAM)",t(Z),xe(t(Z))]]},dt,(G,Q)=>{var V=N(()=>ta(t(Q),3));let R=()=>t(V)[0],H=()=>t(V)[1];const te=N(()=>Math.max(0,Math.min(100,H()||0)));var ve=Zo(),Ie=r(ve),Ee=r(Ie),ut=r(Ee),Et=i(Ee),De=r(Et),xt=i(Ie,2),Rn=r(xt);P((Un,la)=>{g(ut,R()),g(De,`${Un??""} %`),Dt(xt,1,`bar ${t(te)>=90?"bad":t(te)>=75?"warn":""}`),Ot(Rn,`width:${la??""}%`)},[()=>Math.round(t(te)),()=>Math.max(2,t(te))]),f(G,ve)}),f(C,Ge)},m=C=>{var Z=Yo();f(C,Z)};K(se,C=>{t(s)?C(le):C(m,-1)})}var L=i(I,2),ne=i(r(L),2);{var ee=C=>{var Z=Xo(),Ge=i(et(Z),2),he=r(Ge);He(he,()=>Wt("search"),!0);var G=i(he,4);He(G,()=>Wt("chevron"),!0);var Q=i(Ge,2),V=r(Q);He(V,()=>Wt("swap"),!0);var R=i(V,4);He(R,()=>Wt("chevron"),!0);var H=i(Q,2),te=r(H);He(te,()=>Wt("file"),!0);var ve=i(te,4);He(ve,()=>Wt("chevron"),!0),S("click",Ge,()=>B("cookbook")),S("click",Q,()=>B("connect")),S("click",H,()=>B("guides")),f(C,Z)},U=C=>{var Z=ed(),Ge=i(et(Z),2),he=r(Ge);He(he,()=>Wt("search"),!0);var G=i(he,4);He(G,()=>Wt("chevron"),!0);var Q=i(Ge,2),V=r(Q);He(V,()=>Wt("refresh"),!0);var R=i(V,4);He(R,()=>Wt("chevron"),!0);var H=i(Q,2),te=r(H);He(te,()=>Wt("file"),!0);var ve=i(te,4);He(ve,()=>Wt("chevron"),!0);var Ie=i(H,2),Ee=r(Ie);He(Ee,()=>Wt("swap"),!0);var ut=i(Ee,4);He(ut,()=>Wt("chevron"),!0),S("click",Ge,()=>B("cookbook")),S("click",Q,A),S("click",H,()=>B("server")),S("click",Ie,()=>B("connect")),f(C,Z)};K(ne,C=>{t(v).length?C(U,-1):C(ee)})}var be=i(E,2),_e=r(be),Le=r(_e),Qe=i(r(Le),2),Me=r(Qe),Ze=i(Le,2);{var $=C=>{var Z=Zr();rt(Z,21,()=>t(v),dt,(Ge,he)=>{const G=N(()=>c.includes(t(he).state)),Q=N(()=>t(he).state==="downloading"),V=N(()=>t(he).state==="loading"||t(he).state==="starting"||t(Q)?"load":t(G)?"on":""),R=N(()=>t(Q)?`↓ ${t(he).download_progress!=null?Math.round(t(he).download_progress)+"%":"..."}`:t(he).state==="loading"||t(he).state==="starting"?"lädt…":t(G)?"geladen ✓":"bereit");var H=sd(),te=r(H),ve=i(te,2),Ie=r(ve),Ee=r(Ie),ut=r(Ee),Et=i(Ee,2);{var De=ye=>{var We=td();f(ye,We)},xt=N(()=>{var ye,We;return(We=(ye=t(he).meta)==null?void 0:ye.caps)==null?void 0:We.includes("Bild")}),Rn=ye=>{var We=nd();f(ye,We)},Un=N(()=>{var ye,We;return(We=(ye=t(he).meta)==null?void 0:ye.caps)==null?void 0:We.includes("Code")}),la=ye=>{var We=ad();f(ye,We)};K(Et,ye=>{t(xt)?ye(De):t(Un)?ye(Rn,1):ye(la,-1)})}var Hn=i(Et,2);{var Ja=ye=>{var We=id();f(ye,We)};K(Hn,ye=>{t(he).ttl>=99999&&ye(Ja)})}var w=i(Ie,2),k=r(w),J=i(ve,2),j=r(J),Se=r(j),_t=i(j,2);{var wt=ye=>{var We=rd(),Xe=r(We);P(()=>{Ot(We,`padding:3px 9px;font-size:12px;opacity:${t(x)===t(he).name?".5":"1"}`),We.disabled=t(x)===t(he).name,g(Xe,t(x)===t(he).name?"…":"Laden")}),S("click",We,()=>D(t(he).name)),f(ye,We)};K(_t,ye=>{!t(G)&&!t(Q)&&t(o)&&ye(wt)})}P((ye,We)=>{var Xe;Dt(te,1,`li-dot ${t(V)??""}`),Ot(Ee,t(G)?"color:var(--accent)":""),g(ut,t(he).name),g(k,`${ye??""}
|
||
${(Xe=t(he).meta)!=null&&Xe.quant?" · "+t(he).meta.quant:""}
|
||
${We??""}`),Ot(j,`white-space:nowrap;color:${t(G)?"var(--on)":"var(--mut)"}`),g(Se,t(R))},[()=>{var ye;return(ye=t(he).meta)!=null&&ye.ctx?Math.round(t(he).meta.ctx/1024)+"k ctx":""},()=>{var ye;return(ye=t(he).meta)!=null&&ye.size_bytes?" · "+(t(he).meta.size_bytes/1073741824).toFixed(1)+" GB":""}]),f(Ge,H)}),f(C,Z)},de=C=>{var Z=ld(),Ge=i(r(Z),4);S("click",Ge,()=>B("cookbook")),f(C,Z)};K(Ze,C=>{t(v).length?C($):C(de,-1)})}var Te=i(_e,2),ze=r(Te),me=i(r(ze),2),Tt=i(ze,2);{var $t=C=>{var Z=Zr();rt(Z,21,()=>t(y),dt,(Ge,he)=>{var G=od(),Q=r(G),V=r(Q),R=r(V),H=i(V,2),te=r(H);P(()=>{_i(G,"href",t(he).link),g(R,t(he).title),g(te,`${t(he).source??""}${t(he).relevant?" · für dich":""}`)}),f(Ge,G)}),f(C,Z)},zt=C=>{var Z=dd();f(C,Z)};K(Tt,C=>{t(y).length?C($t):C(zt,-1)})}P(C=>{g(Ce,`${t(p)??""} `),g(z,t(_)),Dt(ge,1,`kpi ${t(o)?"green":"red"}`),g(ue,t(o)?"Online":"Offline"),g(Y,C),Dt(pe,1,`kpi ${t(d)?"blue":"muted"}`),g(ct,t(d)?t(d).name:"Keins"),g(Me,t(v).length?t(v).length+" konfiguriert":"")},[()=>{var C,Z;return((Z=(C=t(a))==null?void 0:C.swap_url)==null?void 0:Z.replace(/^https?:\/\//,""))??"—"}]),S("click",me,()=>B("news")),S("keydown",me,C=>C.key==="Enter"&&B("news")),f(e,Ae),Bn()}jn(["click","keydown"]);var ud=b("<option> </option>"),pd=b('<div class="reply" style="margin-top:12px"> </div>'),fd=b('<div class="empty-c"><div class="e-t">Noch keine Modelle konfiguriert</div> <div class="e-s">Hol dir unter „Cookbook" ein passendes Modell.</div></div>'),hd=b('<tr style="opacity:.9"><td class="mid" style="font-weight:500"> <div class="li-sub mono-sm" style="color:var(--warn)">kein Modell hinterlegt</div></td><td>—</td><td><span class="mono-sm text-mut">leere Rolle</span></td><td><span class="badge">leer</span></td><td class="port">—</td><td style="text-align:right;white-space:nowrap"><button class="ghost">Modell zuweisen</button> <button class="ghost del">Löschen</button></td></tr>'),gd=b('<span class="tag" style="background:rgba(45,212,191,.14);color:var(--accent);border-color:rgba(45,212,191,.3)"> </span>'),md=b('<div class="li-sub mono-sm"> </div>'),bd=b('<code style="cursor:pointer" title="Klicken zum Kopieren"> </code>'),_d=b('<tr><td class="mid"><div style="font-weight:500;display:flex;align-items:center;gap:7px;flex-wrap:wrap"> <!></div> <!> <div class="li-sub mono-sm" style="margin-top:3px;display:flex;align-items:center;gap:6px;flex-wrap:wrap"><span class="text-mut">API-Name:</span> <!></div></td><td></td><td></td><td></td><td class="port"> </td><td style="text-align:right;white-space:nowrap"><button class="ghost">Rolle</button> <button class="ghost">Konfigurieren</button> <button class="ghost">Entladen</button> <button class="ghost del">Löschen</button></td></tr>'),yd=b('<table><thead><tr><th>Modell</th><th>Kann</th><th>Details</th><th>Status</th><th>Port</th><th style="text-align:right">Aktionen</th></tr></thead><tbody></tbody></table>'),kd=b('<div class="tile" style="display:flex;justify-content:space-between;align-items:center;margin:8px 0 10px"><div style="flex:1"><div style="font-size:13px">Empfohlen für deine Hardware</div> <div class="hint" style="margin:4px 0 0"> <br/> </div></div> <button class="ghost">Optimal übernehmen</button></div>'),xd=b('<div class="modal-overlay" role="dialog"><div class="modal-card"><button class="ghost" style="position:absolute;top:14px;right:14px">Schließen</button> <h3>Modell konfigurieren</h3> <p class="mono-sm" style="margin:-4px 0 16px"> </p> <label>Kontext-Größe (Tokens) <!></label> <input type="number"/> <!> <div class="hint" style="margin-bottom:14px">Es läuft immer nur <b>ein</b> Modell gleichzeitig — ein größerer Kontext hier beeinflusst deine anderen Modelle nicht.</div> <div class="tile" style="display:flex;justify-content:space-between;align-items:center;margin:0 0 14px"><div style="flex:1"><div style="font-size:13px;font-weight:500">Immer aktiv halten</div> <div class="hint" style="margin:3px 0 0">Modell bleibt dauerhaft im RAM — nie automatisch entladen. Ideal für den kleinen Scout (~5 GB), der immer schnell antworten soll.</div></div> <label style="display:flex;align-items:center;gap:8px;margin:0;cursor:pointer;flex:0 0 auto"><input type="checkbox" style="width:18px;height:18px;accent-color:var(--accent);cursor:pointer"/> <span class="mono-sm"> </span></label></div> <button class="primary" style="width:100%;margin-top:6px">Speichern</button></div></div>'),wd=b('<button style="border-radius:999px"> </button>'),Sd=b('<div class="modal-overlay" role="dialog"><div class="modal-card"><button class="ghost" style="position:absolute;top:14px;right:14px">Schließen</button> <h3>Rolle festlegen <!></h3> <p class="mono-sm" style="margin:-4px 0 16px"> </p> <div class="hint" style="margin-bottom:10px">Wähle eine Rolle als zweiten, sprechenden Namen. In deinen Tools funktionieren danach <b>beide</b>: der echte Modellname und die Rolle.</div> <div class="flex gap-2" style="flex-wrap:wrap;margin-bottom:12px"></div> <label>Eigene Rolle (optional)</label> <input placeholder="z.B. uebersetzer"/> <div class="btn-row" style="margin-top:14px;display:flex;gap:8px"><button class="ghost" style="flex:1">Rolle entfernen</button> <button class="primary" style="flex:2">Speichern</button></div></div></div>'),Md=b('<div id="m-head"><div class="pagehead"><div><h1>Modelle</h1> <div class="sub">Deine konfigurierten Modelle — testen, Kontext anpassen oder aus dem Speicher werfen.</div></div></div></div> <div class="card"><div class="card-h"><h3>Schnelltest</h3></div> <div class="card-sub">Schreib eine Nachricht — das gewählte Modell wird automatisch geweckt.</div> <label>Modell</label> <select></select> <label>Nachricht</label> <textarea placeholder="z.B. „Erklär mir kurz, was du kannst.""></textarea> <button class="primary"> </button> <!></div> <div class="card"><div class="card-h"><h3>Modelle & Ports</h3><span class="meta"> </span></div> <div class="card-sub">Modelle laden automatisch, sobald eine Anfrage kommt — du musst nichts manuell starten.</div> <!></div> <!> <!>',1);function Ed(e,n){On(n,!0);const a="Kontext = das Kurzzeitgedächtnis des Modells. Größer = merkt sich mehr (längere Dateien/Chats), braucht aber mehr Speicher und wird etwas langsamer.",s="Die Rolle ist ein zusätzlicher, sprechender Name (z.B. coder). Du kannst in deinen Tools entweder den echten Modellnamen ODER die Rolle angeben — beides führt zum selben Modell.",l=[{id:"coder",label:"Coder",desc:"Programmieren & Code"},{id:"vision",label:"Vision",desc:"Bilder verstehen"},{id:"scout",label:"Scout",desc:"Schneller Allrounder"},{id:"reviewer",label:"Reviewer",desc:"Code/Texte prüfen"},{id:"manager",label:"Manager",desc:"Planen & koordinieren"}],o=N(()=>{var E;return((E=ki.value)==null?void 0:E.models)||[]});function c(){document.dispatchEvent(new Event("mc:refresh"))}let d=O(""),v=O(""),p=O(""),_=O(!1);const T=N(()=>t(o).filter(E=>!E.incomplete));async function y(){var I;const E=t(d)||((I=t(T)[0])==null?void 0:I.name);if(!(!E||!t(v).trim())){u(_,!0),u(p,"(wecke Modell, kann beim Laden kurz dauern…)");try{const se=await $e("/api/chat",{method:"POST",body:JSON.stringify({model:E,message:t(v)})});u(p,se.reply,!0)}catch(se){u(p,"Fehler: "+se.message)}u(_,!1),c()}}const x=300;let A=O(!1),D=O(null),M=O(8192),B=O(!1);function qe(E){var I;u(D,t(o).find(se=>se.name===E),!0),t(D)&&(u(M,((I=t(D).meta)==null?void 0:I.ctx)||8192,!0),u(B,(t(D).ttl??x)>=99999),u(A,!0))}async function ke(){const E=t(B)?99999:x;try{await $e("/api/update_model",{method:"POST",body:JSON.stringify({alias:t(D).name,ctx:t(M),ttl:E})}),ie("Gespeichert — aktiv beim nächsten Modell-Start."),u(A,!1),c()}catch(I){ie(I.message,!0)}}let xe=O(!1),Ae=O(""),W=O(""),ae=O("");function we(E){const I=t(o).find(se=>se.name===E);u(Ae,E,!0),u(ae,(I==null?void 0:I.role)||"",!0),u(W,""),u(xe,!0)}async function Ce(E){try{await $e("/api/set_role",{method:"POST",body:JSON.stringify({alias:t(Ae),role:E})}),ie(E?`Rolle gesetzt: ${E}`:"Rolle entfernt."),u(xe,!1),c()}catch(I){ie(I.message,!0)}}async function Be(E){if(await mn({title:`„${E}" entladen?`,body:"Das Modell wird aus dem Grafikspeicher geworfen und lädt beim nächsten Aufruf automatisch neu.",confirmLabel:"Entladen"}))try{await $e("/api/unload?model="+encodeURIComponent(E),{method:"POST"}),ie("Entladen: "+E),setTimeout(c,600)}catch(I){ie(I.message,!0)}}async function je(E){if(await mn({title:`„${E}" wirklich löschen?`,body:"Das Modell wird aus der Konfiguration ausgetragen und seine Dateien werden von der Festplatte gelöscht, um Speicher freizugeben. <b>Das lässt sich nicht rückgängig machen</b> — später brauchst du dafür einen neuen Download.",confirmLabel:"Endgültig löschen",danger:!0}))try{const I=await $e("/api/delete_model",{method:"POST",body:JSON.stringify({alias:E})});ie(I.note||"Gelöscht: "+E),setTimeout(c,600)}catch(I){ie(I.message,!0)}}function bt(E){return E!=null&&E.length?E.map(I=>I==="Code"?'<span class="tag code">Code</span>':I==="Bild"?'<span class="tag img">Bild</span>':'<span class="tag text">Text</span>').join(" "):"–"}function z(E){if(!E)return"–";const I=E.quant||"?",se=E.ctx?Math.round(E.ctx/1024)+"K":"?",le=E.size_bytes?(E.size_bytes/1024**3).toFixed(1)+" GB":"?";return`<span class="mono-sm">${I} · ${se} · ${le}</span>`}function re(E){var I;(I=navigator.clipboard)==null||I.writeText(E),ie("Kopiert: "+E)}var ge=Md(),tt=i(et(ge),2),oe=i(r(tt),6);rt(oe,21,()=>t(T),dt,(E,I)=>{var se=ud(),le=r(se),m={};P(()=>{g(le,t(I).name),m!==(m=t(I).name)&&(se.value=(se.__value=t(I).name)??"")}),f(E,se)});var Fe=i(oe,4),ue=i(Fe,2),q=r(ue),Y=i(ue,2);{var pe=E=>{var I=pd(),se=r(I);P(()=>g(se,t(p))),f(E,I)};K(Y,E=>{t(p)&&E(pe)})}var fe=i(tt,2),Ke=r(fe),Ye=i(r(Ke)),ct=r(Ye),st=i(Ke,4);{var lt=E=>{var I=fd();f(E,I)},Re=E=>{var I=yd(),se=i(r(I));rt(se,21,()=>t(o),dt,(le,m)=>{var L=Va(),ne=et(L);{var ee=be=>{var _e=hd(),Le=r(_e),Qe=r(Le),Me=i(Le,5),Ze=r(Me),$=i(Ze,2);P(()=>g(Qe,t(m).name)),S("click",Ze,()=>{var de;ie("Lade im Cookbook ein Modell und setze den Alias auf: "+t(m).name),(de=document.querySelector(".nav-item[data-view='cookbook']"))==null||de.dispatchEvent(new MouseEvent("click"))}),S("click",$,()=>je(t(m).name)),f(be,_e)},U=be=>{var _e=_d(),Le=r(_e),Qe=r(Le),Me=r(Qe),Ze=i(Me);{var $=R=>{var H=gd(),te=r(H);P(()=>g(te,t(m).role)),f(R,H)};K(Ze,R=>{t(m).role&&R($)})}var de=i(Qe,2);{var Te=R=>{var H=md(),te=r(H);P(()=>g(te,t(m).meta.filename)),f(R,H)};K(de,R=>{var H;(H=t(m).meta)!=null&&H.filename&&R(Te)})}var ze=i(de,2),me=i(r(ze),2);rt(me,17,()=>{var R;return(R=t(m).api_ids)!=null&&R.length?t(m).api_ids:[t(m).name]},dt,(R,H)=>{var te=bd(),ve=r(te);P(()=>g(ve,t(H))),S("click",te,()=>re(t(H))),f(R,te)});var Tt=i(Le);He(Tt,()=>{var R;return bt((R=t(m).meta)==null?void 0:R.caps)},!0);var $t=i(Tt);He($t,()=>z(t(m).meta),!0);var zt=i($t);He(zt,()=>Vo(t(m).state,t(m).download_progress),!0);var C=i(zt),Z=r(C),Ge=i(C),he=r(Ge),G=i(he,2),Q=i(G,2),V=i(Q,2);P(()=>{g(Me,`${t(m).name??""} `),g(Z,t(m).port??"auto")}),S("click",he,()=>we(t(m).name)),S("click",G,()=>qe(t(m).name)),S("click",Q,()=>Be(t(m).name)),S("click",V,()=>je(t(m).name)),f(be,_e)};K(ne,be=>{t(m).incomplete?be(ee):be(U,-1)})}f(le,L)}),f(E,I)};K(st,E=>{t(o).length?E(Re,-1):E(lt)})}var Je=i(fe,2);{var vt=E=>{var I=xd(),se=r(I),le=r(se),m=i(le,4),L=r(m),ne=i(m,2),ee=i(r(ne));He(ee,()=>mr(a));var U=i(ne,2),be=i(U,2);{var _e=Te=>{var ze=kd(),me=r(ze),Tt=i(r(me),2),$t=r(Tt),zt=i($t,2),C=i(me,2);P((Z,Ge)=>{g($t,`Optimal ~${Z??""}k → ~${t(D).meta.peak_ram_optimal_gb??""} GB Spitzenbedarf.`),g(zt,` Aktuell ~${Ge??""}k → ~${t(D).meta.peak_ram_gb??""} GB.`)},[()=>Math.round(t(D).meta.optimal_ctx/1024),()=>Math.round((t(D).meta.ctx||0)/1024)]),S("click",C,()=>u(M,t(D).meta.optimal_ctx,!0)),f(Te,ze)};K(be,Te=>{var ze;(ze=t(D).meta)!=null&&ze.optimal_ctx&&Te(_e)})}var Le=i(be,4),Qe=i(r(Le),2),Me=r(Qe),Ze=i(Me,2),$=r(Ze),de=i(Le,2);P(()=>{g(L,t(D).name),Ot(Ze,`color:${t(B)?"var(--accent)":"var(--mut)"}`),g($,t(B)?"An (TTL = ∞)":"Aus (TTL = 5 min)")}),S("click",I,Te=>{Te.target.classList.contains("modal-overlay")&&u(A,!1)}),S("click",le,()=>u(A,!1)),vn(U,()=>t(M),Te=>u(M,Te)),Ro(Me,()=>t(B),Te=>u(B,Te)),S("click",de,ke),f(E,I)};K(Je,E=>{t(A)&&t(D)&&E(vt)})}var F=i(Je,2);{var X=E=>{var I=Sd(),se=r(I),le=r(se),m=i(le,2),L=i(r(m));He(L,()=>mr(s));var ne=i(m,2),ee=r(ne),U=i(ne,4);rt(U,21,()=>l,dt,(Me,Ze)=>{var $=wd(),de=r($);P(()=>{Dt($,1,t(ae)===t(Ze).id?"primary":"ghost"),_i($,"title",t(Ze).desc),g(de,t(Ze).label)}),S("click",$,()=>Ce(t(Ze).id)),f(Me,$)});var be=i(U,4),_e=i(be,2),Le=r(_e),Qe=i(Le,2);P(()=>g(ee,t(Ae))),S("click",I,Me=>{Me.target.classList.contains("modal-overlay")&&u(xe,!1)}),S("click",le,()=>u(xe,!1)),vn(be,()=>t(W),Me=>u(W,Me)),S("click",Le,()=>Ce("")),S("click",Qe,()=>Ce(t(W).trim().toLowerCase())),f(E,I)};K(F,E=>{t(xe)&&E(X)})}P(()=>{ue.disabled=t(_),g(q,t(_)?"…":"Senden"),g(ct,t(o).length?t(o).length+" konfiguriert":"")}),xa(oe,()=>t(d),E=>u(d,E)),vn(Fe,()=>t(v),E=>u(v,E)),S("click",ue,y),f(e,ge),Bn()}jn(["click"]);var Ad=b('<div class="tiles"><div class="tile"><div class="t-l">Prozessor (CPU)</div> <div class="t-v"> <small>%</small></div> <div class="t-s"> </div></div> <div class="tile"><div class="t-l">Arbeitsspeicher</div> <div class="t-v"> <small>%</small></div> <div class="t-s"> </div></div> <div class="tile"><div class="t-l">Grafikspeicher</div> <div class="t-v"> <small>%</small></div> <div class="t-s"> </div></div></div> <div class="card"><div class="card-h"><h3>System-Metriken (Bosgame)</h3></div> <div class="card-sub">Live-Auslastung deines Mini-PCs, alle 0,5 Sekunden.</div> <div class="kv" style="margin-bottom:6px"><div class="kv-row"><span class="kv-k">Arbeitsspeicher (RAM)</span><span class="kv-v"> </span></div> <div class="kv-row"><span class="kv-k">Grafikspeicher (VRAM + GTT)</span> <span class="kv-v"> </span></div> <div class="kv-row"><span class="kv-k">Speicherplatz (Disk)</span><span class="kv-v"> </span></div> <div class="kv-row"><span class="kv-k">Temperatur (GPU / CPU)</span> <span class="kv-v"> </span></div></div> <div class="grid grid-3" style="margin-top:14px"><div><div class="meta text-xs">CPU-Verlauf</div><div style="display:flex;align-items:flex-end;gap:2px;height:38px;margin-top:10px"></div></div> <div><div class="meta text-xs">RAM-Verlauf</div><div style="display:flex;align-items:flex-end;gap:2px;height:38px;margin-top:10px"></div></div> <div><div class="meta text-xs">VRAM-Verlauf</div><div style="display:flex;align-items:flex-end;gap:2px;height:38px;margin-top:10px"></div></div></div></div>',1),Cd=b('<button class="ghost" style="margin-left:auto;padding:4px 11px;font-size:12px">Verlauf leeren</button>'),Td=b('<div class="empty-c"><div class="e-t">Gerade nichts los.</div> <div class="e-s">Alles ruhig — keine laufenden Aufgaben.</div></div>'),zd=b('<span class="mono-sm" style="margin-left:auto"> </span>'),Pd=b('<button class="ghost">Abbrechen</button>'),Dd=b('<button class="ghost" title="Aus Verlauf entfernen" style="margin-left:auto;margin-right:2px;padding:2px 9px;font-size:14px;line-height:1">×</button>'),$d=b('<div class="bar" style="margin-top:8px"><i></i></div>'),Ld=b('<div class="log"> </div>'),Id=b('<div class="job"><div class="job-h" role="button" tabindex="0"><span></span> <span class="mid"> </span> <!> <!> <!></div> <!> <!></div>'),Od=b('<div class="pagehead"><div><h1>Aktivität</h1> <div class="sub">Live-Auslastung und laufende Aufgaben (Downloads, Updates) mit Protokoll.</div></div></div> <!> <div class="card"><div class="card-h"><h3>Hintergrund-Aufgaben</h3> <span class="meta"> </span> <!></div> <div class="card-sub">Downloads & Updates erscheinen hier mit Live-Protokoll — zum Aufklappen klicken.</div> <!></div>',1);function Bd(e,n){On(n,!0);const a=N(()=>ua.value),s=N(()=>ua.tracked),l=N(()=>Pr.value);let o=jt({cpu:[],ram:[],gpu:[]});mi(()=>{var ge;if(!t(l))return;const z=t(l).gpu,re=z&&z.vram.total+z.gtt.total>0?(z.vram.used+z.gtt.used)/(z.vram.total+z.gtt.total)*100:0;o.cpu=[...o.cpu,((ge=t(l).cpu)==null?void 0:ge.percent)??0].slice(-60),o.ram=[...o.ram,t(l).ram.percent].slice(-60),o.gpu=[...o.gpu,re].slice(-60)});const c=N(()=>()=>{var re;const z=(re=t(l))==null?void 0:re.gpu;return z&&z.vram.total+z.gtt.total>0?(z.vram.used+z.gtt.used)/(z.vram.total+z.gtt.total)*100:0}),d=N(()=>t(a).filter(z=>z.state!=="running"&&z.state!=="queued").length),v=N(()=>t(a).filter(z=>z.state==="failed").length);function p(z){if(z.state!=="running")return null;if(typeof z.progress=="number")return Math.min(100,z.progress);const ge=((z.log||[]).at(-1)||"").match(/(\d+(?:\.\d+)?)\s*%/);return ge?Math.min(100,parseFloat(ge[1])):null}function _(z){return z==null||z<0?"":z>=90?`noch ~${Math.round(z/60)} min`:`noch ~${Math.max(1,Math.round(z))} s`}function T(z){return z==="done"?'<span class="badge b-run">fertig</span>':z==="failed"?'<span class="badge b-err">fehler</span>':z==="canceled"?'<span class="badge">abgebrochen</span>':'<span class="badge b-load">läuft…</span>'}function y(z){return z==="done"?"on":z==="failed"||z==="canceled"?"":"load"}async function x(z){try{await $e(`/api/jobs/${z}/cancel`,{method:"POST"}),ie("Abbruch angefordert…")}catch(re){ie(re.message,!0)}}async function A(z){try{await $e(`/api/jobs/${z}`,{method:"DELETE"})}catch(re){ie(re.message,!0)}}async function D(){try{const z=await $e("/api/jobs/clear",{method:"POST"});ie(`${z.removed} Einträge entfernt.`)}catch(z){ie(z.message,!0)}}function M(z,re){return z.map(ge=>`<div style="width:4px;background:var(${re});opacity:.55;height:${Math.max(2,ge)}%;border-radius:2px"></div>`).join("")}var B=Od(),qe=i(et(B),2);{var ke=z=>{const re=N(()=>t(c)());var ge=Ad(),tt=et(ge),oe=r(tt),Fe=i(r(oe),2),ue=r(Fe),q=i(Fe,2),Y=r(q),pe=i(oe,2),fe=i(r(pe),2),Ke=r(fe),Ye=i(fe,2),ct=r(Ye),st=i(pe,2),lt=i(r(st),2),Re=r(lt),Je=i(lt,2),vt=r(Je),F=i(tt,2),X=i(r(F),4),E=r(X),I=i(r(E)),se=r(I),le=i(E,2),m=i(r(le),2),L=r(m),ne=i(le,2),ee=i(r(ne)),U=r(ee),be=i(ne,2),_e=i(r(be),2),Le=r(_e),Qe=i(X,2),Me=r(Qe),Ze=i(r(Me));He(Ze,()=>M(o.cpu,"--accent"),!0);var $=i(Me,2),de=i(r($));He(de,()=>M(o.ram,"--purple"),!0);var Te=i($,2),ze=i(r(Te));He(ze,()=>M(o.gpu,"--on"),!0),P((me,Tt,$t,zt,C,Z,Ge,he,G,Q,V,R,H)=>{g(ue,me),g(Y,Tt),g(Ke,$t),g(ct,`${zt??""} / ${C??""}`),g(Re,Z),g(vt,Ge),g(se,`${he??""} / ${G??""}`),g(L,Q),g(U,`${V??""} % belegt`),g(Le,`${R??""} / ${H??""}`)},[()=>{var me;return Math.round(((me=t(l).cpu)==null?void 0:me.percent)??0)},()=>{var me;return((me=t(l).cpu)==null?void 0:me.temp)!=null?`${Math.round(t(l).cpu.temp)}° CPU-Temp`:"Auslastung"},()=>Math.round(t(l).ram.percent),()=>oa(t(l).ram.used),()=>oa(t(l).ram.total),()=>Math.round(t(re)),()=>t(l).gpu_temp!=null?`${Math.round(t(l).gpu_temp)}° GPU-Temp`:"VRAM + GTT",()=>oa(t(l).ram.used),()=>oa(t(l).ram.total),()=>t(l).gpu?`${oa(t(l).gpu.vram.used+t(l).gpu.gtt.used)} / ${oa(t(l).gpu.vram.total+t(l).gpu.gtt.total)}`:"–",()=>{var me;return Math.round(((me=t(l).disk)==null?void 0:me.percent)??0)},()=>t(l).gpu_temp!=null?Math.round(t(l).gpu_temp)+"°":"–",()=>{var me;return((me=t(l).cpu)==null?void 0:me.temp)!=null?Math.round(t(l).cpu.temp)+"°":"–"}]),f(z,ge)};K(qe,z=>{t(l)&&z(ke)})}var xe=i(qe,2),Ae=r(xe),W=i(r(Ae),2),ae=r(W),we=i(W,2);{var Ce=z=>{var re=Cd();S("click",re,D),f(z,re)};K(we,z=>{t(d)&&z(Ce)})}var Be=i(Ae,4);{var je=z=>{var re=Td();f(z,re)},bt=z=>{var re=Va(),ge=et(re);rt(ge,17,()=>t(a),dt,(tt,oe)=>{const Fe=N(()=>p(t(oe))),ue=N(()=>t(oe).state==="running"?_(t(oe).eta_s):""),q=N(()=>t(oe).state==="running"&&t(oe).rate_bps?oa(t(oe).rate_bps)+"/s":""),Y=N(()=>[t(ue),t(q)].filter(Boolean).join(" · ")),pe=N(()=>t(s).includes(t(oe).id));var fe=Id(),Ke=r(fe),Ye=r(Ke),ct=i(Ye,2),st=r(ct),lt=i(ct,2);{var Re=m=>{var L=zd(),ne=r(L);P(ee=>g(ne,`${ee??""} %${t(Y)?` · ${t(Y)}`:""}`),[()=>Math.round(t(Fe))]),f(m,L)};K(lt,m=>{t(Fe)!=null&&m(Re)})}var Je=i(lt,2);{var vt=m=>{var L=Pd();P(()=>Ot(L,`${t(Fe)==null?"margin-left:auto;":""}margin-right:2px;padding:2px 9px;font-size:12px`)),S("click",L,ne=>{ne.stopPropagation(),x(t(oe).id)}),f(m,L)},F=m=>{var L=Dd();S("click",L,ne=>{ne.stopPropagation(),A(t(oe).id)}),f(m,L)};K(Je,m=>{t(oe).state==="running"?m(vt):m(F,-1)})}var X=i(Je,2);He(X,()=>T(t(oe).state));var E=i(Ke,2);{var I=m=>{var L=$d(),ne=r(L);P(()=>Ot(ne,`width:${t(Fe)??""}%`)),f(m,L)};K(E,m=>{t(Fe)!=null&&t(oe).state==="running"&&m(I)})}var se=i(E,2);{var le=m=>{var L=Ld(),ne=r(L);P(ee=>g(ne,ee),[()=>(t(oe).log||[]).join(`
|
||
`)]),f(m,L)};K(se,m=>{t(pe)&&m(le)})}P(m=>{Dt(Ye,1,`li-dot ${m??""}`),g(st,t(oe).label)},[()=>y(t(oe).state)]),S("click",Ke,()=>ua.toggle(t(oe).id)),S("keydown",Ke,m=>m.key==="Enter"&&ua.toggle(t(oe).id)),f(tt,fe)}),f(z,re)};K(Be,z=>{t(a).length?z(bt,-1):z(je)})}P(()=>g(ae,t(a).length?t(v)?t(v)+" Fehler":t(a).length+" gesamt":"")),f(e,B),Bn()}jn(["click","keydown"]);var Rd=b('<span class="mono-sm"> </span>'),Fd=b('<button class="ghost" style="margin-left:auto;padding:3px 12px">Abbrechen</button>'),Kd=b('<span class="badge b-run">✓ fertig</span>'),Nd=b('<span class="badge b-err">✗ fehlgeschlagen</span>'),qd=b('<span class="badge">abgebrochen</span>'),Wd=b('<span class="badge b-load">läuft…</span>'),Gd=b('<div class="bar" style="margin-bottom:10px"><i></i></div>'),Vd=b('<div class="card"><div class="card-h"><h3>Aktueller Vorgang</h3> <!> <span style="margin-left:10px"><!></span></div> <div class="card-sub"> </div> <!> <div class="log" style="max-height:280px"> </div></div>'),jd=b('<div class="pagehead"><div><h1>Server & Wartung</h1> <div class="sub">Dienste steuern, Updates einspielen und live mitlesen — ganz ohne SSH oder Terminal.</div></div></div> <div class="card"><div class="card-h"><h3>LLM-Engine (llama-swap)</h3> <span class="chip"> </span></div> <div class="card-sub">Das Herzstück: lädt bei jeder Anfrage automatisch das passende Modell.</div> <div class="kv" style="margin-bottom:6px"><div class="kv-row"><span class="kv-k">Adresse (für deine Tools)</span><span class="kv-v mono-sm"> </span></div> <div class="kv-row"><span class="kv-k">Aktuell geladen</span> <span class="kv-v"> </span></div> <div class="kv-row"><span class="kv-k">Konfigurierte Modelle</span> <span class="kv-v"> </span></div></div> <div class="btn-row" style="display:flex;align-items:center;gap:10px"><button class="ghost">Verbindung prüfen</button> <!></div></div> <div class="card"><div class="card-h"><h3>Dienste & Applikation</h3></div> <div class="card-sub">Diese Aktionen sind harmlos und passwortlos — es geht nichts dabei verloren.</div> <button class="qa"><span class="qa-ic teal">↻</span> <span class="qa-main"><span class="qa-t">LLM-Engine neustarten</span><span class="qa-s">Startet llama-swap neu. Geladene Modelle laden danach automatisch wieder.</span></span> <span class="qa-arrow">›</span></button> <button class="qa"><span class="qa-ic blue">↻</span> <span class="qa-main"><span class="qa-t">Dashboard neustarten</span><span class="qa-s">Startet diese Oberfläche neu (~5 Sek).</span></span> <span class="qa-arrow">›</span></button> <button class="qa"><span class="qa-ic teal">⬇</span> <span class="qa-main"><span class="qa-t">Mission Control aktualisieren</span><span class="qa-s">Holt die neueste Version aus Gitea und startet automatisch neu (~10 Sek).</span></span> <span class="qa-arrow">›</span></button> <button class="qa"><span class="qa-ic blue">⚡</span> <span class="qa-main"><span class="qa-t">LLM-Engine aktualisieren</span><span class="qa-s">Lädt die neueste llama.cpp-Version (ROCm) für deine GPU.</span></span> <span class="qa-arrow">›</span></button> <button class="qa"><span class="qa-ic amber">🗄</span> <span class="qa-main"><span class="qa-t">Grafikspeicher leeren</span><span class="qa-s">Wirft alle aktuell geladenen Modelle aus dem VRAM. Fragt vorher nach.</span></span> <span class="qa-arrow">›</span></button></div> <div class="card"><div class="card-h"><h3>Betriebssystem (Bosgame)</h3></div> <div class="card-sub">Tiefe Eingriffe — das Dashboard fragt einmalig nach deinem sudo-Passwort.</div> <button class="qa"><span class="qa-ic amber">↻</span> <span class="qa-main"><span class="qa-t">OS-Updates installieren</span><span class="qa-s">Führt apt update & upgrade aus. Kann ein paar Minuten dauern.</span></span> <span class="qa-arrow">›</span></button> <button class="qa qa-danger"><span class="qa-ic red">⚡</span> <span class="qa-main"><span class="qa-t">Server neustarten (Reboot)</span><span class="qa-s">Bootet den ganzen Bosgame neu. Alles ist für ~1 Minute offline.</span></span> <span class="qa-arrow">›</span></button></div> <!> <div class="card"><div class="card-h"><h3>Live-Konsole</h3> <select style="margin:0 0 0 auto;width:240px"><option>LLM-Engine (llama-swap)</option><option>Dashboard (mission-control)</option><option>System (ganzer Server)</option></select></div> <div class="card-sub">Live mitlesen, was der Dienst gerade tut.</div> <div class="console"> </div></div>',1);function Ud(e,n){On(n,!0);const a=N(()=>ki.value),s=N(()=>ua.value);let l=null,o=O(`Verbinde…
|
||
`),c=O("llama-swap"),d,v=O(null),p=O("");const _=new Set,T=N(()=>t(v)?t(s).find($=>$.id===t(v)):null);mi(()=>{if(!t(T))return;const $=t(T),de=$.state==="done",Te=$.state==="failed",ze=$.state==="canceled";(de||Te||ze)&&!_.has($.id)&&(_.add($.id),ie(de?`✓ ${t(p)} abgeschlossen.`:ze?`${t(p)} abgebrochen.`:`✗ ${t(p)} fehlgeschlagen.`,Te),de&&setTimeout(()=>document.dispatchEvent(new Event("mc:refresh")),800))});function y($,de){u(v,$,!0),u(p,de,!0),ua.track($)}yi(()=>{x()}),Ko(()=>{l==null||l.close()});function x(){l==null||l.close();const $=t(c);u(o,`Verbinde mit ${$}…
|
||
`);const de=location.protocol==="https:"?"wss:":"ws:";l=new WebSocket(`${de}//${location.host}/api/logs/${$}?token=${encodeURIComponent(tl())}`),l.onmessage=Te=>{u(o,t(o)+Te.data),d&&(d.scrollTop=d.scrollHeight)},l.onclose=()=>{u(o,t(o)+`
|
||
— Verbindung getrennt —`)},l.onerror=()=>l==null?void 0:l.close()}async function A($,de,Te){if(await mn({title:de,body:Te,confirmLabel:"Neustarten"}))try{await $e(`/api/service/${$}/restart`,{method:"POST"}),ie("Neustart ausgelöst: "+$),setTimeout(()=>document.dispatchEvent(new Event("mc:refresh")),2e3)}catch(ze){ie(ze.message,!0)}}async function D(){if(await mn({title:"Mission Control aktualisieren?",body:"Holt die neueste Dashboard-Version aus Gitea und startet automatisch neu. Die Seite trennt kurz und verbindet von selbst wieder (~10 Sek)."}))try{const $=await $e("/api/self-update",{method:"POST"});ie("Update läuft — Dashboard startet gleich neu."),y($.job_id,"Mission Control Update")}catch($){ie($.message,!0)}}async function M(){if(await mn({title:"LLM-Engine aktualisieren?",body:"Lädt die neueste llama.cpp-ROCm-Version und installiert sie. Die Engine ist während des Updates kurz nicht erreichbar."}))try{const $=await $e("/api/update",{method:"POST"});ie("LLM-Engine-Update läuft."),y($.job_id,"LLM-Engine-Update")}catch($){ie($.message,!0)}}async function B(){if(await mn({title:"Grafikspeicher leeren?",body:"Alle geladenen Modelle werden entladen. Sie laden beim nächsten Aufruf automatisch neu — es geht nichts verloren.",confirmLabel:"Leeren"}))try{await $e("/api/unload",{method:"POST"}),ie("Grafikspeicher geleert."),setTimeout(()=>document.dispatchEvent(new Event("mc:refresh")),600)}catch($){ie($.message,!0)}}async function qe(){if(!await mn({title:"OS-Updates installieren?",body:"Führt <code>apt update & upgrade</code> aus. Das kann ein paar Minuten dauern; der Fortschritt erscheint in der Aktivität."}))return;const $=await Ur({title:"sudo-Passwort",body:"Für die System-Updates wird einmalig dein sudo-Passwort gebraucht.",placeholder:"sudo-Passwort",password:!0,confirmLabel:"Installieren"});if($)try{const de=await $e("/api/os-update",{method:"POST",body:JSON.stringify({password:$})});ie("OS-Update gestartet."),y(de.job_id,"OS-Update")}catch(de){ie(de.message,!0)}}async function ke(){if(!await mn({title:"Server wirklich neu starten?",body:"Der ganze Bosgame startet physisch neu. Alles ist für ~1 Minute offline — auch dieses Dashboard.",confirmLabel:"Reboot",danger:!0}))return;const $=await Ur({title:"sudo-Passwort",body:"Für den Reboot wird einmalig dein sudo-Passwort gebraucht.",placeholder:"sudo-Passwort",password:!0,confirmLabel:"Jetzt neustarten",danger:!0});if($)try{await $e("/api/reboot",{method:"POST",body:JSON.stringify({password:$})}),ie("Reboot ausgelöst — bis gleich.")}catch(de){ie(de.message,!0)}}async function xe(){u(Ae,"prüfe…");try{const $=await $e("/api/integration/test");u(Ae,$.ok?`✓ Engine antwortet — ${$.models.length} Modell(e): ${$.models.join(", ")}`:`✗ keine Verbindung: ${$.error}`,!0),u(W,$.ok,!0)}catch($){u(Ae,"✗ "+$.message),u(W,!1)}}let Ae=O(""),W=O(!1);const ae=N(()=>{var $;return(($=t(a))==null?void 0:$.models)||[]}),we=["running","ready","loading","starting"],Ce=N(()=>t(ae).find($=>we.includes($.state)));function Be($){if(!$||$.state!=="running")return null;if(typeof $.progress=="number")return Math.min(100,$.progress);const Te=(($.log||[]).at(-1)||"").match(/(\d+(?:\.\d+)?)\s*%/);return Te?Math.min(100,parseFloat(Te[1])):null}var je=jd(),bt=i(et(je),2),z=r(bt),re=i(r(z),2),ge=r(re),tt=i(z,4),oe=r(tt),Fe=i(r(oe)),ue=r(Fe),q=i(oe,2),Y=i(r(q),2),pe=r(Y),fe=i(q,2),Ke=i(r(fe),2),Ye=r(Ke),ct=i(tt,2),st=r(ct),lt=i(st,2);{var Re=$=>{var de=Rd(),Te=r(de);P(()=>{Ot(de,`color:${t(W)?"#7ee29a":"#ff9b95"}`),g(Te,t(Ae))}),f($,de)};K(lt,$=>{t(Ae)&&$(Re)})}var Je=i(bt,2),vt=i(r(Je),4),F=i(vt,2),X=i(F,2),E=i(X,2),I=i(E,2),se=i(Je,2),le=i(r(se),4),m=i(le,2),L=i(se,2);{var ne=$=>{const de=N(()=>t(T)),Te=N(()=>t(de).state==="done"),ze=N(()=>t(de).state==="failed"),me=N(()=>t(de).state==="canceled"),Tt=N(()=>t(Te)||t(ze)||t(me)),$t=N(()=>Be(t(de)));var zt=Vd(),C=r(zt),Z=i(r(C),2);{var Ge=De=>{var xt=Fd();S("click",xt,async()=>{await mn({title:t(p)+" abbrechen?",body:"Der laufende Vorgang wird gestoppt.",confirmLabel:"Abbrechen",danger:!0})&&$e(`/api/jobs/${t(de).id}/cancel`,{method:"POST"})}),f(De,xt)};K(Z,De=>{t(Tt)||De(Ge)})}var he=i(Z,2),G=r(he);{var Q=De=>{var xt=Kd();f(De,xt)},V=De=>{var xt=Nd();f(De,xt)},R=De=>{var xt=qd();f(De,xt)},H=De=>{var xt=Wd();f(De,xt)};K(G,De=>{t(Te)?De(Q):t(ze)?De(V,1):t(me)?De(R,2):De(H,-1)})}var te=i(C,2),ve=r(te),Ie=i(te,2);{var Ee=De=>{var xt=Gd(),Rn=r(xt);P(()=>Ot(Rn,`width:${t($t)??""}%`)),f(De,xt)};K(Ie,De=>{t($t)!=null&&!t(Tt)&&De(Ee)})}var ut=i(Ie,2),Et=r(ut);P(De=>{g(ve,`${t(p)??""}${t(Tt)?t(Te)?" — erfolgreich.":t(me)?" — abgebrochen.":" — fehlgeschlagen.":" läuft…"}`),g(Et,De)},[()=>(t(de).log||[]).join(`
|
||
`)]),f($,zt)};K(L,$=>{t(T)&&$(ne)})}var ee=i(L,2),U=r(ee),be=i(r(U),2),_e=r(be);_e.value=_e.__value="llama-swap";var Le=i(_e);Le.value=Le.__value="mission-control";var Qe=i(Le);Qe.value=Qe.__value="system";var Me=i(U,4),Ze=r(Me);Fo(Me,$=>d=$,()=>d),P($=>{var de,Te,ze;Ot(re,`margin-left:auto;${(de=t(a))!=null&&de.swap_ok?"background:rgba(63,185,80,.12);border-color:rgba(63,185,80,.25);color:#7ee29a":"background:rgba(248,81,73,.12);border-color:rgba(248,81,73,.3);color:#ff9b95"}`),g(ge,(Te=t(a))!=null&&Te.swap_ok?"● erreichbar":"● offline"),g(ue,(((ze=t(a))==null?void 0:ze.swap_url)||"—")+"/v1"),g(pe,t(Ce)?t(Ce).name+` (${t(Ce).state})`:"nichts geladen — lädt bei der nächsten Anfrage"),g(Ye,$),g(Ze,t(o))},[()=>t(ae).filter($=>!$.incomplete).length||"keine"]),S("click",st,xe),S("click",vt,()=>A("llama-swap","LLM-Engine neustarten?","Die Engine startet neu. Geladene Modelle werden kurz entladen (~5 Sekunden), laden danach automatisch wieder.")),S("click",F,()=>A("mission-control","Dashboard neustarten?","Diese Oberfläche trennt sich kurz und verbindet automatisch wieder.")),S("click",X,D),S("click",E,M),S("click",I,B),S("click",le,qe),S("click",m,ke),S("change",be,x),xa(be,()=>t(c),$=>u(c,$)),f(e,je),Bn()}jn(["click","change"]);var Hd=b('<div class="empty" style="text-align:center;padding:30px">Lade Setups…</div>'),Jd=b('<span title="Setup bearbeiten" style="position:absolute;top:10px;right:36px;color:var(--accent);cursor:pointer;font-size:14px;line-height:1" role="button" tabindex="0">✎</span> <span title="Setup löschen" style="position:absolute;top:9px;right:12px;color:var(--err);cursor:pointer;font-size:18px;line-height:1" role="button" tabindex="0">×</span>',1),er=b('<div class="cb-best-tag">★ Beste Wahl für dein System</div>'),Qd=b('<div class="cb-best-tag" style="background:var(--act);color:#fff">Dein Setup</div>'),Zd=b('<button style="text-align:left;position:relative"><!> <!> <div class="flex justify-between items-center"><span class="flex items-center gap-2"><h3 style="margin:0;font-size:15px"> </h3></span> <span> </span></div> <p> </p> <div class="text-xs text-mut"> </div></button>'),Yd=b('<div id="cb-recipes" class="grid grid-3" style="gap:10px;margin-top:6px"></div>'),Xd=b('<span style="color:var(--warn)">· ⚠ Cache veraltet</span>'),ec=b("<!> <!>",1),tc=b('<div class="empty" style="text-align:center;padding:30px">Frage Quellen ab…</div>'),nc=b('<div class="li-sub" style="color:var(--warn);margin-top:3px"> </div>'),ac=b('<span class="fit-badge ok">✓ installiert</span>'),ic=b('<button class="primary" style="padding:6px 12px;font-size:12.5px">Installieren</button>'),rc=b('<div style="display:flex;flex-direction:column;position:relative"><!> <div class="flex justify-between" style="align-items:flex-start;gap:8px"><div style="min-width:0"><h3 style="margin:0;font-size:14px;font-weight:500;word-break:break-word"> </h3> <div class="text-xs text-mut" style="margin-top:3px"> </div></div> <span> </span></div> <div class="flex gap-2" style="flex-wrap:wrap;margin-top:7px"><!> <!></div> <div class="mono-sm text-mut" style="margin-top:8px;font-size:11.5px"> </div> <!> <div style="flex:1;min-height:8px"></div> <div class="flex justify-end" style="margin-top:10px"><!></div></div>'),sc=b('<div style="margin-bottom:8px"><div class="flex items-center gap-2" style="margin:6px 0 8px"><h4 style="margin:0;font-size:13.5px;font-weight:600"> </h4></div> <div class="grid grid-3"></div></div>'),lc=b('<button style="padding:4px 10px;border-radius:999px;font-size:12px"> </button>'),oc=b('<div style="display:flex;flex-direction:column;cursor:pointer"><!> <div class="flex justify-between" style="align-items:flex-start;gap:8px"><div style="min-width:0"><h3 style="margin:0;font-size:14.5px;font-weight:500;word-break:break-word"> </h3> <div class="text-xs text-mut" style="margin-top:3px"> </div></div> <span> </span></div> <div class="flex gap-2" style="flex-wrap:wrap;margin-top:7px"><!> <!></div> <div style="flex:1;margin-top:12px"></div> <div class="flex justify-between items-center text-xs text-mut" style="border-top:1px solid var(--line);padding-top:11px"><span class="mono-sm"> </span> <span class="mono-sm"> </span></div></div>'),dc=b('<div class="grid grid-3" id="cb-grid"></div>'),cc=b('<div class="li-sub"> </div>'),vc=b('<div class="li-sub mono-sm"> </div>'),uc=b("<span> </span>"),pc=b('<div class="li" style="align-items:flex-start"><div class="li-main"><div class="flex items-center gap-2" style="flex-wrap:wrap"><span class="li-id"> </span> <span class="tag text"> </span> <!></div> <!> <!></div> <!></div>'),fc=b('<div class="hint" style="margin:12px 0">Größter Spitzenbedarf: <b> </b>. Es läuft immer nur <b>ein</b> Modell gleichzeitig — das größte bestimmt, ob das Setup passt.</div>'),hc=b('Alternative: <a href="#" style="color:var(--accent)"> </a> — passt auf dein System.',1),gc=b('<div class="hint" style="color:var(--warn);margin-bottom:10px;border-left:2px solid var(--warn);padding-left:10px">⚠ Dieses Setup übersteigt deinen verfügbaren Speicher. <!></div>'),mc=b('<div class="modal-overlay" role="dialog"><div class="modal-card" style="max-width:560px"><button class="ghost" style="position:absolute;top:14px;right:14px">Schließen</button> <h3> </h3> <p class="text-mut text-sm" style="margin:-4px 0 16px"> </p> <div class="list"></div> <!> <!> <button id="cb-r-install-btn" style="width:100%"> </button></div></div>'),bc=b('<div class="hint">Lade Dateien von HuggingFace…</div>'),Yr=b("<option> </option>"),_c=b('<div class="hint" style="margin:-6px 0 14px">Empfohlener Kontext für deine Hardware: <b> </b> — <a href="#">übernehmen</a></div>'),yc=b('<div class="tile" style="display:flex;justify-content:space-between;align-items:center;margin:8px 0 18px"><div><div style="font-size:13px">Ressourcen-Check</div> <div class="hint" style="margin:4px 0 0"> </div></div> <span> </span></div>'),kc=b('<div class="hint" style="color:var(--warn);margin:-8px 0 14px;border-left:2px solid var(--warn);padding-left:10px">⚠ Diese Datei ist zu groß für deinen Speicher. Kleinere Alternative: <a href="#" style="color:var(--accent)"> </a> — einfach auswählen.</div>'),xc=b('<div class="hint" style="color:var(--warn);margin:-8px 0 14px;border-left:2px solid var(--warn);padding-left:10px">⚠ Alle Varianten dieses Modells sind zu groß für deinen Speicher. Ein kleineres Modell aus den Empfehlungen wäre die bessere Wahl.</div>'),wc=b('<label>Quantisierung (GGUF-Datei) wählen</label> <select></select> <div class="row" style="margin-top:4px"><div><label>Rolle (optional)</label> <input placeholder="z.B. coder, vision, scout"/></div> <div><label>Kontext-Größe <!></label> <input type="number"/></div></div> <!> <!> <!> <button style="width:100%"> </button>',1),Sc=b('<div class="hint">Keine GGUF-Dateien im Repo gefunden.</div>'),Mc=b('<div class="modal-overlay" role="dialog"><div class="modal-card" style="max-width:560px"><button class="ghost" style="position:absolute;top:14px;right:14px">Schließen</button> <h3> </h3> <p class="mono-sm" style="margin:-4px 0 16px"> </p> <!></div></div>'),Ec=b('<div class="flex gap-2" style="margin-bottom:8px;align-items:center"><input placeholder="Repo, z.B. unsloth/Qwen3-8B-GGUF" style="flex:2;margin:0"/> <input placeholder="Rolle (z.B. coder)" style="flex:1;margin:0"/> <select style="width:auto;margin:0"></select> <button class="ghost del" style="margin:0;padding:6px 10px">×</button></div>'),Ac=b('<div class="modal-overlay" role="dialog"><div class="modal-card" style="max-width:640px"><button class="ghost" style="position:absolute;top:14px;right:14px">Schließen</button> <h3> </h3> <p class="text-mut text-sm" style="margin:-4px 0 16px">Stell dir aus beliebigen Modellen ein eigenes Setup zusammen.</p> <label>Titel</label> <input placeholder="z.B. Mein Schreib-Stack"/> <label>Kurzbeschreibung (optional)</label> <input placeholder="Wofür ist dieses Setup gut?"/> <label style="margin-top:10px">Modelle</label> <!> <button class="ghost" style="margin-top:8px">+ Modell hinzufügen</button> <div class="hint" style="margin-top:10px">Die <b>Repo-ID</b> findest du über die <b>Profi-Suche</b> weiter unten (z.B. <code>unsloth/Qwen3-8B-GGUF</code>).</div> <button class="primary" style="width:100%;margin-top:14px"> </button></div></div>'),Cc=b('<div class="pagehead"><div><h1>Cookbook</h1><div class="sub">Modelle finden, installieren und eigene Setups zusammenstellen.</div></div></div> <div class="card"><div class="card-h"><h3>1 · Anwendungsfall wählen & installieren</h3> <button class="ghost" style="margin-left:auto">+ Eigenes Setup</button></div> <div class="card-sub">Hier starten: Fertige Modell-Bundles für deinen Anwendungsfall — ein Klick installiert alles. Die Hardware-Ampel zeigt vorab, ob das Setup auf deinen PC passt.</div> <!></div> <div class="card"><div class="card-h"><h3>Aktuell die besten Modelle für dein System</h3> <span class="meta" style="margin-left:auto"><!></span> <button class="ghost" style="margin-left:8px"> </button></div> <div class="card-sub">Top-Modelle je Kategorie von HuggingFace — Hardware-Fit wird live für dein System berechnet.</div> <!></div> <div class="card"><div class="card-h"><h3>Profi-Suche (HuggingFace)</h3></div> <div class="card-sub">Direkt HuggingFace durchsuchen — oder eine Modell-URL einfügen für den direkten Sprung.</div> <div class="flex gap-2" style="align-items:stretch;margin-bottom:10px"><input placeholder="Suchbegriff oder HuggingFace-URL…" style="flex:1;margin:0"/> <select style="width:auto;margin:0"><option>Downloads</option><option>Trending</option><option>Neu</option></select> <button class="primary"> </button></div> <div class="flex gap-2" style="flex-wrap:wrap;margin-bottom:12px"></div> <!></div> <!> <!> <!>',1);function Tc(e,n){On(n,!0);const a="Kontext = das Kurzzeitgedächtnis des Modells. Größer = merkt sich mehr, braucht aber mehr Speicher und wird etwas langsamer.",s="MoE (Mixture of Experts): viele Parameter fürs Wissen, aber pro Wort ist nur ein kleiner Teil aktiv → fast große-Modell-Qualität bei hohem Tempo. Ideal für deine APU.",l={perfect:0,marginal:1,too_tight:2},o={vision:"Bilder",coder:"Coden",reasoning:"Logik",agent:"Agenten & Tools",scout:"Allrounder",reviewer:"Review",manager:"Manager"},c=[{label:"Bilder",kw:["-vl-","-vl","vision","llava","multimodal","-mm-","pixtral"]},{label:"Coden",kw:["coder","-code-","code-","codestral","starcoder"]},{label:"Logik",kw:["-r1","deepseek-r1","reasoning","qwq","magistral","-think","thinking","-o1"]},{label:"Agenten & Tools",kw:["hermes","-tool","command-r","watt","-fc-","function"]}];function d(w){const k=(w||"").toLowerCase();for(const J of c)if(J.kw.some(j=>k.includes(j)))return J.label;return"Allrounder"}function v(w=""){const k=w.toLowerCase();return/\d+x\d+(\.\d+)?b/.test(k)||new RegExp("(?<![a-z])a\\d+(\\.\\d+)?b\\b").test(k)||k.includes("mixtral")||/\bmoe\b/.test(k)}function p(w=""){const k=w.toLowerCase().match(new RegExp("(?<![a-z])a(\\d+(?:\\.\\d+)?)b\\b"));return k?k[1]:null}function _(w){return w==="perfect"?"ok":w==="marginal"?"warn":"bad"}function T(w){return w==="perfect"?"Passt":w==="marginal"?"Knapp":"Zu groß"}function y(w){return`~${(w.req_gb??0).toFixed(1)} GB · ~${Math.round(w.tps??0)} Tok/s`}let x=O(jt([])),A=O(null),D=O(!0),M=O(null),B=O(!1),qe=O(!1),ke=O(""),xe=O(jt([])),Ae=O(!1),W=O(""),ae=O("downloads"),we=O(jt([])),Ce=O(-1),Be=O(null),je=O(!1),bt=O(""),z=O(""),re=O(null),ge=O(""),tt=O(""),oe=O(8192),Fe=O(!1),ue=O(null),q=O(!1),Y=O(""),pe=O(""),fe=O(jt([{repo:"",role:"",quant:"Q4_K_M"}])),Ke=O(null);function Ye(w){var k;(k=document.querySelector(`.nav-item[data-view="${w}"]`))==null||k.dispatchEvent(new MouseEvent("click"))}yi(()=>{ct(),st()});async function ct(){u(D,!0);try{const w=await $e("/api/cookbook/recipes");u(x,w.recipes||[],!0),u(A,w.recommended_id||null,!0)}catch(w){ie(w.message,!0)}u(D,!1)}async function st(w=!1){u(B,!0);try{const k=await $e("/api/cookbook/discover"+(w?"?force=true":""));u(M,k,!0),u(qe,k.stale,!0)}catch(k){ie("Empfehlungen nicht ladbar: "+k.message,!0)}u(B,!1)}function lt(w){w=w.trim();const k=w.match(/huggingface\.co\/([^\s/]+\/[^\s/?#]+)/i);return k?k[1]:/^[\w.-]+\/[\w.-]+$/.test(w)?w:null}async function Re(){const w=t(ke).trim(),k=lt(w);let J=w;if(t(W)&&!k&&(J=J?J+" "+t(W):t(W)),!J&&!k){u(xe,[],!0);return}u(Ae,!0),u(we,[],!0),u(Ce,-1);try{if(k)u(xe,[{id:k,author:k.split("/")[0],downloads:0}],!0);else{const j=`https://huggingface.co/api/models?search=${encodeURIComponent(J)}&filter=gguf&sort=${encodeURIComponent(t(ae))}&direction=-1&limit=40`,Se=await fetch(j);u(xe,await Se.json(),!0)}t(xe).forEach((j,Se)=>Je(Se,j.id))}catch(j){ie(j.message,!0),u(xe,[],!0)}u(Ae,!1)}async function Je(w,k){var J;try{const j=await $e("/api/cookbook/analyze",{method:"POST",body:JSON.stringify({repo_id:k,ctx:8192})});if(!((J=j.files)!=null&&J.length)){t(we)[w]=null,vt();return}const Se=j.files.find(_t=>{var wt;return(wt=_t.quant)==null?void 0:wt.includes("Q4_K_M")})||j.files[0];t(we)[w]=Se.fit.level,vt()}catch{t(we)[w]=null,vt()}}function vt(){let w=-1,k=99;t(we).forEach((J,j)=>{if(J==null)return;const Se=l[J]??99;Se<k&&(k=Se,w=j)}),u(Ce,w>=0&&k<=1?w:-1,!0)}function F(w){u(Be,t(x).find(k=>k.id===w),!0)}async function X(w){const k=document.getElementById("cb-r-install-btn");k&&(k.disabled=!0,k.textContent="Starte…");try{const J=await $e("/api/cookbook/install-recipe",{method:"POST",body:JSON.stringify({recipe_id:w,hf_token:oi()})});ie(`${J.count} Download${J.count!==1?"s":""} läuft — Modelle erscheinen danach automatisch im Modelle-Tab.`),u(Be,null),Ye("activity")}catch(J){ie(J.message,!0),k&&(k.disabled=!1,k.textContent="Installieren")}}async function E(w,k){var J,j;u(je,!0),u(bt,k,!0),u(z,w,!0),u(tt,""),u(oe,8192),u(re,null),u(ue,null),u(ge,""),u(Fe,!0);try{if(u(re,await $e("/api/cookbook/analyze",{method:"POST",body:JSON.stringify({repo_id:w,ctx:8192})}),!0),(j=(J=t(re))==null?void 0:J.files)!=null&&j.length){const Se=t(re).files.find(_t=>{var wt;return(wt=_t.quant)==null?void 0:wt.includes("Q4_K_M")})||t(re).files[0];u(ge,Se.filename,!0),Se.optimal_ctx&&t(oe)===8192&&u(oe,Se.optimal_ctx,!0),I()}}catch(Se){ie(Se.message,!0)}u(Fe,!1)}function I(){var w,k,J;!((k=(w=t(re))==null?void 0:w.files)!=null&&k.length)||!t(ge)||(u(ue,t(re).files.find(j=>j.filename===t(ge))||null,!0),(J=t(ue))!=null&&J.optimal_ctx&&t(oe)===8192&&u(oe,t(ue).optimal_ctx,!0))}async function se(){var w,k;if(!t(z)||!t(ge))return ie("Bitte eine GGUF-Datei wählen.",!0);u(Fe,!0);try{const J=((w=t(re))==null?void 0:w.params_b)??7,j=((k=t(ue))==null?void 0:k.quant)??"Q4_K_M";await $e("/api/cookbook/install-model",{method:"POST",body:JSON.stringify({repo:t(z),role:t(tt),params_b:J,quant:j,file:t(ge),ctx:t(oe),hf_token:oi()})}),ie("Download läuft — Modell erscheint danach automatisch im Modelle-Tab."),u(je,!1),Ye("activity")}catch(J){ie("Fehler: "+J.message,!0)}u(Fe,!1)}async function le(w,k,J,j){j.disabled=!0,j.textContent="Starte…";try{await $e("/api/cookbook/install-model",{method:"POST",body:JSON.stringify({repo:w,role:k,params_b:J,quant:"Q4_K_M",hf_token:oi()})}),ie("Download läuft — Modell erscheint danach automatisch im Modelle-Tab."),Ye("activity")}catch(Se){ie(Se.message,!0),j.disabled=!1,j.textContent="Installieren"}}function m(){u(Ke,null),u(Y,""),u(pe,""),u(fe,[{repo:"",role:"",quant:"Q4_K_M"}],!0),u(q,!0)}function L(w){const k=t(x).find(J=>J.id===w);k&&(u(Ke,w,!0),u(Y,k.title,!0),u(pe,k.desc||"",!0),u(fe,k.models.map(J=>({repo:J.repo,role:J.role,quant:J.quant||"Q4_K_M"})),!0),u(q,!0))}async function ne(){if(!t(Y).trim())return ie("Bitte einen Titel angeben.",!0);const w=t(fe).filter(k=>k.repo.trim());if(!w.length)return ie("Mindestens ein Modell (Repo) angeben.",!0);try{t(Ke)?(await $e("/api/cookbook/user-recipe/"+encodeURIComponent(t(Ke)),{method:"PUT",body:JSON.stringify({title:t(Y),desc:t(pe),models:w})}),ie("Setup aktualisiert.")):(await $e("/api/cookbook/user-recipe",{method:"POST",body:JSON.stringify({title:t(Y),desc:t(pe),models:w})}),ie("Setup gespeichert.")),u(q,!1),ct()}catch(k){ie(k.message,!0)}}async function ee(w){const k=t(x).find(J=>J.id===w);if(await mn({title:`„${(k==null?void 0:k.title)||w}" löschen?`,body:"Dein eigenes Setup wird aus dem Cookbook entfernt. Bereits installierte Modelle bleiben unangetastet.",confirmLabel:"Löschen",danger:!0}))try{await $e("/api/cookbook/user-recipe/"+encodeURIComponent(w),{method:"DELETE"}),ie("Setup gelöscht."),ct()}catch(J){ie(J.message,!0)}}function U(w){if(!v(w))return"";const k=p(w);return`<span class="chip" title="${$n(s)}">MoE${k?` · ~${k}B aktiv`:""}</span>`}function be(w){return w?`<span class="chip">${$n(w)}</span>`:""}var _e=Cc(),Le=i(et(_e),2),Qe=r(Le),Me=i(r(Qe),2),Ze=i(Qe,4);{var $=w=>{var k=Hd();f(w,k)},de=w=>{var k=Yd();rt(k,21,()=>t(x),dt,(J,j)=>{const Se=N(()=>t(j).id===t(A));var _t=Zd(),wt=r(_t);{var ye=Ne=>{var gt=Jd(),Ht=et(gt),Kt=i(Ht,2);S("click",Ht,Lt=>{Lt.stopPropagation(),L(t(j).id)}),S("keydown",Ht,Lt=>{Lt.key==="Enter"&&(Lt.stopPropagation(),L(t(j).id))}),S("click",Kt,Lt=>{Lt.stopPropagation(),ee(t(j).id)}),S("keydown",Kt,Lt=>{Lt.key==="Enter"&&(Lt.stopPropagation(),ee(t(j).id))}),f(Ne,gt)};K(wt,Ne=>{t(j).user&&Ne(ye)})}var We=i(wt,2);{var Xe=Ne=>{var gt=er();f(Ne,gt)},At=Ne=>{var gt=Qd();f(Ne,gt)};K(We,Ne=>{t(Se)?Ne(Xe):t(j).user&&Ne(At,1)})}var nt=i(We,2),ot=r(nt),St=r(ot),Rt=r(St),tn=i(ot,2),Ct=r(tn),at=i(nt,2),Ft=r(at),Ut=i(at,2),Pt=r(Ut);P((Ne,gt)=>{Dt(_t,1,`card-btn${t(Se)?" cb-best":""}`),g(Rt,t(j).title),Dt(tn,1,`fit-badge ${Ne??""}`),g(Ct,gt),g(Ft,t(j).desc),g(Pt,`${t(j).models.length??""} Modell${t(j).models.length>1?"e":""} im Setup`)},[()=>_(t(j).fit_level),()=>T(t(j).fit_level)]),S("click",_t,()=>F(t(j).id)),f(J,_t)}),f(w,k)};K(Ze,w=>{t(D)?w($):w(de,-1)})}var Te=i(Le,2),ze=r(Te),me=i(r(ze),2),Tt=r(me);{var $t=w=>{const k=N(()=>Math.round((Date.now()/1e3-t(M).updated)/60));var J=ec(),j=et(J);{var Se=Xe=>{var At=si();P(()=>g(At,`Quellen befragt vor ${t(k)??""} min`)),f(Xe,At)},_t=Xe=>{var At=si();P(nt=>g(At,`Quellen befragt vor ${nt??""} h`),[()=>Math.round(t(k)/60)]),f(Xe,At)},wt=Xe=>{var At=si();P(nt=>g(At,`Quellen befragt vor ${nt??""} Tg.`),[()=>Math.round(t(k)/1440)]),f(Xe,At)};K(j,Xe=>{t(k)<60?Xe(Se):t(k)<1440?Xe(_t,1):Xe(wt,-1)})}var ye=i(j,2);{var We=Xe=>{var At=Xd();f(Xe,At)};K(ye,Xe=>{t(qe)&&Xe(We)})}f(w,J)};K(Tt,w=>{var k;(k=t(M))!=null&&k.updated&&w($t)})}var zt=i(me,2),C=r(zt),Z=i(ze,4);{var Ge=w=>{var k=tc();f(w,k)},he=w=>{var k=Va(),J=et(k);rt(J,17,()=>t(M).categories,dt,(j,Se)=>{var _t=sc(),wt=r(_t),ye=r(wt),We=r(ye),Xe=i(wt,2);rt(Xe,21,()=>t(Se).models,dt,(At,nt)=>{const ot=N(()=>t(Se).recommended&&t(nt).repo===t(Se).recommended);var St=rc(),Rt=r(St);{var tn=mt=>{var kt=er();f(mt,kt)};K(Rt,mt=>{t(ot)&&mt(tn)})}var Ct=i(Rt,2),at=r(Ct),Ft=r(at),Ut=r(Ft),Pt=i(Ft,2),Ne=r(Pt),gt=i(at,2),Ht=r(gt),Kt=i(Ct,2),Lt=r(Kt);He(Lt,()=>be(o[t(nt).role]||d(t(nt).repo)));var Fn=i(Lt,2);He(Fn,()=>U(t(nt).repo));var Jn=i(Kt,2),An=r(Jn),Ea=i(Jn,2);rt(Ea,17,()=>t(nt).requirements||[],dt,(mt,kt)=>{var qt=nc(),Cn=r(qt);P(()=>g(Cn,`⚠ ${t(kt)??""}`)),f(mt,qt)});var Mt=i(Ea,4),pt=r(Mt);{var yt=mt=>{var kt=ac();P(()=>_i(kt,"title",`bereits eingerichtet als ${t(nt).installed??""}`)),f(mt,kt)},It=mt=>{var kt=ic();S("click",kt,qt=>le(t(nt).repo,t(nt).role,t(nt).params_b,qt.currentTarget)),f(mt,kt)};K(pt,mt=>{t(nt).installed?mt(yt):mt(It,-1)})}P((mt,kt,qt)=>{Dt(St,1,`card${t(ot)?" res-best":""}`),g(Ut,t(nt).name),g(Ne,`${t(nt).author??""} · ${t(nt).params_b??""}B`),Dt(gt,1,`fit-badge ${mt??""}`),g(Ht,t(nt).fit.text),g(An,`${kt??""} · ⬇ ${qt??""}`)},[()=>_(t(nt).fit.level),()=>y(t(nt).fit),()=>(t(nt).downloads||0).toLocaleString()]),f(At,St)}),P(()=>g(We,t(Se).title)),f(j,_t)}),f(w,k)};K(Z,w=>{var k;t(B)&&!t(M)?w(Ge):(k=t(M))!=null&&k.categories&&w(he,1)})}var G=i(Te,2),Q=i(r(G),4),V=r(Q),R=i(V,2),H=r(R);H.value=H.__value="downloads";var te=i(H);te.value=te.__value="trending";var ve=i(te);ve.value=ve.__value="created_at";var Ie=i(R,2),Ee=r(Ie),ut=i(Q,2);rt(ut,20,()=>["","coder","vision","reasoning","chat","agent"],dt,(w,k)=>{var J=lc(),j=r(J);P(()=>{Dt(J,1,t(W)===k?"primary":"ghost"),g(j,k||"Alle")}),S("click",J,()=>{u(W,k,!0),Re()}),f(w,J)});var Et=i(ut,2);{var De=w=>{var k=dc();rt(k,21,()=>t(xe),dt,(J,j,Se)=>{var _t=oc(),wt=r(_t);{var ye=Kt=>{var Lt=er();f(Kt,Lt)};K(wt,Kt=>{Se===t(Ce)&&Kt(ye)})}var We=i(wt,2),Xe=r(We),At=r(Xe),nt=r(At),ot=i(At,2),St=r(ot),Rt=i(Xe,2),tn=r(Rt),Ct=i(We,2),at=r(Ct);He(at,()=>be(d(t(j).id)));var Ft=i(at,2);He(Ft,()=>U(t(j).id));var Ut=i(Ct,4),Pt=r(Ut),Ne=r(Pt),gt=i(Pt,2),Ht=r(gt);P((Kt,Lt,Fn,Jn,An)=>{Dt(_t,1,`card${Se===t(Ce)?" res-best":""}`),g(nt,Kt),g(St,t(j).author||""),Dt(Rt,1,`fit-badge ${Lt??""}`),g(tn,Fn),g(Ne,Jn),g(Ht,`⬇ ${An??""}`)},[()=>t(j).id.split("/").pop(),()=>t(we)[Se]?_(t(we)[Se]):"warn",()=>t(we)[Se]?T(t(we)[Se]):"prüfe…",()=>t(we)[Se]?y({req_gb:0,tps:0}):"Hardware-Fit…",()=>(t(j).downloads||0).toLocaleString()]),S("click",_t,()=>E(t(j).id,t(j).id.split("/").pop())),f(J,_t)}),f(w,k)};K(Et,w=>{t(xe).length&&w(De)})}var xt=i(G,2);{var Rn=w=>{const k=N(()=>t(Be));var J=mc(),j=r(J),Se=r(j),_t=i(Se,2),wt=r(_t),ye=i(_t,2),We=r(ye),Xe=i(ye,2);rt(Xe,21,()=>t(k).models,dt,(Ct,at)=>{var Ft=pc(),Ut=r(Ft),Pt=r(Ut),Ne=r(Pt),gt=r(Ne),Ht=i(Ne,2),Kt=r(Ht),Lt=i(Ht,2);He(Lt,()=>U(t(at).repo));var Fn=i(Pt,2);{var Jn=yt=>{var It=cc(),mt=r(It);P(()=>g(mt,t(at).why)),f(yt,It)};K(Fn,yt=>{t(at).why&&yt(Jn)})}var An=i(Fn,2);{var Ea=yt=>{var It=vc(),mt=r(It);P((kt,qt,Cn)=>g(mt,`~${kt??""} GB · ~${qt??""} Tok/s · optimal ~${Cn??""}k Kontext`),[()=>(t(at).fit.req_gb??0).toFixed(1),()=>Math.round(t(at).fit.tps??0),()=>Math.round((t(at).optimal_ctx||8192)/1024)]),f(yt,It)};K(An,yt=>{t(at).fit&&yt(Ea)})}var Mt=i(Ut,2);{var pt=yt=>{var It=uc(),mt=r(It);P(kt=>{Dt(It,1,`fit-badge ${kt??""}`),g(mt,t(at).fit.text)},[()=>_(t(at).fit.level)]),f(yt,It)};K(Mt,yt=>{t(at).fit&&yt(pt)})}P(()=>{g(gt,t(at).name),g(Kt,t(at).role)}),f(Ct,Ft)});var At=i(Xe,2);{var nt=Ct=>{const at=N(()=>Math.max(...t(k).models.map(Ne=>{var gt;return((gt=Ne.fit)==null?void 0:gt.req_gb)??0})));var Ft=fc(),Ut=i(r(Ft)),Pt=r(Ut);P(Ne=>g(Pt,`~${Ne??""} GB`),[()=>t(at).toFixed(1)]),f(Ct,Ft)};K(At,Ct=>{t(k).models.length&&t(k).models[0].fit&&Ct(nt)})}var ot=i(At,2);{var St=Ct=>{const at=N(()=>t(x).find(Ne=>!Ne.user&&Ne.fit_level!=="too_tight"&&Ne.id!==t(k).id));var Ft=gc(),Ut=i(r(Ft));{var Pt=Ne=>{var gt=hc(),Ht=i(et(gt)),Kt=r(Ht);P(()=>g(Kt,`„${t(at).title??""}" ansehen`)),S("click",Ht,Lt=>{Lt.preventDefault(),u(Be,null),setTimeout(()=>F(t(at).id),50)}),f(Ne,gt)};K(Ut,Ne=>{t(at)&&Ne(Pt)})}f(Ct,Ft)};K(ot,Ct=>{t(k).fit_level==="too_tight"&&Ct(St)})}var Rt=i(ot,2),tn=r(Rt);P(()=>{g(wt,t(k).title),g(We,t(k).desc),Dt(Rt,1,`primary${t(k).fit_level==="too_tight"?" warn":""}`),g(tn,t(k).fit_level==="too_tight"?"Trotzdem installieren (nicht empfohlen)":"Komplettes Setup installieren")}),S("click",J,Ct=>{Ct.target.classList.contains("modal-overlay")&&u(Be,null)}),S("click",Se,()=>u(Be,null)),S("click",Rt,()=>X(t(k).id)),f(w,J)};K(xt,w=>{t(Be)&&w(Rn)})}var Un=i(xt,2);{var la=w=>{var k=Mc(),J=r(k),j=r(J),Se=i(j,2),_t=r(Se),wt=i(Se,2),ye=r(wt),We=i(wt,2);{var Xe=ot=>{var St=bc();f(ot,St)},At=ot=>{var St=wc(),Rt=i(et(St),2);rt(Rt,21,()=>t(re).files,dt,(Mt,pt)=>{const yt=N(()=>t(pt).fit.level==="perfect"?"●":t(pt).fit.level==="marginal"?"◐":"○");var It=Yr(),mt=r(It),kt={};P(()=>{g(mt,`${t(yt)??""} ${t(pt).filename??""}`),kt!==(kt=t(pt).filename)&&(It.value=(It.__value=t(pt).filename)??"")}),f(Mt,It)});var tn=i(Rt,2),Ct=r(tn),at=i(r(Ct),2),Ft=i(Ct,2),Ut=r(Ft),Pt=i(r(Ut));He(Pt,()=>mr(a));var Ne=i(Ut,2),gt=i(tn,2);{var Ht=Mt=>{var pt=_c(),yt=i(r(pt)),It=r(yt),mt=i(yt,2);P(kt=>g(It,`~${kt??""}k`),[()=>Math.round(t(ue).optimal_ctx/1024)]),S("click",mt,kt=>{kt.preventDefault(),u(oe,t(ue).optimal_ctx,!0)}),f(Mt,pt)};K(gt,Mt=>{var pt;(pt=t(ue))!=null&&pt.optimal_ctx&&Mt(Ht)})}var Kt=i(gt,2);{var Lt=Mt=>{var pt=yc(),yt=r(pt),It=i(r(yt),2),mt=r(It),kt=i(yt,2),qt=r(kt);P((Cn,xi,Vi)=>{g(mt,`~${Cn??""} GB · ~${xi??""} Tok/s · ${(t(ue).quant||"GGUF")??""}`),Dt(kt,1,`fit-badge ${Vi??""}`),g(qt,t(ue).fit.text)},[()=>(t(ue).fit.req_gb??0).toFixed(1),()=>Math.round(t(ue).fit.tps??0),()=>_(t(ue).fit.level)]),f(Mt,pt)};K(Kt,Mt=>{t(ue)&&Mt(Lt)})}var Fn=i(Kt,2);{var Jn=Mt=>{const pt=N(()=>t(re).files.find(qt=>qt.fit.level!=="too_tight"&&qt.filename!==t(ge)));var yt=Va(),It=et(yt);{var mt=qt=>{var Cn=kc(),xi=i(r(Cn)),Vi=r(xi);P(ji=>g(Vi,`${t(pt).filename??""} (${ji??""})`),[()=>T(t(pt).fit.level)]),S("click",xi,ji=>{ji.preventDefault(),u(ge,t(pt).filename,!0),I()}),f(qt,Cn)},kt=qt=>{var Cn=xc();f(qt,Cn)};K(It,qt=>{t(pt)?qt(mt):qt(kt,-1)})}f(Mt,yt)};K(Fn,Mt=>{var pt,yt;((pt=t(ue))==null?void 0:pt.fit.level)==="too_tight"&&((yt=t(re))!=null&&yt.files)&&Mt(Jn)})}var An=i(Fn,2),Ea=r(An);P(()=>{var Mt,pt;Dt(An,1,`primary${((Mt=t(ue))==null?void 0:Mt.fit.level)==="too_tight"?" warn":""}`),An.disabled=t(Fe),g(Ea,t(Fe)?"Starte…":((pt=t(ue))==null?void 0:pt.fit.level)==="too_tight"?"Trotzdem holen (zu groß — nicht empfohlen)":"Herunterladen & Einpflegen")}),S("change",Rt,I),xa(Rt,()=>t(ge),Mt=>u(ge,Mt)),vn(at,()=>t(tt),Mt=>u(tt,Mt)),vn(Ne,()=>t(oe),Mt=>u(oe,Mt)),S("click",An,se),f(ot,St)},nt=ot=>{var St=Sc();f(ot,St)};K(We,ot=>{var St,Rt;t(Fe)&&!t(re)?ot(Xe):(Rt=(St=t(re))==null?void 0:St.files)!=null&&Rt.length?ot(At,1):t(Fe)||ot(nt,2)})}P(()=>{g(_t,t(bt)),g(ye,t(z))}),S("click",k,ot=>{ot.target.classList.contains("modal-overlay")&&u(je,!1)}),S("click",j,()=>u(je,!1)),f(w,k)};K(Un,w=>{t(je)&&w(la)})}var Hn=i(Un,2);{var Ja=w=>{var k=Ac(),J=r(k),j=r(J),Se=i(j,2),_t=r(Se),wt=i(Se,6),ye=i(wt,4),We=i(ye,4);rt(We,17,()=>t(fe),dt,(ot,St,Rt)=>{var tn=Ec(),Ct=r(tn),at=i(Ct,2),Ft=i(at,2);rt(Ft,20,()=>["Q4_K_M","Q5_K_M","Q6_K","Q8_0","Q3_K_M"],dt,(Pt,Ne)=>{var gt=Yr(),Ht=r(gt),Kt={};P(()=>{g(Ht,Ne),Kt!==(Kt=Ne)&&(gt.__value=Ne)}),f(Pt,gt)});var Ut=i(Ft,2);vn(Ct,()=>t(St).repo,Pt=>t(St).repo=Pt),vn(at,()=>t(St).role,Pt=>t(St).role=Pt),xa(Ft,()=>t(St).quant,Pt=>t(St).quant=Pt),S("click",Ut,()=>u(fe,t(fe).filter((Pt,Ne)=>Ne!==Rt),!0)),f(ot,tn)});var Xe=i(We,2),At=i(Xe,4),nt=r(At);P(()=>{g(_t,t(Ke)?"Setup bearbeiten":"Eigenes Setup erstellen"),g(nt,t(Ke)?"Änderungen speichern":"Setup speichern")}),S("click",k,ot=>{ot.target.classList.contains("modal-overlay")&&u(q,!1)}),S("click",j,()=>u(q,!1)),vn(wt,()=>t(Y),ot=>u(Y,ot)),vn(ye,()=>t(pe),ot=>u(pe,ot)),S("click",Xe,()=>u(fe,[...t(fe),{repo:"",role:"",quant:"Q4_K_M"}],!0)),S("click",At,ne),f(w,k)};K(Hn,w=>{t(q)&&w(Ja)})}P(()=>{zt.disabled=t(B),g(C,t(B)?"Suche…":"Aktualisieren"),Ie.disabled=t(Ae),g(Ee,t(Ae)?"Lade…":"Suchen")}),S("click",Me,m),S("click",zt,()=>st(!0)),S("keydown",V,w=>w.key==="Enter"&&Re()),vn(V,()=>t(ke),w=>u(ke,w)),xa(R,()=>t(ae),w=>u(ae,w)),S("click",Ie,Re),f(e,_e),Bn()}jn(["click","keydown","change"]);var zc=b(`<div class="alert warn" style="margin:0 0 12px"><span class="a-dot"></span> <span>Du öffnest Mission Control über einen <b>Proxy/Namen</b>. Die Engine läuft auf <b>Port 8080 ohne HTTPS</b> direkt am Bosgame.
|
||
Trag in deinen Tools die <b>LAN-IP</b> ein: <code>http://192.168.178.151:8080/v1</code> — nicht den Proxy-Namen.</span></div>`),Pc=b('<span class="mono-sm"> </span>'),Dc=b('<div class="tile" style="display:flex;gap:12px;align-items:flex-start"><span style="font-size:20px;line-height:1;flex:0 0 auto"> </span> <div><div style="font-weight:500;font-size:13.5px"> </div> <div class="card-sub" style="margin:4px 0 0"> </div></div></div>'),$c=b('<span class="chip" role="button" tabindex="0"> </span>'),Lc=b('<div style="margin-top:10px"><a href="#" style="color:var(--mut);font-size:12.5px">Auswahl aufheben (alle)</a></div>'),Xr=b('<button style="text-align:left;padding:12px 16px"><div style="font-weight:500;font-size:13.5px"> </div> <div class="card-sub" style="margin:3px 0 0"> </div></button>'),Ic=b('<p><b>Jan AI</b> ist eine Desktop-App — kein Browser, kein Server, kein Admin-Panel. Einfach installieren und loslegen.</p> <p>Jan AI öffnen → linke Leiste → <b>Remote-Modelle</b> → <b>+ Modell hinzufügen</b>:</p> <label>Basis-URL (kopieren und in Jan AI einfügen)</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <label>Modell-ID (in Jan AI als „Model name" eintragen)</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <div class="hint">API-Key: ein beliebiger Wert (z.B. <code>local</code>). Jan AI fragt danach beim Einrichten.</div> <div class="hint" style="margin-top:8px">Jan AI herunterladen: <a href="https://jan.ai" target="_blank" rel="noopener">jan.ai</a> — kostenlos, open source, Windows/macOS/Linux.</div>',1),Oc=b('<p>Datei anlegen oder öffnen: <code>~/.continue/config.json</code></p> <div class="alert warn" style="margin:8px 0 12px;padding:10px 14px"><span class="a-dot"></span><span>Falls bereits eine <code>config.json</code> vorhanden: nur den <code>"models"</code>-Eintrag ergänzen, nicht die ganze Datei ersetzen.</span></div> <div style="position:relative"><button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1">Kopieren</button> <div class="log" style="max-height:none"><code> </code></div></div> <p style="margin-top:12px">Danach Continue in VS Code neu starten → im Chat-Panel das Modell <b> </b> wählen.</p> <div class="hint">Continue: <a href="https://continue.dev" target="_blank" rel="noopener">continue.dev</a> — kostenlose VS Code / JetBrains Extension. Hinweis: 2026 von Cursor akquiriert — aktuell weiter aktiv und kostenlos.</div>',1),Bc=b('<p><b>Antigravity</b> (Googles agentic IDE, VS Code-basiert) unterstützt OpenAI-kompatible Endpoints direkt:</p> <p>Settings → Models → <b>Custom Endpoint</b> → <b>+ hinzufügen</b>:</p> <label>Basis-URL</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <label>Modell-ID</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <div class="hint">API-Key: ein beliebiger Wert (z.B. <code>local</code>). Danach das Modell <b> </b> in der Model-Liste auswählen.</div> <div class="hint" style="margin-top:8px">Antigravity herunterladen: <a href="https://antigravityide.net" target="_blank" rel="noopener">antigravityide.net</a> — kostenlose Einzelperson-Tier, VS Code-basiert.</div>',1),Rc=b('<p>Öffne die Zed-Settings mit <code>Cmd/Strg + ,</code> und <b>füge diesen Block</b> in deine bestehende <code>settings.json</code> ein. Falls bereits ein <code>"bosgame"</code>-Eintrag existiert: vorher löschen.</p> <div class="alert warn" style="margin-bottom:12px;padding:10px 14px"><span class="a-dot"></span><span>Nur diesen Block einfügen, <b>nicht die ganze Datei ersetzen</b> — sonst gehen andere Einstellungen verloren.</span></div> <div style="position:relative"><button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1">Kopieren</button> <div class="log" style="max-height:none"><code> </code></div></div> <p style="margin-top:12px"><b>API-Key:</b> Öffne den Agent-Panel → Anbieter <b>bosgame</b> → trag irgendeinen Wert ein (z.B. <code>local</code>).</p> <div class="hint">Danach im Agent-Panel das Modell <b> </b> auswählen.</div>',1),Fc=b('<p>Datei anlegen oder öffnen:</p> <p class="mono-sm" style="line-height:1.6">Windows: <code>%USERPROFILE%\\.config\\opencode\\opencode.json</code></p> <div class="alert warn" style="margin:8px 0 12px;padding:10px 14px"><span class="a-dot"></span><span>Nur den <code>"provider"</code>-Block einfügen. Falls bereits ein <code>"llama-swap"</code>-Eintrag vorhanden: <b>vorher löschen</b>, sonst erscheinen Modelle doppelt.</span></div> <div style="position:relative"><button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1">Kopieren</button> <div class="log" style="max-height:none"><code> </code></div></div> <p style="margin-top:12px">Danach in OpenCode <code>/models</code> → <b> </b> wählen.</p>',1),Kc=b('<p>In Cline/Cursor den Provider <b>„OpenAI Compatible"</b> wählen:</p> <label>Basis-URL</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <label>Modell-ID</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <div class="hint">API-Key: ein beliebiger Wert (z.B. <code>local</code>).</div>',1),Nc=b('<p>Settings → Admin Panel → Connections → neue OpenAI-Verbindung:</p> <label>Basis-URL</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <label>API-Key</label> <div class="flex gap-2" style="align-items:stretch"><input class="mono-sm" readonly="" value="dummy-key" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div>',1),qc=b('<div class="card"><div class="card-h"><h3>Bilder einbinden (Vision)</h3> <span class="chip" style="background:rgba(63,185,80,.12);border-color:rgba(63,185,80,.25);color:#7ee29a"><!> </span></div> <div class="card-sub">Mit Vision-Modellen kannst du Screenshots oder Fehlerbilder direkt mitschicken.</div> <div style="position:relative;margin-top:8px"><button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1">Kopieren</button> <div class="log" style="max-height:none"><code> </code></div></div></div>'),Wc=b('<div class="card"><div class="card-h"><h3>2 · Modelle auswählen</h3> <span class="meta"> </span></div> <div class="card-sub">Wähle, welche Modelle im Config-Snippet erscheinen sollen.</div> <div class="flex gap-2" style="flex-wrap:wrap"></div> <!></div> <div class="card"><div class="card-h"><h3>3 · Tool wählen</h3></div> <div class="card-sub" style="margin-bottom:8px">Für welches Werkzeug brauchst du die Konfiguration?</div> <div style="font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent);margin-bottom:6px">Chat</div> <div class="grid grid-3" style="gap:8px;margin-bottom:14px"></div> <div style="font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent);margin-bottom:6px">Coding-Assistenten</div> <div class="grid grid-3" style="gap:8px"></div></div> <div class="card"><div class="card-h"><h3>4 · Config-Snippet</h3></div> <!></div> <!>',1),Gc=b('<div class="card"><div class="card-h"><h3>2 · Erst ein Modell installieren</h3></div> <div class="empty-c" style="padding:8px 0 4px"><div class="e-t">Noch kein Modell eingerichtet</div> <div class="e-s">Bevor du ein Tool verbinden kannst, braucht die Engine mindestens ein Modell. Das Config-Snippet wird dann automatisch mit deinen echten Modellnamen befüllt.</div> <button class="primary" style="margin-top:14px">→ Zum Cookbook (Modell holen)</button></div></div>'),Vc=b('<button style="text-align:left;padding:10px 14px"><div style="font-weight:500;font-size:13px"> </div> <div class="card-sub" style="margin:2px 0 0;font-size:11.5px"> </div></button>'),jc=b('<p style="margin-top:12px">In <b>Cline</b>: MCP-Einstellungen öffnen (Stecker-Icon in der Cline-Sidebar) → „Add MCP Server" → diesen Block einfügen.</p> <p>In <b>Claude Code</b>: Block in <code>~/.claude/settings.json</code> unter <code>"mcpServers"</code> einfügen.</p> <div class="alert warn" style="margin-top:8px;padding:10px 14px"><span class="a-dot"></span> <span>Einmalig auf dem Windows-PC: <code>pip install mcp httpx</code> ausführen — danach <code>mcp_memory.py</code> aus dem Repo-Ordner erreichbar machen (Pfad im Snippet anpassen).</span></div>',1),Uc=b('<p style="margin-top:12px">Block in <code>~/.config/opencode/opencode.json</code> unter <code>"mcpServers"</code> einfügen.</p> <div class="alert warn" style="margin-top:8px;padding:10px 14px"><span class="a-dot"></span> <span>Einmalig: <code>pip install mcp httpx</code> — und Pfad zu <code>mcp_memory.py</code> im Snippet anpassen.</span></div>',1),Hc=b('<p style="margin-top:12px">Block in die MCP-Config des jeweiligen Tools einfügen. Der Bosgame-Pfad <code>/opt/mission-control/mcp_memory.py</code> ist bereits korrekt — kein weiteres Setup nötig.</p>'),Jc=b(`<div class="pagehead"><div><h1>Verbinden</h1> <div class="sub">Schritt für Schritt: KI-Modelle in deine Tools einbinden — getestet, erklärt, mit Copy-Paste-Config.</div></div></div> <div class="card"><div class="card-h"><h3>1 · Verbindung prüfen</h3></div> <div class="card-sub">Stelle sicher, dass die LLM-Engine erreichbar ist, bevor du Tools konfigurierst.</div> <label>Engine-Adresse (für alle Tools)</label> <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px"><input class="mono-sm" readonly="" style="flex:1;margin:0"/> <button class="ghost">Kopieren</button></div> <!> <div class="btn-row" style="display:flex;align-items:center;gap:10px"><button class="primary">Verbindung testen</button> <!></div></div> <div class="card"><div class="card-h"><h3>Wie funktioniert das Auto-Swap?</h3></div> <div style="display:flex;flex-direction:column;gap:10px"></div></div> <!> <div class="card"><div class="card-h"><h3>Gedächtnis-MCP</h3> <span class="chip" style="background:rgba(45,212,191,.1);border-color:rgba(45,212,191,.3);color:var(--accent)">Neu in v7</span></div> <div class="card-sub" style="margin-bottom:14px">Damit Cline, OpenCode und Claude Code sich Projektfakten, Entscheidungen und Präferenzen
|
||
über Sessions hinweg merken — geteilt über alle Tools, verwaltet im <a href="#" style="color:var(--accent)">Gedächtnis-Tab</a>.</div> <div class="flex gap-2" style="margin-bottom:14px;flex-wrap:wrap"></div> <div style="position:relative"><button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1">Kopieren</button> <div class="log" style="max-height:none"><code> </code></div></div> <!></div>`,1);function Qc(e,n){On(n,!0);const a=N(()=>ki.value),s=N(()=>{var m;return(((m=t(a))==null?void 0:m.models)||[]).filter(L=>!L.incomplete)}),l=N(T);let o=O("zed"),c=O(jt([])),d=O(""),v=O(!1),p=O("cline");const _=N(()=>ae(t(p)));function T(){return`http://${location.hostname}:8080/v1`}function y(m){return/^\d{1,3}(\.\d{1,3}){3}$/.test(m)}function x(){return location.protocol==="https:"||!y(location.hostname)}const A=N(()=>t(c).length?t(c):t(s).map(m=>m.name)),D=N(()=>t(A)[0]||"coder"),M=N(()=>{var m;return(m=t(s).find(L=>{var ne,ee;return(ee=(ne=L.meta)==null?void 0:ne.caps)==null?void 0:ee.includes("Bild")}))==null?void 0:m.name});function B(m,L){const ee=(L.length?t(s).filter(U=>L.includes(U.name)):t(s).length?t(s):[{name:"coder",meta:{}}]).map(U=>{var Le,Qe;const be=(((Le=U.meta)==null?void 0:Le.caps)||[]).some(Me=>/Bild|Vision/i.test(Me)),_e=((Qe=U.meta)==null?void 0:Qe.ctx)||131072;return` { "name": "${U.name}", "display_name": "${U.name}", "max_tokens": ${_e}${be?', "capabilities": { "tools": true, "images": true }':""} }`}).join(`,
|
||
`);return`"language_models": {
|
||
"openai_compatible": {
|
||
"bosgame": {
|
||
"api_url": "${m}",
|
||
"available_models": [
|
||
${ee}
|
||
]
|
||
}
|
||
}
|
||
}`}function qe(m,L){const ee=(L.length?t(s).filter(U=>L.includes(U.name)):t(s).length?t(s):[{name:"coder",meta:{}}]).map(U=>{var _e;const be=((_e=U.meta)==null?void 0:_e.ctx)||131072;return` "${U.name}": { "name": "${U.name}", "contextWindowSize": ${be} }`}).join(`,
|
||
`);return`"provider": {
|
||
"llama-swap": {
|
||
"npm": "@ai-sdk/openai-compatible",
|
||
"name": "Bosgame (llama-swap)",
|
||
"options": {
|
||
"baseURL": "${m}",
|
||
"apiKey": "local"
|
||
},
|
||
"models": {
|
||
${ee}
|
||
}
|
||
}
|
||
}`}function ke(m,L){return`{
|
||
"models": [
|
||
${(L.length?t(s).filter(U=>L.includes(U.name)):t(s).length?t(s):[{name:"coder",meta:{}}]).map(U=>` {
|
||
"title": "llama-swap / ${U.name}",
|
||
"provider": "openai",
|
||
"model": "${U.name}",
|
||
"apiBase": "${m}",
|
||
"apiKey": "local"
|
||
}`).join(`,
|
||
`)}
|
||
]
|
||
}`}async function xe(){u(d,"Teste…");try{const m=await $e("/api/integration/test");u(v,m.ok,!0),u(d,m.ok?`✓ Verbunden — ${m.models.length} Modell(e): ${m.models.join(", ")}`:`✗ Keine Verbindung: ${m.error}`,!0)}catch(m){u(v,!1),u(d,"✗ "+m.message)}}function Ae(m){var ne;const L=m.querySelector("code");L&&((ne=navigator.clipboard)==null||ne.writeText(L.textContent||""))}function W(m){var L;(L=navigator.clipboard)==null||L.writeText(m.value)}function ae(m){return`{
|
||
"mcpServers": {
|
||
"mission-control-memory": {
|
||
"command": "${m==="bosgame"?"/opt/mission-control/.venv/bin/python":"python"}",
|
||
"args": ["${m==="bosgame"?"/opt/mission-control/mcp_memory.py":"C:\\\\Users\\\\TobisPC\\\\mission-control\\\\mcp_memory.py"}"],
|
||
"env": {
|
||
"MC_URL": "http://192.168.178.151:9000"
|
||
}
|
||
}
|
||
}
|
||
}`}var we=Jc(),Ce=i(et(we),2),Be=i(r(Ce),6),je=r(Be),bt=i(je,2),z=i(Be,2);{var re=m=>{var L=zc();f(m,L)},ge=N(()=>x());K(z,m=>{t(ge)&&m(re)})}var tt=i(z,2),oe=r(tt),Fe=i(oe,2);{var ue=m=>{var L=Pc(),ne=r(L);P(()=>{Ot(L,`color:${t(v)?"#7ee29a":"#ff9b95"}`),g(ne,t(d))}),f(m,L)};K(Fe,m=>{t(d)&&m(ue)})}var q=i(Ce,2),Y=i(r(q),2);rt(Y,20,()=>[["⚡","Kein manuelles Starten nötig",'Wenn du in Zed oder OpenCode „coder" auswählst und eine Anfrage sendest, lädt llama-swap das Modell automatisch — in ca. 2–5 Sekunden.'],["🔄","Modelle wechseln sich automatisch ab","Rufst du ein anderes Modell auf, entlädt llama-swap das aktuelle (nach TTL-Ablauf) und lädt das neue. Es läuft immer nur eines gleichzeitig."],["🧠","Zwei Modelle gleichzeitig aktiv halten","Du hast 124 GB RAM — genug für z.B. Scout 8B (~5 GB) dauerhaft geladen + ein größeres Modell das swappt. Dafür beim Scout im Modelle-Tab → Konfigurieren die TTL auf 99999 setzen."]],dt,(m,L)=>{var ne=N(()=>ta(L,3));let ee=()=>t(ne)[0],U=()=>t(ne)[1],be=()=>t(ne)[2];var _e=Dc(),Le=r(_e),Qe=r(Le),Me=i(Le,2),Ze=r(Me),$=r(Ze),de=i(Ze,2),Te=r(de);P(()=>{g(Qe,ee()),g($,U()),g(Te,be())}),f(m,_e)});var pe=i(q,2);{var fe=m=>{var L=Wc(),ne=et(L),ee=r(ne),U=i(r(ee),2),be=r(U),_e=i(ee,4);rt(_e,21,()=>t(s),dt,(G,Q)=>{const V=N(()=>t(c).includes(t(Q).name));var R=$c(),H=r(R);P(()=>{Ot(R,`cursor:pointer;${t(V)?"background:rgba(45,212,191,.2);border-color:var(--accent);color:var(--accent)":""}`),g(H,t(Q).name)}),S("click",R,()=>u(c,t(V)?t(c).filter(te=>te!==t(Q).name):[...t(c),t(Q).name],!0)),S("keydown",R,te=>te.key==="Enter"&&u(c,t(V)?t(c).filter(ve=>ve!==t(Q).name):[...t(c),t(Q).name],!0)),f(G,R)});var Le=i(_e,2);{var Qe=G=>{var Q=Lc(),V=r(Q);S("click",V,R=>{R.preventDefault(),u(c,[],!0)}),f(G,Q)};K(Le,G=>{t(c).length&&G(Qe)})}var Me=i(ne,2),Ze=i(r(Me),6);rt(Ze,20,()=>[["janai","Jan AI","Einfachstes Chat-Interface — Desktop-App, kein Setup"],["openwebui","OpenWebUI","Browser-Chat für Teams — mehr Features, mehr Setup"]],dt,(G,Q)=>{var V=N(()=>ta(Q,3));let R=()=>t(V)[0],H=()=>t(V)[1],te=()=>t(V)[2];var ve=Xr(),Ie=r(ve),Ee=r(Ie),ut=i(Ie,2),Et=r(ut);P(()=>{Dt(ve,1,`card-btn${t(o)===R()?" cb-best":""}`),g(Ee,H()),g(Et,te())}),S("click",ve,()=>u(o,R(),!0)),f(G,ve)});var $=i(Ze,4);rt($,20,()=>[["continue","Continue","VS Code/JetBrains — Hilfe ohne Agent-Overhead"],["cline","Cline","VS Code/JetBrains/Zed — voller Coding-Agent"],["antigravity","Antigravity","Googles agentic IDE — VS Code-basiert"],["opencode","OpenCode","Terminal-Agent — autonom, mächtig"],["zed","Zed","Schneller nativer Editor mit KI-Panel"]],dt,(G,Q)=>{var V=N(()=>ta(Q,3));let R=()=>t(V)[0],H=()=>t(V)[1],te=()=>t(V)[2];var ve=Xr(),Ie=r(ve),Ee=r(Ie),ut=i(Ie,2),Et=r(ut);P(()=>{Dt(ve,1,`card-btn${t(o)===R()?" cb-best":""}`),g(Ee,H()),g(Et,te())}),S("click",ve,()=>u(o,R(),!0)),f(G,ve)});var de=i(Me,2),Te=i(r(de),2);{var ze=G=>{var Q=Ic(),V=i(et(Q),6),R=r(V),H=i(R,2),te=i(V,4),ve=r(te),Ie=i(ve,2);P(()=>{Zn(R,t(l)),Zn(ve,t(D))}),S("click",H,Ee=>W(Ee.currentTarget.previousElementSibling)),S("click",Ie,Ee=>W(Ee.currentTarget.previousElementSibling)),f(G,Q)},me=G=>{const Q=N(()=>ke(t(l),t(A)));var V=Oc(),R=i(et(V),4),H=r(R),te=i(H,2),ve=r(te),Ie=r(ve),Ee=i(R,2),ut=i(r(Ee)),Et=r(ut);P(()=>{g(Ie,t(Q)),g(Et,`llama-swap / ${t(D)??""}`)}),S("click",H,De=>Ae(De.currentTarget.parentElement)),f(G,V)},Tt=G=>{var Q=Bc(),V=i(et(Q),6),R=r(V),H=i(R,2),te=i(V,4),ve=r(te),Ie=i(ve,2),Ee=i(te,2),ut=i(r(Ee),3),Et=r(ut);P(()=>{Zn(R,t(l)),Zn(ve,t(D)),g(Et,t(D))}),S("click",H,De=>W(De.currentTarget.previousElementSibling)),S("click",Ie,De=>W(De.currentTarget.previousElementSibling)),f(G,Q)},$t=G=>{const Q=N(()=>B(t(l),t(A)));var V=Rc(),R=i(et(V),4),H=r(R),te=i(H,2),ve=r(te),Ie=r(ve),Ee=i(R,4),ut=i(r(Ee)),Et=r(ut);P(()=>{g(Ie,t(Q)),g(Et,`bosgame / ${t(D)??""}`)}),S("click",H,De=>Ae(De.currentTarget.parentElement)),f(G,V)},zt=G=>{const Q=N(()=>qe(t(l),t(A)));var V=Fc(),R=i(et(V),6),H=r(R),te=i(H,2),ve=r(te),Ie=r(ve),Ee=i(R,2),ut=i(r(Ee),3),Et=r(ut);P(()=>{g(Ie,t(Q)),g(Et,`llama-swap/${t(D)??""}`)}),S("click",H,De=>Ae(De.currentTarget.parentElement)),f(G,V)},C=G=>{var Q=Kc(),V=i(et(Q),4),R=r(V),H=i(R,2),te=i(V,4),ve=r(te),Ie=i(ve,2);P(()=>{Zn(R,t(l)),Zn(ve,t(D))}),S("click",H,Ee=>W(Ee.currentTarget.previousElementSibling)),S("click",Ie,Ee=>W(Ee.currentTarget.previousElementSibling)),f(G,Q)},Z=G=>{var Q=Nc(),V=i(et(Q),4),R=r(V),H=i(R,2),te=i(V,4),ve=r(te),Ie=i(ve,2);P(()=>Zn(R,t(l))),S("click",H,Ee=>W(Ee.currentTarget.previousElementSibling)),S("click",Ie,Ee=>W(Ee.currentTarget.previousElementSibling)),f(G,Q)};K(Te,G=>{t(o)==="janai"?G(ze):t(o)==="continue"?G(me,1):t(o)==="antigravity"?G(Tt,2):t(o)==="zed"?G($t,3):t(o)==="opencode"?G(zt,4):t(o)==="cline"?G(C,5):t(o)==="openwebui"&&G(Z,6)})}var Ge=i(de,2);{var he=G=>{const Q=N(()=>`curl ${t(l)}/chat/completions \\
|
||
-H "Content-Type: application/json" \\
|
||
-d '{
|
||
"model": "${t(M)}",
|
||
"messages": [{"role":"user","content":[{"type":"text","text":"Was ist auf dem Bild falsch?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,<DEIN_BILD>"}}]}]
|
||
}'`);var V=qc(),R=r(V),H=i(r(R),2),te=r(H);He(te,()=>Wt("check"));var ve=i(te),Ie=i(R,4),Ee=r(Ie),ut=i(Ee,2),Et=r(ut),De=r(Et);P(()=>{g(ve,` „${t(M)??""}" bereit`),g(De,t(Q))}),S("click",Ee,xt=>Ae(xt.currentTarget.parentElement)),f(G,V)};K(Ge,G=>{t(M)&&G(he)})}P(()=>g(be,t(c).length?`${t(c).length} von ${t(s).length} ausgewählt`:"alle werden eingeschlossen")),f(m,L)},Ke=m=>{var L=Gc(),ne=i(r(L),2),ee=i(r(ne),4);S("click",ee,()=>{var U;return(U=document.querySelector(".nav-item[data-view='cookbook']"))==null?void 0:U.dispatchEvent(new MouseEvent("click"))}),f(m,L)};K(pe,m=>{t(s).length?m(fe):m(Ke,-1)})}var Ye=i(pe,2),ct=i(r(Ye),2),st=i(r(ct)),lt=i(ct,2);rt(lt,20,()=>[["cline","Cline / Claude Code","Windows — Tools auf dem Entwicklungs-PC"],["opencode","OpenCode","Windows — Terminal-Agent"],["bosgame","Direkt am Bosgame","Wenn das Tool am Server läuft"]],dt,(m,L)=>{var ne=N(()=>ta(L,3));let ee=()=>t(ne)[0],U=()=>t(ne)[1],be=()=>t(ne)[2];var _e=Vc(),Le=r(_e),Qe=r(Le),Me=i(Le,2),Ze=r(Me);P(()=>{Dt(_e,1,`card-btn${t(p)===ee()?" cb-best":""}`),g(Qe,U()),g(Ze,be())}),S("click",_e,()=>u(p,ee(),!0)),f(m,_e)});var Re=i(lt,2),Je=r(Re),vt=i(Je,2),F=r(vt),X=r(F),E=i(Re,2);{var I=m=>{var L=jc();f(m,L)},se=m=>{var L=Uc();f(m,L)},le=m=>{var L=Hc();f(m,L)};K(E,m=>{t(p)==="cline"?m(I):t(p)==="opencode"?m(se,1):m(le,-1)})}P(()=>{Zn(je,t(l)),g(X,t(_))}),S("click",bt,m=>{const L=m.currentTarget.previousElementSibling;W(L)}),S("click",oe,xe),S("click",st,m=>{var L;m.preventDefault(),(L=document.querySelector(".nav-item[data-view='memory']"))==null||L.click()}),S("click",Je,m=>Ae(m.currentTarget.parentElement)),f(e,we),Bn()}jn(["click","keydown"]);var Zc=b('<div class="li" style="align-items:flex-start"><div class="li-main"><div class="flex items-center gap-2" style="flex-wrap:wrap"><span class="li-id" style="font-family:var(--sans);font-weight:500"> </span> <span> </span></div> <div class="li-sub"> </div></div> <button class="primary">Installieren</button></div>'),Yc=b('<div class="card" style="margin-bottom:18px;border-color:rgba(45,212,191,.25)"><div class="card-h"><h3>Für dich: Upgrades</h3> <span class="meta"> </span></div> <div class="card-sub">Neuere Modelle, die ein installiertes ersetzen können.</div> <div class="list"></div></div>'),Xc=b('<div class="empty" style="text-align:center;padding:40px">Lade News… (erstes Laden kann kurz dauern)</div>'),ev=b('<div class="alert err" style="margin:0"> </div>'),tv=b('<div class="empty-c"><div class="e-t">Keine News geladen</div> <div class="e-s">Die Quellen sind gerade nicht erreichbar — später nochmal probieren.</div></div>'),nv=b('<span class="news-rel">für dich</span>'),av=b('<a target="_blank" rel="noopener"><div class="news-meta"><span class="news-src"> </span> <!> <span class="news-date"> </span></div> <div class="news-title"> </div></a>'),iv=b('<div class="news-grid"></div>'),rv=b('<div class="pagehead"><div><h1>News</h1> <div class="sub">Aktuelles aus der Local-LLM-Welt — aus kuratierten Quellen.</div></div> <button class="ghost">Aktualisieren</button></div> <!> <!>',1);function sv(e,n){On(n,!0);let a=O(jt([])),s=O(jt([])),l=O(!0),o=O("");const c=W=>W==="perfect"?"ok":W==="marginal"?"warn":"bad";function d(W){const ae=Math.max(0,Date.now()/1e3-W);return ae<60?ae+"s":ae<3600?Math.floor(ae/60)+"m":ae<86400?Math.floor(ae/3600)+"h":Math.floor(ae/86400)+"d"}async function v(){u(l,!0),u(o,"");try{u(a,(await $e("/api/news")).items||[],!0)}catch(W){u(o,W.message||"Fehler beim Laden",!0)}finally{u(l,!1)}}async function p(){try{u(s,(await $e("/api/cookbook/upgrades")).upgrades||[],!0)}catch{u(s,[],!0)}}async function _(W,ae){var we;ae.disabled=!0,ae.textContent="Starte…";try{await $e("/api/cookbook/install-model",{method:"POST",body:JSON.stringify({repo:W.repo,role:W.role,params_b:W.params_b,quant:W.quant,hf_token:oi()})}),(we=document.querySelector(".nav-item[data-view='activity']"))==null||we.dispatchEvent(new MouseEvent("click"))}catch(Ce){ae.disabled=!1,ae.textContent="Installieren",alert("Fehler: "+Ce.message)}}function T(){v(),p()}yi(()=>{v(),p()});var y=rv(),x=et(y),A=i(r(x),2),D=i(x,2);{var M=W=>{var ae=Yc(),we=r(ae),Ce=i(r(we),2),Be=r(Ce),je=i(we,4);rt(je,21,()=>t(s),dt,(bt,z)=>{var re=Zc(),ge=r(re),tt=r(ge),oe=r(tt),Fe=r(oe),ue=i(oe,2),q=r(ue),Y=i(tt,2),pe=r(Y),fe=i(ge,2);P(Ke=>{g(Fe,t(z).name),Dt(ue,1,`fit-badge ${Ke??""}`),g(q,t(z).fit.text),g(pe,`Ersetzt dein „${t(z).old??""}". ${t(z).why??""}`)},[()=>c(t(z).fit.level)]),S("click",fe,Ke=>_(t(z),Ke.currentTarget)),f(bt,re)}),P(()=>g(Be,t(s).length)),f(W,ae)};K(D,W=>{t(s).length&&W(M)})}var B=i(D,2);{var qe=W=>{var ae=Xc();f(W,ae)},ke=W=>{var ae=ev(),we=r(ae);P(()=>g(we,t(o))),f(W,ae)},xe=W=>{var ae=tv();f(W,ae)},Ae=W=>{var ae=iv();rt(ae,21,()=>t(a),dt,(we,Ce,Be)=>{var je=av();Dt(je,1,`news-card${Be===0?" featured":""}`);var bt=r(je),z=r(bt),re=r(z),ge=i(z,2);{var tt=Y=>{var pe=nv();f(Y,pe)};K(ge,Y=>{t(Ce).relevant&&Y(tt)})}var oe=i(ge,2),Fe=r(oe),ue=i(bt,2),q=r(ue);P(Y=>{_i(je,"href",t(Ce).link),g(re,t(Ce).source),g(Fe,Y),g(q,t(Ce).title)},[()=>t(Ce).ts?d(t(Ce).ts):""]),f(we,je)}),f(W,ae)};K(B,W=>{t(l)?W(qe):t(o)?W(ke,1):t(a).length?W(Ae,-1):W(xe,2)})}S("click",A,T),f(e,y),Bn()}jn(["click"]);const lv=[{label:"Einstieg",tutorials:[["Dein erster Workflow — in 3 Schritten",`
|
||
<ol class="tut-steps">
|
||
<li><b>Modell holen:</b> Tab <b>Cookbook</b> → Anwendungsfall wählen (z.B. „Coden & Programmieren") →
|
||
<b>Komplettes Setup installieren</b>. Der Download läuft im Tab <b>Aktivität</b> — einfach warten bis der Job grün wird.</li>
|
||
<li><b>Verbinden:</b> Tab <b>Verbinden</b> → Tool wählen → Config-Snippet kopieren und einfügen.
|
||
<b>Verbindung testen</b> bestätigt, dass alles klappt.</li>
|
||
<li><b>Arbeiten:</b> Im Tool das gewünschte Modell auswählen und loslegen.
|
||
Das Modell wird <b>automatisch geladen</b> — du musst nichts manuell starten.</li>
|
||
</ol>
|
||
<p style="margin-top:10px"><b>Nicht sicher welches Tool du nehmen sollst?</b>
|
||
Lies den Abschnitt „Welches Tool ist das richtige für mich?" weiter unten.</p>`],["Kontext — das Kurzzeitgedächtnis des Modells",`
|
||
<p>Der Kontext ist wie ein Blatt Papier: alles was du mit dem Modell besprochen hast,
|
||
steht darauf. Wird es voll, fallen die ältesten Nachrichten raus.</p>
|
||
<p><b>Was du meist nicht tun musst:</b> Tools wie OpenCode, Cline und OpenWebUI
|
||
verwalten das Kontextfenster automatisch. Ein neuer Chat = leeres Blatt.</p>
|
||
<p><b>Wenn der Kontext volläuft</b> (Fehler „context length exceeded" oder das Modell vergisst den Anfang):</p>
|
||
<ol class="tut-steps">
|
||
<li><b>Neuen Chat starten</b> — der einfachste Reset.</li>
|
||
<li>Vorher: <em>„Fasse kurz zusammen was wir bisher erreicht haben"</em> — dann diesen Stand in den neuen Chat einfügen.</li>
|
||
<li><b>Kontext vergrößern:</b> Tab <b>Modelle</b> → <b>Konfigurieren</b> → Empfehlung für deine Hardware übernehmen.</li>
|
||
</ol>
|
||
<p><b>Wichtig:</b> „Grafikspeicher leeren" (Tab <b>Server</b>) ist etwas anderes —
|
||
das wirft das <em>Modell</em> aus dem Speicher, nicht den Gesprächsverlauf.</p>`],["Auto-Swap — Modelle laden sich von selbst",`
|
||
<p>llama-swap lädt automatisch das Modell, das gerade angefragt wird —
|
||
und entlädt es nach einer Leerlaufzeit wieder. <b>Es läuft immer nur eines gleichzeitig.</b></p>
|
||
<p>Du richtest beliebig viele Modelle ein und wählst im Tool das passende.
|
||
Das Laden und Entladen passiert unsichtbar im Hintergrund.</p>
|
||
<p><b>Warum dauert die erste Antwort manchmal 5–15 Sekunden?</b><br>
|
||
Das Modell wird gerade geladen — danach geht es normal weiter.
|
||
Die Topbar zeigt <em>„[Modellname] lädt…"</em> während das passiert.</p>
|
||
<p><b>Scout immer sofort verfügbar halten:</b> Tab <b>Modelle</b> → Konfigurieren →
|
||
<em>Immer aktiv halten</em> aktivieren (TTL = ∞). Das Modell bleibt dann dauerhaft im RAM
|
||
und antwortet ohne Wartezeit — ideal für den kleinen, schnellen Allrounder.</p>`]]},{label:"Tools einrichten",tutorials:[["Welches Tool ist das richtige für mich?",`
|
||
<p><b>Chat — ich will einfach reden, schreiben, fragen:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Einfachster Einstieg</div>
|
||
<div class="tut-cell-bd">→ <b>Jan AI</b> — Desktop-App, Doppelklick-Installer, sofort loslegen.
|
||
Vertraut wie ChatGPT, läuft komplett lokal. Kein Admin-Panel, kein Docker.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Teams / Power-User</div>
|
||
<div class="tut-cell-bd">→ <b>OpenWebUI</b> — viele Features (RAG, Bilder, Plugins, Mehrbenutzer).
|
||
Mehr Setup-Aufwand, aber der mächtigste Chat-Client.</div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:12px"><b>Coding — ich will KI beim Programmieren:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Simpler Einstieg in VS Code</div>
|
||
<div class="tut-cell-bd">→ <b>Continue</b> — Chat + Autocomplete direkt im Editor, kein Agent-Overhead.
|
||
Macht keinen Schritt ohne dich.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Voller Coding-Agent im Editor</div>
|
||
<div class="tut-cell-bd">→ <b>Cline</b> — liest Dateien, schreibt Code, fragt vor jeder Änderung.
|
||
VS Code, JetBrains, Zed u.a.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Agent-IDE mit VS Code-Feeling</div>
|
||
<div class="tut-cell-bd">→ <b>Antigravity</b> — Googles agentic IDE (VS Code-Fork), kostenlos.
|
||
Multi-Agent, planen + coden + testen in einem.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Autonomer Terminal-Agent</div>
|
||
<div class="tut-cell-bd">→ <b>OpenCode</b> — mächtigster lokaler Agent, lebt im Terminal.
|
||
Ideal für „bau mir Feature X komplett fertig".</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Schneller Editor, minimalistisch</div>
|
||
<div class="tut-cell-bd">→ <b>Zed</b> — nativer Editor (Rust), eingebautes KI-Panel.
|
||
Für Leute die Performance über Features stellen.</div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:10px"><b>Faustregel:</b> Fang mit <b>Jan AI</b> zum Chatten an.
|
||
Für Coding: <b>Continue</b> als sanfter Einstieg oder gleich <b>Cline/Antigravity</b>
|
||
wenn du bereit bist, dem Agenten mehr Kontrolle zu geben.</p>`],["OpenCode verbinden und die ersten Schritte",`
|
||
<p>OpenCode ist installiert? Dann in vier Schritten verbinden:</p>
|
||
<ol class="tut-steps">
|
||
<li><b>Config-Snippet holen:</b> Tab <b>Verbinden</b> → <em>OpenCode</em> auswählen →
|
||
Snippet kopieren und in <code>~/.config/opencode/opencode.json</code> einfügen.</li>
|
||
<li><b>OpenCode starten:</b> Terminal öffnen, <code>opencode</code> eintippen —
|
||
immer im Projektordner starten, damit der Agent deine Dateien sieht.</li>
|
||
<li><b>Modell wählen:</b> <code>/models</code> eintippen → <em>llama-swap/coder</em> auswählen.</li>
|
||
<li><b>Erste Aufgabe geben</b> — z.B.:
|
||
<em>„Lies die Datei README.md und erkläre mir kurz was dieses Projekt macht."</em></li>
|
||
</ol>
|
||
<p><b>Die wichtigsten Slash-Commands:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd"><code>/model</code></div>
|
||
<div class="tut-cell-bd">Modell wechseln — z.B. mitten im Gespräch auf <em>scout</em> für kurze Fragen</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd"><code>/compact</code> · <code>/summarize</code></div>
|
||
<div class="tut-cell-bd">Kontext komprimieren wenn er voll wird — fasst die Session zusammen und setzt fort</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd"><code>/clear</code> · <code>/new</code></div>
|
||
<div class="tut-cell-bd">Neue Session starten — komplett leerer Kontext</div>
|
||
</div>
|
||
</div>
|
||
<p>Bevor OpenCode eine Datei ändert, fragt es nach — mit <b>y</b> bestätigen oder <b>n</b> ablehnen.</p>
|
||
<p><b>Terminal oder Desktop-App?</b> Die Anleitung gilt für beide —
|
||
der Config-Snippet landet in derselben Datei (<code>~/.config/opencode/opencode.json</code>),
|
||
und alle Slash-Commands funktionieren in beiden Versionen gleich.
|
||
Unterschied: Im Terminal startest du mit <code>cd ~/mein-projekt && opencode</code>;
|
||
in der Desktop-App öffnest du einfach die App und wählst den Projektordner über die GUI.</p>
|
||
<p><b>Multi-Agenten (2026):</b> Du kannst in OpenCode mehrere spezialisierte Agenten definieren
|
||
— z.B. einen <em>review</em>-Agent und einen <em>coder</em>-Agent.
|
||
Mit <b>Tab</b> wechselst du zwischen primären Agenten; mit <b>@review</b> rufst du einen Subagenten direkt im Chat auf.
|
||
Agenten werden als Markdown-Dateien angelegt: eine Datei <code>review.md</code> im
|
||
<code>~/.config/opencode/</code>-Ordner erstellt automatisch den Agenten <em>review</em>.</p>
|
||
<p class="tut-sources">Weitere Infos: <a href="https://opencode.ai/docs" target="_blank" rel="noopener">opencode.ai/docs</a> · <a href="https://opencode.ai/docs/agents/" target="_blank" rel="noopener">Agenten-Docs</a></p>`],["Cline verbinden und nutzen",`
|
||
<p>Cline (v3.81, Stand Juni 2026) läuft in: <b>VS Code, JetBrains, Cursor, Windsurf, Zed, Neovim</b>
|
||
und als CLI auf macOS/Linux. Verbinden funktioniert überall gleich:</p>
|
||
<ol class="tut-steps">
|
||
<li>Das Cline-Panel öffnen (Roboter-Icon in der Seitenleiste).</li>
|
||
<li>Provider <b>„OpenAI Compatible"</b> wählen.</li>
|
||
<li>Tab <b>Verbinden</b> → <em>Cline / Cursor</em> → Basis-URL und Modell-ID kopieren und eintragen.</li>
|
||
<li>API-Key: irgendeinen beliebigen Text eingeben (z.B. <code>local</code>) — wird nicht geprüft.</li>
|
||
</ol>
|
||
<p><b>Plan-Modus vs. Act-Modus:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Plan</div>
|
||
<div class="tut-cell-bd">Cline liest und denkt nach — erklärt den Plan bevor es handelt.
|
||
Billiger (weniger Tokens) und ideal für Anfänger.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Act</div>
|
||
<div class="tut-cell-bd">Cline handelt sofort, fragt aber vor jeder Dateiänderung um Erlaubnis.
|
||
Schneller für klare Aufgaben.</div>
|
||
</div>
|
||
</div>
|
||
<p><b>Memory Bank (empfohlen):</b> Lege eine Datei <code>projectbrief.md</code> im Projektordner an —
|
||
Cline liest sie zu Beginn jeder Aufgabe automatisch. Sie ist das Fundament: Projektziel, Tech-Stack,
|
||
wichtigste Regeln. Ergänzend: <code>activeContext.md</code> für den aktuellen Fokus,
|
||
<code>progress.md</code> für den Stand.</p>
|
||
<p><b>.clinerules:</b> Für größere Projekte kannst du statt einer einzelnen Datei ein ganzes
|
||
Verzeichnis <code>.clinerules/</code> anlegen — jede Datei darin gilt als separate Regel.
|
||
Achtung: Jedes Zeichen in .clinerules verbraucht Kontext — kurze, präzise Regeln schlagen lange Listen.</p>
|
||
<p><b>Ausgaben-Limit (seit April 2026):</b> In Settings → Spending Limits kannst du ein
|
||
Tages- oder Monats-Budget setzen — verhindert dass ein laufender Agent unbemerkt viel Token verbraucht.</p>
|
||
<p class="tut-sources">Weitere Infos: <a href="https://cline.bot" target="_blank" rel="noopener">cline.bot</a> · <a href="https://docs.cline.bot/best-practices/memory-bank" target="_blank" rel="noopener">Memory Bank Docs</a></p>`],["Jan AI — einfachstes Chat-Interface",`
|
||
<p><b>Jan AI</b> ist die einfachste Art, lokal mit KI zu chatten —
|
||
Desktop-App, kein Terminal, kein Docker, kein Admin-Panel.</p>
|
||
<ol class="tut-steps">
|
||
<li><b>Jan AI installieren:</b> <a href="https://jan.ai" target="_blank" rel="noopener">jan.ai</a>
|
||
→ Download → Doppelklick-Installer (Windows/macOS/Linux).</li>
|
||
<li><b>Remote-Modell hinzufügen:</b> In der linken Leiste auf das Hub-Icon →
|
||
oben rechts <b>+ Remote-Modell</b>.</li>
|
||
<li><b>Verbindung eintragen:</b> Tab <b>Verbinden</b> → <em>Jan AI</em> auswählen →
|
||
Basis-URL und Modell-ID kopieren und in Jan einfügen.</li>
|
||
<li>API-Key: irgendeinen Text (z.B. <code>local</code>). Speichern.</li>
|
||
</ol>
|
||
<p>Danach erscheint das Modell in der Modell-Liste — auswählen und loslegen.</p>
|
||
<p><b>Gut für:</b> Chatten, Texte schreiben, übersetzen, Fragen stellen —
|
||
genauso wie ChatGPT, aber 100% lokal und privat. Bilder mitschicken klappt auch
|
||
sobald ein Vision-Modell eingetragen ist.</p>
|
||
<p class="tut-sources">Download & Docs: <a href="https://jan.ai" target="_blank" rel="noopener">jan.ai</a> · <a href="https://www.jan.ai/docs" target="_blank" rel="noopener">jan.ai/docs</a></p>`],["Continue — Coding-Hilfe in VS Code ohne Agent-Overhead",`
|
||
<p><b>Continue</b> ist die einfachste Coding-Erweiterung für VS Code und JetBrains —
|
||
kein autonomer Agent, sondern ein KI-Assistent der nur auf Anfrage handelt.</p>
|
||
<ol class="tut-steps">
|
||
<li><b>Extension installieren:</b> VS Code → Extensions → „Continue" suchen → Installieren.<br>
|
||
Oder: <a href="https://continue.dev" target="_blank" rel="noopener">continue.dev</a></li>
|
||
<li><b>Config holen:</b> Tab <b>Verbinden</b> → <em>Continue</em> auswählen →
|
||
Snippet kopieren und in <code>~/.continue/config.json</code> einfügen.</li>
|
||
<li>Continue in VS Code neu starten → im Chat-Panel Modell wählen → loslegen.</li>
|
||
</ol>
|
||
<p><b>Was Continue kann:</b></p>
|
||
<ul class="tut-steps" style="list-style:disc">
|
||
<li><b>Chat:</b> Frage direkt im Editor — markiere Code und drücke <code>Strg+L</code></li>
|
||
<li><b>Autocomplete:</b> Ergänzt Code während du tippst (wie Copilot)</li>
|
||
<li><b>Inline-Edit:</b> Markieren → <code>Strg+I</code> → „Refactore das zu TypeScript"</li>
|
||
</ul>
|
||
<p><b>Unterschied zu Cline:</b> Continue macht nichts von alleine — du steuerst jeden Schritt.
|
||
Ideal als erster Einstieg bevor man mit vollen Agenten arbeitet.</p>
|
||
<p class="tut-sources">Weitere Infos: <a href="https://continue.dev" target="_blank" rel="noopener">continue.dev</a>
|
||
— Hinweis: 2026 von Cursor akquiriert, weiterhin kostenlos & open source.</p>`],["Antigravity — Googles agentic IDE",`
|
||
<p><b>Antigravity</b> ist Googles agent-first IDE — ein Fork von VS Code, der Planung,
|
||
Coding, Testing und Deployment in einem Workflow zusammenführt. Kostenlos für Einzelpersonen.</p>
|
||
<ol class="tut-steps">
|
||
<li><b>Antigravity installieren:</b>
|
||
<a href="https://antigravityide.net" target="_blank" rel="noopener">antigravityide.net</a>
|
||
→ Download → läuft wie VS Code.</li>
|
||
<li><b>Eigenen Endpoint einrichten:</b> Settings → Models → <b>Custom Endpoint</b> → + hinzufügen.</li>
|
||
<li><b>Verbindung eintragen:</b> Tab <b>Verbinden</b> → <em>Antigravity</em> auswählen →
|
||
Basis-URL und Modell-ID kopieren und eintragen.</li>
|
||
<li>API-Key: beliebiger Text (z.B. <code>local</code>). Danach das Modell aus der Liste wählen.</li>
|
||
</ol>
|
||
<p><b>Was Antigravity besonders macht:</b></p>
|
||
<ul class="tut-steps" style="list-style:disc">
|
||
<li><b>Agent-First:</b> Statt Code-Completion steht der Agent im Mittelpunkt —
|
||
du beschreibst, er plant und setzt um</li>
|
||
<li><b>Multi-Agent:</b> Mehrere Agenten arbeiten parallel an verschiedenen Teilen</li>
|
||
<li><b>Manager-Oberfläche:</b> Übersicht über alle laufenden Agenten-Sessions</li>
|
||
<li><b>VS Code-kompatibel:</b> Extensions und Keybindings funktionieren wie gewohnt</li>
|
||
</ul>
|
||
<p><b>Wann Antigravity statt OpenCode?</b> Wenn du lieber eine grafische IDE als ein Terminal magst
|
||
und trotzdem volle Agenten-Kontrolle willst. OpenCode ist mächtiger im Terminal-Flow;
|
||
Antigravity ist komfortabler für Umsteiger aus VS Code.</p>
|
||
<p class="tut-sources">Weitere Infos: <a href="https://antigravityide.net" target="_blank" rel="noopener">antigravityide.net</a> ·
|
||
<a href="https://developers.googleblog.com/build-with-google-antigravity-our-new-agentic-development-platform/" target="_blank" rel="noopener">Google Dev Blog</a></p>`],["OpenWebUI — für Teams und Power-User",`
|
||
<p>OpenWebUI ist der mächtigste lokale Chat-Client — aber auch der komplexeste.
|
||
Empfohlen wenn du mehr als ein einfaches Chat-Interface brauchst.</p>
|
||
<p><b>Was OpenWebUI besonders kann (gegenüber Jan AI):</b></p>
|
||
<ul class="tut-steps" style="list-style:disc">
|
||
<li>RAG: eigene Dokumente hochladen, KI liest und beantwortet Fragen dazu</li>
|
||
<li>Mehrbenutzer: eigene Accounts für verschiedene Personen im Heimnetz</li>
|
||
<li>Plugins und Agenten: erweiterbar mit Tools und Custom-Pipelines</li>
|
||
<li>Bilder generieren (mit Stable Diffusion), Sprachausgabe, Web-Suche</li>
|
||
</ul>
|
||
<p><b>Verbinden</b> (braucht Docker oder eine lokale Installation):</p>
|
||
<ol class="tut-steps">
|
||
<li>OpenWebUI im Browser öffnen → <b>Admin Panel</b> → <b>Connections</b>.</li>
|
||
<li><b>+ OpenAI-Verbindung</b> → Tab <b>Verbinden</b> → <em>OpenWebUI</em> → Basis-URL kopieren.</li>
|
||
<li>API-Key: <code>dummy-key</code>. Speichern.</li>
|
||
</ol>
|
||
<p>Danach Modell auswählen und loslegen. Für einfaches Chatten: <b>Jan AI</b> ist einfacher.
|
||
OpenWebUI lohnt sich ab dem Moment, wo du mehr als nur Chat willst.</p>
|
||
<p class="tut-sources">Weitere Infos: <a href="https://openwebui.com" target="_blank" rel="noopener">openwebui.com</a></p>`]]},{label:"Agenten meistern",tutorials:[["Was ein Agent tut — und was er nicht kann",`
|
||
<p>Ein nacktes Modell antwortet auf Text — das war's.
|
||
Ein <b>Agent</b> ist das Programm drumherum, das das Modell in eine <b>Handlungsschleife</b> bringt:</p>
|
||
<p style="text-align:center;padding:8px 0;font-family:monospace;font-size:12.5px;color:var(--accent)">
|
||
Planen → Werkzeug nutzen → Ergebnis prüfen → nächsten Schritt planen → …
|
||
</p>
|
||
<p>Konkret: Datei lesen → Code verstehen → Änderung schreiben → Test ausführen → Fehler beheben —
|
||
ohne dass du jeden Schritt anstoßen musst.</p>
|
||
<p><b>Was Agenten gut können:</b></p>
|
||
<ul class="tut-steps" style="list-style:disc">
|
||
<li>Features über mehrere Dateien implementieren</li>
|
||
<li>Bugs finden und in ihrem Kontext beheben</li>
|
||
<li>Code refactoren, Dokumentation schreiben, Tests ergänzen</li>
|
||
<li>Recherchieren und das Ergebnis direkt umsetzen (mit MCP)</li>
|
||
<li>Parallele Teilaufgaben an Subagenten delegieren (OpenCode 2026)</li>
|
||
</ul>
|
||
<p><b>Was Agenten schlecht können:</b></p>
|
||
<ul class="tut-steps" style="list-style:disc">
|
||
<li>Kreative Richtungsentscheidungen ohne klare Vorgabe treffen</li>
|
||
<li>Sehr komplexe, undokumentierte Systeme ohne Kontext verstehen</li>
|
||
<li>Fehler in externer Hardware oder fremden APIs beheben</li>
|
||
</ul>
|
||
<p><b>Faustregel:</b> Je klarer die Aufgabe, desto besser das Ergebnis. Unklarer Auftrag → unklares Ergebnis.</p>`],["Einen Agenten richtig briefen",`
|
||
<p>Der Unterschied zwischen „es passiert nichts Sinnvolles" und „es funktioniert auf Anhieb"
|
||
ist meistens die Qualität des Auftrags.</p>
|
||
<p><b>Schlecht → Gut:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd bad">„Mach meine App besser."</div>
|
||
<div class="tut-cell-bd">→ <em>„Die Login-Seite in <code>src/pages/Login.tsx</code> zeigt
|
||
bei falschem Passwort gar keinen Fehler an. Füge unter dem Passwortfeld eine rote Fehlermeldung
|
||
ein wenn die API 401 zurückgibt."</em></div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd bad">„Erkläre mir Python."</div>
|
||
<div class="tut-cell-bd">→ <em>„Ich bin Anfänger. Erkläre mir in 5 Schritten wie ich eine CSV-Datei
|
||
in Python einlese und die Summe einer Spalte berechne — mit echtem Code-Beispiel."</em></div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd bad">„Mach das schneller."</div>
|
||
<div class="tut-cell-bd">→ <em>„Die Funktion <code>loadUsers()</code> in <code>src/api/users.ts</code>
|
||
braucht 3 Sekunden. Die Daten kommen vom Backend. Prüfe ob Caching helfen würde und schlage eine
|
||
konkrete Lösung vor."</em></div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:12px"><b>Die 3 Zutaten für einen guten Auftrag:</b></p>
|
||
<ol class="tut-steps">
|
||
<li><b>WO:</b> Welche Datei / welcher Ordner / welches Feature</li>
|
||
<li><b>WAS:</b> Was ist das genaue Problem oder Ziel</li>
|
||
<li><b>WIE:</b> Welches Ergebnis erwartest du</li>
|
||
</ol>
|
||
<p><b>Trick:</b> Wenn du nicht sicher bist ob der Auftrag klar genug ist, frag den Agenten:
|
||
<em>„Hast du alles was du brauchst, oder fehlt dir etwas?"</em></p>`],["MCP — deinem Agenten echte Werkzeuge geben",`
|
||
<p><b>MCP</b> (Model Context Protocol) ist ein einheitlicher „Stecker", über den ein Agent
|
||
zusätzliche <b>Werkzeuge</b> bekommt. Ohne MCP kann er nur Text lesen und schreiben.
|
||
Mit MCP kann er z.B.:</p>
|
||
<ul class="tut-steps" style="list-style:disc">
|
||
<li>Im Web suchen (Brave Search, Tavily)</li>
|
||
<li>GitHub Issues lesen und kommentieren</li>
|
||
<li>Deine Datenbank abfragen</li>
|
||
<li>Screenshots machen, E-Mails lesen, Kalender verwalten</li>
|
||
</ul>
|
||
<p><b>Wie MCPs eingebunden werden</b> (Beispiel für OpenCode):</p>
|
||
<p>In der Konfigurationsdatei (<code>~/.config/opencode/opencode.json</code>) einen
|
||
<code>"mcp"</code>-Block hinzufügen:</p>
|
||
<pre class="tut-code">{
|
||
"mcp": {
|
||
"brave-search": {
|
||
"command": "npx",
|
||
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
|
||
"env": { "BRAVE_API_KEY": "dein-key" }
|
||
}
|
||
}
|
||
}</pre>
|
||
<p>Danach OpenCode neu starten — der Agent nutzt das Werkzeug automatisch wenn er es braucht.</p>
|
||
<p><b>Empfohlene MCPs 2026 — nach Anwendungsfall:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Web-Suche</div>
|
||
<div class="tut-cell-bd"><b>brave-search</b> oder <b>tavily</b> — recherchieren, aktuelle Infos holen</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">GitHub</div>
|
||
<div class="tut-cell-bd"><b>github</b> — meistinstallierter MCP überhaupt. Issues, PRs, Commits, Repos direkt im Chat verwalten</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Lokale Dateien</div>
|
||
<div class="tut-cell-bd"><b>filesystem</b> — meistgenutzter MCP überhaupt. Sichere Dateizugriffe auf beliebige Ordner</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Browser</div>
|
||
<div class="tut-cell-bd"><b>playwright</b> — Browser-Automatisierung und UI-Tests. Agent öffnet Seiten, klickt, prüft</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Gedächtnis</div>
|
||
<div class="tut-cell-bd"><b>memory / mem0</b> — persistentes Gedächtnis über Sessions hinweg. Agent erinnert sich an deine Präferenzen und Projekt-Kontext auch in neuen Chats</div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:8px">Über <b>36.000 MCPs</b> sind mittlerweile verfügbar (Stand Juni 2026).
|
||
Fang mit filesystem + github an — die decken 80% der täglichen Arbeit ab.</p>
|
||
<p class="tut-sources"><b>Wo MCPs finden:</b>
|
||
<a href="https://mcp.run" target="_blank" rel="noopener">mcp.run</a> ·
|
||
<a href="https://smithery.ai" target="_blank" rel="noopener">smithery.ai</a> ·
|
||
<a href="https://modelcontextprotocol.io/servers" target="_blank" rel="noopener">modelcontextprotocol.io/servers</a>
|
||
— oder fragen: <em>„Welche MCPs gibt es für [dein Werkzeug]?"</em></p>
|
||
<p><b>Merksatz:</b> Fehlt dem Agenten eine <em>Fähigkeit</em> → MCP.
|
||
Soll er etwas nur <em>besser machen</em> → Skill (nächster Abschnitt).</p>`],["Skills & Rules — Agenten Gewohnheiten beibringen",`
|
||
<p><b>Skills</b> (auch <em>Rules</em>, <em>AGENTS.md</em> oder <em>Instructions</em> genannt)
|
||
sind kurze Texte, die dem Agenten beibringen wie er in deinem Projekt arbeiten soll —
|
||
immer, ohne dass du es jedes Mal neu sagen musst.</p>
|
||
<p><b>Beispiel</b> — eine einfache AGENTS.md:</p>
|
||
<pre class="tut-code">Schreib alle Variablen in camelCase.
|
||
Kommentare immer auf Deutsch.
|
||
Tests immer mit describe/it-Blöcken (Jest).
|
||
Importiere nichts was nicht schon in package.json steht.
|
||
Bevor du Dateien änderst: erkläre kurz was du vorhast.</pre>
|
||
<p>Der Agent liest das vor jeder Aufgabe und hält sich daran.</p>
|
||
<p><b>Wo die Datei ablegen:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">OpenCode</div>
|
||
<div class="tut-cell-bd"><code>AGENTS.md</code> im Projektordner (pro Projekt)<br>
|
||
<code>~/.config/opencode/AGENTS.md</code> (global, gilt überall)</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Cline</div>
|
||
<div class="tut-cell-bd"><code>.clinerules</code> im Projektordner<br>
|
||
<code>~/.clinerules</code> (global)</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Zed</div>
|
||
<div class="tut-cell-bd">Zed Settings → Assistant → System Prompt</div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:10px"><b>Fertige Skills finden:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd"><a href="https://skills.sh" target="_blank" rel="noopener">skills.sh</a></div>
|
||
<div class="tut-cell-bd">Von Vercel gestartet (Jan 2026) — das npm für Agent-Skills. Funktioniert mit Claude Code, OpenCode, Cursor u.v.m. One-Command-Installer.
|
||
<b>Hinweis:</b> Community-Inhalte ohne formale Prüfung — Skill vor dem Einsatz kurz lesen.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd"><a href="https://skillhub.ai" target="_blank" rel="noopener">SkillHub</a></div>
|
||
<div class="tut-cell-bd">KI-bewertete Skills (S/A/B-Ranking nach Qualität, Klarheit, Wirkung). Kleinerer Katalog, höhere Signal-Qualität.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd"><a href="https://cursor.directory" target="_blank" rel="noopener">cursor.directory</a></div>
|
||
<div class="tut-cell-bd">Vorgefertigte Rules für React, Vue, Python, Go etc. — direkt als .clinerules oder AGENTS.md nutzbar.</div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:8px"><b>Sicherheitshinweis:</b> Ein Snyk-Audit (2026) fand in 13,4% der Community-Skills
|
||
kritische Probleme (Prompt Injection, exponierte Secrets). Regel: Skill-Datei kurz lesen bevor du sie einsetzt.</p>
|
||
<p style="margin-top:8px">Oder einfach fragen: <em>„Schreib mir eine AGENTS.md für ein React + TypeScript Projekt mit Tailwind."</em></p>`],["Die Persona — Rolle, Beziehung & Onboarding",`
|
||
<p>Eine Persona hat <b>zwei Dimensionen</b> — beide sind wichtig:</p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Was der Agent tut</div>
|
||
<div class="tut-cell-bd">Fokus, Fachgebiet, Grenzen — die klassische Rollenbeschreibung.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Wie er mit dir umgeht</div>
|
||
<div class="tut-cell-bd">Ton, Proaktivität, Feedback-Stil — antwortet er kurz oder ausführlich?
|
||
Hakt er nach oder liefert er einfach? Spricht er Fehler direkt an oder verpackt er sie?</div>
|
||
</div>
|
||
</div>
|
||
<p style="margin-top:10px">Ein Agent der technisch gleich konfiguriert ist, verhält sich komplett anders
|
||
wenn er weiß: <em>Du willst kurze Antworten ohne Erklärung.</em> Oder: <em>Du lernst noch —
|
||
ermutige mich und erkläre immer warum.</em></p>
|
||
|
||
<p><b>Das vollständige Persona-Template:</b></p>
|
||
<pre class="tut-code">Du bist [Name], [Rolle].
|
||
|
||
Fokus: [Was du hauptsächlich tust]
|
||
Wie du kommunizierst: [Stil — direkt/erklärend/ermutigend, kurze oder ausführliche Antworten]
|
||
Wie du mit mir umgehst: [Proaktivität, Rückfragen, Feedback-Stil, Fehlerkultur]
|
||
Sprache: Immer auf Deutsch. Code-Kommentare auf Englisch.
|
||
Grenzen: [Was du nicht tust, was du nachfragst statt zu raten]</pre>
|
||
|
||
<p><b>Beispiel 1 — Coding-Assistent (direkt, erfahren):</b></p>
|
||
<pre class="tut-code">Du bist Alex, ein erfahrener Senior-Entwickler spezialisiert auf TypeScript und React.
|
||
|
||
Fokus: Code schreiben, reviewen, erklären — immer mit konkreten Beispielen.
|
||
Wie du kommunizierst: direkt, pragmatisch. Keine Erklärung wenn der Code für sich spricht.
|
||
Wie du mit mir umgehst: Du fragst nach bevor du loslegst wenn die Aufgabe unklar ist.
|
||
Fehler sprichst du klar an — aber ohne Schuldzuweisungen. Du machst Gegenvorschläge
|
||
wenn du eine bessere Lösung siehst, aber respektierst meine Entscheidung.
|
||
Sprache: Deutsch. Code-Kommentare auf Englisch.
|
||
Grenzen: Kein Code ohne Datei-Kontext. Keine neuen Dependencies ohne Rückfrage.</pre>
|
||
|
||
<p><b>Beispiel 2 — Lernbegleiter (geduldig, ermutigend):</b></p>
|
||
<pre class="tut-code">Du bist Sam, eine geduldige Lernbegleiterin für Programmier-Anfänger.
|
||
|
||
Fokus: Konzepte erklären, Fehler korrigieren, Schritt für Schritt führen.
|
||
Wie du kommunizierst: freundlich, mit Analogien aus dem Alltag. Fachbegriffe sofort erklären.
|
||
Wie du mit mir umgehst: Du lobst Fortschritte, auch kleine. Fehler sind Lernchancen —
|
||
du zeigst was falsch war und warum, ohne zu urteilen. Du fragst ob ich es verstanden
|
||
habe bevor du weitermachst.
|
||
Sprache: Immer auf Deutsch. Niemals Englisch ohne Übersetzung.</pre>
|
||
|
||
<hr style="border:none;border-top:1px solid var(--line);margin:18px 0">
|
||
<p><b>Der schnellste Weg: Onboarding-Interview</b></p>
|
||
<p>Statt die Persona selbst auszufüllen — lass den Agenten <em>dich</em> befragen.
|
||
Starte einen frischen Chat und gib ihm diesen Prompt:</p>
|
||
<pre class="tut-code">Ich möchte dich in mein Projekt und meinen Arbeitsstil einarbeiten.
|
||
Führe mit mir ein kurzes Interview durch — stelle mir 6–8 Fragen,
|
||
eine nach der anderen — um zu verstehen:
|
||
|
||
1. Wer ich bin und wie ich am liebsten kommuniziere
|
||
2. Was unser Projekt ist und welches Ziel es hat
|
||
3. Was ich gut kann und wobei ich Unterstützung brauche
|
||
4. Meine Arbeitsgewohnheiten und Präferenzen
|
||
5. Was mir wichtig ist und was mich stört
|
||
|
||
Wenn du alle Antworten hast, erstelle daraus:
|
||
- Eine vollständige AGENTS.md als dauerhaftes Fundament
|
||
- Einen Satz der zusammenfasst wer ich für dich bin</pre>
|
||
<p>Das Ergebnis: eine maßgeschneiderte Persona die <em>wirklich</em> zu dir passt —
|
||
weil du sie nicht selbst formulieren musstest, sondern im Gespräch entstanden ist.</p>
|
||
|
||
<p><b>Wo eintragen:</b></p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Für ein Projekt</div>
|
||
<div class="tut-cell-bd">Erste Zeilen der <code>AGENTS.md</code> im Projektordner.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Global (überall)</div>
|
||
<div class="tut-cell-bd"><code>~/.config/opencode/AGENTS.md</code> (OpenCode) ·
|
||
Settings → System Prompt (OpenWebUI)</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">Nur dieser Chat</div>
|
||
<div class="tut-cell-bd"><em>„Ab jetzt bist du …"</em> direkt eintippen.</div>
|
||
</div>
|
||
</div>
|
||
<p class="tut-sources" style="margin-top:10px">Fertige Personas: <a href="https://skills.sh" target="_blank" rel="noopener">skills.sh</a> · <a href="https://cursor.directory" target="_blank" rel="noopener">cursor.directory</a></p>`],["AGENTS.MD & SAVEPOINT.MD — Gedächtnis für den Agenten",`
|
||
<p>Jedes Mal wenn du einen neuen Chat startest, weiß der Agent <b>nichts</b> über dein Projekt.
|
||
Diese zwei Dateien lösen das Problem.</p>
|
||
<p><b>AGENTS.md ist 2026 der plattformübergreifende Standard</b> — nativ gelesen von:
|
||
OpenCode, Claude Code, Codex CLI, Cursor, Aider, Devin, GitHub Copilot, Gemini CLI, Windsurf, Amazon Q.
|
||
Eine Datei, alle Tools.</p>
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">AGENTS.md</div>
|
||
<div class="tut-cell-bd"><b>Was das Projekt ist</b> — Tech-Stack, Konventionen,
|
||
Struktur. Wird vor jeder Aufgabe gelesen. Einmal schreiben, immer wirksam.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">SAVEPOINT.md</div>
|
||
<div class="tut-cell-bd"><b>Wo wir gerade stehen</b> — aktueller Stand, offene Punkte,
|
||
nächste Schritte. Wird am Ende einer Session aktualisiert und zu Beginn der nächsten gelesen.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p style="margin-top:14px"><b>AGENTS.MD — Vorlage:</b></p>
|
||
<pre class="tut-code"># Projekt: [Name]
|
||
|
||
## Persona
|
||
Du bist [Name], [Rolle]. [Stil, Sprache, Grenzen]
|
||
|
||
## Tech-Stack
|
||
- Frontend: [z.B. React 18, TypeScript, Tailwind CSS]
|
||
- Backend: [z.B. FastAPI, Python 3.12]
|
||
- Datenbank:[z.B. PostgreSQL via Prisma]
|
||
|
||
## Konventionen
|
||
- Variablen: camelCase (JS) / snake_case (Python)
|
||
- Kommentare: auf Deutsch
|
||
- Commits: konventionell (feat/fix/chore/docs)
|
||
- Tests: immer mit describe/it-Blöcken
|
||
|
||
## Projektstruktur
|
||
src/
|
||
components/ → UI-Komponenten (eine Datei = eine Komponente)
|
||
pages/ → Seiten / Routes
|
||
api/ → Backend-Calls und Typen
|
||
|
||
## Regeln
|
||
- Vor jeder Dateiänderung kurz erklären was geplant ist
|
||
- Keine neuen Dependencies ohne Rückfrage hinzufügen
|
||
- Bei Unklarheiten fragen, nicht raten
|
||
|
||
<!-- Ziel: 200–500 Zeilen. AGENTS.md wird in jeden Kontext geladen —
|
||
kürzer = mehr Platz für Code und Gespräch. --></pre>
|
||
<p style="color:var(--mut);font-size:12px;margin:4px 0 8px">
|
||
<b>Größe:</b> 200–500 Zeilen sind der empfohlene Sweet Spot (Stand 2026).
|
||
AGENTS.md wird in jeden Kontext geladen — je kürzer, desto mehr Platz bleibt für Code und Gespräch.</p>
|
||
|
||
<p><b>SAVEPOINT.MD — Vorlage:</b></p>
|
||
<pre class="tut-code"># Savepoint — [Datum / Uhrzeit]
|
||
|
||
## Aktueller Stand
|
||
[1–2 Sätze: wo steht das Projekt gerade?]
|
||
|
||
## Zuletzt erledigt
|
||
- [Aufgabe] ✓
|
||
- [Aufgabe] ✓
|
||
|
||
## In Arbeit / halbfertig
|
||
- [Was noch offen ist — welche Datei, welcher Schritt fehlt noch]
|
||
|
||
## Als nächstes
|
||
1. [Konkrete nächste Aufgabe]
|
||
2. [Übernächste Aufgabe]
|
||
|
||
## Wichtige Entscheidungen
|
||
- [Was entschieden wurde]: [Warum]
|
||
|
||
## Bekannte Probleme
|
||
- [Problem]: [Was bekannt ist, noch nicht gelöst]</pre>
|
||
|
||
<p><b>Workflow:</b></p>
|
||
<ol class="tut-steps">
|
||
<li><b>Session starten:</b> <em>„Lies AGENTS.md und SAVEPOINT.md und mach weiter."</em></li>
|
||
<li><b>Session beenden:</b> <em>„Aktualisiere SAVEPOINT.md mit dem aktuellen Stand."</em></li>
|
||
</ol>
|
||
<p><b>Tipp:</b> Lass den Agenten die SAVEPOINT.md selbst schreiben — er sieht was er getan hat.
|
||
Du prüfst nur ob der Stand stimmt und ergänzt bei Bedarf.</p>
|
||
<p class="tut-sources">Vorlagen & Inspiration: <a href="https://skills.sh" target="_blank" rel="noopener">skills.sh</a> · <a href="https://opencode.ai/docs" target="_blank" rel="noopener">opencode.ai/docs</a></p>`]]},{label:"Wenn etwas nicht klappt",tutorials:[["Häufige Probleme & Lösungen",`
|
||
<div class="tut-table">
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">🔴 Engine offline, rotes Licht in der Topbar</div>
|
||
<div class="tut-cell-bd">Tab <b>Server</b> → LLM-Engine-Karte → <b>Neustart</b>.
|
||
Warte 10–15 Sekunden — danach sollte die Verbindung wieder grün sein.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">⏳ Modell lädt länger als 5 Minuten</div>
|
||
<div class="tut-cell-bd">Tab <b>Aktivität</b> prüfen: läuft ein Download-Job?
|
||
Der muss erst abgeschlossen sein bevor das Modell ladbar ist.
|
||
Bei Fehler → Job-Zeile aufklappen, Log lesen.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">💬 „context length exceeded" Fehler im Tool</div>
|
||
<div class="tut-cell-bd">Neuen Chat starten. Vorher: <em>„Fasse kurz zusammen was wir
|
||
erreicht haben"</em> eingeben und diesen Text in den neuen Chat mitnehmen.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">🌐 Modell antwortet immer auf Englisch</div>
|
||
<div class="tut-cell-bd">Am Anfang der Unterhaltung schreiben: <em>„Antworte immer auf Deutsch."</em>
|
||
Für dauerhaft: eine <code>AGENTS.md</code> / <code>.clinerules</code> mit dieser Anweisung anlegen
|
||
(siehe Abschnitt Skills & Rules).</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">🔌 Tool findet keine Modelle / Verbindung schlägt fehl</div>
|
||
<div class="tut-cell-bd">Tab <b>Verbinden</b> → <b>Verbindung testen</b>. Wenn Fehler:
|
||
läuft llama-swap? (Tab Server). URL korrekt? Muss <code>http://</code> (nicht https) sein,
|
||
Port <b>8080</b>. Über Proxy? → LAN-IP direkt nutzen: <code>http://192.168.178.151:8080/v1</code></div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">⬇ Download schlägt fehl / bricht ab</div>
|
||
<div class="tut-cell-bd">Tab <b>Aktivität</b> → Job-Zeile aufklappen → Log lesen.
|
||
Häufigste Ursache: HuggingFace braucht einen Token für dieses Modell (gated model).
|
||
→ Einstellungen (Zahnrad-Icon oben) → <b>HuggingFace-Token</b> eintragen.</div>
|
||
</div>
|
||
<div class="tut-row">
|
||
<div class="tut-cell-hd">🔄 Seite lädt / Dashboard hängt komplett</div>
|
||
<div class="tut-cell-bd">Strg+Shift+R (Hard Reload). Wenn das nicht hilft:
|
||
Tab <b>Server</b> → Mission Control → <b>Neu starten</b>.</div>
|
||
</div>
|
||
</div>`]]}],ov=[["LLM / Modell","Die KI selbst — versteht und schreibt Text (wie ChatGPT, nur lokal auf deinem PC). Ein Modell ist eine konkrete Datei, oft auf etwas spezialisiert (Code, Bilder, Chat)."],["GGUF","Das lokal lauffähige Dateiformat. llama-swap lädt nur GGUF — Repos ohne GGUF kann die Engine nicht nutzen."],["Quantisierung (Q4_K_M)","Verkleinert ein Modell (16-Bit → 4-Bit), damit es in den Speicher passt — bei kaum Qualitätsverlust. Q4_K_M ist der bewährte Sweetspot. Für Coding/Reasoning: Q8_0 (nahezu verlustfrei). Wenn Q4_K_M 1 GB zu groß ist: IQ4_XS als Alternative (ähnliche Qualität, etwas kleiner)."],["Kontextfenster","Das Kurzzeitgedächtnis: wie viel Text sich das Modell gleichzeitig merken kann. Größer = mehr Überblick, mehr Speicher, etwas langsamer."],["Token","Die kleinste Einheit die ein Modell verarbeitet — meist 3–4 Zeichen oder ein kurzes Wort. 1 000 Tokens ≈ 750 Wörter. Kontextfenster, Geschwindigkeit und Kosten werden in Tokens gemessen."],["Auto-Swap","llama-swap lädt/entlädt Modelle automatisch — immer nur eins gleichzeitig. Du managst nichts."],["TTL (Time to Live)","Wie lange ein Modell nach der letzten Anfrage im RAM bleibt bevor es entladen wird. Standard: 5 Minuten. ∞ = bleibt dauerhaft geladen (sinnvoll für den Scout)."],["Agent","Ein Programm (OpenCode, Cline, Continue), das das Modell in einer Handlungsschleife laufen lässt — Dateien lesen/ändern, Befehle ausführen, planen, bis die Aufgabe erledigt ist."],["MCP","Model Context Protocol — der Stecker, über den ein Agent zusätzliche Werkzeuge bekommt (Web, Datenbank, GitHub …). MCP = neue Fähigkeiten."],["Skills / Rules","Kurze Textdatei (AGENTS.md, .clinerules …) mit Anweisungen wie der Agent in deinem Projekt arbeiten soll — einmal geschrieben, immer befolgt. Seit 2026 plattformübergreifender Standard: AGENTS.md wird von über 10 Tools nativ gelesen."],["Memory Bank","Clines Konzept für dauerhaften Projekt-Kontext: projectbrief.md (Ziel & Scope), activeContext.md (aktueller Fokus), progress.md (Stand). Wird zu Beginn jeder Aufgabe automatisch gelesen — ähnlich wie AGENTS.md, aber aufgeteilt nach Zweck."],["System-Prompt","Eine unsichtbare Anweisung die vor deiner Nachricht steht und das Verhalten des Modells grundlegend prägt (Sprache, Ton, Rolle). Skills nutzen oft den System-Prompt."],["Vision","Modelle mit Vision-Fähigkeit können Bilder verstehen — Screenshots, Diagramme, Fehlerfotos. Erkennbar am mmproj-Projektor der mitgeladen wird."]];var dv=b('<details class="guide-acc"><summary> </summary> <div class="acc-body"></div></details>'),cv=b('<div class="card guide-card svelte-112sh7i"><div class="guide-group-hd svelte-112sh7i"> </div> <!></div>'),vv=b('<div class="concept"><h4> </h4> <p> </p></div>'),uv=b('<div class="pagehead"><div><h1>Guide</h1> <div class="sub">Schritt für Schritt erklärt — von der ersten Einrichtung bis zu echten Agenten-Workflows.</div></div></div> <!> <div class="card-h" style="margin-top:8px"><h3>Begriffe kurz erklärt</h3></div> <div class="concept-grid"></div>',1);function pv(e){var n=uv(),a=i(et(n),2);rt(a,17,()=>lv,dt,(l,o,c)=>{var d=cv(),v=r(d),p=r(v),_=i(v,2);rt(_,17,()=>t(o).tutorials,dt,(T,y,x)=>{var A=N(()=>ta(t(y),2));let D=()=>t(A)[0],M=()=>t(A)[1];var B=dv();B.open=c===0&&x===0;var qe=r(B),ke=r(qe),xe=i(qe,2);He(xe,M,!0),P(()=>g(ke,D())),f(T,B)}),P(()=>g(p,t(o).label)),f(l,d)});var s=i(a,4);rt(s,21,()=>ov,dt,(l,o)=>{var c=N(()=>ta(t(o),2));let d=()=>t(c)[0],v=()=>t(c)[1];var p=vv(),_=r(p),T=r(_),y=i(_,2),x=r(y);P(()=>{g(T,d()),g(x,v())}),f(l,p)}),f(e,n)}var fv=b('<div class="card"><div class="card-h"><h3>Neuer Eintrag</h3></div> <label>Inhalt</label> <textarea rows="3" placeholder="z.B.: Mission Control läuft auf Port 9000 — oder: Wir nutzen SQLite statt Qdrant" style="width:100%;box-sizing:border-box;resize:vertical;margin-bottom:10px"></textarea> <label>Kategorie</label> <select style="margin-bottom:14px"><option>Über mich — Wer du bist, Präferenzen, Arbeitsweise</option><option>Verhalten — Wie alle KI-Tools sich verhalten sollen</option><option>Stabil — Projektfakten, die sich selten ändern</option><option>Versioniert — Tech-Versionen (bei Updates überschreiben)</option><option>Temporär — Aktuelle Aufgabe (nach 7 Tagen gelöscht)</option></select> <div class="btn-row"><button class="primary">Speichern</button> <button class="ghost">Abbrechen</button> <span class="card-sub" style="font-size:11.5px;margin-left:4px">Strg+Enter zum Speichern</span></div></div>'),hv=b('<span class="chip" role="button" tabindex="0"> <span style="color:var(--mut);margin-left:2px"> </span></span>'),gv=b('<div class="card"><div class="card-sub">Lade…</div></div>'),mv=b('<button class="primary" style="margin-top:14px">+ Ersten Eintrag anlegen</button>'),bv=b('<div class="card"><div class="empty-c" style="padding:8px 0 4px"><div class="e-t"> </div> <div class="e-s"> </div> <!></div></div>'),_v=b('<textarea rows="3" style="width:100%;box-sizing:border-box;resize:vertical;margin-bottom:8px"></textarea> <select style="margin-bottom:10px"><option>Über mich</option><option>Verhalten</option><option>Stabil</option><option>Versioniert</option><option>Temporär</option></select> <div class="btn-row"><button class="primary">Speichern</button> <button class="ghost">Abbrechen</button></div>',1),yv=b('<div style="display:flex;gap:10px;align-items:flex-start"><div style="flex:1;min-width:0"><div style="font-size:13.5px;line-height:1.55;word-break:break-word"> </div> <div class="flex gap-2" style="margin-top:8px;flex-wrap:wrap;align-items:center"><span class="chip"> </span> <span class="chip"> </span> <span style="font-size:11px;color:var(--mut)"> </span></div></div> <div class="flex gap-2" style="flex-shrink:0;margin-top:2px"><button class="ghost" style="padding:4px 10px;font-size:12px">Bearbeiten</button> <button class="ghost" style="padding:4px 10px;font-size:12px;color:var(--err)">Löschen</button></div></div>'),kv=b("<div><!></div>"),xv=b('<div class="card" style="padding:0;overflow:hidden"></div>'),wv=b(`<div class="pagehead" style="display:flex;justify-content:space-between;align-items:flex-start"><div><h1>Gedächtnis</h1> <div class="sub">Fakten, Entscheidungen und Kontext — geteilt von allen KI-Tools via MCP.</div></div> <button class="primary" style="flex-shrink:0;margin-top:4px"> </button></div> <!> <div class="card" style="padding:10px 16px"><div class="flex gap-2" style="flex-wrap:wrap;align-items:center"><span style="font-size:11.5px;color:var(--mut);margin-right:4px">Filter:</span> <!></div></div> <!> <div class="card" style="background:rgba(45,212,191,.04);border-color:rgba(45,212,191,.2)"><div class="card-h"><h3 style="font-size:13px;font-weight:500">Wie KI-Tools dieses Gedächtnis nutzen</h3></div> <div class="card-sub" style="line-height:1.6">Cline, OpenCode und Claude Code greifen über den <b>Memory MCP-Server</b> auf diese Einträge zu.
|
||
Beim Start einer Session lädt der Agent automatisch alle Einträge — er kennt dann deinen Stack,
|
||
deine Präferenzen und frühere Entscheidungen. Den Setup-Guide findest du unter <a href="#" style="color:var(--accent)">Verbinden → Gedächtnis-MCP</a>.</div> <div class="card-sub" style="margin-top:8px;font-size:11.5px"><b style="color:#a78bfa">Über mich</b> = wer du bist, Präferenzen · <b style="color:#fb923c">Verhalten</b> = Regeln für alle KI-Tools · <b style="color:var(--accent)">Stabil</b> = Projektfakten · <b style="color:#f59e0b">Versioniert</b> = Tech-Versionen · <b style="color:var(--mut)">Temporär</b> = 7 Tage, dann weg</div></div>`,1);function Sv(e,n){On(n,!0);let a=O(jt([])),s=O(!0),l=O("all"),o=O(!1),c=O(""),d=O("stable"),v=O(null),p=O(""),_=O("stable");const T=N(()=>t(l)==="all"?t(a):t(a).filter(q=>q.category===t(l))),y={user:{label:"Über mich",color:"#a78bfa"},instruction:{label:"Verhalten",color:"#fb923c"},stable:{label:"Stabil",color:"var(--accent)"},versioned:{label:"Versioniert",color:"#f59e0b"},ephemeral:{label:"Temporär",color:"var(--mut)"}};function x(q){const Y=Math.floor((Date.now()-new Date(q).getTime())/1e3);return Y<60?"gerade eben":Y<3600?`vor ${Math.floor(Y/60)} Min`:Y<86400?`vor ${Math.floor(Y/3600)} Std`:`vor ${Math.floor(Y/86400)} Tagen`}function A(q){return t(a).filter(Y=>Y.category===q).length}async function D(){try{u(a,await $e("/api/memory"),!0)}catch(q){ie("Laden fehlgeschlagen: "+q.message,!0)}finally{u(s,!1)}}async function M(){if(t(c).trim())try{const q=await $e("/api/memory",{method:"POST",body:JSON.stringify({content:t(c).trim(),category:t(d),source:"manual"})});u(a,[q,...t(a)],!0),u(c,""),u(d,"stable"),u(o,!1),ie("Gespeichert")}catch(q){ie("Fehler: "+q.message,!0)}}async function B(q){try{const Y=await $e(`/api/memory/${q.id}`,{method:"PUT",body:JSON.stringify({content:t(p),category:t(_)})});u(a,t(a).map(pe=>pe.id===q.id?Y:pe),!0),u(v,null),ie("Aktualisiert")}catch(Y){ie("Fehler: "+Y.message,!0)}}async function qe(q){if(await mn({title:"Eintrag löschen?",body:`„${q.content.length>80?q.content.slice(0,80)+"…":q.content}" wird dauerhaft entfernt.`,danger:!0}))try{await $e(`/api/memory/${q.id}`,{method:"DELETE"}),u(a,t(a).filter(pe=>pe.id!==q.id),!0),ie("Gelöscht")}catch(pe){ie("Fehler: "+pe.message,!0)}}function ke(q){u(v,q.id,!0),u(p,q.content,!0),u(_,q.category,!0)}mi(()=>{D()});var xe=wv(),Ae=et(xe),W=i(r(Ae),2),ae=r(W),we=i(Ae,2);{var Ce=q=>{var Y=fv(),pe=i(r(Y),4),fe=i(pe,4),Ke=r(fe);Ke.value=Ke.__value="user";var Ye=i(Ke);Ye.value=Ye.__value="instruction";var ct=i(Ye);ct.value=ct.__value="stable";var st=i(ct);st.value=st.__value="versioned";var lt=i(st);lt.value=lt.__value="ephemeral";var Re=i(fe,2),Je=r(Re),vt=i(Je,2);P(F=>Je.disabled=F,[()=>!t(c).trim()]),S("keydown",pe,F=>{F.key==="Enter"&&(F.ctrlKey||F.metaKey)&&M()}),vn(pe,()=>t(c),F=>u(c,F)),xa(fe,()=>t(d),F=>u(d,F)),S("click",Je,M),S("click",vt,()=>{u(o,!1),u(c,"")}),f(q,Y)};K(we,q=>{t(o)&&q(Ce)})}var Be=i(we,2),je=r(Be),bt=i(r(je),2);rt(bt,17,()=>[["all","Alle","",t(a).length],["user","Über mich","#a78bfa",A("user")],["instruction","Verhalten","#fb923c",A("instruction")],["stable","Stabil","var(--accent)",A("stable")],["versioned","Versioniert","#f59e0b",A("versioned")],["ephemeral","Temporär","var(--mut)",A("ephemeral")]],dt,(q,Y)=>{var pe=N(()=>ta(t(Y),4));let fe=()=>t(pe)[0],Ke=()=>t(pe)[1],Ye=()=>t(pe)[2],ct=()=>t(pe)[3];var st=hv(),lt=r(st),Re=i(lt),Je=r(Re);P(()=>{Ot(st,`cursor:pointer;${t(l)===fe()?`background:rgba(45,212,191,.12);border-color:${Ye()||"var(--accent)"};color:${Ye()||"var(--accent)"}`:""}`),g(lt,`${Ke()??""} `),g(Je,ct())}),S("click",st,()=>u(l,fe(),!0)),S("keydown",st,vt=>vt.key==="Enter"&&u(l,fe(),!0)),f(q,st)});var z=i(Be,2);{var re=q=>{var Y=gv();f(q,Y)},ge=q=>{var Y=bv(),pe=r(Y),fe=r(pe),Ke=r(fe),Ye=i(fe,2),ct=r(Ye),st=i(Ye,2);{var lt=Re=>{var Je=mv();S("click",Je,()=>u(o,!0)),f(Re,Je)};K(st,Re=>{t(a).length===0&&Re(lt)})}P(()=>{g(Ke,t(a).length===0?"Noch keine Einträge":"Keine Treffer"),g(ct,t(a).length===0?'Klicke „+ Eintrag" um manuell etwas zu speichern, oder verbinde ein KI-Tool via MCP.':"Andere Kategorie wählen oder Eintrag anlegen.")}),f(q,Y)},tt=q=>{var Y=xv();rt(Y,23,()=>t(T),pe=>pe.id,(pe,fe,Ke)=>{var Ye=kv(),ct=r(Ye);{var st=Re=>{var Je=_v(),vt=et(Je),F=i(vt,2),X=r(F);X.value=X.__value="user";var E=i(X);E.value=E.__value="instruction";var I=i(E);I.value=I.__value="stable";var se=i(I);se.value=se.__value="versioned";var le=i(se);le.value=le.__value="ephemeral";var m=i(F,2),L=r(m),ne=i(L,2);vn(vt,()=>t(p),ee=>u(p,ee)),xa(F,()=>t(_),ee=>u(_,ee)),S("click",L,()=>B(t(fe))),S("click",ne,()=>u(v,null)),f(Re,Je)},lt=Re=>{var Je=yv(),vt=r(Je),F=r(vt),X=r(F),E=i(F,2),I=r(E),se=r(I),le=i(I,2),m=r(le),L=i(le,2),ne=r(L),ee=i(vt,2),U=r(ee),be=i(U,2);P(_e=>{var Le,Qe,Me;g(X,t(fe).content),Ot(I,`border-color:${(((Le=y[t(fe).category])==null?void 0:Le.color)||"var(--mut)")??""};color:${(((Qe=y[t(fe).category])==null?void 0:Qe.color)||"var(--mut)")??""}`),g(se,((Me=y[t(fe).category])==null?void 0:Me.label)||t(fe).category),g(m,t(fe).source),g(ne,_e)},[()=>x(t(fe).updated_at)]),S("click",U,()=>ke(t(fe))),S("click",be,()=>qe(t(fe))),f(Re,Je)};K(ct,Re=>{t(v)===t(fe).id?Re(st):Re(lt,-1)})}P(()=>Ot(Ye,`padding:14px 16px;${t(Ke)<t(T).length-1?"border-bottom:1px solid var(--brd, rgba(255,255,255,.07))":""}`)),f(pe,Ye)}),f(q,Y)};K(z,q=>{t(s)?q(re):t(T).length===0?q(ge,1):q(tt,-1)})}var oe=i(z,2),Fe=i(r(oe),2),ue=i(r(Fe),3);P(()=>g(ae,t(o)?"Abbrechen":"+ Eintrag")),S("click",W,()=>{u(o,!t(o)),u(c,"")}),S("click",ue,q=>{var Y;q.preventDefault(),(Y=document.querySelector(".nav-item[data-view='connect']"))==null||Y.click()}),f(e,xe),Bn()}jn(["click","keydown"]);var Mv=b('<div class="log svelte-h40163" style="margin-top:8px"><code class="svelte-h40163">pip install faster-whisper</code></div>'),Ev=b('<div class="log svelte-h40163" style="margin-top:8px"><code class="svelte-h40163"> </code></div>'),Av=b('<div style="margin-bottom:8px" class="svelte-h40163"><div class="card-sub svelte-h40163" style="font-size:11.5px;margin-bottom:4px">4. Bosgame-Key eintragen (in Windows PowerShell):</div> <div style="position:relative" class="svelte-h40163"><button class="ghost svelte-h40163" style="position:absolute;top:6px;right:6px;font-size:11px;padding:2px 8px;z-index:1">Kopieren</button> <div class="log svelte-h40163"><code class="svelte-h40163"> </code></div></div></div>'),Cv=b('<div class="card-sub svelte-h40163" style="font-size:11.5px">SSH-Key nicht gefunden — bitte auf dem Bosgame generieren: <code style="display:block;margin-top:4px" class="svelte-h40163">ssh-keygen -t ed25519 -C "hermes-agent@bosgame" -f ~/.ssh/id_ed25519_hermes_agent -N ""</code></div>'),Tv=b('<div style="margin-top:12px" class="svelte-h40163"><div style="font-size:12.5px;font-weight:500;margin-bottom:8px" class="svelte-h40163">Einrichtung (einmalig, ~3 Minuten):</div> <div style="margin-bottom:8px" class="svelte-h40163"><div class="card-sub svelte-h40163" style="font-size:11.5px;margin-bottom:4px">1. PowerShell als Admin — OpenSSH Server installieren:</div> <div class="log svelte-h40163"><code class="svelte-h40163">Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0</code></div></div> <div style="margin-bottom:8px" class="svelte-h40163"><div class="card-sub svelte-h40163" style="font-size:11.5px;margin-bottom:4px">2. Dienst starten und dauerhaft aktivieren:</div> <div class="log svelte-h40163"><code class="svelte-h40163"></code></div></div> <div style="margin-bottom:8px" class="svelte-h40163"><div class="card-sub svelte-h40163" style="font-size:11.5px;margin-bottom:4px">3. SSH-Ordner erstellen:</div> <div class="log svelte-h40163"><code class="svelte-h40163"></code></div></div> <!> <div style="margin-bottom:8px" class="svelte-h40163"><div class="card-sub svelte-h40163" style="font-size:11.5px;margin-bottom:4px">5. Windows-IP in Mission Control Env-Var setzen:</div> <div class="log svelte-h40163"><code class="svelte-h40163">HERMES_WINDOWS_HOST=192.168.178.XXX</code></div></div> <button class="primary svelte-h40163" style="margin-top:4px">Verbindung testen</button></div>'),zv=b('<div class="card svelte-h40163" style="border-color:rgba(45,212,191,.3)"><div class="card-h svelte-h40163"><h3 class="svelte-h40163">Hermes Setup-Wizard</h3></div> <div class="tile svelte-h40163" style="margin-bottom:10px"><div style="display:flex;justify-content:space-between;align-items:center" class="svelte-h40163"><div class="svelte-h40163"><b class="svelte-h40163">Whisper (Sprache → Text)</b> <div class="card-sub svelte-h40163" style="font-size:12px">faster-whisper muss auf dem Bosgame installiert sein</div></div> <span class="chip svelte-h40163"> </span></div> <!></div> <div class="tile svelte-h40163" style="margin-bottom:10px"><div style="display:flex;justify-content:space-between;align-items:center" class="svelte-h40163"><div class="svelte-h40163"><b class="svelte-h40163">Piper TTS (Text → Sprache)</b> <div class="card-sub svelte-h40163" style="font-size:12px">Piper-Binary + deutsche Stimme</div></div> <span class="chip svelte-h40163"> </span></div> <!></div> <div class="tile svelte-h40163"><div style="display:flex;justify-content:space-between;align-items:center" class="svelte-h40163"><div class="svelte-h40163"><b class="svelte-h40163">Windows SSH-Verbindung</b> <div class="card-sub svelte-h40163" style="font-size:12px">Damit Hermes Dateien auf deinem Windows-PC ändern kann</div></div> <span class="chip svelte-h40163"> </span></div> <!></div></div>'),Pv=b('<button class="ghost svelte-h40163" style="font-size:12.5px;text-align:left"> </button>'),Dv=b('<div class="empty-c svelte-h40163" style="margin:auto"><div class="e-t svelte-h40163">Hermes ist bereit</div> <div class="e-s svelte-h40163">Stelle eine Frage oder gib einen Auftrag — per Text oder Sprache.</div> <div style="margin-top:16px;display:flex;flex-direction:column;gap:6px" class="svelte-h40163"></div></div>'),$v=b(`<div style="display:flex;justify-content:flex-end" class="svelte-h40163"><div style="background:rgba(45,212,191,.15);border:1px solid rgba(45,212,191,.3);
|
||
border-radius:12px 12px 2px 12px;padding:10px 14px;max-width:75%;
|
||
font-size:13.5px;line-height:1.5;word-break:break-word" class="svelte-h40163"> </div></div>`),Lv=b(`<div style="display:flex;gap:8px;align-items:flex-start" class="svelte-h40163"><div style="width:28px;height:28px;border-radius:50%;background:rgba(45,212,191,.2);
|
||
border:1px solid rgba(45,212,191,.4);display:flex;align-items:center;
|
||
justify-content:center;font-size:14px;flex-shrink:0" class="svelte-h40163">H</div> <div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);
|
||
border-radius:2px 12px 12px 12px;padding:10px 14px;max-width:80%;
|
||
font-size:13.5px;line-height:1.6;word-break:break-word;white-space:pre-wrap" class="svelte-h40163"> </div></div>`),Iv=b(`<span style="font-family:monospace;font-size:11px;opacity:.7;overflow:hidden;
|
||
text-overflow:ellipsis;white-space:nowrap;max-width:400px" class="svelte-h40163"> </span>`),Ov=b(`<div style="display:flex;align-items:center;gap:8px;color:var(--mut);font-size:11.5px;
|
||
padding:4px 8px;background:rgba(255,255,255,.02);border-radius:6px" class="svelte-h40163"><span class="svelte-h40163"> </span> <!></div>`),Bv=b('<div style="text-align:center;color:var(--mut);font-size:11px" class="svelte-h40163"> </div>'),Rv=b(`<div style="background:rgba(240,87,63,.1);border:1px solid rgba(240,87,63,.3);
|
||
border-radius:8px;padding:8px 12px;color:#ff9b95;font-size:12.5px" class="svelte-h40163"> </div>`),Fv=b(`<div style="display:flex;gap:8px;align-items:center;color:var(--mut);font-size:12px" class="svelte-h40163"><div style="width:28px;height:28px;border-radius:50%;background:rgba(45,212,191,.1);
|
||
border:1px solid rgba(45,212,191,.2);display:flex;align-items:center;
|
||
justify-content:center;font-size:14px" class="svelte-h40163">H</div> <span style="animation:pulse 1.2s ease-in-out infinite" class="svelte-h40163">denkt nach…</span></div>`),Kv=b('<div class="pagehead svelte-h40163" style="display:flex;justify-content:space-between;align-items:flex-start"><div class="svelte-h40163"><h1 class="svelte-h40163">Hermes</h1> <div class="sub svelte-h40163">Dein lokaler KI-Assistent — kennt den Bosgame, lernt mit.</div></div> <div class="flex gap-2 svelte-h40163" style="flex-shrink:0;margin-top:6px;flex-wrap:wrap;align-items:center"><span class="chip svelte-h40163"> </span> <span class="chip svelte-h40163"> </span> <button class="ghost svelte-h40163"> </button> <button class="ghost svelte-h40163" style="padding:4px 10px;font-size:12px">⚙ Setup</button></div></div> <!> <div class="card svelte-h40163" style="padding:0;display:flex;flex-direction:column;min-height:420px"><div style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px" id="hermes-msgs" class="svelte-h40163"><!> <!> <!></div> <div style="border-top:1px solid rgba(255,255,255,.07);padding:12px 16px;display:flex;gap:8px;align-items:flex-end" class="svelte-h40163"><textarea rows="2" placeholder="Frage stellen oder Aufgabe beschreiben…" style="flex:1;resize:none;font-size:13.5px;line-height:1.5;min-height:44px;max-height:160px" class="svelte-h40163"></textarea> <button class="ghost svelte-h40163"> </button> <button class="primary svelte-h40163" style="padding:10px 18px;flex-shrink:0">Senden</button></div></div>',1);function Nv(e,n){On(n,!0);let a=O(jt([])),s=O(""),l=O(!1),o=O(!1),c=O(!1),d=O(null),v=O(!1),p=O(""),_=O(null),T=O("");function y(){const F=location.protocol==="https:"?"wss:":"ws:",X=localStorage.getItem("mc_token")||"",E=`${F}//${location.host}/api/hermes/chat${X?"?token="+X:""}`,I=new WebSocket(E);I.onmessage=se=>{const le=JSON.parse(se.data);if(le.type==="thinking")u(l,!0);else if(le.type!=="info")if(le.type==="token"){u(l,!1),u(T,t(T)+le.content);const m=t(a)[t(a).length-1];(m==null?void 0:m.role)==="hermes"?u(a,[...t(a).slice(0,-1),{role:"hermes",content:t(T)}],!0):u(a,[...t(a),{role:"hermes",content:t(T)}],!0)}else if(le.type==="tool_call"){u(l,!1);const m=le.args||{},L=Object.values(m).join(" ").slice(0,60);u(a,[...t(a),{role:"tool",content:L,tool:le.name}],!0)}else if(le.type==="tool_result"){const m=t(a).findLast(L=>L.role==="tool"&&L.tool===le.name);m&&(m.content=le.content),u(a,[...t(a)],!0)}else le.type==="error"?(u(l,!1),u(a,[...t(a),{role:"error",content:le.content}],!0)):le.type==="done"&&(u(l,!1),u(T,""),t(o)&&ke())},I.onclose=()=>{u(_,null),setTimeout(y,3e3)},I.onerror=()=>I.close(),u(_,I,!0)}async function x(){const F=t(s).trim();!F||!t(_)||t(_).readyState!==1||(u(a,[...t(a),{role:"user",content:F}],!0),u(s,""),u(T,""),t(_).send(JSON.stringify({message:F})))}let A=null,D=[];async function M(){try{const F=await navigator.mediaDevices.getUserMedia({audio:!0});D=[],A=new MediaRecorder(F),A.ondataavailable=X=>D.push(X.data),A.onstop=()=>{F.getTracks().forEach(X=>X.stop()),qe()},A.start(),u(c,!0)}catch(F){ie("Mikrofon-Zugriff verweigert: "+F.message,!0)}}function B(){A==null||A.stop(),u(c,!1)}async function qe(){const F=new Blob(D,{type:"audio/webm"}),X=new FormData;X.append("audio",F,"voice.webm");try{const I=await(await fetch("/api/hermes/transcribe",{method:"POST",headers:localStorage.getItem("mc_token")?{"X-MC-Token":localStorage.getItem("mc_token")}:{},body:X})).json();I.text?(u(s,I.text,!0),x()):ie("Konnte Audio nicht verstehen.",!0)}catch(E){ie("Transkription fehlgeschlagen: "+E.message,!0)}}async function ke(){const F=[...t(a)].reverse().find(X=>X.role==="hermes");if(F)try{const X=await fetch("/api/hermes/tts",{method:"POST",headers:{"Content-Type":"application/json",...localStorage.getItem("mc_token")?{"X-MC-Token":localStorage.getItem("mc_token")}:{}},body:JSON.stringify({text:F.content})});if(!X.ok)return;const E=await X.blob(),I=URL.createObjectURL(E),se=new Audio(I);se.onended=()=>URL.revokeObjectURL(I),se.play()}catch{}}async function xe(){try{u(d,await $e("/api/hermes/status"),!0)}catch{u(d,null)}}async function Ae(){try{const F=await $e("/api/hermes/pubkey");u(p,F.pubkey,!0)}catch{u(p,"")}}function W(F){return{read_file:"📄 Lese Datei",list_directory:"📁 Liste Verzeichnis",run_command:"⚡ Befehl",get_system_status:"📊 System-Status",get_memories:"🧠 Gedächtnis",add_memory:"💾 Speichern",web_search:"🌐 Websuche"}[F]||F}function ae(){var F;(F=navigator.clipboard)==null||F.writeText(t(p)),ie("SSH-Key kopiert")}mi(()=>{y(),xe()});var we=Kv(),Ce=et(we),Be=i(r(Ce),2),je=r(Be),bt=r(je),z=i(je,2),re=r(z),ge=i(z,2),tt=r(ge),oe=i(ge,2),Fe=i(Ce,2);{var ue=F=>{var X=zv(),E=i(r(X),2),I=r(E),se=i(r(I),2),le=r(se),m=i(I,2);{var L=ze=>{var me=Mv();f(ze,me)};K(m,ze=>{var me;((me=t(d))==null?void 0:me.whisper)==="not_installed"&&ze(L)})}var ne=i(E,2),ee=r(ne),U=i(r(ee),2),be=r(U),_e=i(ee,2);{var Le=ze=>{var me=Ev(),Tt=r(me),$t=r(Tt);P(zt=>g($t,zt),[()=>["# 1. Piper Binary (Linux x86_64)","mkdir -p /opt/mission-control/piper/voices","cd /tmp && wget -q https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_linux_x86_64.tar.gz","tar -xzf piper_linux_x86_64.tar.gz -C /opt/mission-control/piper/ --strip-components=1","","# 2. Deutsche Stimme — Kerstin (weiblich, ~25 MB)","wget -q -O /opt/mission-control/piper/voices/de_DE-kerstin-low.onnx \\",' "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/de/de_DE/kerstin/low/de_DE-kerstin-low.onnx"',"wget -q -O /opt/mission-control/piper/voices/de_DE-kerstin-low.onnx.json \\",' "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/de/de_DE/kerstin/low/de_DE-kerstin-low.onnx.json"'].join(`
|
||
`)]),f(ze,me)};K(_e,ze=>{var me;((me=t(d))==null?void 0:me.piper)!=="ready"&&ze(Le)})}var Qe=i(ne,2),Me=r(Qe),Ze=i(r(Me),2),$=r(Ze),de=i(Me,2);{var Te=ze=>{var me=Tv(),Tt=i(r(me),4),$t=i(r(Tt),2),zt=r($t);zt.textContent=`Start-Service sshd
|
||
Set-Service -Name sshd -StartupType Automatic`;var C=i(Tt,2),Z=i(r(C),2),Ge=r(Z);Ge.textContent='New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.ssh"';var he=i(C,2);{var G=R=>{var H=Av(),te=i(r(H),2),ve=r(te),Ie=i(ve,2),Ee=r(Ie),ut=r(Ee);P(()=>g(ut,'echo "'+t(p)+'" >> "$env:USERPROFILE\\.ssh\\authorized_keys"')),S("click",ve,ae),f(R,H)},Q=R=>{var H=Cv();f(R,H)};K(he,R=>{t(p)?R(G):R(Q,-1)})}var V=i(he,4);S("click",V,()=>{xe(),ie("Status aktualisiert")}),f(ze,me)};K(de,ze=>{var me;(me=t(d))!=null&&me.ssh_ok||ze(Te)})}P(()=>{var ze,me,Tt,$t,zt,C;Ot(se,`font-size:11px;${((ze=t(d))==null?void 0:ze.whisper)!=="not_installed"?"color:#7ee29a":"color:#ff9b95"}`),g(le,((me=t(d))==null?void 0:me.whisper)!=="not_installed"?"✓ OK":"✗ fehlt"),Ot(U,`font-size:11px;${((Tt=t(d))==null?void 0:Tt.piper)==="ready"?"color:#7ee29a":"color:#ff9b95"}`),g(be,(($t=t(d))==null?void 0:$t.piper)==="ready"?"✓ OK":"✗ fehlt"),Ot(Ze,`font-size:11px;${(zt=t(d))!=null&&zt.ssh_ok?"color:#7ee29a":"color:var(--mut)"}`),g($,(C=t(d))!=null&&C.ssh_ok?"✓ verbunden":"optional")}),f(F,X)};K(Fe,F=>{t(v)&&F(ue)})}var q=i(Fe,2),Y=r(q),pe=r(Y);{var fe=F=>{var X=Dv(),E=i(r(X),4);rt(E,20,()=>["Was läuft gerade auf dem System?","Zeig mir den Inhalt von /etc/llama-swap/config.yaml","Suche nach den neuesten Qwen3-Modellen"],dt,(I,se)=>{var le=Pv(),m=r(le);P(()=>g(m,se)),S("click",le,()=>{u(s,se,!0),x()}),f(I,le)}),f(F,X)};K(pe,F=>{t(a).length===0&&F(fe)})}var Ke=i(pe,2);rt(Ke,16,()=>t(a),F=>F,(F,X)=>{var E=Va(),I=et(E);{var se=ee=>{var U=$v(),be=r(U),_e=r(be);P(()=>g(_e,X.content)),f(ee,U)},le=ee=>{var U=Lv(),be=i(r(U),2),_e=r(be);P(()=>g(_e,X.content)),f(ee,U)},m=ee=>{var U=Ov(),be=r(U),_e=r(be),Le=i(be,2);{var Qe=Me=>{var Ze=Iv(),$=r(Ze);P(()=>g($,X.content)),f(Me,Ze)};K(Le,Me=>{X.content&&Me(Qe)})}P(Me=>g(_e,Me),[()=>W(X.tool||"")]),f(ee,U)},L=ee=>{var U=Bv(),be=r(U);P(()=>g(be,X.content)),f(ee,U)},ne=ee=>{var U=Rv(),be=r(U);P(()=>g(be,`⚠ ${X.content??""}`)),f(ee,U)};K(I,ee=>{X.role==="user"?ee(se):X.role==="hermes"?ee(le,1):X.role==="tool"?ee(m,2):X.role==="info"?ee(L,3):X.role==="error"&&ee(ne,4)})}f(F,E)});var Ye=i(Ke,2);{var ct=F=>{var X=Fv();f(F,X)};K(Ye,F=>{t(l)&&F(ct)})}var st=i(Y,2),lt=r(st),Re=i(lt,2),Je=r(Re),vt=i(Re,2);P(F=>{var X,E,I,se,le,m;Ot(je,`font-size:11px;${((X=t(d))==null?void 0:X.whisper)==="ready"||((E=t(d))==null?void 0:E.whisper)==="installed"?"color:var(--accent);border-color:var(--accent)":"color:var(--mut)"}`),g(bt,`🎙 Whisper: ${((I=t(d))==null?void 0:I.whisper)??"…"??""}`),Ot(z,`font-size:11px;${(se=t(d))!=null&&se.ssh_ok?"color:var(--accent);border-color:var(--accent)":"color:var(--mut)"}`),g(re,`🔑 SSH: ${(le=t(d))!=null&&le.ssh_ok?"verbunden":(m=t(d))!=null&&m.ssh_configured?"Fehler":"nicht eingerichtet"}`),Ot(ge,`padding:4px 12px;font-size:12px;${t(o)?"border-color:var(--accent);color:var(--accent)":""}`),g(tt,`🔊 Voice ${t(o)?"an":"aus"}`),Ot(Re,`padding:10px 12px;flex-shrink:0;font-size:18px;line-height:1;
|
||
${t(c)?"border-color:var(--err);color:var(--err)":""}`),_i(Re,"title",t(c)?"Aufnahme stoppen":"Spracheingabe"),g(Je,t(c)?"⏹":"🎤"),vt.disabled=F},[()=>!t(s).trim()||!t(_)||t(_).readyState!==1]),S("click",ge,()=>u(o,!t(o))),S("click",oe,()=>{u(v,!t(v)),t(v)&&(xe(),Ae())}),S("keydown",lt,F=>{F.key==="Enter"&&!F.shiftKey&&(F.preventDefault(),x())}),vn(lt,()=>t(s),F=>u(s,F)),S("mousedown",Re,M),S("mouseup",Re,B),S("touchstart",Re,M),S("touchend",Re,B),S("click",vt,x),f(e,we),Bn()}jn(["click","keydown","mousedown","mouseup","touchstart","touchend"]);let es={};function qv(){const e=document.getElementById("top-active-text");e&&(e.classList.add("swap-flash"),setTimeout(()=>e.classList.remove("swap-flash"),900))}function ts(e){var l;const n=document.getElementById("swdot"),a=document.getElementById("swlabel"),s=document.getElementById("top-active-text");if(!e)n&&(n.className="dot off"),a&&(a.textContent="Backend nicht erreichbar"),s&&(s.textContent="Backend offline"),ns("Backend nicht erreichbar – läuft uvicorn?",!1);else{const o=(e.swap_url||"").replace(/^https?:\/\//,"");n&&(n.className="dot "+(e.swap_ok?"on":"off")),a&&(a.textContent=(e.swap_ok?"LLM-Engine: Online – ":"LLM-Engine: Offline – ")+o);const c=["running","ready","loading","starting"],d=(e.models||[]).find(p=>c.includes(p.state));if(s)if(d){const p=(l=d.meta)!=null&&l.ctx?` <span style="color:var(--mut);font-size:11.5px">· ${Math.round(d.meta.ctx/1024)}k ctx</span>`:"",_=d.state==="loading"||d.state==="starting"?' <span style="color:var(--warn);font-size:11.5px">lädt…</span>':"";s.innerHTML=`<b style="color:var(--accent)">${d.name}</b>${p}${_}`}else s.innerHTML='<span style="color:var(--mut)">Kein Modell im VRAM</span>';e.swap_ok?jv():ns(`LLM-Engine nicht erreichbar unter <b>${o}</b> – läuft der llama-swap Dienst?`,!0);const v={};for(const p of e.models||[])v[p.name]=p.state;for(const[p,_]of Object.entries(v)){const T=es[p];if(T&&T!==_&&(_==="running"||_==="loading")){qv();break}}es=v}Wv(e),ki.set(e)}function Wv(e){const n=document.getElementById("sec-chip"),a=document.getElementById("sec-chip-tx");!n||!a||(n.classList.toggle("ok",!!(e!=null&&e.secured)),a.textContent=e!=null&&e.secured?"Geschützt · Heimnetz":"Nur im Heimnetz (offen)")}function Gv(e){ua.set(e||[])}function Vv(e){Pr.set(e)}function ns(e,n){const a=document.getElementById("alert");a.className="alert"+(n?" warn":""),a.innerHTML=`<span class="a-dot"></span><span>${e}</span>`,a.style.display="flex"}function jv(){const e=document.getElementById("alert");e&&(e.style.display="none")}const Uv=e=>{var n;return(n=document.querySelector(`.nav-item[data-view="${e}"]`))==null?void 0:n.click()};function tr(e,n,a,s){const l=document.createElement("span");return l.className="upd-badge"+(n?" "+n:""),l.textContent=e,s&&(l.title=s),l.onclick=()=>Uv(a),l}async function nl(){try{const e=await $e("/api/updates"),n=document.getElementById("update-badges");if(!n)return;const a=e.apt_cache_age_h,s=a!=null&&a>24,l=a!=null?` · apt-Cache: vor ${a}h`:"";n.innerHTML="",n.appendChild(tr(e.os>0?`OS: ${e.os} Updates`:s?"OS: ?":"OS: aktuell",e.os>0||s?"warn":"ok","server",e.os>0?`${e.os} Pakete${l}`:s?`apt-Cache veraltet (${a}h)`:`Keine Updates${l}`)),n.appendChild(tr(e.engine>0?"Engine: Update":"Engine: aktuell",e.engine>0?"warn":"ok","server")),n.appendChild(tr(e.models>0?`Modelle: ${e.models}`:"Modelle: aktuell",e.models>0?"warn":"ok","news"))}catch{}}async function Gi(){try{ts(await $e("/api/status"))}catch{ts(null)}}async function al(){try{Gv(await $e("/api/jobs"))}catch{}}function il(){const e=window.location.protocol==="https:"?"wss:":"ws:",n=new WebSocket(`${e}//${window.location.host}/api/system/stream`);n.onmessage=a=>{try{Vv(JSON.parse(a.data))}catch{}},n.onclose=()=>{setTimeout(il,3e3)},n.onerror=()=>n.close()}var os;((os=document.getElementById("logo"))==null?void 0:os.innerHTML)!==void 0&&(document.getElementById("logo").innerHTML=Wi.logo);document.querySelectorAll("[data-ic]").forEach(e=>{e.innerHTML=Wi[e.dataset.ic||""]||""});const Hv=[["overview",vd],["models",Ed],["activity",Bd],["server",Ud],["cookbook",Tc],["connect",Qc],["news",sv],["guides",pv],["memory",Sv],["hermes",Nv]];for(const[e,n]of Hv){const a=document.querySelector(`.view[data-view="${e}"]`);a&&So(n,{target:a})}jo("overview");const nr=document.getElementById("token");nr&&(nr.value=tl(),nr.addEventListener("change",e=>{No(e.target.value),Gi()}));const ar=document.getElementById("hf-token");ar&&(ar.value=oi(),ar.addEventListener("change",e=>Wo(e.target.value)));const as=document.getElementById("nav-settings"),ir=document.getElementById("settings-modal"),is=document.getElementById("sm-close");as&&ir&&is&&(as.addEventListener("click",()=>ir.style.display="flex"),is.addEventListener("click",()=>ir.style.display="none"));function Jv(){const e=document.getElementById("clock");e&&(e.textContent=new Date().toTimeString().slice(0,5))}document.addEventListener("mc:refresh",Gi);Gi();al();il();setInterval(Jv,1e3);setInterval(Gi,3e3);setInterval(al,1500);nl();setInterval(nl,6e4);
|