ogerl commited on
Commit
47134ca
·
verified ·
1 Parent(s): 898a82c

Doku-Deep-Links: #doku-Hash-Routing (App) + Anker-Highlight (Doku)

Browse files
Files changed (3) hide show
  1. assets/main-VmvG1jUP.js +20 -0
  2. doku.html +24 -0
  3. index.html +1 -1
assets/main-VmvG1jUP.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))s(n);new MutationObserver(n=>{for(const i of n)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&s(o)}).observe(document,{childList:!0,subtree:!0});function e(n){const i={};return n.integrity&&(i.integrity=n.integrity),n.referrerPolicy&&(i.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?i.credentials="include":n.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(n){if(n.ep)return;n.ep=!0;const i=e(n);fetch(n.href,i)}})();const O="aams-webgpu-agent",v="documents",S="current";function M(){return new Promise((r,t)=>{const e=indexedDB.open(O,1);e.onupgradeneeded=()=>{e.result.objectStoreNames.contains(v)||e.result.createObjectStore(v)},e.onsuccess=()=>r(e.result),e.onerror=()=>t(e.error??new Error("IndexedDB open fehlgeschlagen"))})}const w={async load(){const r=await M();return new Promise((t,e)=>{const n=r.transaction(v,"readonly").objectStore(v).get(S);n.onsuccess=()=>t(n.result??null),n.onerror=()=>e(n.error)})},async save(r){const t=await M();return new Promise((e,s)=>{const n=t.transaction(v,"readwrite");n.objectStore(v).put(r,S),n.oncomplete=()=>e(),n.onerror=()=>s(n.error)})},async clear(){const r=await M();return new Promise((t,e)=>{const s=r.transaction(v,"readwrite");s.objectStore(v).clear(),s.oncomplete=()=>t(),s.onerror=()=>e(s.error)})}};function I(){return`s_${Date.now()}_${Math.random().toString(36).slice(2,8)}`}async function j(r){const t=r.session.id,e={tasks:r.session.tasks.length,auditLog:r.session.auditLog.length,memory:r.session.memory.length,knowledge:r.session.knowledge.length},s=JSON.parse(JSON.stringify(r.session)),n=Date.now();r.session.id=I(),r.session.title="Neue Session",r.session.createdAt=n,r.session.updatedAt=n,r.session.status="active",r.session.tasks=[],r.session.memory=[],r.session.knowledge=[],r.session.auditLog=[{id:`a_reset_${n}`,ts:n,actor:"user",action:"session.reset",note:`Gedächtnis zurückgesetzt. Vorherige Session ${t} (${e.tasks} Tasks, ${e.auditLog} Audit, ${e.memory} Memory, ${e.knowledge} Wissen) — Safety-Export ausgelöst.`}];try{await w.save(r)}catch(i){throw r.session=s,new Error(`Reset fehlgeschlagen (Speicherfehler) — Zustand wiederhergestellt: ${i.message}`)}return{previousId:t,previousCounts:e,newId:r.session.id}}function H(r){return JSON.stringify(r,null,2)}function N(r,t=`aams-session-${r.session.id}.json`){const e=new Blob([H(r)],{type:"application/json"}),s=URL.createObjectURL(e),n=document.createElement("a");n.href=s,n.download=t,n.click(),URL.revokeObjectURL(s)}function F(r){let t;try{t=JSON.parse(r)}catch(s){throw new Error("Ungültiges JSON: "+s.message)}const e=t;if(!e||typeof e!="object"||!e.session)throw new Error("Ungültiges AAMS-Dokument: fehlendes Feld 'session'.");return e.session.tasks??=[],e.session.auditLog??=[],e.session.memory??=[],e.session.knowledge??=[],e}const E=/```[a-zA-Z0-9]*\n([\s\S]*?)```/g,T=/<html[\s>]/i;function A(r){if(!r)return null;const t=r;if(!T.test(t))return null;const e=[];E.lastIndex=0;let s;for(;(s=E.exec(t))!==null;)e.push(s[1]);let n=null;for(const o of e)T.test(o)&&(n===null||o.length>n.length)&&(n=o);if(n!==null)return x(n);const i=[t.search(/<!doctype html/i),t.search(/<html[\s>]/i)].filter(o=>o>=0);if(i.length>0){const o=Math.min(...i),a=t.lastIndexOf("</html>"),c=a>=o?a+7:t.length;return x(t.slice(o,c))}return null}function x(r){const t=r.trim();return{html:t,filename:"index.html",bytes:new TextEncoder().encode(t).length}}const q=[{id:"Qwen2.5-0.5B-Instruct-q4f16_1-MLC",label:"Qwen2.5 0.5B Instruct",vramMB:944.62,contextWindow:4096},{id:"Qwen2.5-Coder-0.5B-Instruct-q4f16_1-MLC",label:"Qwen2.5-Coder 0.5B Instruct",vramMB:944.62,contextWindow:4096},{id:"Qwen2.5-1.5B-Instruct-q4f16_1-MLC",label:"Qwen2.5 1.5B Instruct",vramMB:1629.75,contextWindow:4096},{id:"Qwen2.5-Coder-1.5B-Instruct-q4f16_1-MLC",label:"Qwen2.5-Coder 1.5B Instruct",vramMB:1629.75,contextWindow:4096},{id:"Llama-3.2-3B-Instruct-q4f16_1-MLC",label:"Llama-3.2 3B Instruct",vramMB:2263.69,contextWindow:4096},{id:"Qwen2.5-3B-Instruct-q4f16_1-MLC",label:"Qwen2.5 3B Instruct",vramMB:2504.76,contextWindow:4096},{id:"Qwen2.5-Coder-3B-Instruct-q4f16_1-MLC",label:"Qwen2.5-Coder 3B Instruct",vramMB:2504.76,contextWindow:4096}],z=4096,U="Qwen2.5-0.5B-Instruct-q4f16_1-MLC",B="Llama-3.2-3B-Instruct-q4f16_1-MLC",C="Qwen2.5-1.5B-Instruct-q4f16_1-MLC";function m(r){return q.find(t=>t.id===r)}const G="modulepreload",V=function(r,t){return new URL(r,t).href},P={},J=function(t,e,s){let n=Promise.resolve();if(e&&e.length>0){const o=document.getElementsByTagName("link"),a=document.querySelector("meta[property=csp-nonce]"),c=a?.nonce||a?.getAttribute("nonce");n=Promise.allSettled(e.map(l=>{if(l=V(l,s),l in P)return;P[l]=!0;const d=l.endsWith(".css"),g=d?'[rel="stylesheet"]':"";if(!!s)for(let k=o.length-1;k>=0;k--){const y=o[k];if(y.href===l&&(!d||y.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${g}`))return;const f=document.createElement("link");if(f.rel=d?"stylesheet":G,d||(f.as="script"),f.crossOrigin="",f.href=l,c&&f.setAttribute("nonce",c),document.head.appendChild(f),d)return new Promise((k,y)=>{f.addEventListener("load",k),f.addEventListener("error",()=>y(new Error(`Unable to preload CSS for ${l}`)))})}))}function i(o){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=o,window.dispatchEvent(a),!a.defaultPrevented)throw o}return n.then(o=>{for(const a of o||[])a.status==="rejected"&&i(a.reason);return t().catch(i)})},K="Llama-3.2-3B-Instruct-q4f16_1-MLC";function Q(r){return r.role==="system"?{role:"system",content:r.content}:r.role==="assistant"?{role:"assistant",content:r.content}:{role:"user",content:r.content}}class Z{constructor(t={}){this.opts=t}engine=null;get modelName(){return this.opts.model??K}ready(){return this.engine!==null}async load(){if(this.engine)return;const{CreateMLCEngine:t}=await J(async()=>{const{CreateMLCEngine:s}=await import("./index-6jKzjS7h.js");return{CreateMLCEngine:s}},[],import.meta.url),e=this.opts.initProgressCallback?{initProgressCallback:this.opts.initProgressCallback}:void 0;this.engine=await t(this.modelName,e)}async chat(t,e={}){if(!this.engine)throw new Error("WebLLM-Engine nicht geladen — zuerst `load()` aufrufen.");const s=await this.engine.chat.completions.create({messages:t.map(Q),temperature:e.temperature??.7,max_tokens:e.maxTokens??1024}),n=s.choices[0]?.message?.content??"",i=s.usage?{promptTokens:s.usage.prompt_tokens,completionTokens:s.usage.completion_tokens,totalTokens:s.usage.total_tokens}:void 0;return{content:n,usage:i}}async unload(){this.engine&&(await this.engine.unload(),this.engine=null)}}function X(r,t){if(t>=100)return 3;const e=(r??"").toLowerCase();return/shader|compil|pipeline|finish/.test(e)?2:/cache|creating model|loading model/.test(e)?1:/fetch|download/.test(e)?0:1}class Y{constructor(t={}){this.opts=t}waechterModel=U;planerSelected=B;planerLoadedModel=null;waechter=null;planer=null;loading=null;loadingRole=null;degraded=!1;progress=null;get budgetMB(){return this.opts.vramBudgetMB??z}getWaechterModel(){return this.waechterModel}getPlannerModel(){return this.planerSelected}getLoadedPlannerModel(){return this.planerLoadedModel??this.planerSelected}selectWaechter(t){this.waechterModel===t||!m(t)||(this.waechterModel=t,this.emit("select",t,"waechter"))}selectPlanner(t){this.planerSelected===t||!m(t)||(this.planerSelected=t,this.emit("select",t,"planer"))}waechterReady(){return this.waechter!==null&&this.waechter.ready()}async loadWaechter(){if(this.waechterReady())return;const t=this.waechterModel;this.waechter=this.createEngine(t),this.loadingRole="waechter",this.emit("load",t,"waechter");try{await this.waechter.load()}catch(e){throw this.waechter=null,this.loadingRole=null,this.emit("error",t,e.message),e}this.loadingRole=null,this.emit("ready",t,"waechter")}async unloadWaechter(){this.waechter&&this.waechter.ready()&&(await this.waechter.unload(),this.emit("unload",this.waechterModel,"waechter")),this.waechter=null}async ensureWaechter(){return this.waechterReady()||await this.loadWaechter(),this.waechter}planerReady(){return this.planer!==null&&this.planer.ready()}async ensurePlanner(){if(this.planerReady())return this.planer;if(this.loading)return this.loading;this.loading=(async()=>{const t=this.planerLadder();let e=null;for(const n of t){const i=this.createEngine(n.model);this.loadingRole="planer";try{return this.emit("load",n.model,"planer"),await i.load(),this.planer=i,this.planerLoadedModel=n.model,this.loadingRole=null,this.emit("ready",n.model,"planer"),i}catch(o){e=o,this.emit("fallback",n.model,o.message)}}this.degraded=!0;const s=await this.ensureWaechter();return this.emit("degraded",void 0,e?e.message:"Planer nicht ladbar"),s})();try{return await this.loading}finally{this.loading=null}}async unloadPlanner(){this.planer&&this.planer.ready()&&(await this.planer.unload(),this.emit("unload",this.getLoadedPlannerModel(),"planer")),this.planer=null,this.planerLoadedModel=null,this.degraded=!1}getProgress(){return this.progress}status(){const t=m(this.waechterModel),e=m(this.planerSelected),s=(this.waechterReady()?t?.vramMB??0:0)+(this.planerReady()?m(this.getLoadedPlannerModel())?.vramMB??e?.vramMB??0:0);return{waechter:{model:this.waechterModel,loaded:this.waechterReady(),vramMB:t?.vramMB??0},planer:{model:this.planerSelected,loaded:this.planerReady(),vramMB:e?.vramMB??0},degraded:this.degraded,vram:{loadedMB:s,budgetMB:this.budgetMB}}}planerLadder(){const t=this.planerSelected;return t===B?[{model:t,vramMB:m(t)?.vramMB??0},{model:C,vramMB:m(C)?.vramMB??0}]:[{model:t,vramMB:m(t)?.vramMB??0}]}createEngine(t){const e=s=>{this.progress={model:t,text:s.text,progress:s.progress,timeElapsed:s.timeElapsed},this.emit("progress",t,this.loadingRole??"planer")};return new Z({model:t,initProgressCallback:e})}emit(t,e,s){this.opts.onEvent?.({action:t,model:e,note:s})}}function D(r){return`${r}_${Date.now()}_${Math.random().toString(36).slice(2,8)}`}class ee{constructor(t){this.session=t}all(){return this.session.tasks}create(t,e,s=null){const n=Date.now(),i={id:D("t"),parentId:s,title:t,detail:e,status:"pending",createdAt:n,updatedAt:n};return this.session.tasks.push(i),this.audit("task.created",i.id,t),i}children(t){return this.all().filter(e=>e.parentId===t)}setStatus(t,e,s){const n=this.all().find(i=>i.id===t);if(n)return n.status=e,n.updatedAt=Date.now(),s!==void 0&&(n.result=s),this.audit(`task.${e}`,n.id),n}pending(){return this.all().filter(t=>t.status==="pending")}next(){return this.pending().sort((t,e)=>t.createdAt-e.createdAt)[0]}pendingChildren(t){return this.pending().filter(e=>e.parentId===t)}nextExecutable(){return this.pending().sort((e,s)=>e.createdAt-s.createdAt).find(e=>this.pendingChildren(e.id).length===0)}allChildrenDone(t){const e=this.children(t);return e.length>0&&e.every(s=>s.status==="done")}audit(t,e,s){this.session.auditLog.push({id:D("a"),ts:Date.now(),actor:"agent",action:t,target:e,note:s}),this.session.updatedAt=Date.now()}}function R(r,t=220){const e=r.replace(/\s+/g," ").trim();return e.length>t?e.slice(0,t).trimEnd()+"…":e}const te=/status|aktueller stand|^stand|fortschritt|was (läuft|laeuft)/,se=/\b(ok|okay|beginne|beginnen|starte?|starten|los|weiter|go|fahre? fort|fahre? weiter|mach es|ausf[uü]hren|durchf[uü]hren)\b/,ne=/^(plane|mache?|erledige|schreibe|fasse|prüfe|pruefe|erstelle|baue|recherchiere)\b/;function u(r,t,e,s){r.session.auditLog.push({id:`a_${t.replace(/\./g,"_")}_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,ts:Date.now(),actor:"agent",action:t,target:e,note:s})}function W(r,t){return["Du bist der Planer. Zerlege die Aufgabe in Teilaufgaben.",t?`Erwarte genau ${t} Teilaufgaben.`:"Bestimme die passende Anzahl.","Antworte NUR mit kompaktem JSON (kein Markdown, kein Extra-Text):",'{"verstaendnis":"…","teilaufgaben":[{"id":"T1","beschreibung":"…","prioritaet":1}],"vorentscheidungen":["…"],"risiken_oder_offen":["…"]}',`Aufgabe: ${r}`].join(`
2
+ `)}function re(r,t){return["Erledige die Teilaufgabe vollständig und praktisch nutzbar.",r?`Gesamtaufgabe: ${r}`:null,`Teilaufgabe: ${t.title}`,t.detail?`Details: ${t.detail}`:null,"Regeln: Die Antwort IST das Ergebnis (kompakt, direkt nutzbar). Bei Code: vollständiger Code, keine Erklärungen."].filter(e=>e!==null).join(`
3
+ `)}class ie{constructor(t,e,s={}){this.doc=t,this.pool=e,this.cb=s,this.queue=new ee(t.session)}queue;working=!1;async plan(t,e){if(e===1){const l=await this.pool.ensureWaechter(),d=this.queue.create(t,"Einfache Aufgabe (Executor: Wächter)");u(this.doc,"plan.created",d.id,`simple · model=${l.modelName} · Executor=Wächter`),this.cb.onStatus?.(`Aufgabe geplant (Wächter): ${t}`),await this.persist(),this.cb.onTaskChange?.();return}const s=await this.pool.ensurePlanner(),n=this.pool.status().degraded;this.cb.onStatus?.(`Planer bereit: ${s.modelName}${n?" (DEGRADED)":""}`);let i=null,o="";for(let l=1;l<=2&&!i;l++){const d=l===1?W(t,e):W(t,e)+`
4
+
5
+ WICHTIG: Antworte NUR mit dem JSON-Objekt.`,g=await s.chat([{role:"user",content:d}]);o=g.content,i=this.tryParsePlan(g.content)}if(!i||!i.teilaufgaben?.length){u(this.doc,"plan.error",void 0,`Planer-JSON unlesbar nach 2 Versuchen: ${o.slice(0,200)}`),this.cb.onStatus?.("Planer-JSON unlesbar — Abbruch (Audit: plan.error). Planer wird entladen."),await this.pool.unloadPlanner(),await this.persist(),this.cb.onTaskChange?.();return}const a=this.queue.create(t,i.verstaendnis??"Ziel"),c=i.teilaufgaben.slice().sort((l,d)=>(l.prioritaet??99)-(d.prioritaet??99));c.forEach(l=>this.queue.create(l.beschreibung??"Teilaufgabe",void 0,a.id)),i.verstaendnis&&this.memory("decision",`Plan: ${i.verstaendnis}`,["planer","plan"]),u(this.doc,"plan.created",a.id,`model=${s.modelName} · ${c.length} Teilaufgaben${n?" · DEGRADED":""}`),await this.pool.unloadPlanner(),this.cb.onChat?.(`Plan: ${c.length} Teilaufgaben — `+c.map((l,d)=>`${d+1}) ${l.beschreibung??"…"}`).join(" · "),"planer"),this.cb.onStatus?.(`Plan fertig: ${c.length} Teilaufgaben · Planer entladen (VRAM frei).`),await this.persist(),this.cb.onTaskChange?.()}async runStep(){const t=this.queue.nextExecutable();if(!t){this.cb.onStatus?.("Keine offenen Aufgaben mehr — Session abgeschlossen.");return}const e=t.parentId?this.doc.session.tasks.find(a=>a.id===t.parentId)??null:null;e&&e.status==="pending"&&this.queue.setStatus(e.id,"in_progress"),this.queue.setStatus(t.id,"in_progress");const s=t.parentId!==null?await this.pool.ensurePlanner():await this.pool.ensureWaechter(),n=t.parentId!==null?"planer":"waechter";let i=1,o=1;if(t.parentId){const a=this.doc.session.tasks.filter(c=>c.parentId===t.parentId);o=a.length,i=a.findIndex(c=>c.id===t.id)+1}else{const a=this.doc.session.tasks.filter(c=>c.status!=="done");o=a.length,i=a.indexOf(t)+1}this.cb.onChat?.(`⏳ ${i}/${o} · ${t.title} …`,n);try{const a=Date.now(),c=e?e.title:null,l=await s.chat([{role:"user",content:re(c,t)}]);this.queue.setStatus(t.id,"done",l.content);const d=l.usage?.totalTokens??(l.usage?(l.usage.promptTokens??0)+(l.usage.completionTokens??0):void 0),g=Math.round((Date.now()-a)/1e3);u(this.doc,"llm.execute",t.id,`model=${s.modelName} · ${g} s${d!==void 0?` · tokens=${d}`:""}`),this.cb.onChat?.(`✓ ${t.title} — ${R(l.content)}`,n);const b=A(l.content);b&&(u(this.doc,"artifact.ready",t.id,`html · ${b.filename} · ${b.bytes} B`),this.cb.onChat?.(`📦 ${b.filename} bereit — Vorschau & Download im Tab „Arbeit"`,n)),this.cb.onStatus?.(`Fertig: ${t.title} (${s.modelName}${d!==void 0?`, ${d} Tokens`:""}).`)}catch(a){this.queue.setStatus(t.id,"pending"),u(this.doc,"llm.error",t.id,a.message),this.cb.onChat?.(`✗ ${t.title} — ${a.message}`,n),this.cb.onStatus?.(`Fehler bei „${t.title}": ${a.message}`)}if(e&&this.queue.allChildrenDone(e.id)){const a=this.queue.children(e.id).length;this.queue.setStatus(e.id,"done",`Ziel erreicht: ${a}/${a} Teilaufgaben`),u(this.doc,"task.root_done",e.id,`${a}/${a}`)}await this.persist(),this.cb.onTaskChange?.()}async chat(t){const e=t.trim();u(this.doc,"chat.user",void 0,e.slice(0,200));const s=e.toLowerCase();if(te.test(s)){const n=this.statusReply();return u(this.doc,"chat.reply",void 0,"intent=status · Template (0 LLM-Tokens)"),{text:n,badge:"waechter"}}if(se.test(s))return this.hasOpenTasks()?(u(this.doc,"chat.reply",void 0,"intent=ausfuehrung · Ausführung gestartet"),this.runAll(),{text:"Alles klar — ich beginne jetzt. Du siehst jeden Schritt hier im Chat, am Ende bekommst du das Ergebnis.",badge:"waechter"}):(u(this.doc,"chat.reply",void 0,"intent=ausfuehrung · keine offenen Aufgaben"),{text:"Keine offenen Aufgaben. Was ist die neue Aufgabe? Beschreib kurz, was ich erledigen soll — ich plane und starte sie.",badge:"waechter"});if(ne.test(s)||e.length>80){const n=e.length>120?e.slice(0,120)+"…":e;return u(this.doc,"chat.reply",void 0,`intent=task · goal="${e.slice(0,120)}"`),(async()=>(await this.plan(e),this.hasOpenTasks()&&await this.runAll()))(),{text:`Aufgabe angenommen: „${n}“ — ich zerlege sie in Teilaufgaben (Planer) und starte danach die Ausführung. Jeder Schritt erscheint hier im Chat, am Ende das Ergebnis.`,badge:"planer"}}try{const n=await this.pool.ensurePlanner(),i=!this.pool.planerReady(),o=await n.chat([{role:"user",content:["Du bist der Planer — der kluge Assistent des Users.","Antworte auf die Nachricht kurz, präzise und in Deutsch (max. 4 Sätze).","Wenn die Nachricht eine Aufgabe zu sein scheint, beschreibe kurz, wie du sie umsetzen würdest — und bitte um das Kommando „beginne“.","Wenn unklar ist, was der User will, stell eine kurze Gegenfrage.",`Nachricht: ${e}`].join(`
6
+ `)}],{temperature:.5,maxTokens:250}),a=o.content.trim()||"Was ist die neue Aufgabe? Beschreib kurz, was ich erledigen soll.";return u(this.doc,"chat.reply",void 0,`intent=frage · model=${n.modelName} · tokens=${o.usage?.totalTokens??"?"}${i?" · DEGRADED":""}`),!i&&!this.working&&await this.pool.unloadPlanner(),{text:a,badge:i?"waechter":"planer"}}catch(n){return u(this.doc,"chat.error",void 0,n.message),{text:`Das habe ich gerade nicht beantwortet (${n.message}). Was ist die neue Aufgabe?`,badge:"waechter"}}}hasOpenTasks(){return this.doc.session.tasks.some(t=>t.status!=="done")}async runAll(){if(this.working)return this.cb.onStatus?.("Ausführung läuft bereits — ich kümmere mich drum."),0;this.working=!0,this.cb.onWork?.(!0);const t=new Set(this.doc.session.tasks.filter(n=>n.status==="done").map(n=>n.id));let e=0;try{for(;e<20;){const n=this.doc.session.tasks.filter(o=>o.status!=="done").length;if(n===0||(await this.runStep(),e++,this.doc.session.tasks.filter(o=>o.status!=="done").length>=n))break}}finally{this.working=!1,this.cb.onWork?.(!1)}const s=this.doc.session.tasks.filter(n=>n.status!=="done").length;if(this.cb.onStatus?.(s===0?`Ausführung abgeschlossen: ${e} ${e===1?"Schritt":"Schritte"}, alle Aufgaben erledigt.`:`Ausführung pausiert nach ${e} ${e===1?"Schritt":"Schritten"} — ${s} Aufgaben offen (Audit: llm.error prüfen).`),e>0){const n=this.doc.session.tasks.filter(o=>o.status==="done"&&!t.has(o.id)).sort((o,a)=>o.createdAt-a.createdAt),i=[s===0?`Fertig — alle ${n.length} Aufgabe${n.length===1?"":"n"} erledigt:`:`Pausiert nach ${e} ${e===1?"Schritt":"Schritten"} — ${s} Aufgabe${s===1?"":"n"} noch offen:`];for(const o of n)i.push(o.result?`• ${o.title}: ${R(o.result,200)}`:`• ${o.title}`);if(s>0)for(const o of this.doc.session.tasks.filter(a=>a.status!=="done"))n.some(a=>a.id===o.id)||i.push(`• offen: ${o.title} (Audit: llm.error)`);s===0&&n.some(o=>o.result)&&i.push("(Volltext je Teilaufgabe: Tab „Arbeit“)"),this.cb.onChat?.(i.join(`
7
+ `),n.some(o=>o.parentId!==null)?"planer":"waechter")}return e}statusReply(){const t=this.doc.session,e=this.pool.status(),s=t.tasks.filter(c=>c.status!=="done").length,n=t.tasks.length-s,i=m(e.waechter.model)?.label??e.waechter.model,o=m(e.planer.model)?.label??e.planer.model,a=[`Session ${t.id} · ${t.title} · ${t.status}`,`Aufgaben: ${t.tasks.length} gesamt · ${s} offen · ${n} erledigt`,`Wächter: ${e.waechter.loaded?`bereit (${i})`:"nicht geladen"} · ${e.waechter.loaded?Math.round(e.waechter.vramMB)+" MB VRAM":"0 MB"}`,`Planer: ${e.planer.loaded?`bereit (${o})`:e.degraded?"DEGRADED (Wächter übernimmt)":"nicht geladen"} · ${e.planer.loaded?Math.round(e.planer.vramMB)+" MB VRAM":"0 MB"}`,`VRAM-Budget: ${Math.round(e.vram.loadedMB)} / ${e.vram.budgetMB} MB`];return s>0&&a.push("→ Sag „beginne“, um die Ausführung zu starten."),e.degraded&&a.push("Achtung: DEGRADED — Planer nicht ladbar, Wächter übernimmt Aufgaben."),a.join(`
8
+ `)}tryParsePlan(t){if(!t)return null;const e=t.replace(/```json/gi,"```").replace(/```/g,"").trim(),s=e.indexOf("{"),n=e.lastIndexOf("}");if(s===-1||n<=s)return null;try{const i=JSON.parse(e.slice(s,n+1));return i&&typeof i=="object"&&Array.isArray(i.teilaufgaben)?i:null}catch{return null}}memory(t,e,s){const n=Date.now();this.doc.session.memory.push({id:`m_${n}_${Math.random().toString(36).slice(2,6)}`,ts:n,kind:t,content:e,tags:s})}async persist(){this.doc.session.updatedAt=Date.now(),await w.save(this.doc)}}class ae{constructor(t,e=.8,s){this.ctx=t,this.threshold=e,this.onFlush=s}ratio(){return this.ctx.limit===0?0:this.ctx.tokens/this.ctx.limit}consume(t){this.ctx.tokens+=t}check(){const t=this.ratio();if(t<this.threshold)return{triggered:!1,ratio:t};const e=`Context ${Math.round(t*100)}% ≥ ${Math.round(this.threshold*100)}%`;return this.onFlush?.(e),this.ctx.tokens=0,{triggered:!0,ratio:t,reason:e}}}class oe{constructor(t,e=1500,s=600,n=.8,i={}){this.doc=t,this.tickMs=e,this.tokensPerStep=s,this.threshold=n,this.cb=i,this.watcher=new ae(this.ctx,this.threshold,o=>this.flush(o))}ctx={tokens:0,limit:4096};step=0;timer=null;watcher;get running(){return this.timer!==null}start(){this.timer||(this.timer=setInterval(this.tick,this.tickMs))}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),w.save(this.doc).catch(()=>{})}reset(){this.timer&&(clearInterval(this.timer),this.timer=null),this.step=0,this.ctx.tokens=0}tick=()=>{this.step++;const t=Date.now(),e=`KERN-Loop Schritt ${this.step}`;this.doc.session.tasks.push({id:`t_kern_${t}`,parentId:null,title:e,status:"done",result:"Arbeitsschritt (simuliert)",createdAt:t,updatedAt:t}),this.doc.session.auditLog.push({id:`a_step_${t}`,ts:t,actor:"agent",action:"loop.step",target:e,note:"mechanischer Loop-Schritt (simuliert)"}),this.watcher.consume(this.tokensPerStep);const s=this.watcher.check();this.cb.onTick?.({step:this.step,tokens:this.ctx.tokens,limit:this.ctx.limit,ratio:this.watcher.ratio(),threshold:this.threshold,flushed:s.triggered,reason:s.reason})};flush(t){const e=Date.now();this.doc.session.memory.push({id:`m_flush_${e}`,ts:e,kind:"note",content:`Tokenwächter-Flush: ${t}`,tags:["tokenwaechter","flush"]}),this.doc.session.auditLog.push({id:`a_flush_${e}`,ts:e,actor:"agent",action:"tokenwatcher.flush",note:t}),w.save(this.doc).catch(()=>{})}}function _(r){const t=new Blob([r.html],{type:"text/html;charset=utf-8"}),e=URL.createObjectURL(t),s=document.createElement("a");s.href=e,s.download=r.filename,s.click(),URL.revokeObjectURL(e)}const le=["Download","Cache","Shader","Bereit"];function h(r){return String(r).replace(/[&<>"]/g,t=>t==="&"?"&amp;":t==="<"?"&lt;":t===">"?"&gt;":"&quot;")}const ce=()=>new Date().toLocaleTimeString("de-DE");function de(r){return r.startsWith("llm")?"llm":r.startsWith("plan")||r.startsWith("task")||r.startsWith("chat")||r.startsWith("artifact")?"task":r.startsWith("tokenwatcher")||r.startsWith("loop")||r.startsWith("kern")?"guard":"session"}class he{constructor(t){this.root=t,this.root.addEventListener("click",e=>this.onArtifactClick(e)),this.el("pvClose")?.addEventListener("click",()=>this.closePreview()),this.el("pvDownload")?.addEventListener("click",()=>this.pvDownload())}onSend=null;onLoad=null;onUnload=null;onLoop=null;onStep=null;onReset=null;onExport=null;onImport=null;onArtifact=null;roles={waechter:{status:"idle",label:"",mb:0,pct:0,stage:0,time:0,raw:""},planer:{status:"idle",label:"",mb:0,pct:0,stage:0,time:0,raw:""}};taskList=[];logs=[];memList=[];filter="all";budget=4096;liveSince=null;liveTimer=null;pvArtifact=null;pvTaskId=null;progress(t,e,s){const n=this.roles[t];n.status="loading",n.mb=s,n.pct=Math.min(100,(e.progress||0)*100),n.time=e.timeElapsed||n.time,n.raw=e.text||"",n.stage=X(e.text,n.pct),n.pct>=100&&(n.stage=3),e.model&&(n.label=m(e.model)?.label??e.model),this.renderRole(t),this.renderVram()}ready(t,e){const s=this.roles[t];s.status="ready",s.pct=100,s.stage=3,e&&(s.label=e),this.renderRole(t),this.renderVram()}unloaded(t){const e=this.roles[t];e.status="idle",e.pct=0,e.stage=0,e.time=0,e.raw="",this.renderRole(t),this.renderVram()}error(t,e){const s=this.roles[t];s.status="error",s.raw=e,this.renderRole(t),this.renderVram()}degraded(t,e){const s=this.roles[t];s.status="degraded",s.raw=e,this.renderRole(t)}vramBudget(t){this.budget=t,this.renderVram()}log(t,e,s){this.logs.push({kind:t,name:e,msg:s,t:ce()}),this.logs.length>1e3&&this.logs.shift(),this.renderFeed(),this.renderAudit()}seedLogs(t){this.logs=t.map(e=>({kind:de(e.action),name:e.action,msg:e.note??e.target??"",t:new Date(e.ts).toLocaleTimeString("de-DE")})),this.renderFeed(),this.renderAudit()}setFilter(t){this.filter=t,this.renderAudit()}tasks(t){this.taskList=t.slice(),this.renderTasks()}memory(t){this.memList=t.slice(),this.renderMem()}context(t,e,s=.8){const n=this.el("ctxTxt");n&&(n.textContent=e?`${t} / ${e} Tokens (${Math.round(t/e*100)}% · Schwelle ${Math.round(s*100)}%)`:`${t} Tokens`);const i=this.el("ctxBar");if(i){const o=e?Math.min(100,t/e*100):0;i.style.width=`${o}%`,i.style.background=o>85?"var(--err)":o>65?"var(--warn)":"var(--ok)"}}loop(t){this.el("led")?.classList.toggle("on",t);const e=this.el("loopTxt");e&&(e.textContent=t?"läuft":"gestoppt")}session(t,e,s){const n=this.el("sess");n&&(n.innerHTML=`Session ${h(t)} · ${h(e)} · <b>${h(s)}</b>`)}say(t,e,s){const n=this.el("msgs");if(!n)return;const i=document.createElement("div");if(i.className="m "+t,t==="agent"){const o=s?`<span class="badge ${s==="planer"?"p":"w"}">${s==="planer"?"Planer":"Wächter"}</span>`:"";i.innerHTML=`<div class="who">Agent ${o}</div>`+h(e)}else i.textContent=e;n.appendChild(i),n.scrollTop=n.scrollHeight}typing(t){const e=this.el("msgs");if(e&&(e.querySelector(".typing-wrap")?.remove(),t)){const s=document.createElement("div");s.className="m agent typing-wrap",s.innerHTML='<span class="typing"><i></i><i></i><i></i></span>',e.appendChild(s),e.scrollTop=e.scrollHeight}}chatState(t){const e=this.el("chatState");e&&(e.textContent=t)}live(t,e=""){this.liveSince=t?Date.now():null,this.el("liveNow")?.classList.toggle("busy",t!==null);const s=this.el("lnAction");s&&(s.textContent=t??"bereit");const n=this.el("lnDetail");n&&(n.textContent=t?e:"warte auf Aufgabe");const i=this.el("lnTime");i&&(i.textContent=""),this.liveTimer&&(clearInterval(this.liveTimer),this.liveTimer=null),t&&(this.liveTimer=setInterval(()=>{if(!this.liveSince)return;const o=Math.round((Date.now()-this.liveSince)/1e3),a=this.el("lnTime");a&&(a.textContent=`${o} s`)},1e3))}onArtifactClick(t){const e=t.target.closest("button[data-art]");if(!e)return;const s=this.taskList.find(i=>i.id===e.dataset.art),n=s?A(s.result):null;!s||!n||(e.dataset.artact==="download"?(_(n),this.onArtifact?.(s.id,"download")):(this.showPreview(s.id,s.title,n),this.onArtifact?.(s.id,"preview")))}showPreview(t,e,s){this.pvArtifact=s,this.pvTaskId=t;const n=this.el("pvTitle");n&&(n.textContent=`${s.filename} — ${e}`);const i=this.el("pvFrame");i&&(i.srcdoc=s.html),this.el("pvModal")?.classList.add("open")}closePreview(){this.el("pvModal")?.classList.remove("open");const t=this.el("pvFrame");t&&(t.srcdoc=""),this.pvArtifact=null,this.pvTaskId=null}pvDownload(){this.pvArtifact&&(_(this.pvArtifact),this.pvTaskId&&this.onArtifact?.(this.pvTaskId,"download"))}el(t){return this.root.querySelector("#"+t)}renderRole(t){const e=this.roles[t],s=this.el("m-"+t),n=this.el("pill-"+t),i=this.el("load-"+t);if(!s||!n||!i)return;if(s.classList.toggle("loading",e.status==="loading"),s.classList.toggle("ready",e.status==="ready"),s.classList.toggle("error",e.status==="error"),s.classList.toggle("degraded",e.status==="degraded"),n.className="pill "+{idle:"idle",loading:"loading",ready:"ready",error:"error",degraded:"degraded"}[e.status],n.textContent={idle:"nicht geladen",loading:"lädt …",ready:"bereit",error:"Fehler",degraded:"⚠ DEGRADED"}[e.status],e.status==="idle"){i.innerHTML="";return}if(e.status==="error"){i.innerHTML=`<div class="raw err" title="${h(e.raw)}">${h(e.raw)}</div>`;return}if(e.status==="degraded"){i.innerHTML=`<div class="raw warn">Wächter übernimmt: ${h(e.raw||"Planer nicht ladbar")}</div>`;return}const o=e.mb*e.pct/100,a=e.time>0?o/e.time:0,c=e.status==="loading"&&a>0?Math.max(0,Math.round((e.mb-o)/a)):null,l=le.map((d,g)=>`<div class="step ${e.status==="ready"||g<e.stage?"done":g===e.stage&&e.status==="loading"?"act":""}"><i></i>${d}</div>`).join("");i.innerHTML=`
9
+ <div class="steps">${l}</div>
10
+ <div class="pct"><b>${Math.round(e.pct)}%</b><span>${h(e.label)} · ≈ ${Math.round(e.mb)} MB</span></div>
11
+ <div class="pbar"><i style="width:${e.pct}%"></i></div>
12
+ <div class="stats" style="margin-top:10px">
13
+ <div class="stat"><small>Geladen</small><b>${Math.round(o)} MB</b></div>
14
+ <div class="stat"><small>Tempo</small><b>${a?a.toFixed(1)+" MB/s":"–"}</b></div>
15
+ <div class="stat"><small>${e.status==="ready"?"Dauer":"Restzeit"}</small><b>${e.status==="ready"?Math.round(e.time)+" s":c!=null?"~"+c+" s":"–"}</b></div>
16
+ </div>
17
+ ${e.raw?`<div class="raw" title="${h(e.raw)}">${h(e.raw)}</div>`:""}`}renderVram(){const t=a=>{const c=this.roles[a];return c.status==="ready"?c.mb:c.status==="loading"?c.mb*c.pct/100:0},e=t("waechter"),s=t("planer"),n=this.el("vW"),i=this.el("vP"),o=this.el("vramTxt");n&&(n.style.width=`${e/this.budget*100}%`),i&&(i.style.width=`${s/this.budget*100}%`),o&&(o.textContent=`${Math.round(e+s)} / ${this.budget} MB`)}renderFeed(){const t=this.el("feed");if(t){const s=t.scrollTop+t.clientHeight>=t.scrollHeight-40,n=this.logs.slice(-200);t.innerHTML=n.map(i=>`<div class="log ${i.kind}"><time>${i.t}</time><span class="k">${h(i.name)}</span><span class="msg">${h(i.msg)}</span></div>`).join(""),s&&(t.scrollTop=t.scrollHeight)}const e=this.el("nLive");e&&(e.textContent=String(this.logs.length))}renderAudit(){const t=this.el("logs");if(t){const s=t.scrollTop+t.clientHeight>=t.scrollHeight-40,n=this.logs.filter(i=>this.filter==="all"||i.kind===this.filter).slice().reverse();t.innerHTML=n.length?n.map(i=>`<div class="log ${i.kind}"><time>${i.t}</time><span class="k">${h(i.name)}</span><span class="msg">${h(i.msg)}</span></div>`).join(""):'<div class="empty">Keine Einträge.</div>',s&&(t.scrollTop=t.scrollHeight)}const e=this.el("nAudit");e&&(e.textContent=String(this.logs.length))}renderTasks(){const t=this.el("tasks"),e=this.el("nWork");if(e&&(e.textContent=String(this.taskList.length)),!t)return;if(!this.taskList.length){t.innerHTML='<div class="empty">Noch keine Aufgaben.<br>Schreib im Chat oder starte den Loop.</div>';return}const s=new Map;for(const i of this.taskList){const o=s.get(i.parentId)??[];o.push(i),s.set(i.parentId,o)}const n=(i,o)=>(s.get(i)??[]).slice().sort((c,l)=>c.createdAt-l.createdAt).map(c=>{const l=c.status==="done"?"done":c.status==="in_progress"?"run":"wait",d=c.status==="done"?"✓":c.status==="in_progress"?"":"○",g=c.parentId?'<span class="badge p">Planer</span>':'<span class="badge w">Wächter</span>',b=A(c.result),f=b?`<div class="art"><button class="btn sm" data-art="${h(c.id)}" data-artact="preview">👁 Vorschau</button><button class="btn sm pri" data-art="${h(c.id)}" data-artact="download">⬇ ${h(b.filename)}</button></div>`:"";return`<div class="task ${l}" style="padding-left:${16+o*18}px"><div class="ic">${d}</div><div><div class="t">${h(c.title)}</div>`+(c.detail?`<div class="s">${h(c.detail)}</div>`:"")+(c.result?`<div class="res">${h(c.result)}</div>`:"")+f+`<div class="s">Executor: ${g} · ${new Date(c.updatedAt).toLocaleTimeString("de-DE")}</div></div></div>`+n(c.id,o+1)}).join("");t.innerHTML=n(null,0)}renderMem(){const t=this.el("mem"),e=this.el("nMem");if(e&&(e.textContent=String(this.memList.length)),!t)return;const s=this.memList.slice().reverse();t.innerHTML=s.length?s.map(n=>`<div class="mem"><div class="mk"><span class="kind">${h(n.kind)}</span><time>${new Date(n.ts).toLocaleTimeString("de-DE")}</time>`+(n.tags.length?`<span class="tags">${n.tags.map(i=>`<i>${h(i)}</i>`).join("")}</span>`:"")+`</div><div class="v">${h(n.content)}</div></div>`).join(""):'<div class="empty">Gedächtnis ist leer.</div>'}}function ue(r,t){const e=l=>r.root.querySelector("#"+l),s=e("sel-waechter"),n=e("sel-planer"),i=(l,d)=>{l&&(l.innerHTML=q.map(g=>`<option value="${g.id}">${g.label} · ≈ ${Math.round(g.vramMB)} MB</option>`).join(""),l.value=d)};i(s,t.getWaechterModel()),i(n,t.getPlannerModel()),s?.addEventListener("change",()=>t.selectWaechter(s.value)),n?.addEventListener("change",()=>t.selectPlanner(n.value)),r.onLoad=l=>{l==="waechter"?t.loadWaechter():t.ensurePlanner()},r.onUnload=l=>{l==="waechter"?t.unloadWaechter():t.unloadPlanner()},r.root.querySelectorAll("[data-load]").forEach(l=>l.addEventListener("click",()=>r.onLoad?.(l.dataset.load))),r.root.querySelectorAll("[data-unload]").forEach(l=>l.addEventListener("click",()=>r.onUnload?.(l.dataset.unload))),e("kern-start")?.addEventListener("click",()=>r.onLoop?.(!0)),e("kern-stop")?.addEventListener("click",()=>r.onLoop?.(!1)),e("step-btn")?.addEventListener("click",()=>r.onStep?.()),e("export-btn")?.addEventListener("click",()=>r.onExport?.()),e("reset-btn")?.addEventListener("click",()=>r.onReset?.());const o=e("import-file");e("import-btn")?.addEventListener("click",()=>o?.click()),o?.addEventListener("change",l=>{const d=l.target.files?.[0];d&&r.onImport?.(d),l.target.value=""});const a=e("inp"),c=()=>{if(!a)return;const l=a.value.trim();l&&(a.value="",r.onSend?.(l))};e("send")?.addEventListener("click",c),a?.addEventListener("keydown",l=>{l.key==="Enter"&&!l.shiftKey&&(l.preventDefault(),c())}),r.root.querySelectorAll("[data-q]").forEach(l=>l.addEventListener("click",()=>{a&&(a.value=l.dataset.q??""),c()})),r.root.querySelectorAll(".tab").forEach(l=>l.addEventListener("click",()=>{r.root.querySelectorAll(".tab").forEach(d=>d.classList.toggle("act",d===l)),r.root.querySelectorAll(".pane").forEach(d=>d.classList.toggle("act",d.id==="pane-"+(l.dataset.tab??"")))})),r.root.querySelectorAll("[data-f]").forEach(l=>l.addEventListener("click",()=>{r.root.querySelectorAll("[data-f]").forEach(d=>d.classList.toggle("on",d===l)),r.setFilter(l.dataset.f??"all")}))}function ge(r){const t=Date.now();return{version:"0.1.0",session:{id:I(),title:r,createdAt:t,updatedAt:t,status:"active",tasks:[],auditLog:[],memory:[],knowledge:[]}}}const p=r=>r?m(r)?.label??r:"–",$=r=>r==="waechter"?"Wächter":"Planer";async function me(){const r=document.getElementById("app");if(!r)throw new Error("#app nicht gefunden");const e=await w.load()??ge("Neue Session");await w.save(e);const s=new he(r);s.vramBudget(4096),s.session(e.session.id,e.session.title,e.session.status),s.seedLogs(e.session.auditLog),s.tasks(e.session.tasks),s.memory(e.session.memory),s.loop(!1),s.context(0,4096);const n=new Y({onEvent:a=>{const c=a.note??"planer";switch(a.action){case"select":u(e,"pool.select",void 0,`${$(a.note)}: ${p(a.model)}`),s.log("session","pool.select",`${$(a.note)}: ${p(a.model)}`);return;case"load":u(e,"llm.load",void 0,`model=${a.model} role=${a.note}`),s.log("llm","llm.load",`${$(a.note)}: ${p(a.model)}`),s.live(`${$(a.note)} lädt …`,p(a.model));return;case"progress":{const l=n.getProgress();l&&s.progress(c,l,m(l.model)?.vramMB??0);return}case"ready":u(e,"llm.ready",void 0,`model=${a.model} role=${a.note}`),s.ready(c,p(a.model)),s.log("llm","llm.ready",`${$(a.note)}: ${p(a.model)} bereit`),s.live(null);return;case"unload":u(e,"llm.unload",void 0,`model=${a.model}`),s.unloaded(c),s.log("llm","llm.unload",`${p(a.model)} — VRAM frei`),s.live(null);return;case"fallback":u(e,"llm.fallback",void 0,`${p(a.model)} nicht ladbar — nächstes Modell (${a.note})`),s.log("guard","llm.fallback",`${p(a.model)} → nächstes Modell`);return;case"degraded":u(e,"llm.degraded",void 0,a.note??"Planer nicht ladbar"),s.degraded(c,a.note??"Planer nicht ladbar"),s.log("guard","llm.degraded","DEGRADED: Planer nicht ladbar — Wächter übernimmt"),s.live(null);return;case"error":default:u(e,"llm.error",void 0,a.note??p(a.model)),s.error(c,a.note??"Fehler"),s.log("error","llm.error",a.note??"Fehler"),s.live(null)}}}),i=new ie(e,n,{onStatus:a=>s.log("task","agent",a),onTaskChange:()=>{s.tasks(e.session.tasks),s.memory(e.session.memory)},onWork:a=>{a?s.live("führt Aufgabe aus …","Agent"):s.live(null)},onChat:(a,c)=>s.say("agent",a,c??"waechter")}),o=new oe(e,1500,600,.8,{onTick:a=>{s.context(a.tokens,a.limit,a.threshold),a.flushed&&s.log("guard","tokenwatcher.flush",a.reason??"Context fast voll → in AAMS-B gesichert"),s.tasks(e.session.tasks),s.memory(e.session.memory)}});s.onSend=a=>void fe(a,i,s),s.onLoop=a=>{a?o.start():o.stop(),s.loop(a),s.log("session","kern.loop",a?"KERN-Loop gestartet":"KERN-Loop gestoppt")},s.onStep=()=>{s.live("führe nächsten Schritt aus …","Agent"),i.runStep().finally(()=>s.live(null))},s.onExport=()=>{N(e),s.log("session","session.export","JSON-Export gestartet")},s.onImport=a=>void pe(a,e,s),s.onReset=()=>void be(e,s,o),s.onArtifact=(a,c)=>{s.log("task",`artifact.${c}`,"Artefakt-Aktion (Vorschau/Download)"),(async()=>{const l=e.session.tasks.find(g=>g.id===a),d=l?A(l.result):null;u(e,`artifact.${c}`,a,d?`html · ${d.filename} · ${d.bytes} B`:"–"),await w.save(e)})()},ue(s,n),s.say("agent","Hallo! Ich bin dein lokaler Agent (WebGPU, AAMS). Was ist die neue Aufgabe? Beschreib kurz, was ich erledigen soll — ich zerlege sie in Teilaufgaben (Planer) und starte danach die Ausführung. Du siehst jeden Schritt hier im Chat, am Ende bekommst du das Ergebnis. „Was ist dein aktueller Stand?“ zeigt dir den Fortschritt.","waechter")}async function fe(r,t,e){e.say("user",r),e.chatState("denkt …"),e.typing(!0);try{const s=await t.chat(r);e.say("agent",s.text,s.badge)}catch(s){e.say("sys",`Fehler: ${s.message}`)}finally{e.typing(!1),e.chatState("bereit")}}async function pe(r,t,e){try{const s=F(await r.text());Object.assign(t.session,s.session),e.session(t.session.id,t.session.title,t.session.status),e.tasks(t.session.tasks),e.memory(t.session.memory),e.seedLogs(t.session.auditLog),e.log("session","session.import",`Import: ${r.name}`)}catch(s){e.say("sys",`Import fehlgeschlagen: ${s.message}`)}}async function be(r,t,e){const s=r.session;if(confirm(`Gedächtnis KOMPLETT zurücksetzen?
18
+
19
+ Wird gelöscht: ${s.tasks.length} Tasks · ${s.auditLog.length} Audit-Einträge · ${s.memory.length} Memory-Einträge · ${s.knowledge.length} Wissen.
20
+ Der KERN-Loop wird gestoppt. Ein Safety-Export (JSON) wird automatisch ausgelöst.`))try{e.reset(),N(r,`aams-safety-${r.session.id}.json`),t.log("session","session.reset","Zurücksetzen … (Safety-Export ausgelöst)");const i=await j(r);t.session(r.session.id,r.session.title,r.session.status),t.tasks(r.session.tasks),t.memory(r.session.memory),t.seedLogs(r.session.auditLog),t.context(0,4096),t.loop(!1),t.live(null),t.say("sys",`Gedächtnis zurückgesetzt → neue Session ${i.newId} (alter Stand als Safety-Export gesichert).`)}catch(i){t.tasks(r.session.tasks),t.memory(r.session.memory),t.seedLogs(r.session.auditLog),t.say("sys",`Fehler: ${i.message}`)}}const L=window.location.hash;if(L==="#doku"||L.startsWith("#doku/")){const r=L.startsWith("#doku/")?L.slice(6):"";window.location.replace("./doku.html"+(r?"#"+r:""))}else me().catch(r=>{const t=r instanceof Error?r.message:String(r),e=document.querySelector("#msgs");if(e){const s=document.createElement("div");s.className="m sys",s.textContent=`Boot fehlgeschlagen: ${t}`,e.appendChild(s)}});
doku.html CHANGED
@@ -14,8 +14,11 @@
14
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
15
  }
16
  * { box-sizing: border-box; }
 
17
  body { margin: 0; background: var(--bg); color: var(--txt); line-height: 1.65;
18
  font-family: "Segoe UI", system-ui, -apple-system, Arial, sans-serif; }
 
 
19
  a { color: var(--acc); }
20
  code { font-family: var(--mono); background: var(--panel2); border: 1px solid var(--line);
21
  padding: 0 5px; border-radius: 5px; font-size: .88em; }
@@ -104,6 +107,11 @@
104
  <li><a href="#waechter">Ein eigenes Modell für den Wächter</a></li>
105
  <li><a href="#links">Links</a></li>
106
  </ol>
 
 
 
 
 
107
  </nav>
108
 
109
  <h2 id="warum">1. Warum machen wir das?</h2>
@@ -534,5 +542,21 @@
534
  <li><strong>Mitarbeit:</strong> Feedback, Issues und Pull Requests sind willkommen — siehe README des Repositories.</li>
535
  </ul>
536
  </main>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  </body>
538
  </html>
 
14
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
15
  }
16
  * { box-sizing: border-box; }
17
+ html { scroll-behavior: smooth; }
18
  body { margin: 0; background: var(--bg); color: var(--txt); line-height: 1.65;
19
  font-family: "Segoe UI", system-ui, -apple-system, Arial, sans-serif; }
20
+ .hl { animation: hl 1.8s ease-out; border-radius: 10px; }
21
+ @keyframes hl { 0% { background: rgba(77,163,255,.22); } 100% { background: transparent; } }
22
  a { color: var(--acc); }
23
  code { font-family: var(--mono); background: var(--panel2); border: 1px solid var(--line);
24
  padding: 0 5px; border-radius: 5px; font-size: .88em; }
 
107
  <li><a href="#waechter">Ein eigenes Modell für den Wächter</a></li>
108
  <li><a href="#links">Links</a></li>
109
  </ol>
110
+ <p class="meta" style="margin:10px 0 0">
111
+ <strong>Deep-Links (Anker):</strong> <code>doku.html#warum</code> · <code>#ziel</code> ·
112
+ <code>#stand</code> · <code>#forschung</code> · <code>#probleme</code> · <code>#waechter</code> ·
113
+ <code>#links</code> — und aus der App: <code>index.html#doku</code> bzw. <code>index.html#doku/probleme</code>
114
+ </p>
115
  </nav>
116
 
117
  <h2 id="warum">1. Warum machen wir das?</h2>
 
542
  <li><strong>Mitarbeit:</strong> Feedback, Issues und Pull Requests sind willkommen — siehe README des Repositories.</li>
543
  </ul>
544
  </main>
545
+
546
+ <script>
547
+ // Anker-Navigation (WP-APP-DOKU): Ziel-Sektion sanft einscrollen + kurz hervorheben,
548
+ // wenn die Seite mit Anker geöffnet wird (Deep-Link aus App/Chat/Foren).
549
+ (function () {
550
+ const id = window.location.hash.slice(1);
551
+ if (!id) return;
552
+ const el = document.getElementById(id);
553
+ if (!el) return;
554
+ requestAnimationFrame(function () {
555
+ el.scrollIntoView({ behavior: "smooth", block: "start" });
556
+ el.classList.add("hl");
557
+ setTimeout(function () { el.classList.remove("hl"); }, 1800);
558
+ });
559
+ })();
560
+ </script>
561
  </body>
562
  </html>
index.html CHANGED
@@ -5,7 +5,7 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
  <title>webgpu-agent · Dashboard</title>
7
  <!-- Theme: src/ui/theme.css (Import in main.ts) — WP-UI-DASH §3.2 -->
8
- <script type="module" crossorigin src="./assets/main-DhZnfRk6.js"></script>
9
  <link rel="stylesheet" crossorigin href="./assets/main-BFlNjmg3.css">
10
  </head>
11
  <body>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
  <title>webgpu-agent · Dashboard</title>
7
  <!-- Theme: src/ui/theme.css (Import in main.ts) — WP-UI-DASH §3.2 -->
8
+ <script type="module" crossorigin src="./assets/main-VmvG1jUP.js"></script>
9
  <link rel="stylesheet" crossorigin href="./assets/main-BFlNjmg3.css">
10
  </head>
11
  <body>