@madh-io/alfred-ai 0.19.0-jarvis.1188 → 0.19.0-jarvis.1189

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bundle/index.js +4 -4
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -6396,7 +6396,7 @@ Antworte "ja" oder "nein".`;try{if(e.platform==="telegram"&&i){let o=[[{text:"\u
6396
6396
  ${E}`:`\u2705 ${y.label}`:`\u274C ${y.label} fehlgeschlagen: ${_?.error??"unknown"}`;await g.sendMessage(e,T)}}else g&&await g.sendMessage(e,`\u274C Skill "${y.skillName}" nicht registriert.`)}break}case"dismiss":{await this.confirmRepo.resolve(f.id,"rejected"),g&&await g.sendMessage(e,`\u{1F645} ${y.label}: Aktion verworfen \u2014 keine weitere Eskalation.`);break}case"cancel-item":{if(await this.confirmRepo.resolve(f.id,"rejected"),this.projectRepo&&y.openItemId)try{await this.projectRepo.updateOpenItemStatus(y.openItemId,"cancelled"),g&&await g.sendMessage(e,"\u{1F5D1} Open-Item geschlossen (cancelled).")}catch(w){g&&await g.sendMessage(e,`\u26A0\uFE0F Konnte Item nicht schlie\xDFen: ${w.message}`)}else g&&await g.sendMessage(e,`\u26A0\uFE0F ${y.label}: kein Projekt-Repo verkabelt.`);break}case"defer":{await this.confirmRepo.resolve(f.id,"expired");let w=y.deferHours??24;if(this.memoryRepo&&y.openItemId)try{let _=new Date(Date.now()+w*36e5).toISOString();await this.memoryRepo.saveWithMetadata(n.masterUserId||n.userId,`open_item_snoozed:${y.openItemId}`,`Snoozed bis ${_}`,"general","feedback",1,"auto"),g&&await g.sendMessage(e,`\u23F0 Zur\xFCckgestellt \u2014 Erinnerung in ${w}h.`)}catch(_){g&&await g.sendMessage(e,`\u26A0\uFE0F Defer fehlgeschlagen: ${_.message}`)}else g&&await g.sendMessage(e,"\u23F0 Zur\xFCckgestellt.");break}}this.activityLogger?.logConfirmation({confirmationId:f.id,skillName:f.skillName,description:f.description,source:f.source,sourceId:f.sourceId,outcome:"approved",userId:n.userId,platform:t,chatId:e})}catch(w){this.logger.error({err:w,confirmationId:f.id,key:o},"Extra-Action fehlgeschlagen"),g&&await g.sendMessage(e,`\u274C ${y.label} fehlgeschlagen: ${w.message}`)}return!0}if(u){await this.confirmRepo.resolve(f.id,"approved");try{let w=hf(f);if(w){let _=await this.confirmRepo.findAllPending(e,t);for(let E of _){if(E.id===f.id)continue;let T=hf(E);T&&T===w&&(await this.confirmRepo.resolve(E.id,"expired"),this.logger.info({resolved:E.id,by:f.id,topic:w},"Auto-resolved sibling confirmation (same topic key)"))}}}catch{}let y=this.skillRegistry.get(f.skillName);if(y)try{let w=await this.skillSandbox.execute(y,f.skillParams,n);if(w&&!w.success)throw new Error(w.error??"Skill returned success=false");if(g){let _=w?.display??w?.data?String(w.display??JSON.stringify(w.data)):"",E=_?`\u2705 **${f.description}**
6397
6397
 
6398
6398
  ${_}`:`\u2705 Aktion ausgef\xFChrt: ${f.description}`;await g.sendMessage(e,E)}this.activityLogger?.logConfirmation({confirmationId:f.id,skillName:f.skillName,description:f.description,source:f.source,sourceId:f.sourceId,outcome:"approved",userId:n.userId,platform:t,chatId:e})}catch(w){this.logger.error({err:w,confirmationId:f.id},"Confirmed action failed"),g&&await g.sendMessage(e,`\u274C Aktion fehlgeschlagen: ${w instanceof Error?w.message:String(w)}`),this.activityLogger?.logConfirmation({confirmationId:f.id,skillName:f.skillName,description:f.description,source:f.source,sourceId:f.sourceId,outcome:"error",userId:n.userId,platform:t,chatId:e,error:w instanceof Error?w.message:String(w)})}else g&&await g.sendMessage(e,`\u274C Skill "${f.skillName}" nicht gefunden.`)}else await this.confirmRepo.resolve(f.id,"rejected"),g&&await g.sendMessage(e,`\u274C Aktion abgelehnt: ${f.description}`),this.activityLogger?.logConfirmation({confirmationId:f.id,skillName:f.skillName,description:f.description,source:f.source,sourceId:f.sourceId,outcome:"rejected",userId:n.userId,platform:t,chatId:e}),this.feedbackService?.onWatchRejected({userId:n.userId,watchId:f.sourceId,watchName:f.description,skillName:f.skillName,skillParams:f.skillParams??{},description:f.description});return!0}convRepo;setConversationRepository(e){this.convRepo=e}async handleWebDecision(e){let t=await this.confirmRepo.getById(e.id);if(!t){let r=await this.confirmRepo.getByIdAnyStatus(e.id);return r?{ok:!1,reason:`already-${r.status}`}:{ok:!1,reason:"not-found"}}let s="";if(this.convRepo)try{let r=await this.convRepo.findByPlatformChat(t.platform,t.chatId);r&&(s=r.id)}catch{}let n={userId:e.userId,chatId:t.chatId,platform:t.platform,conversationId:s,masterUserId:e.userId};return await this.checkForConfirmation(t.chatId,t.platform,`confirm:${t.id}:${e.decision}`,n)?{ok:!0}:{ok:!1,reason:"not-handled"}}async listPendingForUser(e,t=50){return typeof this.confirmRepo.findAllPendingForUser!="function"?[]:this.confirmRepo.findAllPendingForUser(e,t)}async expireTick(){try{let e=await this.confirmRepo.expireOld();for(let t of e){this.activityLogger?.logConfirmation({confirmationId:t.id,skillName:t.skillName,description:t.description,source:t.source,sourceId:t.sourceId,outcome:"expired",platform:t.platform,chatId:t.chatId});let s=this.adapters.get(t.platform);if(s)try{await s.sendMessage(t.chatId,`\u23F0 Best\xE4tigung abgelaufen: ${t.description}`)}catch{}}}catch(e){this.logger.error({err:e},"Confirmation expire tick failed")}}}});var QR={};Le(QR,{InsightTracker:()=>An});var An,$l=A(()=>{"use strict";An=class l{static{m(this,"InsightTracker")}memoryRepo;logger;skillState;static STATS_MEMORY_KEY="insight_tracker_stats";pendingBatches=[];stats=new Map;loaded=!1;MIN_SAMPLES=10;static REACTION_WINDOW_MS=120*6e4;constructor(e,t,s){this.memoryRepo=e,this.logger=t,this.skillState=s}async ensureLoaded(e){if(!this.loaded){try{let t;if(this.skillState?t=await this.skillState.get(e,"insight_tracker","stats"):t=(await this.memoryRepo.recall(e,l.STATS_MEMORY_KEY))?.value,t){let s=JSON.parse(t);for(let[n,i]of Object.entries(s))this.stats.set(n,i)}}catch{}this.loaded=!0}}async persistStats(e){let t=Object.fromEntries(this.stats);this.skillState?await this.skillState.set(e,"insight_tracker","stats",JSON.stringify(t)):await this.memoryRepo.save(e,l.STATS_MEMORY_KEY,JSON.stringify(t),"system")}trackInsightBatch(e,t){let s=e.filter((i,r)=>l.classifyInsightType(t[r]??"")==="actionable");if(s.length===0)return;this.pendingBatches.push({categories:s,sentAt:Date.now()});let n=Date.now()-l.REACTION_WINDOW_MS;this.pendingBatches=this.pendingBatches.filter(i=>i.sentAt>n)}trackInsightSent(e,t){this.trackInsightBatch([e],[t??""])}async onUserMessage(e,t){if(await this.ensureLoaded(e),this.pendingBatches.length===0)return;let s=Date.now()-l.REACTION_WINDOW_MS,n=this.pendingBatches.filter(a=>a.sentAt>s);if(n.length===0)return;let i=this.detectSentiment(t);if(i==="neutral")return;let r=n[n.length-1];for(let a of r.categories){let o=this.stats.get(a)??{positive:0,negative:0,ignored:0};i==="positive"?o.positive++:i==="negative"&&o.negative++,this.stats.set(a,o)}await this.persistStats(e).catch(()=>{}),this.pendingBatches=this.pendingBatches.filter(a=>a!==r),await this.savePreferences(e)}async onInsightResolved(e,t){await this.ensureLoaded(e);let s=this.stats.get(t)??{positive:0,negative:0,ignored:0};s.positive++,this.stats.set(t,s),await this.persistStats(e).catch(()=>{}),await this.savePreferences(e)}async processExpired(e){await this.ensureLoaded(e);let t=Date.now()-l.REACTION_WINDOW_MS,s=this.pendingBatches.filter(n=>n.sentAt<=t);for(let n of s)for(let i of n.categories){let r=this.stats.get(i)??{positive:0,negative:0,ignored:0};r.ignored++,this.stats.set(i,r)}this.pendingBatches=this.pendingBatches.filter(n=>n.sentAt>t),s.length>0&&(await this.persistStats(e).catch(()=>{}),this.savePreferences(e).catch(()=>{}))}detectSentiment(e){let t=e.toLowerCase().trim();return/\b(stopp|stop|nervig|nervt|aufhören|nicht mehr|zu viel|spam|egal|unwichtig|brauche? ich nicht|interessiert mich nicht|halt die fresse|sei still|ruhe)\b/.test(t)?"negative":/\b(danke|super|perfekt|genau|gut|toll|klasse|top|prima|stimmt|richtig|mach|erledige|kümmere|passt|alles klar|check|verstanden|noted|thx|thanks)\b/.test(t)?"positive":"neutral"}async savePreferences(e){for(let[t,s]of this.stats){let n=s.positive+s.negative+s.ignored;if(n<this.MIN_SAMPLES)continue;let i=s.positive/n,r=s.negative/n,a,o;if(i>=.5)a=`User findet ${t}-Insights n\xFCtzlich (${s.positive}/${n} positiv)`,o=Math.min(.95,.6+i*.3);else if(r>=.5)a=`User hat ${t}-Insights EXPLIZIT abgelehnt (${s.negative}/${n} negativ) \u2014 H\xE4ufigkeit reduzieren aber nicht eliminieren`,o=Math.min(.95,.6+r*.3);else continue;try{await this.memoryRepo.saveWithMetadata(e,`insight_pref_${t}`,a,"preferences","pattern",o,"auto"),this.logger.info({category:t,preference:a,total:n},"Insight preference saved")}catch{}}}static classifyInsightType(e){let t=e.toLowerCase();return/konflikt|warnung|⚠️|dringend|deadline|handlungsbedarf|reicht nicht|fehlt|überfällig|sofort|laden nötig|prüfen|action|aktion|entscheid|bestätig/.test(t)?"actionable":"informational"}static categorizeInsight(e){let t=e.toLowerCase();return/strom|energie|kwh|laden|wallbox|awattar/.test(t)?"energy":/kalender|termin|meeting|besprechung/.test(t)?"calendar":/crypto|bitcoin|btc|eth|kurs|coin/.test(t)?"crypto":/rss|feed|artikel|news|nachricht/.test(t)?"rss":/todo|aufgabe|erledigen|fällig/.test(t)?"todo":/wetter|temperatur|regen|wind/.test(t)?"weather":/reise|flug|hotel|urlaub/.test(t)?"travel":/preis|angebot|günstig|geizhals|shop/.test(t)?"shopping":/bmw|auto|reichweite|akku|soc/.test(t)?"vehicle":"general"}}});var ff={};Le(ff,{DIGEST_KANDIDAT_MIN_ABGESCHLOSSEN:()=>tN,DIGEST_KANDIDAT_QUOTE:()=>eN,KENNZAHL_NAMEN:()=>Fw,KENNZAHL_PREFIX:()=>Uw,KENNZAHL_QUELLE:()=>YB,Kennzahlen:()=>Cl,SCHRITT_ZU_KENNZAHL:()=>jw,berechneQuoten:()=>ZB,formatiereErledigungJeKategorie:()=>ez,formatiereKennzahlen:()=>QB,summiereKennzahlMesswerte:()=>tz});function ZB(l){let e=l.insightsReagiert+l.insightsVerworfen+l.insightsAbgelaufen,t={};return e>0&&(t.praezision=l.insightsReagiert/e),l.vorgaengeAngelegt>0&&(t.erledigungsquote=Math.min(1,l.vorgaengeErledigt/l.vorgaengeAngelegt),t.kostenJeVorgangUsd=l.kostenUsd/l.vorgaengeAngelegt),t}function Pw(l){return l===void 0?"\u2013":`${Math.round(l*100)} %`}function QB(l,e,t){let s=m(a=>Math.round(l[a]??0),"s"),n=s("vollpaesse")+s("rundgaenge")+s("miniPaesse"),i=n>0?s("miniPaesse")/n:void 0,r=s("aktionenAusgefuehrt")+s("aktionenFehlgeschlagen")+s("aktionenBestaetigung")+s("aktionenBlockiert")+s("aktionenUebersprungen");return[`Jarvis-Kennzahlen (${t} Tage): ${s("vollpaesse")} Vollp\xE4sse, ${s("rundgaenge")} Rundg\xE4nge ohne LLM, ${s("miniPaesse")} Mini-P\xE4sse (Anteil ${Pw(i)})`,`Insights: ${s("insightsGesendet")} gesendet, ${s("insightsAufgeschoben")} aufgeschoben, ${s("insightsStill")} still \xB7 Pr\xE4zision ${Pw(e.praezision)}`,`Gate: ${s("gateTreffer")} Treffer, ${s("gateAusgesetzt")} durch Weltmodell ausgesetzt`,`Aktionen: ${r} gesamt \u2014 ${s("aktionenAusgefuehrt")} ausgef\xFChrt, ${s("aktionenFehlgeschlagen")} fehlgeschlagen, ${s("aktionenBestaetigung")} zur Best\xE4tigung, ${s("aktionenBlockiert")} blockiert, ${s("aktionenUebersprungen")} \xFCbersprungen`,`Vorg\xE4nge: ${s("vorgaengeAngelegt")} angelegt \xB7 Erledigungsquote ${Pw(e.erledigungsquote)} \xB7 Kosten je Vorgang ${e.kostenJeVorgangUsd===void 0?"\u2013":`$${e.kostenJeVorgangUsd.toFixed(2)}`}`]}function ez(l,e){if(l.length===0)return[];let t=[`Erledigung je Kategorie (${e} Tage, erledigt/verworfen/offen):`];for(let s of l){let n=s.erledigt+s.verworfen,i=n>0?s.erledigt/n:void 0,r=i!==void 0&&n>=tN&&i<eN;t.push(`- ${s.kategorie}: ${s.erledigt}/${s.verworfen}/${s.offen}${i===void 0?"":` \xB7 Quote ${Math.round(i*100)} %`}${r?" \u2192 Kandidat Digest-Modus":""}`)}return t}function tz(l){let e={};for(let t of l){if(!t.entity.startsWith(Uw))continue;let s=t.entity.slice(Uw.length);Fw.includes(s)&&(e[s]=(e[s]??0)+(t.wert??0))}return e}var Fw,jw,Uw,YB,Cl,eN,tN,Ll=A(()=>{"use strict";Fw=["vollpaesse","rundgaenge","miniPaesse","insightsGesendet","insightsAufgeschoben","insightsStill","gateTreffer","gateAusgesetzt","aktionenAusgefuehrt","aktionenFehlgeschlagen","aktionenBestaetigung","aktionenBlockiert","aktionenUebersprungen","vorgaengeAngelegt"],jw={ausgefuehrt:"aktionenAusgefuehrt",fehlgeschlagen:"aktionenFehlgeschlagen",zur_bestaetigung:"aktionenBestaetigung",blockiert:"aktionenBlockiert",uebersprungen:"aktionenUebersprungen"},Uw="kennzahl.",YB="kennzahl",Cl=class{static{m(this,"Kennzahlen")}werte=new Map;seitIso=new Date().toISOString();zaehle(e,t=1){!e||!Number.isFinite(t)||t<=0||this.werte.set(e,(this.werte.get(e)??0)+t)}wert(e){return this.werte.get(e)??0}snapshot(){let e={};for(let t of Fw)e[t]=this.werte.get(t)??0;return{seit:this.seitIso,werte:e}}reset(e=new Date){this.werte.clear(),this.seitIso=e.toISOString()}};m(ZB,"berechneQuoten");m(Pw,"prozent");m(QB,"formatiereKennzahlen");eN=.25,tN=4;m(ez,"formatiereErledigungJeKategorie");m(tz,"summiereKennzahlMesswerte")});var nN={};Le(nN,{formatiereGedaechtnis:()=>nz});function nz(l,e,t={}){let s=[],n=t.maxSchritte??15,i=t.maxOffene??10;if(e.length){s.push(`Offene Vorg\xE4nge (${e.length}):`);for(let r of e.slice(0,i))s.push(`- [${r.besitzer==="alfred"?"Alfred":"User"} \xB7 ${r.autonomie}] ${r.titel}${r.naechsterSchritt?` \u2192 n\xE4chster Schritt: ${r.naechsterSchritt}`:""}${r.frist?` (Frist ${sN(r.frist)})`:""}`)}if(l.length){s.push(`Bereits getan (letzte 14 Tage, ${l.length} Schritte) \u2014 NICHT erneut vorschlagen:`);let r=new Set;for(let a of l){let o=`${a.skill??""}|${a.beschreibung.toLowerCase().slice(0,80)}`;if(!r.has(o)&&(r.add(o),s.push(`- ${sN(a.zeit)} ${sz[a.art]??a.art}: ${a.beschreibung}${a.skill?` [${a.skill}${a.aktion?`/${a.aktion}`:""}]`:""}${a.art==="fehlgeschlagen"&&a.ergebnis?` \u2014 ${a.ergebnis.slice(0,80)}`:""}`),r.size>=n))break}}return s.join(`
6399
- `)}var sz,sN,iN=A(()=>{"use strict";sz={ausgefuehrt:"ausgef\xFChrt",vorgeschlagen:"vorgeschlagen",zur_bestaetigung:"zur Best\xE4tigung gestellt",bestaetigt:"best\xE4tigt",abgelehnt:"abgelehnt",fehlgeschlagen:"FEHLGESCHLAGEN",blockiert:"blockiert (Autonomie: nie)",uebersprungen:"\xFCbersprungen",notiz:"Notiz"},sN=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz");m(nz,"formatiereGedaechtnis")});var Bw={};Le(Bw,{BESTAND_DOWN_TAGE:()=>rz,NEU_DOWN_STUNDEN:()=>iz,deuteMikrotik:()=>oz,downSeit:()=>rN});function rN(l,e,t=2){let s=[...l].map(i=>Date.parse(i.zeit)).filter(Number.isFinite).sort((i,r)=>r-i);if(s.length===0||e.getTime()-s[0]>t*36e5)return;let n=s[0];for(let i=1;i<s.length&&!(n-s[i]>t*36e5);i++)n=s[i];return new Date(n).toISOString()}function oz(l){let e=l.jetzt??new Date,t=[],s=[];if(l.aktuellDown.length===0)return t.push(`**Interfaces:** alle up${l.routerText?` \xB7 ${l.routerText}`:""} \u21B3 NORMAL`),{zeilen:t,auffaellig:s};let n=[];for(let i of l.aktuellDown){let r=rN(l.verlauf.filter(o=>o.entity===i),e)??e.toISOString(),a=(e.getTime()-Date.parse(r))/36e5;a<24?(n.push(`\u26A0\uFE0F ${i} NEU down seit ${az(r)} \u2192 pr\xFCfen`),s.push(`mikrotik:${i}:neu-down`)):a>=168?n.push(`${i} down seit ${Math.round(a/24)} Tagen \u21B3 Bestand, laut Korrektur (15.04.) nicht kritisch f\xFCr IPv4 \u2014 NICHT melden`):n.push(`${i} down seit ${Math.round(a/24)} Tagen \u21B3 bekannt, beobachten \u2014 kein neuer Incident`)}return t.push(`**Interfaces down:** ${n.join(" \xB7 ")}${l.routerText?` \xB7 ${l.routerText}`:""}`),{zeilen:t,auffaellig:s}}var iz,rz,az,zw=A(()=>{"use strict";iz=24,rz=7,az=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz");m(rN,"downSeit");m(oz,"deuteMikrotik")});function cz(l,e){let t={};for(let s of[e,l])if(s)for(let[n,i]of Object.entries(s.data)){if(i?.value===void 0||i.value===null||i.value==="")continue;let r=i.timestamp&&!Number.isNaN(Date.parse(i.timestamp))?i.timestamp:s.createdAt,a=t[n];(!a||Date.parse(r)>=Date.parse(a.zeit))&&(t[n]={...i,quelle:s.source,zeit:r})}return t}function Er(l,e){for(let t of aN[e])if(l[t]?.value!==void 0)return String(l[t].value)}function Co(l){if(l===void 0)return;let e=Number(l);return Number.isFinite(e)?e:void 0}function Oi(l){let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}function Lo(l){if(l<60)return`${Math.round(l)} min`;let e=l/60;return e<48?`${Math.round(e)} h`:`${Math.round(e/24)} Tagen`}function lz(l){let e=l.filter(t=>typeof t.km=="number").sort((t,s)=>Date.parse(t.createdAt)-Date.parse(s.createdAt));if(e.length===0)return{};for(let t=e.length-1;t>0;t--)if(e[t].km!==e[t-1].km)return{ende:e[t].kmZeit??e[t].createdAt,von:e[t-1].km,bis:e[t].km};return{keineBewegungSeit:e[0].kmZeit??e[0].createdAt}}function oN(l){let{mqtt:e,rest:t}=l;if(!e&&!t)return;let s=l.now??new Date,n=cz(e,t),i=m(f=>f?Math.max(0,(s.getTime()-Date.parse(f))/6e4):void 0,"minSeit"),r={steht:!0,streamVerdacht:!1,restAusgefallen:!1,laedt:!1,angesteckt:!1,offen:[],reifenAbweichung:[]};r.kilometer=Co(Er(n,"km")),r.soc=Co(Er(n,"soc")),r.socZiel=Co(Er(n,"socZiel")),r.reichweiteKm=Co(Er(n,"reichweite"));let a=(Er(n,"ladeStatus")??"").toUpperCase();r.laedt=a!==""&&a!=="NOCHARGING"&&a!=="NOT_CHARGING"&&a!=="INVALID";let o=(Er(n,"port")??"").toUpperCase();r.angesteckt=o==="CONNECTED"||o==="TRUE"||o==="PLUGGED";let c=(Er(n,"verriegelt")??"").toUpperCase();r.verriegelt=["TRUE","LOCKED","SECURED"].includes(c)?!0:["FALSE","UNLOCKED","OPEN"].includes(c)?!1:void 0;for(let[f,g]of Object.entries(n)){let y=String(g.value).toUpperCase();/\.(door|window|hood|trunk)[.a-z0-9]*\.(isOpen|status)$/i.test(f)&&(y==="TRUE"||y==="OPEN")&&r.offen.push(f.replace(/^vehicle\.(cabin|body)\./,"").replace(/\.(isOpen|status)$/,""));let w=f.match(/^vehicle\.chassis\.axle\.(row\d)\.wheel\.(left|right)\.tire\.pressure$/);if(w){let _=Co(String(g.value)),E=Co(n[`${f}Target`]?.value);_!==void 0&&E&&Math.abs(_-E)/E*100>12&&r.reifenAbweichung.push(`${w[1]} ${w[2]}: ${_} statt ${E}`)}}r.mqttAlterMin=i(e?.createdAt),r.restAlterMin=i(t?.createdAt),r.restAusgefallen=t!==void 0&&(r.restAlterMin??0)>180;let d=l.stream?.restKontingentErschoepftBis;r.restAusgefallen&&d&&Date.parse(d)>s.getTime()&&(r.restAusgefallen=!1,r.restKontingentErschoepft=!0);let u=[...l.verlauf];if(r.kilometer!==void 0){let f=aN.km.map(g=>n[g]).find(Boolean);u.push({createdAt:f?.zeit??s.toISOString(),km:r.kilometer,kmZeit:f?.zeit})}let h=lz(u);h.ende?(r.letzteFahrtEnde=h.ende,r.letzteFahrtKm={von:h.von,bis:h.bis},r.steht=(i(h.ende)??1/0)>30):r.stehtMindestensSeit=h.keineBewegungSeit,e&&r.letzteFahrtEnde&&Date.parse(r.letzteFahrtEnde)-Date.parse(e.createdAt)>5*6e4&&(r.streamVerdacht=!0);let p=[];{let f=[];r.steht?r.letzteFahrtEnde?f.push(`steht seit ${Oi(r.letzteFahrtEnde)} (${Lo(i(r.letzteFahrtEnde))}), letzte Fahrt ${Ol(r.letzteFahrtKm.von)} \u2192 ${Ol(r.letzteFahrtKm.bis)} km`):r.stehtMindestensSeit?f.push(`steht ohne Bewegung mindestens seit ${Oi(r.stehtMindestensSeit)}`):f.push("Bewegungsstatus unbekannt (kein Kilometer-Verlauf)"):f.push("f\xE4hrt gerade (Kilometerstand \xE4ndert sich)"),r.kilometer!==void 0&&f.push(`Kilometerstand ${Ol(r.kilometer)} km`),p.push(`**Fahrzeug:** ${f.join(" \xB7 ")}`)}if(r.soc!==void 0){let f=[`${r.soc} %${r.socZiel?` (Ladeziel ${r.socZiel} %)`:""}`];r.reichweiteKm!==void 0&&f.push(`Reichweite ${r.reichweiteKm} km`),f.push(r.laedt?"Ladevorgang aktiv (charging)":r.angesteckt?"angesteckt, kein Ladevorgang":"nicht angesteckt \u2014 kein Ladevorgang"),r.soc<20?f.push("\u21B3 niedrig (< 20 %)"):f.push("\u21B3 NORMAL \u2014 kein Ladebedarf gemeldet"),p.push(`**Ladestand (SoC):** ${f.join(" \xB7 ")}`)}{let f=[];if(r.verriegelt===!0)f.push("verriegelt");else if(r.verriegelt===!1){let g=r.letzteFahrtEnde?i(r.letzteFahrtEnde):r.stehtMindestensSeit?i(r.stehtMindestensSeit):0;f.push(r.steht&&g>60?`\u26A0\uFE0F UNVERRIEGELT seit ${Lo(g)} im Stand`:"unverriegelt (k\xFCrzlich benutzt \u2014 normal)")}f.push(r.offen.length?`\u26A0\uFE0F offen: ${r.offen.join(", ")}`:"T\xFCren/Fenster/Klappen geschlossen"),f.push(r.reifenAbweichung.length?`\u26A0\uFE0F Reifendruck abweichend: ${r.reifenAbweichung.join("; ")}`:"Reifendruck im Soll"),p.push(`**Zustand:** ${f.join(" \xB7 ")}`)}{let f=[];if(t?f.push(r.restKontingentErschoepft?`REST-Abruf pausiert: BMW-Tageskontingent ersch\xF6pft bis ${Oi(l.stream.restKontingentErschoepftBis)} (letzter vor ${Lo(r.restAlterMin)}) \u21B3 NORMAL, Stream liefert weiter, nichts zu tun`:r.restAusgefallen?`\u26A0\uFE0F REST-Abruf ausgefallen: letzter vor ${Lo(r.restAlterMin)} (erwartet alle 60 min) \u2192 Datenquelle pr\xFCfen`:`REST-Abruf aktuell (vor ${Lo(r.restAlterMin)}, Takt 60 min)`):f.push("kein REST-Abruf vorhanden"),e?r.streamVerdacht?f.push(`\u26A0\uFE0F MQTT-Stream lieferte NICHTS, obwohl das Fahrzeug nach der letzten Stream-Meldung (${Oi(e.createdAt)}) gefahren ist (${Ol(r.letzteFahrtKm.von)} \u2192 ${Ol(r.letzteFahrtKm.bis)} km, Fahrtende ${Oi(r.letzteFahrtEnde)}) \u2192 bmw-streaming pr\xFCfen`):f.push(`MQTT-Stream still seit ${Oi(e.createdAt)} (${Lo(r.mqttAlterMin)}) \u21B3 NORMAL: der Stream sendet nur bei aktivem Fahrzeug; im Stand sind alte Stream-Daten KEIN Fehler und NICHT zu melden`):f.push("kein MQTT-Stream-Snapshot vorhanden"),l.stream?.enabled){let g=l.stream;g.aktiv?f.push(`Stream-Verbindung aktiv${g.letzteDatenAt?` (letzte Daten ${Oi(g.letzteDatenAt)})`:""}`):g.reconnectFaelligAt?f.push(`Stream-Verbindung getrennt, Reconnect ${Oi(g.reconnectFaelligAt)} \u21B3 NORMAL (BMW schlie\xDFt Leerlauf-Verbindungen nach 60 s)`):(f.push(`\u26A0\uFE0F Stream-Verbindung getrennt OHNE geplanten Reconnect${g.letzterFehler?` (letzter Fehler: ${g.letzterFehler.slice(0,60)})`:""} \u2192 W\xE4chter startet neu`),r.streamGetrennt=!0)}p.push(`**Datenlage:** ${f.join(" \xB7 ")}`)}return{zeilen:p,zustand:r}}var aN,Ol,cN=A(()=>{"use strict";aN={soc:["vehicle.drivetrain.batteryManagement.header","vehicle.powertrain.electric.battery.stateOfCharge.displayed","vehicle.drivetrain.electricEngine.charging.level"],socZiel:["vehicle.powertrain.electric.battery.stateOfCharge.target"],reichweite:["vehicle.drivetrain.electricEngine.remainingElectricRange","vehicle.drivetrain.lastRemainingRange","vehicle.drivetrain.electricEngine.kombiRemainingElectricRange"],km:["vehicle.vehicle.travelledDistance"],ladeStatus:["vehicle.drivetrain.electricEngine.charging.status"],port:["vehicle.body.chargingPort.status","vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"],verriegelt:["vehicle.access.centralLocking.isLocked","vehicle.cabin.door.lock.status","vehicle.cabin.door.status"]};m(cz,"verschmelzeSnapshots");m(Er,"wert");m(Co,"zahl");m(Oi,"formatiereZeit");m(Lo,"formatiereDauerMin");Ol=m(l=>l.toLocaleString("de-AT"),"kmFmt");m(lz,"letzteBewegung");m(oN,"deuteBmw")});var Hw={};Le(Hw,{bmwAuffaellig:()=>uz,ladeBmwDeutung:()=>dz});async function dz(l,e,t=new Date,s){let n=await l.getLatestAnyVinBySource(e,"mqtt"),i=await l.getLatestAnyVinBySource(e,"rest"),r=i?(t.getTime()-Date.parse(i.createdAt))/6e4:1/0;if(!n&&!i)return{restAlterMin:r};let a=(n??i).vin,c=(await l.getHistory(e,a,new Date(t.getTime()-7*864e5).toISOString(),t.toISOString(),500).catch(()=>[])).map(u=>{let h=Number(u.telematicData[lN]?.value);return{createdAt:u.createdAt,km:Number.isFinite(h)?h:void 0,kmZeit:u.telematicData[lN]?.timestamp}});return{deutung:oN({mqtt:n?{source:"mqtt",createdAt:n.createdAt,data:n.telematicData}:void 0,rest:i?{source:"rest",createdAt:i.createdAt,data:i.telematicData}:void 0,verlauf:c,now:t,stream:s}),restAlterMin:r}}function uz(l){let e=l.zustand,t=[];return e.streamVerdacht&&t.push("mqtt-stream-fehlt"),e.restAusgefallen&&t.push("bmw-rest-ausgefallen"),e.streamGetrennt&&t.push("mqtt-verbindung-getrennt"),e.verriegelt===!1&&e.steht&&t.push("fahrzeug-unverriegelt"),e.offen.length&&t.push("fahrzeug-offen"),e.reifenAbweichung.length&&t.push("reifendruck"),e.soc!==void 0&&e.soc<20&&t.push("fahrzeug-soc-niedrig"),t}var lN,Xw=A(()=>{"use strict";cN();lN="vehicle.vehicle.travelledDistance";m(dz,"ladeBmwDeutung");m(uz,"bmwAuffaellig")});var Kw={};Le(Kw,{EINZELN_AB_PROZENT:()=>uN,LEER_PROZENT:()=>Ww,NIEDRIG_PROZENT:()=>dN,deuteSensorbatterien:()=>fz,klassifiziere:()=>hN,trendProTag:()=>pN});function pN(l){let e=l.filter(i=>typeof i.wert=="number").sort((i,r)=>Date.parse(i.zeit)-Date.parse(r.zeit));if(e.length<2)return;let t=e[0],s=e[e.length-1],n=(Date.parse(s.zeit)-Date.parse(t.zeit))/864e5;if(!(n<2))return(s.wert-t.wert)/n}function fz(l){if(l.sensoren.length===0)return;let e=l.jetzt??new Date,t=[],s=[],n={mobilgeraet:[],konfiguration:[],hausbatterie:[],sensor:[]};for(let r of l.sensoren)n[hN(r.entity,r.name)].push(r);let i=n.sensor;if(i.length>0){let r=[`${i.length} Sensoren`],a=[],o;for(let c of[...i].sort((d,u)=>(d.wert??101)-(u.wert??101))){let d=c.name??c.entity;if(c.verfuegbar===!1||c.wert===void 0){a.push(`\u26A0\uFE0F ${d}: nicht erreichbar (zuletzt ${hz(c.zeit)}) \u2192 Sensor pr\xFCfen`),s.push(`sensorbatterie:${c.entity}:offline`);continue}if(c.wert>uN){o=o===void 0?c.wert:Math.min(o,c.wert);continue}let u=l.verlauf.filter(f=>f.entity===c.entity),h=pN([...u,{entity:c.entity,wert:c.wert,zeit:c.zeit}]),p=pz(e.getTime()-Date.parse(c.zeit));if(c.wert<=Ww){let f=p>=3?` \u2014 Wert unver\xE4ndert seit ${p} Tagen, vermutlich meldet der Sensor nicht mehr`:"";a.push(`\u26A0\uFE0F ${d}: ${kr(c.wert)} % leer \u2192 Batterie tauschen${f}`),s.push(`sensorbatterie:${c.entity}:leer`)}else if(c.wert<=dN){let f=h!==void 0&&h<-.05?` (\u2212${kr(Math.abs(h)*7)} %/Woche \u2192 leer in ~${Math.max(1,Math.round((c.wert-Ww)/Math.abs(h)/7))} Wochen)`:"";a.push(`\u26A0\uFE0F ${d}: ${kr(c.wert)} % niedrig${f} \u2192 Ersatz bereitlegen`),s.push(`sensorbatterie:${c.entity}:niedrig`)}else{let f=h===void 0?"Trend im Aufbau":Math.abs(h)<.05?"stabil":`${h>0?"+":"\u2212"}${kr(Math.abs(h)*7)} %/Woche`;a.push(`${d}: ${kr(c.wert)} % (${f}) \u21B3 NORMAL, kein Handlungsbedarf`)}}r.push(...a),o!==void 0&&r.push(`\xFCbrige \u2265 ${kr(o)} % \u21B3 NORMAL`),t.push(`**Sensorbatterien:** ${r.join(" \xB7 ")}`)}n.mobilgeraet.length>0&&t.push(`**Mobilger\xE4te:** ${n.mobilgeraet.length} Handys/Watches erfasst \u2014 laden sich selbst, NICHT bewerten und NICHT melden (Korrektur SM-S928B)`);for(let r of n.konfiguration)r.wert!==void 0&&t.push(`**Konfiguration:** ${r.name??r.entity} ${kr(r.wert)} % \u2014 Einstellwert (ESS-Untergrenze), KEIN Ladestand, nicht melden`);return{zeilen:t,auffaellig:s}}var Ww,dN,uN,hN,hz,pz,kr,Gw=A(()=>{"use strict";ze();Ww=5,dN=20,uN=50,hN=Oa,hz=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz"),pz=m(l=>Math.round(l/864e5),"tage"),kr=m(l=>l.toLocaleString("de-AT",{maximumFractionDigits:1}),"fmt");m(pN,"trendProTag");m(fz,"deuteSensorbatterien")});function fN(l){if(l.length===0)return;let e=[...l].sort((s,n)=>s-n),t=Math.floor(e.length/2);return e.length%2?e[t]:(e[t-1]+e[t])/2}function mz(l,e){if(l.length===0)return;let t=l.map(n=>Math.abs(n-e)),s=fN(t);return s===void 0?void 0:s*1.4826}function gz(l,e,t){return l.filter(s=>s.zeit!==t).filter(s=>{let n=new Date(s.zeit).getHours();return Math.min(Math.abs(n-e),24-Math.abs(n-e))<=1}).map(s=>s.wert)}function mN(l,e,t){let s=new Date(e).getHours(),n=gz(t,s,e),i=n.length;if(i<10)return{n:i,urteil:"im-aufbau"};let r=fN(n),a=mz(n,r)??0,o=a>0?(l-r)/a:Math.abs(l-r)>=1?Math.sign(l-r)*3:0;return{n:i,median:r,mad:a,z:o,urteil:Math.abs(o)>=3?"auffaellig":"normal"}}function gN(l,e,t=120){let s=e.getTime()-t*6e4,n=l.filter(o=>Date.parse(o.zeit)>=s).sort((o,c)=>Date.parse(o.zeit)-Date.parse(c.zeit));if(n.length<2)return;let i=n[0],r=n[n.length-1],a=(Date.parse(r.zeit)-Date.parse(i.zeit))/36e5;if(!(a<.25))return(r.wert-i.wert)/a}var yN=A(()=>{"use strict";m(fN,"median");m(mz,"mad");m(gz,"stundenfenster");m(mN,"bewerteGegenBaseline");m(gN,"trendProStunde")});var Zw={};Le(Zw,{SOC_NIEDRIG:()=>Jw,VOLLLADUNG_PROZENT:()=>_N,VOLLLADUNG_REGEL_TAGE:()=>Yw,deuteEnergie:()=>_z,ladeplanLiegtZurueck:()=>EN,rolleVon:()=>TN});function TN(l){let e=l.entity.toLowerCase();return/min(imum)?_?soc|soc_min|minimum_soc/.test(e)?"minSoc":/battery_soc|(^|[._])soc$/.test(e)?"soc":/battery_power/.test(e)?"power":/battery_state/.test(e)?"state":/charge_plan/.test(e)?"plan":/^input_boolean\..*charg/.test(e)?"allowed":/pv_power/.test(e)?"pvPower":/pv_prod|daily_pv/.test(e)?"pvToday":/daily_energy|energie_bedarf|energy_kwh/.test(e)?"consumptionToday":(l.einheit??"").includes("\xB0")?"temperature":"sonst"}function Vw(l,e){return l.filter(t=>t.entity===e&&typeof t.wert=="number").map(t=>({wert:t.wert,zeit:t.zeit}))}function qw(l,e,t,s){let n=mN(l,e,t);if(n.urteil==="im-aufbau")return{text:`Baseline im Aufbau (${n.n} Stichproben zur Stunde)`,auffaellig:!1};let i=(n.z??0)>0?"\xFCber":"unter";return n.urteil==="auffaellig"?{text:`\u26A0\uFE0F deutlich ${i} der Baseline dieser Stunde (Median ${Hs(n.median)} ${s}, n=${n.n})`,auffaellig:!0}:{text:`NORMAL zur Stunde (Median ${Hs(n.median)} ${s}, n=${n.n})`,auffaellig:!1}}function EN(l,e){let t=l.match(/(\d{1,2})\.(\d{1,2})\.(?:\s*(\d{4}))?/);if(!t)return;let s=Number(t[1]),n=Number(t[2])-1,i=t[3]?Number(t[3]):e.getFullYear();return new Date(i,n,s,23,59).getTime()<e.getTime()-24*36e5}function _z(l){if(l.aktuell.length===0)return;let e=l.jetzt??new Date,t=[],s=[],n=new Map;for(let u of l.aktuell){let h=TN(u);n.set(h,[...n.get(h)??[],u])}let i=m(u=>n.get(u)?.[0],"first"),r=i("soc");if(r&&typeof r.wert=="number"){let u=[`SoC ${Hs(r.wert,0)} %`],h=i("power"),p=Vw(l.verlauf,r.entity),f=gN([...p,{wert:r.wert,zeit:r.zeit}],e);if(h&&typeof h.wert=="number")u.push(h.wert<-20?`entl\xE4dt ${Hs(Math.abs(h.wert),0)} W`:h.wert>20?`l\xE4dt ${Hs(h.wert,0)} W`:"Ruhe (\xB10 W)");else{let T=i("state");T?.text&&u.push(T.text.toLowerCase())}f!==void 0&&Math.abs(f)>=.5&&u.push(`${f>0?"+":"\u2212"}${Hs(Math.abs(f))} %/h`);let g=p.filter(T=>new Date(T.zeit).toDateString()===e.toDateString()).map(T=>T.wert);g.length>=2&&u.push(`heute ${Hs(Math.min(...g),0)}\u2013${Hs(Math.max(...g),0)} %`);let y=[...p].filter(T=>T.wert>=_N).sort((T,k)=>Date.parse(k.zeit)-Date.parse(T.zeit))[0],w=p.length?Math.min(...p.map(T=>Date.parse(T.zeit))):void 0,_=w?(e.getTime()-w)/864e5:0;y?u.push(`Vollladung zuletzt ${yz(y.zeit)} (vor ${wz(e.getTime()-Date.parse(y.zeit))})`):_>=Yw?(u.push(`\u26A0\uFE0F seit \xFCber ${Yw} Tagen keine Vollladung (Regel Lademanagement)`),s.push("hausbatterie:vollladung")):p.length&&u.push(`keine Vollladung in den beobachteten ${Math.max(1,Math.round(_))} Tagen (Regel pr\xFCft 30 Tage \u2014 Beobachtung l\xE4uft)`);let E=qw(r.wert,r.zeit,p,"%");r.wert<=Jw?(u.push(`\u26A0\uFE0F niedrig (\u2264 ${Jw} %)`),s.push("hausbatterie:niedrig")):(u.push(`\u21B3 ${E.text}`),E.auffaellig&&s.push("hausbatterie:baseline")),u.push("nicht Teil der BMW-Fahrtplanung"),t.push(`**Hausbatterie:** ${u.join(" \xB7 ")}`)}let a=i("minSoc");a&&typeof a.wert=="number"&&t.push(`**Mindest-SoC:** ${Hs(a.wert,0)} % \u2014 Konfiguration (ESS-Untergrenze), KEIN aktueller Ladestand, NICHT als Batteriealarm melden`);let o=i("allowed"),c=i("plan");if(o||c){let u=[];o&&u.push(`Netzladung erlaubt: ${(o.text??"").toLowerCase()==="on"?"ja":"nein"} (setzt die Automation)`),c?.text&&(u.push(`Ladeplan: \u201E${c.text}"`),EN(c.text,e)===!0&&u.push("\u21B3 Fenster liegt in der Vergangenheit \u2014 derzeit KEIN geplantes Ladefenster, kein Handlungsbedarf")),t.push(`**Netzladung:** ${u.join(" \xB7 ")}`)}let d=i("pvPower");if(d&&typeof d.wert=="number"){let u=[`PV ${Hs(d.wert,0)} W`],h=i("pvToday"),p=i("consumptionToday");h&&typeof h.wert=="number"&&u.push(`Ertrag heute ${Hs(h.wert,2)} kWh`),p&&typeof p.wert=="number"&&u.push(`Verbrauch heute ${Hs(p.wert,2)} kWh`);let f=e.getHours();if(d.wert<=0&&(f>=20||f<7))u.push("\u21B3 nachts 0 W NORMAL");else{let g=qw(d.wert,d.zeit,Vw(l.verlauf,d.entity),"W");u.push(`\u21B3 ${g.text}`),g.auffaellig&&s.push("pv:baseline")}t.push(`**PV:** ${u.join(" \xB7 ")}`)}for(let u of["temperature","sonst"])for(let h of n.get(u)??[])if(typeof h.wert=="number"){let p=qw(h.wert,h.zeit,Vw(l.verlauf,h.entity),h.einheit??"");t.push(`**${wN(h)}:** ${Hs(h.wert)} ${h.einheit??""} \u21B3 ${p.text}`.replace(/\s+↳/," \u21B3")),p.auffaellig&&s.push(`${h.entity}:baseline`)}else h.text&&t.push(`**${wN(h)}:** ${h.text}`);return{zeilen:t,auffaellig:s}}var Jw,_N,Yw,Hs,yz,wz,wN,Qw=A(()=>{"use strict";yN();Jw=20,_N=99,Yw=30;m(TN,"rolleVon");Hs=m((l,e=1)=>l.toLocaleString("de-AT",{maximumFractionDigits:e}),"fmt"),yz=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz"),wz=m(l=>{let e=l/36e5;return e<48?`${Math.round(e)} h`:`${Math.round(e/24)} Tagen`},"dauer"),wN=m(l=>l.name??l.entity.split(".").pop().replace(/_/g," "),"nameVon");m(Vw,"proben");m(qw,"baselineText");m(EN,"ladeplanLiegtZurueck");m(_z,"deuteEnergie")});function Di(l,e=new Date){let t=[];for(let s of l.matchAll(/\b(\d{4})-(\d{2})-(\d{2})\b/g)){let n=new Date(parseInt(s[1],10),parseInt(s[2],10)-1,parseInt(s[3],10),12);isNaN(n.getTime())||t.push(n)}for(let s of l.matchAll(/\b(\d{1,2})\.(\d{1,2})\.(\d{2,4})?(?!\d)/g)){let n=parseInt(s[1],10),i=parseInt(s[2],10);if(n<1||n>31||i<1||i>12)continue;let r=s[3]?parseInt(s[3],10):e.getFullYear();r<100&&(r+=2e3);let a=new Date(r,i-1,n,12);isNaN(a.getTime())||t.push(a)}return t.length===0?null:(t.sort((s,n)=>s.getTime()-n.getTime()),t[t.length-1])}function vN(l){return/→\s*\*?\s*Aktion/i.test(l)||/\*\*[^*]{3,}\*\*/.test(l)&&new RegExp("\\p{Extended_Pictographic}","u").test(l)?!0:/\bDRINGEND\b|Alfred Insights/i.test(l)}function kN(l){return l.replace(/\bvor \d+(?:[.,]\d+)? ?(?:min|h|Tagen?|Std\.?|Sekunden?|s)\b/gi,"vor X").replace(/\bseit \d+(?:[.,]\d+)? ?(?:min|h|Tagen?)\b/gi,"seit X").replace(/\(\d+ ?ms\)/g,"(X ms)").replace(/\b\d+ ?(?:min|Min\.?|Minuten) alt\b/gi,"X min alt").replace(/\b\d{1,2}:\d{2}(?::\d{2})?\b/g,"HH:MM").replace(/\b\d+ ?(?:min|h) ?\)/g,"X)").replace(/\s+/g," ").trim()}function Tz(l){let e=[];for(let t of l.split(`
6399
+ `)}var sz,sN,iN=A(()=>{"use strict";sz={ausgefuehrt:"ausgef\xFChrt",vorgeschlagen:"vorgeschlagen",zur_bestaetigung:"zur Best\xE4tigung gestellt",bestaetigt:"best\xE4tigt",abgelehnt:"abgelehnt",fehlgeschlagen:"FEHLGESCHLAGEN",blockiert:"blockiert (Autonomie: nie)",uebersprungen:"\xFCbersprungen",notiz:"Notiz"},sN=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz");m(nz,"formatiereGedaechtnis")});var Bw={};Le(Bw,{BESTAND_DOWN_TAGE:()=>rz,NEU_DOWN_STUNDEN:()=>iz,deuteMikrotik:()=>oz,downSeit:()=>rN});function rN(l,e,t=2){let s=[...l].map(i=>Date.parse(i.zeit)).filter(Number.isFinite).sort((i,r)=>r-i);if(s.length===0||e.getTime()-s[0]>t*36e5)return;let n=s[0];for(let i=1;i<s.length&&!(n-s[i]>t*36e5);i++)n=s[i];return new Date(n).toISOString()}function oz(l){let e=l.jetzt??new Date,t=[],s=[];if(l.aktuellDown.length===0)return t.push(`**Interfaces:** alle up${l.routerText?` \xB7 ${l.routerText}`:""} \u21B3 NORMAL`),{zeilen:t,auffaellig:s};let n=[];for(let i of l.aktuellDown){let r=rN(l.verlauf.filter(o=>o.entity===i),e)??e.toISOString(),a=(e.getTime()-Date.parse(r))/36e5;a<24?(n.push(`\u26A0\uFE0F ${i} NEU down seit ${az(r)} \u2192 pr\xFCfen`),s.push(`mikrotik:${i}:neu-down`)):a>=168?n.push(`${i} down seit ${Math.round(a/24)} Tagen \u21B3 Bestand, laut Korrektur (15.04.) nicht kritisch f\xFCr IPv4 \u2014 NICHT melden`):n.push(`${i} down seit ${Math.round(a/24)} Tagen \u21B3 bekannt, beobachten \u2014 kein neuer Incident`)}return t.push(`**Interfaces down:** ${n.join(" \xB7 ")}${l.routerText?` \xB7 ${l.routerText}`:""}`),{zeilen:t,auffaellig:s}}var iz,rz,az,zw=A(()=>{"use strict";iz=24,rz=7,az=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz");m(rN,"downSeit");m(oz,"deuteMikrotik")});function cz(l,e){let t={};for(let s of[e,l])if(s)for(let[n,i]of Object.entries(s.data)){if(i?.value===void 0||i.value===null||i.value==="")continue;let r=i.timestamp&&!Number.isNaN(Date.parse(i.timestamp))?i.timestamp:s.createdAt,a=t[n];(!a||Date.parse(r)>=Date.parse(a.zeit))&&(t[n]={...i,quelle:s.source,zeit:r})}return t}function Er(l,e){for(let t of aN[e])if(l[t]?.value!==void 0)return String(l[t].value)}function Co(l){if(l===void 0)return;let e=Number(l);return Number.isFinite(e)?e:void 0}function Oi(l){let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}function Lo(l){if(l<60)return`${Math.round(l)} min`;let e=l/60;return e<48?`${Math.round(e)} h`:`${Math.round(e/24)} Tagen`}function lz(l){let e=l.filter(t=>typeof t.km=="number").sort((t,s)=>Date.parse(t.createdAt)-Date.parse(s.createdAt));if(e.length===0)return{};for(let t=e.length-1;t>0;t--)if(e[t].km!==e[t-1].km)return{ende:e[t].kmZeit??e[t].createdAt,von:e[t-1].km,bis:e[t].km};return{keineBewegungSeit:e[0].kmZeit??e[0].createdAt}}function oN(l){let{mqtt:e,rest:t}=l;if(!e&&!t)return;let s=l.now??new Date,n=cz(e,t),i=m(f=>f?Math.max(0,(s.getTime()-Date.parse(f))/6e4):void 0,"minSeit"),r={steht:!0,streamVerdacht:!1,restAusgefallen:!1,laedt:!1,angesteckt:!1,offen:[],reifenAbweichung:[]};r.kilometer=Co(Er(n,"km")),r.soc=Co(Er(n,"soc")),r.socZiel=Co(Er(n,"socZiel")),r.reichweiteKm=Co(Er(n,"reichweite"));let a=(Er(n,"ladeStatus")??"").toUpperCase();r.laedt=a!==""&&a!=="NOCHARGING"&&a!=="NOT_CHARGING"&&a!=="INVALID";let o=(Er(n,"port")??"").toUpperCase();r.angesteckt=o==="CONNECTED"||o==="TRUE"||o==="PLUGGED";let c=(Er(n,"verriegelt")??"").toUpperCase();r.verriegelt=["TRUE","LOCKED","SECURED"].includes(c)?!0:["FALSE","UNLOCKED","OPEN"].includes(c)?!1:void 0;for(let[f,g]of Object.entries(n)){let y=String(g.value).toUpperCase();/\.(door|window|hood|trunk)[.a-z0-9]*\.(isOpen|status)$/i.test(f)&&(y==="TRUE"||y==="OPEN")&&r.offen.push(f.replace(/^vehicle\.(cabin|body)\./,"").replace(/\.(isOpen|status)$/,""));let w=f.match(/^vehicle\.chassis\.axle\.(row\d)\.wheel\.(left|right)\.tire\.pressure$/);if(w){let _=Co(String(g.value)),E=Co(n[`${f}Target`]?.value);_!==void 0&&E&&Math.abs(_-E)/E*100>12&&r.reifenAbweichung.push(`${w[1]} ${w[2]}: ${_} statt ${E}`)}}r.mqttAlterMin=i(e?.createdAt),r.restAlterMin=i(t?.createdAt),r.restAusgefallen=t!==void 0&&(r.restAlterMin??0)>180;let d=l.stream?.restKontingentErschoepftBis;r.restAusgefallen&&d&&Date.parse(d)>s.getTime()&&(r.restAusgefallen=!1,r.restKontingentErschoepft=!0);let u=[...l.verlauf];if(r.kilometer!==void 0){let f=aN.km.map(g=>n[g]).find(Boolean);u.push({createdAt:f?.zeit??s.toISOString(),km:r.kilometer,kmZeit:f?.zeit})}let h=lz(u);h.ende?(r.letzteFahrtEnde=h.ende,r.letzteFahrtKm={von:h.von,bis:h.bis},r.steht=(i(h.ende)??1/0)>30):r.stehtMindestensSeit=h.keineBewegungSeit,e&&r.letzteFahrtEnde&&Date.parse(r.letzteFahrtEnde)-Date.parse(e.createdAt)>5*6e4&&(r.streamVerdacht=!0);let p=[];{let f=[];r.steht?r.letzteFahrtEnde?f.push(`steht seit ${Oi(r.letzteFahrtEnde)} (${Lo(i(r.letzteFahrtEnde))}), letzte Fahrt ${Ol(r.letzteFahrtKm.von)} \u2192 ${Ol(r.letzteFahrtKm.bis)} km`):r.stehtMindestensSeit?f.push(`steht ohne Bewegung mindestens seit ${Oi(r.stehtMindestensSeit)}`):f.push("Bewegungsstatus unbekannt (kein Kilometer-Verlauf)"):f.push("f\xE4hrt gerade (Kilometerstand \xE4ndert sich)"),r.kilometer!==void 0&&f.push(`Kilometerstand ${Ol(r.kilometer)} km`),p.push(`**Fahrzeug:** ${f.join(" \xB7 ")}`)}if(r.soc!==void 0){let f=[`${r.soc} %${r.socZiel?` (Ladeziel ${r.socZiel} %)`:""}`];r.reichweiteKm!==void 0&&f.push(`Reichweite ${r.reichweiteKm} km`),f.push(r.laedt?"Ladevorgang aktiv (charging)":r.angesteckt?"angesteckt, kein Ladevorgang":"nicht angesteckt \u2014 kein Ladevorgang"),r.soc<20?f.push("\u21B3 niedrig (< 20 %)"):f.push("\u21B3 NORMAL \u2014 kein Ladebedarf gemeldet"),p.push(`**Ladestand (SoC):** ${f.join(" \xB7 ")}`)}{let f=[];if(r.verriegelt===!0)f.push("verriegelt");else if(r.verriegelt===!1){let g=r.letzteFahrtEnde?i(r.letzteFahrtEnde):r.stehtMindestensSeit?i(r.stehtMindestensSeit):0;f.push(r.steht&&g>60?`\u26A0\uFE0F UNVERRIEGELT seit ${Lo(g)} im Stand`:"unverriegelt (k\xFCrzlich benutzt \u2014 normal)")}f.push(r.offen.length?`\u26A0\uFE0F offen: ${r.offen.join(", ")}`:"T\xFCren/Fenster/Klappen geschlossen"),f.push(r.reifenAbweichung.length?`\u26A0\uFE0F Reifendruck abweichend: ${r.reifenAbweichung.join("; ")}`:"Reifendruck im Soll"),p.push(`**Zustand:** ${f.join(" \xB7 ")}`)}{let f=[];if(t?f.push(r.restKontingentErschoepft?`REST-Abruf pausiert: BMW-Tageskontingent ersch\xF6pft bis ${Oi(l.stream.restKontingentErschoepftBis)} (letzter vor ${Lo(r.restAlterMin)}) \u21B3 NORMAL, Stream liefert weiter, nichts zu tun`:r.restAusgefallen?`\u26A0\uFE0F REST-Abruf ausgefallen: letzter vor ${Lo(r.restAlterMin)} (erwartet alle 60 min) \u2192 Datenquelle pr\xFCfen`:`REST-Abruf aktuell (vor ${Lo(r.restAlterMin)}, Takt 60 min)`):f.push("kein REST-Abruf vorhanden"),e?r.streamVerdacht?f.push(`\u26A0\uFE0F MQTT-Stream lieferte NICHTS, obwohl das Fahrzeug nach der letzten Stream-Meldung (${Oi(e.createdAt)}) gefahren ist (${Ol(r.letzteFahrtKm.von)} \u2192 ${Ol(r.letzteFahrtKm.bis)} km, Fahrtende ${Oi(r.letzteFahrtEnde)}) \u2192 bmw-streaming pr\xFCfen`):f.push(`MQTT-Stream still seit ${Oi(e.createdAt)} (${Lo(r.mqttAlterMin)}) \u21B3 NORMAL: der Stream sendet nur bei aktivem Fahrzeug; im Stand sind alte Stream-Daten KEIN Fehler und NICHT zu melden`):f.push("kein MQTT-Stream-Snapshot vorhanden"),l.stream?.enabled){let g=l.stream;g.aktiv?f.push(`Stream-Verbindung aktiv${g.letzteDatenAt?` (letzte Daten ${Oi(g.letzteDatenAt)})`:""}`):g.reconnectFaelligAt?f.push(`Stream-Verbindung getrennt, Reconnect ${Oi(g.reconnectFaelligAt)} \u21B3 NORMAL (BMW schlie\xDFt Leerlauf-Verbindungen nach 60 s)`):(f.push(`\u26A0\uFE0F Stream-Verbindung getrennt OHNE geplanten Reconnect${g.letzterFehler?` (letzter Fehler: ${g.letzterFehler.slice(0,60)})`:""} \u2192 W\xE4chter startet neu`),r.streamGetrennt=!0)}p.push(`**Datenlage:** ${f.join(" \xB7 ")}`)}return{zeilen:p,zustand:r}}var aN,Ol,cN=A(()=>{"use strict";aN={soc:["vehicle.drivetrain.batteryManagement.header","vehicle.powertrain.electric.battery.stateOfCharge.displayed","vehicle.drivetrain.electricEngine.charging.level"],socZiel:["vehicle.powertrain.electric.battery.stateOfCharge.target"],reichweite:["vehicle.drivetrain.electricEngine.remainingElectricRange","vehicle.drivetrain.lastRemainingRange","vehicle.drivetrain.electricEngine.kombiRemainingElectricRange"],km:["vehicle.vehicle.travelledDistance"],ladeStatus:["vehicle.drivetrain.electricEngine.charging.status"],port:["vehicle.body.chargingPort.status","vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"],verriegelt:["vehicle.access.centralLocking.isLocked","vehicle.cabin.door.lock.status","vehicle.cabin.door.status"]};m(cz,"verschmelzeSnapshots");m(Er,"wert");m(Co,"zahl");m(Oi,"formatiereZeit");m(Lo,"formatiereDauerMin");Ol=m(l=>l.toLocaleString("de-AT"),"kmFmt");m(lz,"letzteBewegung");m(oN,"deuteBmw")});var Hw={};Le(Hw,{bmwAuffaellig:()=>uz,ladeBmwDeutung:()=>dz});async function dz(l,e,t=new Date,s){let n=await l.getLatestAnyVinBySource(e,"mqtt"),i=await l.getLatestAnyVinBySource(e,"rest"),r=i?(t.getTime()-Date.parse(i.createdAt))/6e4:1/0;if(!n&&!i)return{restAlterMin:r};let a=(n??i).vin,c=(await l.getHistory(e,a,new Date(t.getTime()-7*864e5).toISOString(),t.toISOString(),500).catch(()=>[])).map(u=>{let h=Number(u.telematicData[lN]?.value);return{createdAt:u.createdAt,km:Number.isFinite(h)?h:void 0,kmZeit:u.telematicData[lN]?.timestamp}});return{deutung:oN({mqtt:n?{source:"mqtt",createdAt:n.createdAt,data:n.telematicData}:void 0,rest:i?{source:"rest",createdAt:i.createdAt,data:i.telematicData}:void 0,verlauf:c,now:t,stream:s}),restAlterMin:r}}function uz(l){let e=l.zustand,t=[];return e.streamVerdacht&&t.push("mqtt-stream-fehlt"),e.restAusgefallen&&t.push("bmw-rest-ausgefallen"),e.streamGetrennt&&t.push("mqtt-verbindung-getrennt"),e.verriegelt===!1&&e.steht&&t.push("fahrzeug-unverriegelt"),e.offen.length&&t.push("fahrzeug-offen"),e.reifenAbweichung.length&&t.push("reifendruck"),e.soc!==void 0&&e.soc<20&&t.push("fahrzeug-soc-niedrig"),t}var lN,Xw=A(()=>{"use strict";cN();lN="vehicle.vehicle.travelledDistance";m(dz,"ladeBmwDeutung");m(uz,"bmwAuffaellig")});var Kw={};Le(Kw,{EINZELN_AB_PROZENT:()=>uN,LEER_PROZENT:()=>Ww,NIEDRIG_PROZENT:()=>dN,deuteSensorbatterien:()=>fz,klassifiziere:()=>hN,trendProTag:()=>pN});function pN(l){let e=l.filter(i=>typeof i.wert=="number").sort((i,r)=>Date.parse(i.zeit)-Date.parse(r.zeit));if(e.length<2)return;let t=e[0],s=e[e.length-1],n=(Date.parse(s.zeit)-Date.parse(t.zeit))/864e5;if(!(n<2))return(s.wert-t.wert)/n}function fz(l){if(l.sensoren.length===0)return;let e=l.jetzt??new Date,t=[],s=[],n={mobilgeraet:[],konfiguration:[],hausbatterie:[],sensor:[]};for(let r of l.sensoren)n[hN(r.entity,r.name)].push(r);let i=n.sensor;if(i.length>0){let r=[`${i.length} Sensoren`],a=[],o;for(let c of[...i].sort((d,u)=>(d.wert??101)-(u.wert??101))){let d=c.name??c.entity;if(c.verfuegbar===!1||c.wert===void 0){a.push(`\u26A0\uFE0F ${d}: nicht erreichbar (zuletzt ${hz(c.zeit)}) \u2192 Sensor pr\xFCfen`),s.push(`sensorbatterie:${c.entity}:offline`);continue}if(c.wert>uN){o=o===void 0?c.wert:Math.min(o,c.wert);continue}let u=l.verlauf.filter(f=>f.entity===c.entity),h=pN([...u,{entity:c.entity,wert:c.wert,zeit:c.zeit}]),p=pz(e.getTime()-Date.parse(c.zeit));if(c.wert<=Ww){let f=p>=3?` \u2014 Wert unver\xE4ndert seit ${p} Tagen, vermutlich meldet der Sensor nicht mehr`:"";a.push(`\u26A0\uFE0F ${d}: ${kr(c.wert)} % leer \u2192 Batterie tauschen${f}`),s.push(`sensorbatterie:${c.entity}:leer`)}else if(c.wert<=dN){let f=h!==void 0&&h<-.05?` (\u2212${kr(Math.abs(h)*7)} %/Woche \u2192 leer in ~${Math.max(1,Math.round((c.wert-Ww)/Math.abs(h)/7))} Wochen)`:"";a.push(`\u26A0\uFE0F ${d}: ${kr(c.wert)} % niedrig${f} \u2192 Ersatz bereitlegen`),s.push(`sensorbatterie:${c.entity}:niedrig`)}else{let f=h===void 0?"Trend im Aufbau":Math.abs(h)<.05?"stabil":`${h>0?"+":"\u2212"}${kr(Math.abs(h)*7)} %/Woche`;a.push(`${d}: ${kr(c.wert)} % (${f}) \u21B3 NORMAL, kein Handlungsbedarf`)}}r.push(...a),o!==void 0&&r.push(`\xFCbrige \u2265 ${kr(o)} % \u21B3 NORMAL`),t.push(`**Sensorbatterien:** ${r.join(" \xB7 ")}`)}n.mobilgeraet.length>0&&t.push(`**Mobilger\xE4te:** ${n.mobilgeraet.length} Handys/Watches erfasst \u2014 laden sich selbst, NICHT bewerten und NICHT melden (Korrektur SM-S928B)`);for(let r of n.konfiguration)r.wert!==void 0&&t.push(`**Konfiguration:** ${r.name??r.entity} ${kr(r.wert)} % \u2014 Einstellwert (ESS-Untergrenze), KEIN Ladestand, nicht melden`);return{zeilen:t,auffaellig:s}}var Ww,dN,uN,hN,hz,pz,kr,Gw=A(()=>{"use strict";ze();Ww=5,dN=20,uN=50,hN=Oa,hz=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz"),pz=m(l=>Math.round(l/864e5),"tage"),kr=m(l=>l.toLocaleString("de-AT",{maximumFractionDigits:1}),"fmt");m(pN,"trendProTag");m(fz,"deuteSensorbatterien")});function fN(l){if(l.length===0)return;let e=[...l].sort((s,n)=>s-n),t=Math.floor(e.length/2);return e.length%2?e[t]:(e[t-1]+e[t])/2}function mz(l,e){if(l.length===0)return;let t=l.map(n=>Math.abs(n-e)),s=fN(t);return s===void 0?void 0:s*1.4826}function gz(l,e,t){return l.filter(s=>s.zeit!==t).filter(s=>{let n=new Date(s.zeit).getHours();return Math.min(Math.abs(n-e),24-Math.abs(n-e))<=1}).map(s=>s.wert)}function mN(l,e,t){let s=new Date(e).getHours(),n=gz(t,s,e),i=n.length;if(i<10)return{n:i,urteil:"im-aufbau"};let r=fN(n),a=mz(n,r)??0,o=a>0?(l-r)/a:Math.abs(l-r)>=1?Math.sign(l-r)*3:0;return{n:i,median:r,mad:a,z:o,urteil:Math.abs(o)>=3?"auffaellig":"normal"}}function gN(l,e,t=120){let s=e.getTime()-t*6e4,n=l.filter(o=>Date.parse(o.zeit)>=s).sort((o,c)=>Date.parse(o.zeit)-Date.parse(c.zeit));if(n.length<2)return;let i=n[0],r=n[n.length-1],a=(Date.parse(r.zeit)-Date.parse(i.zeit))/36e5;if(!(a<.25))return(r.wert-i.wert)/a}var yN=A(()=>{"use strict";m(fN,"median");m(mz,"mad");m(gz,"stundenfenster");m(mN,"bewerteGegenBaseline");m(gN,"trendProStunde")});var Zw={};Le(Zw,{SOC_NIEDRIG:()=>Jw,VOLLLADUNG_PROZENT:()=>_N,VOLLLADUNG_REGEL_TAGE:()=>Yw,deuteEnergie:()=>_z,ladeplanLiegtZurueck:()=>EN,rolleVon:()=>TN});function TN(l){let e=l.entity.toLowerCase();return/min(imum)?_?soc|soc_min|minimum_soc/.test(e)?"minSoc":/battery_soc|(^|[._])soc$/.test(e)?"soc":/battery_power/.test(e)?"power":/battery_state/.test(e)?"state":/charge_plan/.test(e)?"plan":/^input_boolean\..*charg/.test(e)?"allowed":/pv_power/.test(e)?"pvPower":/pv_prod|daily_pv/.test(e)?"pvToday":/daily_energy|energie_bedarf|energy_kwh/.test(e)?"consumptionToday":(l.einheit??"").includes("\xB0")?"temperature":"sonst"}function Vw(l,e){return l.filter(t=>t.entity===e&&typeof t.wert=="number").map(t=>({wert:t.wert,zeit:t.zeit}))}function qw(l,e,t,s){let n=mN(l,e,t);if(n.urteil==="im-aufbau")return{text:`Baseline im Aufbau (${n.n} Stichproben zur Stunde)`,auffaellig:!1};let i=(n.z??0)>0?"\xFCber":"unter";return n.urteil==="auffaellig"?{text:`\u26A0\uFE0F deutlich ${i} der Baseline dieser Stunde (Median ${Hs(n.median)} ${s}, n=${n.n})`,auffaellig:!0}:{text:`NORMAL zur Stunde (Median ${Hs(n.median)} ${s}, n=${n.n})`,auffaellig:!1}}function EN(l,e){let t=l.match(/(\d{1,2})\.(\d{1,2})\.(?:\s*(\d{4}))?/);if(!t)return;let s=Number(t[1]),n=Number(t[2])-1,i=t[3]?Number(t[3]):e.getFullYear();return new Date(i,n,s,23,59).getTime()<e.getTime()-24*36e5}function _z(l){if(l.aktuell.length===0)return;let e=l.jetzt??new Date,t=[],s=[],n=new Map;for(let u of l.aktuell){let h=TN(u);n.set(h,[...n.get(h)??[],u])}let i=m(u=>n.get(u)?.[0],"first"),r=i("soc");if(r&&typeof r.wert=="number"){let u=[`SoC ${Hs(r.wert,0)} %`],h=i("power"),p=Vw(l.verlauf,r.entity),f=gN([...p,{wert:r.wert,zeit:r.zeit}],e);if(h&&typeof h.wert=="number")u.push(h.wert<-20?`entl\xE4dt ${Hs(Math.abs(h.wert),0)} W`:h.wert>20?`l\xE4dt ${Hs(h.wert,0)} W`:"Ruhe (\xB10 W)");else{let T=i("state");T?.text&&u.push(T.text.toLowerCase())}f!==void 0&&Math.abs(f)>=.5&&u.push(`${f>0?"+":"\u2212"}${Hs(Math.abs(f))} %/h`);let g=p.filter(T=>new Date(T.zeit).toDateString()===e.toDateString()).map(T=>T.wert);g.length>=2&&u.push(`heute ${Hs(Math.min(...g),0)}\u2013${Hs(Math.max(...g),0)} %`);let y=[...p].filter(T=>T.wert>=_N).sort((T,k)=>Date.parse(k.zeit)-Date.parse(T.zeit))[0],w=p.length?Math.min(...p.map(T=>Date.parse(T.zeit))):void 0,_=w?(e.getTime()-w)/864e5:0;y?u.push(`Vollladung zuletzt ${yz(y.zeit)} (vor ${wz(e.getTime()-Date.parse(y.zeit))})`):_>=Yw?(u.push(`\u26A0\uFE0F seit \xFCber ${Yw} Tagen keine Vollladung (Regel Lademanagement)`),s.push("hausbatterie:vollladung")):p.length&&u.push(`keine Vollladung in den beobachteten ${Math.max(1,Math.round(_))} Tagen (Regel pr\xFCft 30 Tage \u2014 Beobachtung l\xE4uft)`);let E=qw(r.wert,r.zeit,p,"%");r.wert<=Jw?(u.push(`\u26A0\uFE0F niedrig (\u2264 ${Jw} %)`),s.push("hausbatterie:niedrig")):(u.push(`\u21B3 ${E.text}`),E.auffaellig&&s.push("hausbatterie:baseline")),u.push("nicht Teil der BMW-Fahrtplanung"),t.push(`**Hausbatterie:** ${u.join(" \xB7 ")}`)}let a=i("minSoc");a&&typeof a.wert=="number"&&t.push(`**Mindest-SoC:** ${Hs(a.wert,0)} % \u2014 Konfiguration (ESS-Untergrenze), KEIN aktueller Ladestand, NICHT als Batteriealarm melden`);let o=i("allowed"),c=i("plan");if(o||c){let u=[];o&&u.push(`Netzladung erlaubt: ${(o.text??"").toLowerCase()==="on"?"ja":"nein"} (setzt die Automation)`),c?.text&&(u.push(`Ladeplan: \u201E${c.text}"`),EN(c.text,e)===!0&&u.push("\u21B3 Fenster liegt in der Vergangenheit \u2014 derzeit KEIN geplantes Ladefenster, kein Handlungsbedarf")),t.push(`**Netzladung:** ${u.join(" \xB7 ")}`)}let d=i("pvPower");if(d&&typeof d.wert=="number"){let u=[`PV ${Hs(d.wert,0)} W`],h=i("pvToday"),p=i("consumptionToday");h&&typeof h.wert=="number"&&u.push(`Ertrag heute ${Hs(h.wert,2)} kWh`),p&&typeof p.wert=="number"&&u.push(`Verbrauch heute ${Hs(p.wert,2)} kWh`);let f=e.getHours();if(d.wert<=0&&(f>=20||f<7))u.push("\u21B3 nachts 0 W NORMAL");else{let g=qw(d.wert,d.zeit,Vw(l.verlauf,d.entity),"W");u.push(`\u21B3 ${g.text}`),g.auffaellig&&s.push("pv:baseline")}t.push(`**PV:** ${u.join(" \xB7 ")}`)}for(let u of["temperature","sonst"])for(let h of n.get(u)??[])if(typeof h.wert=="number"){let p=qw(h.wert,h.zeit,Vw(l.verlauf,h.entity),h.einheit??"");t.push(`**${wN(h)}:** ${Hs(h.wert)} ${h.einheit??""} \u21B3 ${p.text}`.replace(/\s+↳/," \u21B3")),p.auffaellig&&s.push(`${h.entity}:baseline`)}else h.text&&t.push(`**${wN(h)}:** ${h.text}`);return{zeilen:t,auffaellig:s}}var Jw,_N,Yw,Hs,yz,wz,wN,Qw=A(()=>{"use strict";yN();Jw=20,_N=99,Yw=30;m(TN,"rolleVon");Hs=m((l,e=1)=>l.toLocaleString("de-AT",{maximumFractionDigits:e}),"fmt"),yz=m(l=>{let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}. ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz"),wz=m(l=>{let e=l/36e5;return e<48?`${Math.round(e)} h`:`${Math.round(e/24)} Tagen`},"dauer"),wN=m(l=>l.name??l.entity.split(".").pop().replace(/_/g," "),"nameVon");m(Vw,"proben");m(qw,"baselineText");m(EN,"ladeplanLiegtZurueck");m(_z,"deuteEnergie")});function Di(l,e=new Date){let t=[];for(let s of l.matchAll(/\b(\d{4})-(\d{2})-(\d{2})\b/g)){let n=new Date(parseInt(s[1],10),parseInt(s[2],10)-1,parseInt(s[3],10),12);isNaN(n.getTime())||t.push(n)}for(let s of l.matchAll(/\b(\d{1,2})\.(\d{1,2})\.(\d{2,4})?(?!\d)/g)){let n=parseInt(s[1],10),i=parseInt(s[2],10);if(n<1||n>31||i<1||i>12)continue;let r=s[3]?parseInt(s[3],10):e.getFullYear();r<100&&(r+=2e3);let a=new Date(r,i-1,n,12);isNaN(a.getTime())||t.push(a)}return t.length===0?null:(t.sort((s,n)=>s.getTime()-n.getTime()),t[t.length-1])}function vN(l){return/→\s*\*?\s*Aktion/i.test(l)||/\*\*[^*]{3,}\*\*/.test(l)&&new RegExp("\\p{Extended_Pictographic}","u").test(l)?!0:/\bDRINGEND\b|Alfred Insights/i.test(l)}function kN(l){return l.replace(/\bvor \d+(?:[.,]\d+)? ?(?:min|h|d|Tagen?|Std\.?|Sekunden?|s)\b/gi,"vor X").replace(/\bseit \d+(?:[.,]\d+)? ?(?:min|h|Tagen?)\b/gi,"seit X").replace(/\(\d+ ?ms\)/g,"(X ms)").replace(/\b\d+ ?(?:min|Min\.?|Minuten) alt\b/gi,"X min alt").replace(/\b\d{1,2}:\d{2}(?::\d{2})?\b/g,"HH:MM").replace(/\b\d+ ?(?:min|h) ?\)/g,"X)").replace(/\s+/g," ").trim()}function Tz(l){let e=[];for(let t of l.split(`
6400
6400
  `)){let s=t.match(/person\.([a-z0-9_]+)/i)?.[1];s&&(/\bnot_home\b|\baway\b|\babwesend\b/i.test(t)?e.push(`${s}: abwesend`):/\bhome\b|\bzuhause\b/i.test(t)&&e.push(`${s}: zuhause`))}return e.length===0?null:`\u{1F4CD} Anwesenheit JETZT: ${e.join(", ")} \u2014 Reise-/R\xFCckfahrt-Themen sind nur relevant, wenn ein K\xDCNFTIGES Ereignis ansteht.`}function bN(l){let e=[];if(l.createdAt&&e.push(`erfasst ${l.createdAt.slice(0,10)}`),l.relevantUntil){let s=l.relevantUntil.slice(0,10),n=l.relevantUntil<new Date().toISOString();e.push(n?`abgelaufen seit ${s}`:`g\xFCltig bis ${s}`)}else{let s=Di(l.value);s&&Date.now()-s.getTime()>24*36e5&&e.push(`EREIGNIS VORBEI seit ${s.toISOString().slice(0,10)} \u2014 nur R\xFCckblick, KEINE Aktionen ableiten`)}l.sourceEventRefs&&l.sourceEventRefs.length>0&&e.push(`betrifft: ${l.sourceEventRefs.slice(0,5).join(", ")}`);let t=e.length>0?` (${e.join("; ")})`:"";return`- [${l.type??"general"}] ${l.key}${t}: ${l.value}`}var e_,Ez,SN,Dl,xl=A(()=>{"use strict";wn();m(Di,"spaetestesDatumImText");m(vN,"istInsightEcho");m(kN,"fachlicherFingerabdruck");m(Tz,"extrahiereAnwesenheit");e_=class{static{m(this,"QuellenSchalter")}schwelle;pauseMs;zustand=new Map;constructor(e=12,t=20*36e5){this.schwelle=e,this.pauseMs=t}istPausiert(e){let t=this.zustand.get(e);return!t||t.fails<this.schwelle?!1:Date.now()<t.pauseBis?!0:(t.pauseBis=Date.now()+this.pauseMs,!1)}fehlschlag(e){let t=this.zustand.get(e)??{fails:0,pauseBis:0};t.fails++;let s=t.fails===this.schwelle;return t.fails>=this.schwelle&&(t.pauseBis=Date.now()+this.pauseMs),this.zustand.set(e,t),s}erfolg(e){this.zustand.delete(e)}fehlversuche(e){return this.zustand.get(e)?.fails??0}};m(bN,"formatMemoryLine");Ez=5e3,SN=5e3,Dl=class l{static{m(this,"ReasoningContextCollector")}skillRegistry;skillSandbox;userRepo;calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;feedbackRepo;defaultChatId;defaultPlatform;defaultLocation;logger;workflowRepo;bmwTelematicRepo;noteRepo;reminderRepo;documentRepo;userTimezone;conversationRepo;runbookRepo;projectRepo;previousContent=new Map;previousSuccess=new Map;resolvedUserId;planningAgent;setPlanningAgent(e){this.planningAgent=e}messwerteRepo;setMesswerteRepo(e){this.messwerteRepo=e}setBmwTelematicRepo(e){this.bmwTelematicRepo=e}vorgaengeRepo;setVorgaengeRepo(e){this.vorgaengeRepo=e}async fetchVorgaenge(){if(!this.vorgaengeRepo)return"(Vorg\xE4nge nicht verf\xFCgbar)";let e=await this.getEffectiveUserId(),[t,s]=await Promise.all([this.vorgaengeRepo.offene(e,20),this.vorgaengeRepo.schritte(e,14,100)]),{formatiereGedaechtnis:n}=await Promise.resolve().then(()=>(iN(),nN));return n(s,t)||"(keine offenen Vorg\xE4nge, nichts ausgef\xFChrt in 14 Tagen)"}constructor(e,t,s,n,i,r,a,o,c,d,u,h,p,f,g,y,w,_,E,T,k,b,v){this.skillRegistry=e,this.skillSandbox=t,this.userRepo=s,this.calendarProvider=n,this.todoRepo=i,this.watchRepo=r,this.memoryRepo=a,this.activityRepo=o,this.skillHealthRepo=c,this.feedbackRepo=d,this.defaultChatId=u,this.defaultPlatform=h,this.defaultLocation=p,this.logger=f,this.workflowRepo=g,this.bmwTelematicRepo=y,this.noteRepo=w,this.reminderRepo=_,this.documentRepo=E,this.userTimezone=T,this.conversationRepo=k,this.runbookRepo=b,this.projectRepo=v}async getEffectiveUserId(){if(this.resolvedUserId)return this.resolvedUserId;try{let e=await this.userRepo.findOrCreate(this.defaultPlatform,this.defaultChatId);this.resolvedUserId=e.masterUserId??e.id}catch{this.resolvedUserId=this.defaultChatId}return this.resolvedUserId}letzteAuffaelligeObjekte=new Set;async collect(){this.letzteAuffaelligeObjekte.clear(),this.resolvedUserId=await this.getEffectiveUserId();let e=new Date,t=this.userTimezone||Intl.DateTimeFormat().resolvedOptions().timeZone,s=e.toLocaleString("de-AT",{weekday:"long",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit",timeZone:t})+` (${t})`,n=this.buildSourceDefs(e),i=n.findIndex(T=>T.key==="memories"),r=i>=0?n.splice(i,1)[0]:void 0,a=Date.now(),o=[],c={},d=m(async T=>{let k=Date.now(),b=await T.fetch();c[T.key]=Date.now()-k;let v=Math.floor(T.maxTokens*3.5);if(b.length>v){let N=Math.ceil(b.length/3.5),I=b.split(`
6401
6401
  `),$=0,L=[];for(let K of I){if($+K.length+1>v)break;L.push(K),$+=K.length+1}b=L.join(`
6402
6402
  `)+`
@@ -6413,7 +6413,7 @@ Hinweis: Wenn ein Runbook passt \u2192 mit \`runbook get\` den vollst\xE4ndigen
6413
6413
  ${[...v.values()].slice(0,5).map(L=>{let K=Math.floor((Date.now()-new Date(L.when).getTime())/864e5),U=K===0?"heute":K===1?"gestern":`vor ${K}d`,D=typeof L.details?.runtime=="string"?` \xB7 runtime=${L.details.runtime}`:"",C=typeof L.details?.process_manager=="string"?` \xB7 pm=${L.details.process_manager}`:"";return`- ${L.project} \u2192 ${L.host} (${U})${D}${C}`}).join(`
6414
6414
  `)}
6415
6415
 
6416
- Hinweis: Wenn der User dasselbe Projekt erneut deployen will, ist Host & Setup oben dokumentiert.`;h.push({key:"deploys",label:"Letzte Deploys",priority:2,content:$,tokenEstimate:Math.ceil($.length/3.5),changed:!1})}}}catch(T){this.logger.debug({err:T},"Recent-deploys section failed (non-critical)")}if(this.projectRepo)try{let T=await this.getEffectiveUserId();if(T){let k=await this.projectRepo.list(T,{status:"active",limit:10});if(k.length>0){let b=[],v=[],N=Date.now(),I=30,$=await this.projectRepo.listOpenItems(T,{status:"open",limit:50}),L=new Map;for(let R of $)L.set(R.projectId,(L.get(R.projectId)??0)+1);for(let R of k.slice(0,5)){let j=Math.floor((N-new Date(R.lastActiveAt).getTime())/864e5),B=j===0?"heute":j===1?"gestern":`vor ${j}d`,F=L.get(R.id)??0,fe=F>0?` \u2014 ${F} offene Punkte`:"";b.push(`- **${R.name.slice(0,60)}** (${B})${fe}`),j>=I&&v.push(`- **${R.name.slice(0,60)}** \u2014 seit ${j} Tagen keine Aktivit\xE4t`)}let K=$.filter(R=>!R.dueAt||new Date(R.dueAt).getTime()<N).sort((R,j)=>(R.priority==="high"?0:2)-(j.priority==="high"?0:2)).slice(0,5),U=[];if(K.length>0){let R=new Map(k.map(j=>[j.id,j.name]));for(let j of K){let B=j.priority==="high"?"\u{1F534}":j.priority==="low"?"\u26AA":"\u{1F7E1}",F=R.get(j.projectId)?.slice(0,30)??"?";U.push(`${B} ${j.title.slice(0,80)} [${F}]`)}}let D=[`Aktive Projekte (${k.length}):`,...b];v.length>0&&D.push("","**Stale (>30d inaktiv):**",...v),U.length>0&&D.push("","Offene Punkte (\xFCberf\xE4llig oder ohne Datum):",...U),D.push("","Hinweis: Wenn das aktuelle Thema zu einem dieser Projekte passt, referenziere es im Insight. Stale-Projekte sind Kandidaten f\xFCr Archivierung-Frage oder Follow-up.");let C=D.join(`
6416
+ Hinweis: Wenn der User dasselbe Projekt erneut deployen will, ist Host & Setup oben dokumentiert.`;h.push({key:"deploys",label:"Letzte Deploys",priority:2,content:$,tokenEstimate:Math.ceil($.length/3.5),changed:!1})}}}catch(T){this.logger.debug({err:T},"Recent-deploys section failed (non-critical)")}if(this.projectRepo)try{let T=await this.getEffectiveUserId();if(T){let k=await this.projectRepo.list(T,{status:"active",limit:10});if(k.length>0){let b=[],v=[],N=Date.now(),I=30,$=await this.projectRepo.listOpenItems(T,{status:"open",limit:50}),L=new Map;for(let R of $)L.set(R.projectId,(L.get(R.projectId)??0)+1);for(let R of k.slice(0,5)){let j=Math.floor((N-new Date(R.lastActiveAt).getTime())/864e5),B=j===0?"heute":j===1?"gestern":`vor ${j}d`,F=L.get(R.id)??0,fe=F>0?` \u2014 ${F} offene Punkte`:"";b.push(`- **${R.name.slice(0,60)}** (${B})${fe}`),j>=I&&v.push(`- **${R.name.slice(0,60)}** \u2014 seit ${j} Tagen keine Aktivit\xE4t`)}let K=$.filter(R=>!R.dueAt||new Date(R.dueAt).getTime()<N).sort((R,j)=>(R.priority==="high"?0:2)-(j.priority==="high"?0:2)||R.title.localeCompare(j.title)).slice(0,5),U=[];if(K.length>0){let R=new Map(k.map(j=>[j.id,j.name]));for(let j of K){let B=j.priority==="high"?"\u{1F534}":j.priority==="low"?"\u26AA":"\u{1F7E1}",F=R.get(j.projectId)?.slice(0,30)??"?";U.push(`${B} ${j.title.slice(0,80)} [${F}]`)}}let D=[`Aktive Projekte (${k.length}):`,...b];v.length>0&&D.push("","**Stale (>30d inaktiv):**",...v),U.length>0&&D.push("","Offene Punkte (\xFCberf\xE4llig oder ohne Datum):",...U),D.push("","Hinweis: Wenn das aktuelle Thema zu einem dieser Projekte passt, referenziere es im Insight. Stale-Projekte sind Kandidaten f\xFCr Archivierung-Frage oder Follow-up.");let C=D.join(`
6417
6417
  `);h.push({key:"projects",label:"Aktive Projekte",priority:2,content:C,tokenEstimate:Math.ceil(C.length/3.5),changed:!1})}}}catch(T){this.logger.debug({err:T},"Active-projects section failed (non-critical)")}let w=[];for(let T of h){let k=this.previousContent.get(T.key);k!==void 0&&kN(k)!==kN(T.content)&&(T.changed=!0,w.push(T.key)),this.previousContent.set(T.key,T.content);let b=T.content.startsWith("(")&&(T.content.includes("fehlgeschlagen")||T.content.includes("error")||T.content.includes("timeout")||T.content.includes("nicht verf\xFCgbar")),v=this.previousSuccess.get(T.key);b&&v===!0?T.content+=`
6418
6418
  \u26A0\uFE0F TRANSIENTER FEHLER \u2014 beim letzten Lauf funktionierte diese Quelle. Wahrscheinlich vor\xFCbergehend, KEIN Handlungsbedarf empfehlen.`:b&&v===!1&&(T.content+=`
6419
6419
  \u{1F534} PERSISTENTER FEHLER \u2014 bereits beim letzten Lauf fehlgeschlagen. Handlungsbedarf m\xF6glich.`),this.previousSuccess.set(T.key,!b)}this.annotateResolvedTopics(h);let _=this.fitToBudget(h,Ez),E=_.reduce((T,k)=>T+k.tokenEstimate,0);return{dateTime:s,sections:_,changedSections:w,totalTokens:E}}buildSourceDefs(e){let t=[];t.push({key:"calendar",label:"Kalender (n\xE4chste 48h)",priority:1,maxTokens:400,fetch:m(()=>this.fetchCalendar(e),"fetch")},{key:"vorgaenge",label:"Vorg\xE4nge & Bereits getan",priority:1,maxTokens:300,fetch:m(()=>this.fetchVorgaenge(),"fetch")},{key:"todos",label:"Offene Todos",priority:1,maxTokens:300,fetch:m(()=>this.fetchTodos(),"fetch")},{key:"watches",label:"Aktive Watches",priority:1,maxTokens:300,fetch:m(()=>this.fetchWatches(),"fetch")},{key:"memories",label:"User-Erinnerungen",priority:1,maxTokens:1200,fetch:m(()=>this.fetchMemories(),"fetch")}),this.workflowRepo&&t.push({key:"workflows",label:"Aktive Workflows",priority:2,maxTokens:200,fetch:m(()=>this.fetchWorkflows(),"fetch")}),this.reminderRepo&&t.push({key:"reminders",label:"Aktive Erinnerungen",priority:2,maxTokens:100,fetch:m(()=>this.fetchReminders(),"fetch")}),this.noteRepo&&t.push({key:"notes",label:"Notizen",priority:2,maxTokens:200,fetch:m(()=>this.fetchNotes(),"fetch")}),this.documentRepo&&t.push({key:"documents",label:"Dokumente",priority:3,maxTokens:150,fetch:m(()=>this.fetchDocuments(),"fetch")}),this.skillRegistry.has("weather")&&t.push({key:"weather",label:"Wetter",priority:2,maxTokens:150,fetch:m(()=>this.fetchWeather(),"fetch")}),this.skillRegistry.has("homeassistant")&&t.push({key:"smarthome",label:"Smart Home",priority:2,maxTokens:400,fetch:m(()=>this.fetchSmartHome(),"fetch")}),this.planningAgent&&t.push({key:"plans",label:"Aktive Pl\xE4ne",priority:1,maxTokens:200,fetch:m(async()=>{let i=this.resolvedUserId??"";return await this.planningAgent.getContextSummary(i)||"(keine aktiven Pl\xE4ne)"},"fetch")}),this.skillRegistry.has("bmw")&&t.push({key:"bmw",label:"BMW Status",priority:2,maxTokens:200,fetch:m(()=>this.fetchBmwFromDb(),"fetch")}),this.skillRegistry.has("mikrotik")&&t.push({key:"mikrotik",label:"MikroTik Router",priority:2,maxTokens:200,fetch:m(async()=>{let i=this.skillRegistry.get("mikrotik"),r=i?.buildReasoningContext?await i.buildReasoningContext():"(MikroTik: keine Daten)";if(!this.messwerteRepo)return r;try{let a=await this.getEffectiveUserId(),o=await this.messwerteRepo.letzteProEntity(a,"mikrotik-down",1),{deuteMikrotik:c}=await Promise.resolve().then(()=>(zw(),Bw)),d=o.length?await this.messwerteRepo.verlaufMehrere(a,o.map(h=>h.entity),new Date(Date.now()-30*864e5).toISOString()):[],u=c({aktuellDown:o.map(h=>h.entity),verlauf:d.map(h=>({entity:h.entity,zeit:h.zeit})),routerText:r});return u.auffaellig.length&&this.logger.info({auffaellig:u.auffaellig},"v1173 Infra-Weltmodell: auff\xE4llig"),u.zeilen.join(`
@@ -6504,7 +6504,7 @@ Wenn nichts Handlungsrelevantes \xFCbrig bleibt: antworte exakt KEINE_INSIGHTS.`
6504
6504
  `),e);d?i.push({zeile:c[0].trim(),treffer:d}):r.push(...c),a=o}return r.some(o=>wf.test(o))?{text:r.join(`
6505
6505
  `),entfernt:i}:{text:null,entfernt:i}}function ON(l){let e=l.split(/(?<=[.!?])\s+/)[0]??l;return(e.length>200?e.slice(0,200)+"\u2026":e).trim()}function o_(l,e){let t=e.filter(n=>c_(n.value));if(t.length===0)return[];let s=new Set;for(let n of l.sections){if(n.key==="memories")continue;let i=new Set;for(let o of n.content.matchAll(/↳ NORMAL laut User-Korrektur[^[]*\[([^\]]+)\]/g))i.add(o[1]);let r=[];for(let o of n.content.split(`
6506
6506
  `)){if(r.push(o),o.trim().length<8||o.includes(r_))continue;let c=t.filter(u=>!i.has(u.key));if(c.length===0)continue;let d=Jn(o,c);if(d){i.add(d.key),s.add(d.key);let u=t.find(h=>h.key===d.key)?.value??"";r.push(` ${r_} [${d.key}]: ${ON(u)} \u2014 KEIN Fehler, NICHT als Problem/Insight melden.`)}}let a=t.filter(o=>!i.has(o.key));if(a.length>0){let o=Jn(n.content,a);if(o){s.add(o.key);let c=t.find(d=>d.key===o.key)?.value??"";r.push(`${r_} f\xFCr diesen Abschnitt [${o.key}]: ${ON(c)} \u2014 entsprechende Beobachtungen sind NORMAL, NICHT melden.`)}}n.content=r.join(`
6507
- `)}return[...s]}function WN(l,e){let t=m(r=>new Set(r.toLowerCase().replace(/[^a-zäöüß0-9\s]/g," ").split(/\s+/).filter(a=>a.length>=4)),"tok"),s=m(r=>{let a=r.toLowerCase();return MN.filter(o=>a.includes(o))},"objekte"),n=t(l);if(n.size===0)return!1;let i=new Set(s(l));for(let r of e){let a=t(r);if(a.size===0)continue;let o=0;for(let d of n)a.has(d)&&o++;let c=o/(n.size+a.size-o);if(c>=.5||c>=.25&&s(r).some(d=>i.has(d)))return!0}return!1}function a_(l){if(!l||l.length<10)return!0;let e=l.trim();return e==="KEINE_INSIGHTS"||e.toLowerCase()==="keine_insights"}function qz(l){if(!l||l.length<10)return{hasInsights:!1,items:[]};try{let t=l.match(/\{[\s\S]*\}/);if(t){let s=JSON.parse(t[0]);if(typeof s.hasInsights=="boolean")return{hasInsights:s.hasInsights,items:Array.isArray(s.items)?s.items:[]}}}catch{}let e=l.toUpperCase();return e.includes("KEINE_INSIGHTS")||e.includes("KEINE NEUEN INSIGHTS")||e.includes("KEINE INSIGHTS")?{hasInsights:!1,items:[]}:{hasInsights:!0,items:[{summary:l,urgency:"normal"}]}}var Bz,MN,PN,zz,Hz,Xz,Kz,jN,BN,wf,r_,DN,Ul,xN,Vz,_f,Oo,Fl=A(()=>{"use strict";ze();pf();$l();Ll();xl();mf();wn();NN();Bz=[7,12,18],MN=["wallbox","bmw","i4","batterie","akku","speicher","victron","ess","pool","heizung","geschirrsp\xFCler","waschmaschine","trockner","pv","solar","wechselrichter","strompreis","awattar","proxmox","unifi","mikrotik","fritzbox","nas","backup","zertifikat","domain","mqtt","kalender","termin","email","todo","erinnerung","tanken","laden","ladevorgang","reichweite","soc"],PN=/\b(ist (doch |völlig |ganz |eh |ohnehin )?(normal|ok|in ordnung|so gewollt)|kein (fehler|problem|defekt|grund zur)|falschalarm|nicht[^.!?\n]{0,60}\b(melden|warnen|alarmieren|erinnern)|sendet nur|nur (wenn|bei|während)|expected behavior|not an? (issue|error))\b/i;m(c_,"istUnterdrueckungsAussage");zz=new Set(["nicht","mehr","wenn","dann","aber","auch","wurde","wurden","bereits","mehrfach","gesagt","wird","sind","ist","eine","einem","einer","dass","das","der","die","weil","nur","sendet","alfred","immer","dauernd","st\xE4ndig","melden","meldung","meldungen","bitte","sich","sein","seit","oder","beim","diese","dieser"]),Hz=new Set(["kritisch","kritischen","batterie","fehler","warnung","status","daten","offline","online","problem","sensor","sensoren","aktuell","aktuelle","aktuellen","daher","verwenden","wert","werte","sollte","sollten","tats\xE4chlich","tats\xE4chlichen","ausschlie\xDFlich","konfiguriert","konfigurierte","minimum","maximum","wieder","weiterhin","gerade","handlungsbedarf","offen","offene","offenen","gemeldet","gemeldeten","vollst\xE4ndig","insight","insights","e-mail","e-mails","nachricht","nachrichten","benachrichtigung","benachrichtigungen"]);m(l_,"wortstamm");Xz=new Set([...Hz].map(l_));m(Wz,"istFachAnker");m(UN,"kernwoerterAusKorrektur");Kz=["mqtt","wallbox","victron","proxmox","unifi","mikrotik","fritzbox","awattar","strompreis","wechselrichter","geschirrsp\xFCler","waschmaschine","trockner","pool","heizung","zertifikat","commvault"];m(FN,"istVorgangsbezogeneKorrektur");jN=new Set(["activity","skillHealth","insightTracking","feedback","action_feedback","trends","weather","energy","crypto","infra","feeds"]),BN=120;m(zN,"istRundgangOhneAenderung");m(HN,"gateAusgesetztDurchWeltmodell");m(Jn,"findeVerletzteUnterdrueckungsKorrektur");m(Gz,"verletztUnterdrueckungsKorrektur");wf=/^\s*(?:[-*•]|\d+[.)])\s+/;m(XN,"filtereSegmentMitKorrekturen");m(ON,"korrekturKurzfassung");r_="\u21B3 NORMAL laut User-Korrektur";m(o_,"annotiereKontextMitKorrekturen");m(WN,"istInhaltlichesInsightDuplikat");DN=1536,Ul="---ACTIONS---",xN=300*1e3,Vz=360*60*1e3,_f="---TOPICS---";m(a_,"isNoInsights");m(qz,"parseScanResponse");Oo=class l{static{m(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;defaultLocation;feedbackRepo;confirmationQueue;nodeId;adapter;insightTracker;kgService;workflowRepo;noteRepo;reminderRepoRef;documentRepo;userTimezone;conversationRepo;runbookRepo;projectRepo;tickTimer;lastRunHour=-1;lastDeferredCleanupDay="";lastEventTriggerAt=0;enabled;schedule;tier;deduplicationHours;collector;deliveryScheduler;planningAgent;notificationRouter;setPlanningAgent(e){this.planningAgent=e}setNotificationRouter(e){this.notificationRouter=e}interestsRepo;setInterestsRepo(e){this.interestsRepo=e}vorgaengeRepo;setVorgaengeRepo(e){this.vorgaengeRepo=e}async protokolliereSchritt(e,t,s,n){if(this.kennzahlen.zaehle(jw[t]),!!this.vorgaengeRepo)try{let{klassifiziereAktion:i}=await Promise.resolve().then(()=>(Pl(),Ml));await this.vorgaengeRepo.schritt({vorgangId:n,userId:this.resolvedOwnerUserId||this.defaultChatId,art:t,skill:e.skillName,aktion:typeof e.skillParams?.action=="string"?e.skillParams.action:void 0,params:e.skillParams,beschreibung:e.description,ergebnis:s,autonomie:i(e.skillName,e.skillParams),quelle:"reasoning"})}catch(i){this.logger.debug({err:i.message},"v1179 Schritt nicht protokolliert")}}async legeInsightVorgaengeAn(e){if(!(!this.vorgaengeRepo||e.length===0))try{let{istHandlungsInsight:t,vorgangTitelAus:s,istGenerischerTitel:n}=await Promise.resolve().then(()=>(Pl(),Ml)),i=this.resolvedOwnerUserId||this.defaultChatId,r=0;for(let a of e){if(!t(a))continue;let o=s(a);if(n(o))continue;let c=await this.vorgaengeRepo.anlegen({userId:i,titel:o,ziel:a.slice(0,500),besitzer:"user",status:"offen",naechsterSchritt:"Owner entscheidet",frist:new Date(Date.now()+7*864e5).toISOString(),quelle:"reasoning-insight",autonomie:"bestaetigen",kategorie:An.categorizeInsight(a),dedupeKey:`insight:${this.insightTopicHash(a)}`});r++,c.erstellt===c.aktualisiert&&this.kennzahlen.zaehle("vorgaengeAngelegt")}r&&this.logger.info({angelegt:r,insights:e.length},"v1180 Handlungs-Insights als Vorg\xE4nge angelegt")}catch(t){this.logger.debug({err:t.message},"v1180 Insight\u2192Vorgang fehlgeschlagen")}}async legeVorgaengeAn(e){let t=new Map;if(!this.vorgaengeRepo||e.length===0)return t;try{let{klassifiziereAktion:s}=await Promise.resolve().then(()=>(Pl(),Ml)),n=this.resolvedOwnerUserId||this.defaultChatId;for(let i of e.slice(0,5)){let r=s(i.skillName,i.skillParams),a=`${i.skillName}:${i.description.toLowerCase().replace(/[^a-zäöüß0-9]+/g," ").trim().slice(0,80)}`,o=await this.vorgaengeRepo.anlegen({userId:n,titel:i.description.slice(0,200),besitzer:r==="auto"?"alfred":"user",status:"offen",naechsterSchritt:r==="auto"?"ausf\xFChren":r==="nie"?"nur manuell durch den Owner":"Best\xE4tigung des Owners",frist:new Date(Date.now()+7*864e5).toISOString(),quelle:"reasoning",autonomie:r,dedupeKey:a,kategorie:i.skillName});t.set(i,o.id),await this.vorgaengeRepo.schritt({vorgangId:o.id,userId:n,art:"vorgeschlagen",skill:i.skillName,aktion:typeof i.skillParams?.action=="string"?i.skillParams.action:void 0,params:i.skillParams,beschreibung:i.description,autonomie:r,quelle:"reasoning"})}}catch(s){this.logger.debug({err:s.message},"v1179 Vorgang nicht angelegt")}return t}resolvedOwnerUserId;activityProfile;constructor(e,t,s,n,i,r,a,o,c,d,u,h,p,f,g,y,w,_,E,T,k="single",b,v,N,I,$,L,K,U,D,C,R,j,B){this.calendarProvider=e,this.todoRepo=t,this.watchRepo=s,this.memoryRepo=n,this.activityRepo=i,this.skillHealthRepo=r,this.notifRepo=a,this.skillRegistry=o,this.skillSandbox=c,this.llm=d,this.adapters=u,this.userRepo=h,this.defaultChatId=p,this.defaultPlatform=f,this.logger=y,this.activityLogger=w,this.defaultLocation=_,this.feedbackRepo=E,this.confirmationQueue=T,this.nodeId=k,this.adapter=b,this.insightTracker=v,this.kgService=I,this.workflowRepo=$,this.noteRepo=K,this.reminderRepoRef=U,this.documentRepo=D,this.userTimezone=C,this.conversationRepo=R,this.runbookRepo=j,this.projectRepo=B,this.enabled=g?.enabled!==!1,this.schedule=g?.schedule??"hourly",this.tier=g?.tier??"default",this.deduplicationHours=g?.deduplicationHours??12;let F=C||Intl.DateTimeFormat().resolvedOptions().timeZone;this.collector=N??new Dl(this.skillRegistry,this.skillSandbox,this.userRepo,this.calendarProvider,this.todoRepo,this.watchRepo,this.memoryRepo,this.activityRepo,this.skillHealthRepo,this.feedbackRepo,this.defaultChatId,this.defaultPlatform,this.defaultLocation,this.logger,this.workflowRepo,L,K,U,D,F,this.conversationRepo,this.runbookRepo,this.projectRepo),this.adapter&&(this.deliveryScheduler=new gf(this.adapter,this.logger.child({component:"delivery-scheduler"}),F,g?.quietHours??[22,7]))}start(){if(!this.enabled){this.logger.info("Reasoning engine disabled");return}let e=!1;this.tickTimer=setInterval(()=>{e||(e=!0,this.tick().catch(t=>this.logger.error({err:t},"Reasoning tick unhandled error")).finally(()=>{e=!1}))},6e4),this.logger.info({schedule:this.schedule,tier:this.tier,nodeId:this.nodeId,budget:3500},"Reasoning engine started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0)}async triggerOnEvent(e,t,s={}){if(!this.enabled)return;let n=Date.now();if(n-this.lastEventTriggerAt<xN){this.logger.debug({eventType:e},"Event-triggered reasoning debounced (local)");return}if(this.lastEventTriggerAt=n,this.adapter&&this.adapter.type==="postgres"){let r=`reasoning-event:${Math.floor(n/xN)}:${e}`;if((await this.adapter.execute("INSERT INTO reasoning_slots (slot_key, node_id, claimed_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING",[r,this.nodeId,new Date().toISOString()])).changes===0)return}try{let i=await this.collector.collect();await this.enrichWithKnowledgeGraph(i),await this.wendeKorrekturenAufKontextAn(i);let r=`Du bist Alfreds holistisches Denk-Modul. Ein Event ist eingetreten:
6507
+ `)}return[...s]}function WN(l,e){let t=m(r=>new Set(r.toLowerCase().replace(/[^a-zäöüß0-9\s]/g," ").split(/\s+/).filter(a=>a.length>=4)),"tok"),s=m(r=>{let a=r.toLowerCase();return MN.filter(o=>a.includes(o))},"objekte"),n=t(l);if(n.size===0)return!1;let i=new Set(s(l));for(let r of e){let a=t(r);if(a.size===0)continue;let o=0;for(let d of n)a.has(d)&&o++;let c=o/(n.size+a.size-o);if(c>=.5||c>=.25&&s(r).some(d=>i.has(d)))return!0}return!1}function a_(l){if(!l||l.length<10)return!0;let e=l.trim();return e==="KEINE_INSIGHTS"||e.toLowerCase()==="keine_insights"}function qz(l){if(!l||l.length<10)return{hasInsights:!1,items:[]};try{let t=l.match(/\{[\s\S]*\}/);if(t){let s=JSON.parse(t[0]);if(typeof s.hasInsights=="boolean")return{hasInsights:s.hasInsights,items:Array.isArray(s.items)?s.items:[]}}}catch{}let e=l.toUpperCase();return e.includes("KEINE_INSIGHTS")||e.includes("KEINE NEUEN INSIGHTS")||e.includes("KEINE INSIGHTS")?{hasInsights:!1,items:[]}:{hasInsights:!0,items:[{summary:l,urgency:"normal"}]}}var Bz,MN,PN,zz,Hz,Xz,Kz,jN,BN,wf,r_,DN,Ul,xN,Vz,_f,Oo,Fl=A(()=>{"use strict";ze();pf();$l();Ll();xl();mf();wn();NN();Bz=[7,12,18],MN=["wallbox","bmw","i4","batterie","akku","speicher","victron","ess","pool","heizung","geschirrsp\xFCler","waschmaschine","trockner","pv","solar","wechselrichter","strompreis","awattar","proxmox","unifi","mikrotik","fritzbox","nas","backup","zertifikat","domain","mqtt","kalender","termin","email","todo","erinnerung","tanken","laden","ladevorgang","reichweite","soc"],PN=/\b(ist (doch |völlig |ganz |eh |ohnehin )?(normal|ok|in ordnung|so gewollt)|kein (fehler|problem|defekt|grund zur)|falschalarm|nicht[^.!?\n]{0,60}\b(melden|warnen|alarmieren|erinnern)|sendet nur|nur (wenn|bei|während)|expected behavior|not an? (issue|error))\b/i;m(c_,"istUnterdrueckungsAussage");zz=new Set(["nicht","mehr","wenn","dann","aber","auch","wurde","wurden","bereits","mehrfach","gesagt","wird","sind","ist","eine","einem","einer","dass","das","der","die","weil","nur","sendet","alfred","immer","dauernd","st\xE4ndig","melden","meldung","meldungen","bitte","sich","sein","seit","oder","beim","diese","dieser"]),Hz=new Set(["kritisch","kritischen","batterie","fehler","warnung","status","daten","offline","online","problem","sensor","sensoren","aktuell","aktuelle","aktuellen","daher","verwenden","wert","werte","sollte","sollten","tats\xE4chlich","tats\xE4chlichen","ausschlie\xDFlich","konfiguriert","konfigurierte","minimum","maximum","wieder","weiterhin","gerade","handlungsbedarf","offen","offene","offenen","gemeldet","gemeldeten","vollst\xE4ndig","insight","insights","e-mail","e-mails","nachricht","nachrichten","benachrichtigung","benachrichtigungen"]);m(l_,"wortstamm");Xz=new Set([...Hz].map(l_));m(Wz,"istFachAnker");m(UN,"kernwoerterAusKorrektur");Kz=["mqtt","wallbox","victron","proxmox","unifi","mikrotik","fritzbox","awattar","strompreis","wechselrichter","geschirrsp\xFCler","waschmaschine","trockner","pool","heizung","zertifikat","commvault"];m(FN,"istVorgangsbezogeneKorrektur");jN=new Set(["activity","skillHealth","insightTracking","feedback","action_feedback","trends","weather","energy","crypto","infra","feeds","vorgaenge","charger"]),BN=120;m(zN,"istRundgangOhneAenderung");m(HN,"gateAusgesetztDurchWeltmodell");m(Jn,"findeVerletzteUnterdrueckungsKorrektur");m(Gz,"verletztUnterdrueckungsKorrektur");wf=/^\s*(?:[-*•]|\d+[.)])\s+/;m(XN,"filtereSegmentMitKorrekturen");m(ON,"korrekturKurzfassung");r_="\u21B3 NORMAL laut User-Korrektur";m(o_,"annotiereKontextMitKorrekturen");m(WN,"istInhaltlichesInsightDuplikat");DN=1536,Ul="---ACTIONS---",xN=300*1e3,Vz=360*60*1e3,_f="---TOPICS---";m(a_,"isNoInsights");m(qz,"parseScanResponse");Oo=class l{static{m(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;defaultLocation;feedbackRepo;confirmationQueue;nodeId;adapter;insightTracker;kgService;workflowRepo;noteRepo;reminderRepoRef;documentRepo;userTimezone;conversationRepo;runbookRepo;projectRepo;tickTimer;lastRunHour=-1;lastDeferredCleanupDay="";lastEventTriggerAt=0;enabled;schedule;tier;deduplicationHours;collector;deliveryScheduler;planningAgent;notificationRouter;setPlanningAgent(e){this.planningAgent=e}setNotificationRouter(e){this.notificationRouter=e}interestsRepo;setInterestsRepo(e){this.interestsRepo=e}vorgaengeRepo;setVorgaengeRepo(e){this.vorgaengeRepo=e}async protokolliereSchritt(e,t,s,n){if(this.kennzahlen.zaehle(jw[t]),!!this.vorgaengeRepo)try{let{klassifiziereAktion:i}=await Promise.resolve().then(()=>(Pl(),Ml));await this.vorgaengeRepo.schritt({vorgangId:n,userId:this.resolvedOwnerUserId||this.defaultChatId,art:t,skill:e.skillName,aktion:typeof e.skillParams?.action=="string"?e.skillParams.action:void 0,params:e.skillParams,beschreibung:e.description,ergebnis:s,autonomie:i(e.skillName,e.skillParams),quelle:"reasoning"})}catch(i){this.logger.debug({err:i.message},"v1179 Schritt nicht protokolliert")}}async legeInsightVorgaengeAn(e){if(!(!this.vorgaengeRepo||e.length===0))try{let{istHandlungsInsight:t,vorgangTitelAus:s,istGenerischerTitel:n}=await Promise.resolve().then(()=>(Pl(),Ml)),i=this.resolvedOwnerUserId||this.defaultChatId,r=0;for(let a of e){if(!t(a))continue;let o=s(a);if(n(o))continue;let c=await this.vorgaengeRepo.anlegen({userId:i,titel:o,ziel:a.slice(0,500),besitzer:"user",status:"offen",naechsterSchritt:"Owner entscheidet",frist:new Date(Date.now()+7*864e5).toISOString(),quelle:"reasoning-insight",autonomie:"bestaetigen",kategorie:An.categorizeInsight(a),dedupeKey:`insight:${this.insightTopicHash(a)}`});r++,c.erstellt===c.aktualisiert&&this.kennzahlen.zaehle("vorgaengeAngelegt")}r&&this.logger.info({angelegt:r,insights:e.length},"v1180 Handlungs-Insights als Vorg\xE4nge angelegt")}catch(t){this.logger.debug({err:t.message},"v1180 Insight\u2192Vorgang fehlgeschlagen")}}async legeVorgaengeAn(e){let t=new Map;if(!this.vorgaengeRepo||e.length===0)return t;try{let{klassifiziereAktion:s}=await Promise.resolve().then(()=>(Pl(),Ml)),n=this.resolvedOwnerUserId||this.defaultChatId;for(let i of e.slice(0,5)){let r=s(i.skillName,i.skillParams),a=`${i.skillName}:${i.description.toLowerCase().replace(/[^a-zäöüß0-9]+/g," ").trim().slice(0,80)}`,o=await this.vorgaengeRepo.anlegen({userId:n,titel:i.description.slice(0,200),besitzer:r==="auto"?"alfred":"user",status:"offen",naechsterSchritt:r==="auto"?"ausf\xFChren":r==="nie"?"nur manuell durch den Owner":"Best\xE4tigung des Owners",frist:new Date(Date.now()+7*864e5).toISOString(),quelle:"reasoning",autonomie:r,dedupeKey:a,kategorie:i.skillName});t.set(i,o.id),await this.vorgaengeRepo.schritt({vorgangId:o.id,userId:n,art:"vorgeschlagen",skill:i.skillName,aktion:typeof i.skillParams?.action=="string"?i.skillParams.action:void 0,params:i.skillParams,beschreibung:i.description,autonomie:r,quelle:"reasoning"})}}catch(s){this.logger.debug({err:s.message},"v1179 Vorgang nicht angelegt")}return t}resolvedOwnerUserId;activityProfile;constructor(e,t,s,n,i,r,a,o,c,d,u,h,p,f,g,y,w,_,E,T,k="single",b,v,N,I,$,L,K,U,D,C,R,j,B){this.calendarProvider=e,this.todoRepo=t,this.watchRepo=s,this.memoryRepo=n,this.activityRepo=i,this.skillHealthRepo=r,this.notifRepo=a,this.skillRegistry=o,this.skillSandbox=c,this.llm=d,this.adapters=u,this.userRepo=h,this.defaultChatId=p,this.defaultPlatform=f,this.logger=y,this.activityLogger=w,this.defaultLocation=_,this.feedbackRepo=E,this.confirmationQueue=T,this.nodeId=k,this.adapter=b,this.insightTracker=v,this.kgService=I,this.workflowRepo=$,this.noteRepo=K,this.reminderRepoRef=U,this.documentRepo=D,this.userTimezone=C,this.conversationRepo=R,this.runbookRepo=j,this.projectRepo=B,this.enabled=g?.enabled!==!1,this.schedule=g?.schedule??"hourly",this.tier=g?.tier??"default",this.deduplicationHours=g?.deduplicationHours??12;let F=C||Intl.DateTimeFormat().resolvedOptions().timeZone;this.collector=N??new Dl(this.skillRegistry,this.skillSandbox,this.userRepo,this.calendarProvider,this.todoRepo,this.watchRepo,this.memoryRepo,this.activityRepo,this.skillHealthRepo,this.feedbackRepo,this.defaultChatId,this.defaultPlatform,this.defaultLocation,this.logger,this.workflowRepo,L,K,U,D,F,this.conversationRepo,this.runbookRepo,this.projectRepo),this.adapter&&(this.deliveryScheduler=new gf(this.adapter,this.logger.child({component:"delivery-scheduler"}),F,g?.quietHours??[22,7]))}start(){if(!this.enabled){this.logger.info("Reasoning engine disabled");return}let e=!1;this.tickTimer=setInterval(()=>{e||(e=!0,this.tick().catch(t=>this.logger.error({err:t},"Reasoning tick unhandled error")).finally(()=>{e=!1}))},6e4),this.logger.info({schedule:this.schedule,tier:this.tier,nodeId:this.nodeId,budget:3500},"Reasoning engine started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0)}async triggerOnEvent(e,t,s={}){if(!this.enabled)return;let n=Date.now();if(n-this.lastEventTriggerAt<xN){this.logger.debug({eventType:e},"Event-triggered reasoning debounced (local)");return}if(this.lastEventTriggerAt=n,this.adapter&&this.adapter.type==="postgres"){let r=`reasoning-event:${Math.floor(n/xN)}:${e}`;if((await this.adapter.execute("INSERT INTO reasoning_slots (slot_key, node_id, claimed_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING",[r,this.nodeId,new Date().toISOString()])).changes===0)return}try{let i=await this.collector.collect();await this.enrichWithKnowledgeGraph(i),await this.wendeKorrekturenAufKontextAn(i);let r=`Du bist Alfreds holistisches Denk-Modul. Ein Event ist eingetreten:
6508
6508
 
6509
6509
  EVENT: ${String(e).replace(/[=\n\r]/g," ").slice(0,100)}
6510
6510
  DETAILS: ${String(t).replace(/[=\n\r]/g," ").slice(0,300)}
@@ -7812,7 +7812,7 @@ Base commit: \`${e.baseCommitSha.slice(0,8)}\``;return{ok:!0,prUrl:(await a.crea
7812
7812
  `)+d.join(`
7813
7813
  `)+`
7814
7814
  `;r(o,u,"utf8")}}catch(i){this.deps.logger.debug({err:i},"v726 .gitignore update skipped")}if(t.kind!=="empty")try{let{copyFileSync:i,statSync:r}=await import("node:fs");if(t.kind==="repo_path"){if(t.path.includes(".."))throw new Error("repo_path darf kein .. enthalten");let a=Xt.resolve(s,t.path);if(!a.startsWith(Xt.resolve(s)))throw new Error("repo_path verl\xE4sst projectCwd");let o=Xt.join(n,Xt.basename(a));i(a,o),this.deps.logger.info({src:a,target:o,size:r(o).size},"v726 db-seed copied from repo_path")}else if(t.kind==="upload"){if(!this.deps.dbSeedRepo||!this.deps.uploadSeedsPath)throw new Error("Upload-Seed angefordert aber dbSeedRepo/uploadSeedsPath nicht konfiguriert");let a=await this.deps.dbSeedRepo.getById(t.seedId);if(!a)throw new Error(`Seed ${t.seedId} nicht gefunden`);if(a.kind!=="upload")throw new Error(`Seed ${t.seedId} ist kind=${a.kind}, nicht upload`);let o=Xt.resolve(this.deps.uploadSeedsPath,a.storageRef);if(!o.startsWith(Xt.resolve(this.deps.uploadSeedsPath)))throw new Error("Upload-Seed verl\xE4sst uploadSeedsPath");let c=Xt.join(n,a.name);i(o,c),this.deps.logger.info({src:o,target:c,size:r(c).size},"v726 db-seed copied from upload")}}catch(i){this.deps.logger.warn({err:i},"v726 db-seed copy failed (sandbox startet mit leerem .alfred-data)")}}};m(Os,"runGit");m(dW,"runGitBoth");uW=[{name:"AWS Access Key",re:/\bAKIA[0-9A-Z]{16}\b/g},{name:"GitHub Token",re:/\bghp_[A-Za-z0-9]{36}\b/g},{name:"GitHub PAT",re:/\bghs_[A-Za-z0-9]{36}\b/g},{name:"GitLab Token",re:/\bglpat-[A-Za-z0-9_-]{20}\b/g},{name:"OpenAI Key",re:/\bsk-[A-Za-z0-9]{48,}\b/g},{name:"Anthropic Key",re:/\bsk-ant-[A-Za-z0-9-_]{24,}\b/g},{name:"Stripe Secret",re:/\bsk_live_[A-Za-z0-9]{24,}\b/g},{name:"Slack Token",re:/\bxox[abp]-[A-Za-z0-9-]{10,}\b/g},{name:"Private Key",re:/-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/g},{name:"JWT Token",re:/\beyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\b/g}];m(hW,"stripAnsi");m(pW,"summarizeTestFailure");m(fW,"scanForSecrets");m(mW,"parseRepoFromUrl");m(gW,"resolveDockerfilesDir")});var jL={};Le(jL,{IdentityResolver:()=>EE});var EE,BL=A(()=>{"use strict";Yi();EE=class{static{m(this,"IdentityResolver")}users;projects;logger;constructor(e,t,s){this.users=e,this.projects=t,this.logger=s}async resolveOwnerFromConfig(e,t){if(!e||typeof e!="string")throw new Error("IdentityResolver.resolveOwnerFromConfig: empty/invalid envValue");if(Jr(e)){try{await this.users.findById(e)||this.logger.warn({envValue:e.slice(0,8)},"v804 owner UUID not found in users-table \u2014 accepting anyway (may belong to alfred_users table)")}catch{}return ug(e)}let s=t??this.guessPlatformFromFormat(e);if(!s)throw new Error(`IdentityResolver.resolveOwnerFromConfig: "${e.slice(0,20)}" ist kein UUID-Format und keine platform-hint angegeben. Setze ALFRED_OWNER_PLATFORM=telegram (oder matrix/discord/etc.) oder ALFRED_OWNER_USER_ID direkt auf den DB-UUID.`);let n=await this.users.findOrCreate(s,e),i=pc(n.id);if(!i)throw new Error(`IdentityResolver: findOrCreate returned non-UUID id "${n.id}"`);return this.logger.info({platform:s,platformUserId:e.slice(0,12)+"\u2026",resolvedUUID:i.slice(0,8)+"\u2026"},"v804 owner platform-id resolved to UUID"),i}async resolveMasterId(e){try{let t=await this.users.getMasterUserId(e);return pc(t)??e}catch(t){return this.logger.debug({err:t,userId:e.slice(0,8)},"v804 getMasterUserId failed, returning original"),e}}async findProjectOwner(e){if(!this.projects)return null;try{let t=await this.projects.getByIdAnyOwner(e);return t?pc(t.userId)??null:null}catch(t){return this.logger.debug({err:t,projectId:e},"v804 findProjectOwner failed"),null}}guessPlatformFromFormat(e){if(/^\d{6,15}$/.test(e))return"telegram";if(/^@[^:]+:[\w.-]+$/.test(e))return"matrix"}}});var zL={};Le(zL,{UserIdAuditScanner:()=>kE});import{randomUUID as yW}from"node:crypto";var wW,kE,HL=A(()=>{"use strict";Yi();wW=[{table:"memories",pk:"id",uidColumn:"user_id"},{table:"documents",pk:"id",uidColumn:"user_id"},{table:"document_chunks",pk:"id",uidColumn:"user_id"},{table:"todos",pk:"id",uidColumn:"user_id"},{table:"notes",pk:"id",uidColumn:"user_id"},{table:"reminders",pk:"id",uidColumn:"user_id"},{table:"conversations",pk:"id",uidColumn:"user_id"},{table:"projects",pk:"id",uidColumn:"user_id"},{table:"background_tasks",pk:"id",uidColumn:"user_id"},{table:"agent_sessions",pk:"id",uidColumn:"user_id"},{table:"sandboxes",pk:"id",uidColumn:"user_id"},{table:"project_automations",pk:"id",uidColumn:"user_id"},{table:"goals",pk:"id",uidColumn:"user_id"},{table:"runbooks",pk:"id",uidColumn:"user_id"},{table:"insights",pk:"id",uidColumn:"user_id"}],kE=class{static{m(this,"UserIdAuditScanner")}adapter;logger;targets;constructor(e,t,s=wW){this.adapter=e,this.logger=t,this.targets=s}async scan(){let e={scanned:0,flaggedNew:0,alreadyFlagged:0,skippedTables:[]},t=new Date().toISOString();for(let s of this.targets)try{let n=await this.adapter.query(`SELECT ${s.pk} AS row_id, ${s.uidColumn} AS uid FROM ${s.table} WHERE ${s.uidColumn} IS NOT NULL`);for(let i of n){e.scanned+=1;let r=hg(i.uid);if(r==="uuid")continue;if(await this.adapter.queryOne("SELECT id FROM user_id_format_audit WHERE table_name = ? AND column_name = ? AND row_id = ?",[s.table,s.uidColumn,String(i.row_id)])){e.alreadyFlagged+=1;continue}await this.adapter.execute(`INSERT INTO user_id_format_audit (id, table_name, column_name, row_id, user_id_value, format_class, detected_at)
7815
- VALUES (?, ?, ?, ?, ?, ?, ?)`,[yW(),s.table,s.uidColumn,String(i.row_id),i.uid,r,t]),e.flaggedNew+=1}}catch(n){let i=n.message??"";if(/no such table|does not exist|relation .* does not exist/i.test(i)){e.skippedTables.push(s.table);continue}this.logger.warn({err:n,table:s.table},"v808 audit-scan failed for table (continuing)")}return e.flaggedNew>0?this.logger.warn({scanned:e.scanned,flaggedNew:e.flaggedNew,alreadyFlagged:e.alreadyFlagged,skipped:e.skippedTables.length},"v808 UserIdAudit: non-UUID user_id rows detected \u2014 see user_id_format_audit table"):this.logger.debug({scanned:e.scanned,alreadyFlagged:e.alreadyFlagged,skipped:e.skippedTables.length},"v808 UserIdAudit: scan complete, all user_id rows have UUID format"),e}}});var rm={};Le(rm,{default:()=>TW});var TW,am=A(()=>{TW={name:"@madh-io/alfred-ai",version:"0.19.0-jarvis.1188",description:"Alfred \u2014 Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",type:"module",bin:{alfred:"bundle/index.js"},files:["bundle"],scripts:{build:"tsc",bundle:"node ../../scripts/bundle.mjs",prepublishOnly:"npm run build && npm run bundle",clean:"rm -rf dist bundle *.tsbuildinfo"},keywords:["ai","assistant","chatbot","telegram","discord","whatsapp","matrix","signal","claude","openai","ollama"],license:"MIT",repository:{type:"git",url:"https://github.com/madh99/alfred-ai.git"},homepage:"https://github.com/madh99/alfred-ai#readme",bugs:{url:"https://github.com/madh99/alfred-ai/issues"},dependencies:{"@anthropic-ai/sdk":"^0.105.0","@google/genai":"^1.45.0","@modelcontextprotocol/sdk":"^1.12.1","better-sqlite3":"^11.8.0",botbuilder:"^4.23.0",ccxt:"^4.4.0","discord.js":"^14.18.0",docx:"^9.0.0",dotenv:"^16.4.0",exceljs:"^4.4.0",grammy:"^1.35.0",imapflow:"^1.2.10","js-yaml":"^4.1.0",mammoth:"^1.8.0",mqtt:"^5.0.0",nodemailer:"^8.0.1",openai:"^6.44.0","pdf-parse":"^1.1.1",pdfkit:"^0.16.0",pino:"^9.6.0","pino-pretty":"^13.0.0",puppeteer:"^24.0.0","puppeteer-core":"^24.0.0","rss-parser":"^3.13.0",sharp:"^0.34.0",sonos:"^1.14.0",undici:"^7.10.0","youtube-transcript":"^1.3.0",zod:"^3.24.0"},optionalDependencies:{"@aws-sdk/client-s3":"^3.700.0","@influxdata/influxdb-client":"^1.35.0","@whiskeysockets/baileys":"6.7.21",googleapis:"^144.0.0","hafas-client":"^6.3.0",ioredis:"^5.4.0","matrix-bot-sdk":"^0.8.0",mongodb:"^6.12.0",mssql:"^11.0.0",mysql2:"^3.12.0",pg:"^8.13.0",tsdav:"^2.1.0"},devDependencies:{"@alfred/config":"workspace:*","@alfred/core":"workspace:*","@alfred/logger":"workspace:*","@alfred/mcp-server":"workspace:*","@alfred/security":"workspace:*","@alfred/storage":"workspace:*","@alfred/types":"workspace:*","@types/js-yaml":"^4.0.9"},publishConfig:{access:"public"},engines:{node:">=20"}}});var XL={};Le(XL,{collectNodeMetrics:()=>om});import Go from"node:os";import{statfs as EW}from"node:fs/promises";async function om(l){let e=[],t=new Set;for(let s of l)if(s)try{let n=await EW(s),i=Number(n.blocks)*Number(n.bsize),r=Number(n.bavail)*Number(n.bsize);if(i<=0)continue;let a=`${i}:${Number(n.bfree)}:${Number(n.type)}`;if(t.has(a))continue;t.add(a),e.push({path:s,totalGb:bE(i/1024**3),freeGb:bE(r/1024**3),usedPct:Math.min(100,Math.max(0,Math.round((1-r/i)*100)))})}catch{}return{cpuLoad1m:bE(Go.loadavg()[0]??0),cpuCores:Go.cpus().length,memTotalMb:Math.round(Go.totalmem()/1024**2),memFreeMb:Math.round(Go.freemem()/1024**2),rssMb:Math.round(process.memoryUsage().rss/1024**2),nodeJs:process.version,platform:Go.platform(),osRelease:Go.release(),disks:e}}function bE(l){return Math.round(l*10)/10}var cm=A(()=>{"use strict";m(om,"collectNodeMetrics");m(bE,"round1")});var KL={};Le(KL,{ClusterManager:()=>Ld});import WL from"node:os";var Ld,SE=A(()=>{"use strict";cm();Ld=class{static{m(this,"ClusterManager")}config;logger;redis;heartbeatTimer;heartbeatMs;failoverMs;constructor(e,t){this.config=e,this.logger=t,this.heartbeatMs=e.heartbeatIntervalMs??1e4,this.failoverMs=e.failoverAfterMs??3e4}async connect(){try{let e;try{e=(await Function('return import("ioredis")')()).default}catch{throw new Error('Cluster mode requires the "ioredis" package. Install it: npm install ioredis')}this.redis=new e(this.config.redisUrl),this.logger.info({nodeId:this.config.nodeId,role:this.config.role},"Cluster manager connected to Redis")}catch(e){this.logger.error({err:e},"Failed to connect to Redis \u2014 cluster features disabled");return}this.heartbeatTimer=setInterval(()=>this.sendHeartbeat(),this.heartbeatMs),await this.sendHeartbeat()}async disconnect(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),await this.redis?.quit()}nodeInfo;setNodeInfo(e){this.nodeInfo=e}async collectMetricsSafe(){try{return JSON.stringify(await om(this.nodeInfo?.diskPaths??["/"]))}catch{return"{}"}}async sendHeartbeat(){try{let e=Math.floor(process.uptime()),t=JSON.stringify({id:this.config.nodeId,role:this.config.role,timestamp:new Date().toISOString(),uptime:e,host:WL.hostname(),version:this.nodeInfo?.version??"",adapters:this.nodeInfo?.adapters?.()??[]});await this.redis.set(`alfred:cluster:heartbeat:${this.config.nodeId}`,t,"EX",Math.ceil(this.failoverMs/1e3))}catch(e){this.logger.warn({err:e},"Heartbeat send failed")}}async getNodes(){if(!this.redis)return[];try{let e=await this.redis.keys("alfred:cluster:heartbeat:*"),t=[];for(let s of e){let n=await this.redis.get(s);if(n)try{let i=JSON.parse(n);t.push({...i,healthy:!0})}catch{}}return t}catch{return[]}}async acquireLock(e,t=3e5){if(!this.redis)return!0;try{return await this.redis.set(`alfred:lock:${e}`,this.config.nodeId,"NX","PX",t)==="OK"}catch{return!0}}async releaseLock(e){if(this.redis)try{await this.redis.get(`alfred:lock:${e}`)===this.config.nodeId&&await this.redis.del(`alfred:lock:${e}`)}catch{}}async publish(e,t){if(this.redis)try{await this.redis.publish(`alfred:${e}`,JSON.stringify({...t,nodeId:this.config.nodeId}))}catch(s){this.logger.warn({err:s,channel:e},"Cluster publish failed")}}async subscribe(e,t){if(this.redis)try{let s=this.redis.duplicate();await s.subscribe(`alfred:${e}`),s.on("message",(n,i)=>{try{let r=JSON.parse(i);r.nodeId!==this.config.nodeId&&t(r)}catch{}})}catch(s){this.logger.warn({err:s,channel:e},"Cluster subscribe failed")}}async routeMessage(e,t,s){await this.publish("messages",{type:"send_message",targetPlatform:e,chatId:t,text:s})}failoverCheckTimer;onFailoverCallback;startFailoverMonitoring(e){this.config.role==="secondary"&&(this.onFailoverCallback=e,this.failoverCheckTimer=setInterval(async()=>{try{let t=await this.getNodes(),s=new Set(t.map(n=>n.id));for(let n of this.config.nodes??[])n.id!==this.config.nodeId&&(s.has(n.id)||(this.logger.warn({deadNodeId:n.id},"Node heartbeat missing \u2014 failover triggered"),this.onFailoverCallback?.(n.id)))}catch(t){this.logger.debug({err:t},"Failover check error")}},this.failoverMs))}stopFailoverMonitoring(){this.failoverCheckTimer&&clearInterval(this.failoverCheckTimer)}async announceTakeover(e,t){await this.publish("events",{type:"failover",deadNodeId:e,takenOverBy:this.config.nodeId,adapters:t}),this.logger.info({deadNodeId:e,adapters:t},"Failover: adapters taken over")}async syncConfig(e,t){await this.publish("config-sync",{type:e,...t})}async onConfigSync(e){await this.subscribe("config-sync",t=>{let{type:s,...n}=t;e(s,n)})}get nodeId(){return this.config.nodeId}get role(){return this.config.role??"node"}get isConnected(){return!!this.redis}pgAdapter;pgHeartbeatTimer;startPgHeartbeat(e){this.pgAdapter=e,this.pgHeartbeatTimer=setInterval(()=>this.sendPgHeartbeat(),this.heartbeatMs),this.sendPgHeartbeat()}async sendPgHeartbeat(){if(this.pgAdapter)try{let e=new Date().toISOString(),t=Math.floor(process.uptime()),s=new Date(Date.now()-t*1e3).toISOString(),n=await this.collectMetricsSafe();await this.pgAdapter.execute(`INSERT INTO node_heartbeats (node_id, host, last_seen_at, started_at, uptime_s, adapters, version, metrics)
7815
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,[yW(),s.table,s.uidColumn,String(i.row_id),i.uid,r,t]),e.flaggedNew+=1}}catch(n){let i=n.message??"";if(/no such table|does not exist|relation .* does not exist/i.test(i)){e.skippedTables.push(s.table);continue}this.logger.warn({err:n,table:s.table},"v808 audit-scan failed for table (continuing)")}return e.flaggedNew>0?this.logger.warn({scanned:e.scanned,flaggedNew:e.flaggedNew,alreadyFlagged:e.alreadyFlagged,skipped:e.skippedTables.length},"v808 UserIdAudit: non-UUID user_id rows detected \u2014 see user_id_format_audit table"):this.logger.debug({scanned:e.scanned,alreadyFlagged:e.alreadyFlagged,skipped:e.skippedTables.length},"v808 UserIdAudit: scan complete, all user_id rows have UUID format"),e}}});var rm={};Le(rm,{default:()=>TW});var TW,am=A(()=>{TW={name:"@madh-io/alfred-ai",version:"0.19.0-jarvis.1189",description:"Alfred \u2014 Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",type:"module",bin:{alfred:"bundle/index.js"},files:["bundle"],scripts:{build:"tsc",bundle:"node ../../scripts/bundle.mjs",prepublishOnly:"npm run build && npm run bundle",clean:"rm -rf dist bundle *.tsbuildinfo"},keywords:["ai","assistant","chatbot","telegram","discord","whatsapp","matrix","signal","claude","openai","ollama"],license:"MIT",repository:{type:"git",url:"https://github.com/madh99/alfred-ai.git"},homepage:"https://github.com/madh99/alfred-ai#readme",bugs:{url:"https://github.com/madh99/alfred-ai/issues"},dependencies:{"@anthropic-ai/sdk":"^0.105.0","@google/genai":"^1.45.0","@modelcontextprotocol/sdk":"^1.12.1","better-sqlite3":"^11.8.0",botbuilder:"^4.23.0",ccxt:"^4.4.0","discord.js":"^14.18.0",docx:"^9.0.0",dotenv:"^16.4.0",exceljs:"^4.4.0",grammy:"^1.35.0",imapflow:"^1.2.10","js-yaml":"^4.1.0",mammoth:"^1.8.0",mqtt:"^5.0.0",nodemailer:"^8.0.1",openai:"^6.44.0","pdf-parse":"^1.1.1",pdfkit:"^0.16.0",pino:"^9.6.0","pino-pretty":"^13.0.0",puppeteer:"^24.0.0","puppeteer-core":"^24.0.0","rss-parser":"^3.13.0",sharp:"^0.34.0",sonos:"^1.14.0",undici:"^7.10.0","youtube-transcript":"^1.3.0",zod:"^3.24.0"},optionalDependencies:{"@aws-sdk/client-s3":"^3.700.0","@influxdata/influxdb-client":"^1.35.0","@whiskeysockets/baileys":"6.7.21",googleapis:"^144.0.0","hafas-client":"^6.3.0",ioredis:"^5.4.0","matrix-bot-sdk":"^0.8.0",mongodb:"^6.12.0",mssql:"^11.0.0",mysql2:"^3.12.0",pg:"^8.13.0",tsdav:"^2.1.0"},devDependencies:{"@alfred/config":"workspace:*","@alfred/core":"workspace:*","@alfred/logger":"workspace:*","@alfred/mcp-server":"workspace:*","@alfred/security":"workspace:*","@alfred/storage":"workspace:*","@alfred/types":"workspace:*","@types/js-yaml":"^4.0.9"},publishConfig:{access:"public"},engines:{node:">=20"}}});var XL={};Le(XL,{collectNodeMetrics:()=>om});import Go from"node:os";import{statfs as EW}from"node:fs/promises";async function om(l){let e=[],t=new Set;for(let s of l)if(s)try{let n=await EW(s),i=Number(n.blocks)*Number(n.bsize),r=Number(n.bavail)*Number(n.bsize);if(i<=0)continue;let a=`${i}:${Number(n.bfree)}:${Number(n.type)}`;if(t.has(a))continue;t.add(a),e.push({path:s,totalGb:bE(i/1024**3),freeGb:bE(r/1024**3),usedPct:Math.min(100,Math.max(0,Math.round((1-r/i)*100)))})}catch{}return{cpuLoad1m:bE(Go.loadavg()[0]??0),cpuCores:Go.cpus().length,memTotalMb:Math.round(Go.totalmem()/1024**2),memFreeMb:Math.round(Go.freemem()/1024**2),rssMb:Math.round(process.memoryUsage().rss/1024**2),nodeJs:process.version,platform:Go.platform(),osRelease:Go.release(),disks:e}}function bE(l){return Math.round(l*10)/10}var cm=A(()=>{"use strict";m(om,"collectNodeMetrics");m(bE,"round1")});var KL={};Le(KL,{ClusterManager:()=>Ld});import WL from"node:os";var Ld,SE=A(()=>{"use strict";cm();Ld=class{static{m(this,"ClusterManager")}config;logger;redis;heartbeatTimer;heartbeatMs;failoverMs;constructor(e,t){this.config=e,this.logger=t,this.heartbeatMs=e.heartbeatIntervalMs??1e4,this.failoverMs=e.failoverAfterMs??3e4}async connect(){try{let e;try{e=(await Function('return import("ioredis")')()).default}catch{throw new Error('Cluster mode requires the "ioredis" package. Install it: npm install ioredis')}this.redis=new e(this.config.redisUrl),this.logger.info({nodeId:this.config.nodeId,role:this.config.role},"Cluster manager connected to Redis")}catch(e){this.logger.error({err:e},"Failed to connect to Redis \u2014 cluster features disabled");return}this.heartbeatTimer=setInterval(()=>this.sendHeartbeat(),this.heartbeatMs),await this.sendHeartbeat()}async disconnect(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),await this.redis?.quit()}nodeInfo;setNodeInfo(e){this.nodeInfo=e}async collectMetricsSafe(){try{return JSON.stringify(await om(this.nodeInfo?.diskPaths??["/"]))}catch{return"{}"}}async sendHeartbeat(){try{let e=Math.floor(process.uptime()),t=JSON.stringify({id:this.config.nodeId,role:this.config.role,timestamp:new Date().toISOString(),uptime:e,host:WL.hostname(),version:this.nodeInfo?.version??"",adapters:this.nodeInfo?.adapters?.()??[]});await this.redis.set(`alfred:cluster:heartbeat:${this.config.nodeId}`,t,"EX",Math.ceil(this.failoverMs/1e3))}catch(e){this.logger.warn({err:e},"Heartbeat send failed")}}async getNodes(){if(!this.redis)return[];try{let e=await this.redis.keys("alfred:cluster:heartbeat:*"),t=[];for(let s of e){let n=await this.redis.get(s);if(n)try{let i=JSON.parse(n);t.push({...i,healthy:!0})}catch{}}return t}catch{return[]}}async acquireLock(e,t=3e5){if(!this.redis)return!0;try{return await this.redis.set(`alfred:lock:${e}`,this.config.nodeId,"NX","PX",t)==="OK"}catch{return!0}}async releaseLock(e){if(this.redis)try{await this.redis.get(`alfred:lock:${e}`)===this.config.nodeId&&await this.redis.del(`alfred:lock:${e}`)}catch{}}async publish(e,t){if(this.redis)try{await this.redis.publish(`alfred:${e}`,JSON.stringify({...t,nodeId:this.config.nodeId}))}catch(s){this.logger.warn({err:s,channel:e},"Cluster publish failed")}}async subscribe(e,t){if(this.redis)try{let s=this.redis.duplicate();await s.subscribe(`alfred:${e}`),s.on("message",(n,i)=>{try{let r=JSON.parse(i);r.nodeId!==this.config.nodeId&&t(r)}catch{}})}catch(s){this.logger.warn({err:s,channel:e},"Cluster subscribe failed")}}async routeMessage(e,t,s){await this.publish("messages",{type:"send_message",targetPlatform:e,chatId:t,text:s})}failoverCheckTimer;onFailoverCallback;startFailoverMonitoring(e){this.config.role==="secondary"&&(this.onFailoverCallback=e,this.failoverCheckTimer=setInterval(async()=>{try{let t=await this.getNodes(),s=new Set(t.map(n=>n.id));for(let n of this.config.nodes??[])n.id!==this.config.nodeId&&(s.has(n.id)||(this.logger.warn({deadNodeId:n.id},"Node heartbeat missing \u2014 failover triggered"),this.onFailoverCallback?.(n.id)))}catch(t){this.logger.debug({err:t},"Failover check error")}},this.failoverMs))}stopFailoverMonitoring(){this.failoverCheckTimer&&clearInterval(this.failoverCheckTimer)}async announceTakeover(e,t){await this.publish("events",{type:"failover",deadNodeId:e,takenOverBy:this.config.nodeId,adapters:t}),this.logger.info({deadNodeId:e,adapters:t},"Failover: adapters taken over")}async syncConfig(e,t){await this.publish("config-sync",{type:e,...t})}async onConfigSync(e){await this.subscribe("config-sync",t=>{let{type:s,...n}=t;e(s,n)})}get nodeId(){return this.config.nodeId}get role(){return this.config.role??"node"}get isConnected(){return!!this.redis}pgAdapter;pgHeartbeatTimer;startPgHeartbeat(e){this.pgAdapter=e,this.pgHeartbeatTimer=setInterval(()=>this.sendPgHeartbeat(),this.heartbeatMs),this.sendPgHeartbeat()}async sendPgHeartbeat(){if(this.pgAdapter)try{let e=new Date().toISOString(),t=Math.floor(process.uptime()),s=new Date(Date.now()-t*1e3).toISOString(),n=await this.collectMetricsSafe();await this.pgAdapter.execute(`INSERT INTO node_heartbeats (node_id, host, last_seen_at, started_at, uptime_s, adapters, version, metrics)
7816
7816
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
7817
7817
  ON CONFLICT (node_id) DO UPDATE SET
7818
7818
  host = excluded.host,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madh-io/alfred-ai",
3
- "version": "0.19.0-jarvis.1188",
3
+ "version": "0.19.0-jarvis.1189",
4
4
  "description": "Alfred — Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",
5
5
  "type": "module",
6
6
  "bin": {