@madh-io/alfred-ai 0.19.0-jarvis.1191 → 0.19.0-jarvis.1192
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.
- package/bundle/index.js +6 -6
- package/package.json +1 -1
package/bundle/index.js
CHANGED
|
@@ -4104,7 +4104,7 @@ ${r}`:r;await this.db.execute("UPDATE cmdb_problems SET analysis_notes = ?, upda
|
|
|
4104
4104
|
ON CONFLICT (tier) DO UPDATE SET provider = excluded.provider, model = excluded.model, letzter_erfolg = excluded.letzter_erfolg,
|
|
4105
4105
|
letzter_fehler = excluded.letzter_fehler, fehler_klasse = excluded.fehler_klasse, fehler_text = excluded.fehler_text,
|
|
4106
4106
|
gestoert_seit = excluded.gestoert_seit, erfolge = excluded.erfolge, fehler = excluded.fehler, updated_at = excluded.updated_at`,[e.tier,e.provider,e.model,e.letzterErfolg??null,e.letzterFehler??null,e.fehlerKlasse??null,e.fehlerText??null,e.gestoertSeit??null,e.erfolge,e.fehler,e.updatedAt])}async ladePuls(){return(await this.db.query("SELECT * FROM provider_puls ORDER BY tier",[])).map(t=>({tier:t.tier,provider:t.provider,model:t.model,letzterErfolg:t.letzter_erfolg??void 0,letzterFehler:t.letzter_fehler??void 0,fehlerKlasse:t.fehler_klasse??void 0,fehlerText:t.fehler_text??void 0,gestoertSeit:t.gestoert_seit??void 0,erfolge:Number(t.erfolge??0),fehler:Number(t.fehler??0),updatedAt:t.updated_at}))}async ladeMeldungen(){return(await this.db.query("SELECT * FROM lebenszeichen_meldungen",[])).map(t=>({key:t.key,offenSeit:t.offen_seit,zuletztGemeldet:t.zuletzt_gemeldet??void 0,text:t.text??void 0}))}async speichereMeldung(e){await this.db.execute(`INSERT INTO lebenszeichen_meldungen (key, offen_seit, zuletzt_gemeldet, text) VALUES (?, ?, ?, ?)
|
|
4107
|
-
ON CONFLICT (key) DO UPDATE SET offen_seit = excluded.offen_seit, zuletzt_gemeldet = excluded.zuletzt_gemeldet, text = excluded.text`,[e.key,e.offenSeit,e.zuletztGemeldet??null,e.text??null])}async loescheMeldung(e){await this.db.execute("DELETE FROM lebenszeichen_meldungen WHERE key = ?",[e])}async juengsteZeit(e){let t=e==="activity_log"?"timestamp":e==="llm_usage"?"date":"created_at";return(await this.db.queryOne(`SELECT MAX(${t}) AS t FROM ${e}`,[]))?.t??void 0}}});import{randomUUID as MU}from"node:crypto";var Ku,fS=A(()=>{"use strict";Ku=class{static{m(this,"MesswerteRepository")}db;constructor(e){this.db=e}async record(e,t){await this.db.execute("INSERT INTO messwerte (id, user_id, entity, wert, text, einheit, gemessen_at, quelle) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",[MU(),e,t.entity,t.wert??null,t.text??null,t.einheit??null,t.zeit,t.quelle??"homeassistant"])}async verlauf(e,t,s,n=2e3){return(await this.db.query("SELECT entity, wert, text, einheit, gemessen_at, quelle FROM messwerte WHERE user_id = ? AND entity = ? AND gemessen_at >= ? ORDER BY gemessen_at ASC LIMIT ?",[e,t,s,n])).map(r=>this.map(r))}async verlaufMehrere(e,t,s){let n=[];for(let i of t)n.push(...await this.verlauf(e,i,s));return n}async letzteProEntity(e,t,s=48){let n=new Date(Date.now()-s*36e5).toISOString();return(await this.db.query(`SELECT m.entity, m.wert, m.text, m.einheit, m.gemessen_at, m.quelle
|
|
4107
|
+
ON CONFLICT (key) DO UPDATE SET offen_seit = excluded.offen_seit, zuletzt_gemeldet = excluded.zuletzt_gemeldet, text = excluded.text`,[e.key,e.offenSeit,e.zuletztGemeldet??null,e.text??null])}async loescheMeldung(e){await this.db.execute("DELETE FROM lebenszeichen_meldungen WHERE key = ?",[e])}async juengsteZeit(e){let t=e==="activity_log"?"timestamp":e==="llm_usage"?"date":e==="messwerte"?"gemessen_at":"created_at";return(await this.db.queryOne(`SELECT MAX(${t}) AS t FROM ${e}`,[]))?.t??void 0}}});import{randomUUID as MU}from"node:crypto";var Ku,fS=A(()=>{"use strict";Ku=class{static{m(this,"MesswerteRepository")}db;constructor(e){this.db=e}async record(e,t){await this.db.execute("INSERT INTO messwerte (id, user_id, entity, wert, text, einheit, gemessen_at, quelle) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",[MU(),e,t.entity,t.wert??null,t.text??null,t.einheit??null,t.zeit,t.quelle??"homeassistant"])}async verlauf(e,t,s,n=2e3){return(await this.db.query("SELECT entity, wert, text, einheit, gemessen_at, quelle FROM messwerte WHERE user_id = ? AND entity = ? AND gemessen_at >= ? ORDER BY gemessen_at ASC LIMIT ?",[e,t,s,n])).map(r=>this.map(r))}async verlaufMehrere(e,t,s){let n=[];for(let i of t)n.push(...await this.verlauf(e,i,s));return n}async letzteProEntity(e,t,s=48){let n=new Date(Date.now()-s*36e5).toISOString();return(await this.db.query(`SELECT m.entity, m.wert, m.text, m.einheit, m.gemessen_at, m.quelle
|
|
4108
4108
|
FROM messwerte m
|
|
4109
4109
|
JOIN (SELECT entity, MAX(gemessen_at) AS t FROM messwerte WHERE user_id = ? AND quelle = ? AND gemessen_at >= ? GROUP BY entity) j
|
|
4110
4110
|
ON j.entity = m.entity AND j.t = m.gemessen_at
|
|
@@ -6395,7 +6395,7 @@ Antworte "ja" oder "nein".`;try{if(e.platform==="telegram"&&i){let o=[[{text:"\u
|
|
|
6395
6395
|
|
|
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
|
-
${_}`:`\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 sN={};Le(sN,{InsightTracker:()=>In});var In,$l=A(()=>{"use strict";In=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:()=>iN,DIGEST_KANDIDAT_QUOTE:()=>nN,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>=iN&&i<nN;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,nN,iN,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");nN=.25,iN=4;m(ez,"formatiereErledigungJeKategorie");m(tz,"summiereKennzahlMesswerte")});var aN={};Le(aN,{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 ${rN(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(`- ${rN(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(`
|
|
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 sN={};Le(sN,{InsightTracker:()=>In});var In,$l=A(()=>{"use strict";In=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:()=>iN,DIGEST_KANDIDAT_QUOTE:()=>nN,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,s){let n=m(d=>Math.round(l[d]??0),"s"),i=n("vollpaesse")+n("rundgaenge")+n("miniPaesse"),r=i>0?n("miniPaesse")/i:void 0,a=n("miniPaesse")>0&&n("miniPassDauerMs")>0?` \xB7 \xD8 Mini-Pass ${(n("miniPassDauerMs")/n("miniPaesse")/1e3).toFixed(1)} s`:"",o=s!==void 0&&n("vollpaesse")>0?` \xB7 Kosten je Vollpass $${(s/n("vollpaesse")).toFixed(3)}`:"",c=n("aktionenAusgefuehrt")+n("aktionenFehlgeschlagen")+n("aktionenBestaetigung")+n("aktionenBlockiert")+n("aktionenUebersprungen");return[`Jarvis-Kennzahlen (${t} Tage): ${n("vollpaesse")} Vollp\xE4sse, ${n("rundgaenge")} Rundg\xE4nge ohne LLM, ${n("miniPaesse")} Mini-P\xE4sse (Anteil ${Pw(r)})${a}${o}`,`Insights: ${n("insightsGesendet")} gesendet, ${n("insightsAufgeschoben")} aufgeschoben, ${n("insightsStill")} still \xB7 Pr\xE4zision ${Pw(e.praezision)}`,`Gate: ${n("gateTreffer")} Treffer, ${n("gateAusgesetzt")} durch Weltmodell ausgesetzt`,`Aktionen: ${c} gesamt \u2014 ${n("aktionenAusgefuehrt")} ausgef\xFChrt, ${n("aktionenFehlgeschlagen")} fehlgeschlagen, ${n("aktionenBestaetigung")} zur Best\xE4tigung, ${n("aktionenBlockiert")} blockiert, ${n("aktionenUebersprungen")} \xFCbersprungen`,`Vorg\xE4nge: ${n("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>=iN&&i<nN;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,nN,iN,Ll=A(()=>{"use strict";Fw=["vollpaesse","rundgaenge","miniPaesse","insightsGesendet","insightsAufgeschoben","insightsStill","gateTreffer","gateAusgesetzt","aktionenAusgefuehrt","aktionenFehlgeschlagen","aktionenBestaetigung","aktionenBlockiert","aktionenUebersprungen","vorgaengeAngelegt","miniPassDauerMs"],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");nN=.25,iN=4;m(ez,"formatiereErledigungJeKategorie");m(tz,"summiereKennzahlMesswerte")});var aN={};Le(aN,{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 ${rN(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(`- ${rN(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
6399
|
`)}var sz,rN,oN=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"},rN=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:()=>cN});function cN(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=cN(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(cN,"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 lN[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 dN(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=lN.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 lN,Ol,uN=A(()=>{"use strict";lN={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(dN,"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[hN]?.value);return{createdAt:u.createdAt,km:Number.isFinite(h)?h:void 0,kmZeit:u.telematicData[hN]?.timestamp}});return{deutung:dN({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 hN,Xw=A(()=>{"use strict";uN();hN="vehicle.vehicle.travelledDistance";m(dz,"ladeBmwDeutung");m(uz,"bmwAuffaellig")});var Kw={};Le(Kw,{EINZELN_AB_PROZENT:()=>fN,LEER_PROZENT:()=>Ww,NIEDRIG_PROZENT:()=>pN,deuteSensorbatterien:()=>fz,klassifiziere:()=>mN,trendProTag:()=>gN});function gN(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[mN(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>fN){o=o===void 0?c.wert:Math.min(o,c.wert);continue}let u=l.verlauf.filter(f=>f.entity===c.entity),h=gN([...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<=pN){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,pN,fN,mN,hz,pz,kr,Gw=A(()=>{"use strict";ze();Ww=5,pN=20,fN=50,mN=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(gN,"trendProTag");m(fz,"deuteSensorbatterien")});function yN(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=yN(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 wN(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=yN(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 _N(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 TN=A(()=>{"use strict";m(yN,"median");m(mz,"mad");m(gz,"stundenfenster");m(wN,"bewerteGegenBaseline");m(_N,"trendProStunde")});var Zw={};Le(Zw,{SOC_NIEDRIG:()=>Jw,VOLLLADUNG_PROZENT:()=>kN,VOLLLADUNG_REGEL_TAGE:()=>Yw,deuteEnergie:()=>_z,ladeplanLiegtZurueck:()=>SN,rolleVon:()=>bN});function bN(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=wN(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 SN(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=bN(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=_N([...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>=kN).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}"`),SN(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(`**${EN(h)}:** ${Hs(h.wert)} ${h.einheit??""} \u21B3 ${p.text}`.replace(/\s+↳/," \u21B3")),p.auffaellig&&s.push(`${h.entity}:baseline`)}else h.text&&t.push(`**${EN(h)}:** ${h.text}`);return{zeilen:t,auffaellig:s}}var Jw,kN,Yw,Hs,yz,wz,EN,Qw=A(()=>{"use strict";TN();Jw=20,kN=99,Yw=30;m(bN,"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"),EN=m(l=>l.name??l.entity.split(".").pop().replace(/_/g," "),"nameVon");m(Vw,"proben");m(qw,"baselineText");m(SN,"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 RN(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 vN(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 AN(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,IN,Dl,xl=A(()=>{"use strict";wn();m(Di,"spaetestesDatumImText");m(RN,"istInsightEcho");m(vN,"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(AN,"formatMemoryLine");Ez=5e3,IN=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(()=>(oN(),aN));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 V of I){if($+V.length+1>v)break;L.push(V),$+=V.length+1}b=L.join(`
|
|
@@ -6525,7 +6525,7 @@ Aufgabe: Analysiere ob dieses Event im Kontext der VERBINDUNGSKARTE eine Handlun
|
|
|
6525
6525
|
|
|
6526
6526
|
${this.buildTopicInstructions()}`,o=(await this.llm.complete({messages:[{role:"user",content:r}],maxTokens:512,tier:this.tier})).content.trim();if(a_(o))return;let{findings:c,topics:d}=this.extractTopics(o),u=new Map;d.length>0&&(u=await this.collector.enrichTopics(d));let h=this.buildEventDetailPrompt(i,e,t,c,u),f=(await this.llm.complete({messages:[{role:"user",content:h}],maxTokens:PN,tier:this.tier})).content.trim();if(a_(f))return;let g=this.parseReasoningResponse(f),y=[];for(let w of g.insights){let _=await this.filtereBulletsDurchKorrekturen(w);_&&(await this.wasRecentlySent(_)||y.push(_))}if(y.length>0||g.actions.length>0){let w=this.resolveUrgency(g.actions),_=w==="low"||w==="normal"?"high":w;await this.deliverOrDefer(y,g.actions,_)}}catch(i){this.logger.warn({err:i,eventType:e},"Event-triggered reasoning failed")}}miniPassZuletzt=new Map;letzterVollpassAt=0;rundgaengeOhneVollpass=0;kennzahlen=new Cl;async triggerMiniPass(e){if(!this.enabled)return;let t=`${e.quelle}:${[...e.objekte].sort().join("+")}`,s=Date.now(),n=(e.cooldownMin??Vz/6e4)*6e4,i=this.miniPassZuletzt.get(t)??0;if(s-i<n){this.logger.debug({key:t},"v1175 Mini-Pass im Cooldown");return}if(this.miniPassZuletzt.set(t,s),this.adapter&&this.adapter.type==="postgres"){let a=`mini:${t}:${Math.floor(s/n)}`.slice(0,180);if((await this.adapter.execute("INSERT INTO reasoning_slots (slot_key, node_id, claimed_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING",[a,this.nodeId,new Date().toISOString()]).catch(()=>({changes:1}))).changes===0)return}let r=Date.now();try{let a=await this.holeUnterdrueckungsKorrekturen(),o={key:e.quelle,label:e.quelle,content:e.ausschnitt.join(`
|
|
6527
6527
|
`)};o_({sections:[o]},a);for(let g of e.objekte)this.collector.letzteAuffaelligeObjekte?.add(g);let{baueMiniPassPrompt:c}=await Promise.resolve().then(()=>(n_(),s_)),d=c({beschreibung:e.beschreibung,quelle:e.quelle,ausschnitt:o.content.split(`
|
|
6528
|
-
`),datum:new Date().toLocaleString("de-AT",{weekday:"long",day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}),korrekturen:a.map(g=>g.value.slice(0,200))}),u=await this.llm.complete({messages:[{role:"user",content:d}],maxTokens:400,tier:this.tier});this.kennzahlen.zaehle("miniPaesse");let h=u.content.trim();if(a_(h)){this.logger.info({quelle:e.quelle,objekte:e.objekte,dauerMs:Date.now()-r},"v1175 Mini-Pass: keine Meldung");return}let p=this.parseReasoningResponse(h),f=[];for(let g of p.insights){let y=await this.filtereBulletsDurchKorrekturen(g);y&&(await this.wasRecentlySent(y)||f.push(y))}this.logger.info({quelle:e.quelle,objekte:e.objekte,insights:f.length,verworfen:p.insights.length-f.length,dauerMs:Date.now()-r},"v1175 Mini-Pass gelaufen"),(f.length>0||p.actions.length>0)&&await this.deliverOrDefer(f,p.actions,"high",Date.now()-r)}catch(a){this.logger.warn({err:a.message,quelle:e.quelle},"v1175 Mini-Pass fehlgeschlagen")}}shouldRun(){let e=new Date,t=e.getHours(),s=e.getMinutes();switch(this.schedule){case"morning_noon_evening":return!!(Bz.includes(t)&&s===0&&this.lastRunHour!==t);case"hourly":return s===0&&this.lastRunHour!==t;case"half_hourly":{let n=s<=1||s>=30&&s<=31,i=t*100+(s<2?0:30),r=this.lastRunHour!==i;return n&&this.logger.debug({hour:t,minute:s,slotId:i,lastRunHour:this.lastRunHour,notRun:r},"half_hourly shouldRun check"),!!(n&&r)}default:return!1}}markRun(){let e=new Date;if(this.schedule==="half_hourly"){let t=e.getMinutes();this.lastRunHour=e.getHours()*100+(t<15?0:30)}else this.lastRunHour=e.getHours()}async tick(){if(!this.shouldRun())return;this.markRun();let e=new Date().toISOString().slice(0,10);if(this.deliveryScheduler&&this.lastDeferredCleanupDay!==e){this.lastDeferredCleanupDay=e;try{let t=await this.deliveryScheduler.cleanup();t>0&&this.logger.info({geloescht:t},"v1158 Deferred-Insights aufger\xE4umt")}catch{}}if(!this.resolvedOwnerUserId)try{let t=await this.userRepo.findOrCreate(this.defaultPlatform,this.defaultChatId);this.resolvedOwnerUserId=t.masterUserId??t.id??this.defaultChatId}catch{this.resolvedOwnerUserId=this.defaultChatId}if(this.deliveryScheduler)try{let t=await this.deliveryScheduler.getPendingDeferred(this.defaultChatId);if(t.length>0){let s=await this.adapter?.queryOne(`SELECT MAX(created_at) as latest FROM messages WHERE conversation_id IN (
|
|
6528
|
+
`),datum:new Date().toLocaleString("de-AT",{weekday:"long",day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}),korrekturen:a.map(g=>g.value.slice(0,200))}),u=await this.llm.complete({messages:[{role:"user",content:d}],maxTokens:400,tier:this.tier});this.kennzahlen.zaehle("miniPaesse"),this.kennzahlen.zaehle("miniPassDauerMs",Date.now()-r);let h=u.content.trim();if(a_(h)){this.logger.info({quelle:e.quelle,objekte:e.objekte,dauerMs:Date.now()-r},"v1175 Mini-Pass: keine Meldung");return}let p=this.parseReasoningResponse(h),f=[];for(let g of p.insights){let y=await this.filtereBulletsDurchKorrekturen(g);y&&(await this.wasRecentlySent(y)||f.push(y))}this.logger.info({quelle:e.quelle,objekte:e.objekte,insights:f.length,verworfen:p.insights.length-f.length,dauerMs:Date.now()-r},"v1175 Mini-Pass gelaufen"),(f.length>0||p.actions.length>0)&&await this.deliverOrDefer(f,p.actions,"high",Date.now()-r)}catch(a){this.logger.warn({err:a.message,quelle:e.quelle},"v1175 Mini-Pass fehlgeschlagen")}}shouldRun(){let e=new Date,t=e.getHours(),s=e.getMinutes();switch(this.schedule){case"morning_noon_evening":return!!(Bz.includes(t)&&s===0&&this.lastRunHour!==t);case"hourly":return s===0&&this.lastRunHour!==t;case"half_hourly":{let n=s<=1||s>=30&&s<=31,i=t*100+(s<2?0:30),r=this.lastRunHour!==i;return n&&this.logger.debug({hour:t,minute:s,slotId:i,lastRunHour:this.lastRunHour,notRun:r},"half_hourly shouldRun check"),!!(n&&r)}default:return!1}}markRun(){let e=new Date;if(this.schedule==="half_hourly"){let t=e.getMinutes();this.lastRunHour=e.getHours()*100+(t<15?0:30)}else this.lastRunHour=e.getHours()}async tick(){if(!this.shouldRun())return;this.markRun();let e=new Date().toISOString().slice(0,10);if(this.deliveryScheduler&&this.lastDeferredCleanupDay!==e){this.lastDeferredCleanupDay=e;try{let t=await this.deliveryScheduler.cleanup();t>0&&this.logger.info({geloescht:t},"v1158 Deferred-Insights aufger\xE4umt")}catch{}}if(!this.resolvedOwnerUserId)try{let t=await this.userRepo.findOrCreate(this.defaultPlatform,this.defaultChatId);this.resolvedOwnerUserId=t.masterUserId??t.id??this.defaultChatId}catch{this.resolvedOwnerUserId=this.defaultChatId}if(this.deliveryScheduler)try{let t=await this.deliveryScheduler.getPendingDeferred(this.defaultChatId);if(t.length>0){let s=await this.adapter?.queryOne(`SELECT MAX(created_at) as latest FROM messages WHERE conversation_id IN (
|
|
6529
6529
|
SELECT id FROM conversations WHERE user_id = ?
|
|
6530
6530
|
) AND role = 'user'`,[this.resolvedOwnerUserId]),n=s?.latest?new Date(s.latest).getTime():0;if(Date.now()-n<30*6e4){let r=this.adapters.get(this.defaultPlatform);if(r){for(let a of t){let o=a.message;if(a.created_at){let c=Math.round((Date.now()-new Date(a.created_at).getTime())/6e4);if(c>30){let d=c>=120?`${Math.round(c/60)}h`:`${c} Min`;o=o.replace(/^(💡 \*\*Alfred Insights\*\*)/,`$1 _(erstellt vor ${d})_`)}}if(await r.sendMessage(this.defaultChatId,o),this.insightTracker&&a.message){let c=a.message.split(`
|
|
6531
6531
|
`).filter(u=>u.trim().length>10),d=c.map(u=>In.categorizeInsight(u));this.insightTracker.trackInsightBatch(d,c)}try{let c=JSON.parse(a.actions);c.length>0&&(this.aktuelleVorgangIds=await this.legeVorgaengeAn(c),await this.processActions(c),this.aktuelleVorgangIds=void 0)}catch{}}await this.deliveryScheduler.markDelivered(t.map(a=>a.id));for(let a of t)if(a.message){let o=a.message.split(`
|
|
@@ -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(uW,"runGitBoth");hW=[{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(pW,"stripAnsi");m(fW,"summarizeTestFailure");m(mW,"scanForSecrets");m(gW,"parseRepoFromUrl");m(yW,"resolveDockerfilesDir")});var BL={};Le(BL,{IdentityResolver:()=>bE});var bE,zL=A(()=>{"use strict";Yi();bE=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 HL={};Le(HL,{UserIdAuditScanner:()=>SE});import{randomUUID as wW}from"node:crypto";var _W,SE,XL=A(()=>{"use strict";Yi();_W=[{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"}],SE=class{static{m(this,"UserIdAuditScanner")}adapter;logger;targets;constructor(e,t,s=_W){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 (?, ?, ?, ?, ?, ?, ?)`,[wW(),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:()=>EW});var EW,am=A(()=>{EW={name:"@madh-io/alfred-ai",version:"0.19.0-jarvis.
|
|
7815
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,[wW(),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:()=>EW});var EW,am=A(()=>{EW={name:"@madh-io/alfred-ai",version:"0.19.0-jarvis.1192",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 WL={};Le(WL,{collectNodeMetrics:()=>om});import Go from"node:os";import{statfs as kW}from"node:fs/promises";async function om(l){let e=[],t=new Set;for(let s of l)if(s)try{let n=await kW(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:vE(i/1024**3),freeGb:vE(r/1024**3),usedPct:Math.min(100,Math.max(0,Math.round((1-r/i)*100)))})}catch{}return{cpuLoad1m:vE(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 vE(l){return Math.round(l*10)/10}var cm=A(()=>{"use strict";m(om,"collectNodeMetrics");m(vE,"round1")});var GL={};Le(GL,{ClusterManager:()=>Ld});import KL from"node:os";var Ld,AE=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:KL.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,
|
|
@@ -8317,7 +8317,7 @@ data: ${JSON.stringify(s)}
|
|
|
8317
8317
|
VALUES (?, ?, ?, ?)
|
|
8318
8318
|
ON CONFLICT (platform) DO UPDATE
|
|
8319
8319
|
SET node_id = excluded.node_id, claimed_at = excluded.claimed_at, expires_at = excluded.expires_at
|
|
8320
|
-
WHERE adapter_claims.expires_at < ? OR adapter_claims.node_id = ?`,[e,this.nodeId,t,s,t,this.nodeId])).changes>0?(this.claimedPlatforms.add(e),!0):await this.adapter.queryOne("SELECT node_id FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])?(this.claimedPlatforms.add(e),!0):!1}start(){this.renewTimer=setInterval(()=>this.renewClaims(),this.claimTtlMs/2),this.checkTimer=setInterval(()=>this.checkExpiredClaims(),15e3)}stop(){this.renewTimer&&clearInterval(this.renewTimer),this.checkTimer&&clearInterval(this.checkTimer),this.releaseClaims().catch(()=>{})}async renewClaims(){if(this.claimedPlatforms.size===0||this.adapter.type==="sqlite")return;let e=new Date(Date.now()+this.claimTtlMs).toISOString();for(let t of this.claimedPlatforms)try{await this.adapter.execute("UPDATE adapter_claims SET expires_at = ? WHERE platform = ? AND node_id = ?",[e,t,this.nodeId])}catch(s){this.logger.warn({err:s,platform:t},"Failed to renew adapter claim")}}knownPlatforms=new Set;registerPlatform(e){this.knownPlatforms.add(e)}async checkExpiredClaims(){if(this.adapter.type!=="sqlite")try{let e=new Date().toISOString();for(let t of this.knownPlatforms){if(this.claimedPlatforms.has(t))continue;let s=await this.adapter.queryOne("SELECT node_id, expires_at FROM adapter_claims WHERE platform = ?",[t]);(!s||s.expires_at<e)&&await this.tryClaim(t)&&(this.logger.info({platform:t,nodeId:this.nodeId},"Acquired adapter claim from dead node"),this.onClaimAcquired?.(t))}}catch(e){this.logger.debug({err:e},"Adapter claim check failed")}}async releaseClaims(){if(this.adapter.type!=="sqlite"){for(let e of this.claimedPlatforms)try{await this.adapter.execute("DELETE FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])}catch{}this.claimedPlatforms.clear()}}owns(e){return this.claimedPlatforms.has(e)}}});var TD={};Le(TD,{applyActionInputs:()=>aK,extractInputFields:()=>rK});function rK(l){let e=l?.inputFields;if(!Array.isArray(e))return[];let t=[];for(let s of e){if(!s||typeof s!="object")continue;let n=s.key,i=s.label,r=s.type;typeof n!="string"||n.length===0||t.push({key:n,label:typeof i=="string"&&i.length>0?i:n,type:r==="date"||r==="number"?r:"text"})}return t}function aK(l,e,t){if(e.length===0)return{ok:!0,params:l};let s=t??{},n={},i=[];for(let a of e){let o=s[a.key],c=o==null?"":String(o).trim();if(c.length===0){i.push(a.key);continue}n[a.key]=c}if(i.length>0)return{ok:!1,missing:i};let r=m(a=>{if(typeof a=="string")return a.replace(/\{\{\s*([a-zA-Z0-9_-]+)\s*\}\}/g,(o,c)=>n[c]??o);if(Array.isArray(a))return a.map(r);if(a&&typeof a=="object"){let o={};for(let[c,d]of Object.entries(a))o[c]=r(d);return o}return a},"substitute");return{ok:!0,params:r(l)}}var ED=A(()=>{"use strict";m(rK,"extractInputFields");m(aK,"applyActionInputs")});var kD={};Le(kD,{blockingItemIds:()=>lK,isItemBlocked:()=>cK,wouldCreateDependencyCycle:()=>oK});function oK(l,e,t){if(t.includes(e))return!0;let s=new Map(l.map(r=>[r.id,r])),n=new Set,i=[...t];for(;i.length>0;){let r=i.pop();if(r===e)return!0;if(n.has(r))continue;n.add(r);let a=s.get(r)?.dependsOn??[];for(let o of a)i.push(o)}return!1}function cK(l,e){let t=l.dependsOn??[];if(t.length===0)return!1;let s=new Map(e.map(n=>[n.id,n]));return t.some(n=>{let i=s.get(n);return i?i.status!=="done"&&i.status!=="cancelled":!1})}function lK(l,e){let t=l.dependsOn??[];if(t.length===0)return[];let s=new Map(e.map(n=>[n.id,n]));return t.filter(n=>{let i=s.get(n);return i?i.status!=="done"&&i.status!=="cancelled":!1})}var bD=A(()=>{"use strict";m(oK,"wouldCreateDependencyCycle");m(cK,"isItemBlocked");m(lK,"blockingItemIds")});var gk={};Le(gk,{listProjectDocs:()=>hK,readProjectDoc:()=>pK});import{promises as xd}from"node:fs";import{existsSync as fk}from"node:fs";import Dn from"node:path";function mk(l){return l.toLowerCase().endsWith(".md")}async function hK(l){if(!fk(l))throw new Error(`cwd does not exist: ${l}`);let e=[],t=m(async(i,r)=>{if(!(e.length>=pk))try{let a=await xd.stat(i);if(!a.isFile())return;e.push({path:r.split(Dn.sep).join("/"),sizeBytes:a.size,modifiedAt:a.mtime.toISOString()})}catch{}},"addFile");try{let i=await xd.readdir(l,{withFileTypes:!0});for(let r of i)r.isFile()&&mk(r.name)&&await t(Dn.join(l,r.name),r.name)}catch{}let s=m(async(i,r,a)=>{if(a>uK||e.length>=pk)return;let o;try{o=await xd.readdir(i,{withFileTypes:!0})}catch{return}for(let c of o){if(e.length>=pk)return;if(c.name.startsWith(".")||dK.has(c.name))continue;let d=Dn.join(i,c.name),u=r?Dn.join(r,c.name):c.name;c.isDirectory()?await s(d,u,a+1):c.isFile()&&mk(c.name)&&await t(d,u)}},"walk"),n=Dn.join(l,"docs");return fk(n)&&await s(n,"docs",1),e.sort((i,r)=>{let a=i.path.toLowerCase()==="readme.md"?0:1,o=r.path.toLowerCase()==="readme.md"?0:1;return a!==o?a-o:i.path.localeCompare(r.path)}),e}async function pK(l,e){if(!fk(l))throw new Error(`cwd does not exist: ${l}`);if(!e||typeof e!="string")throw new Error("path required");if(!mk(e))throw new Error("only .md files are readable");if(Dn.isAbsolute(e))throw new Error("absolute paths are not allowed");let t=Dn.resolve(l),s=Dn.resolve(t,e);if(s!==t&&!s.startsWith(t+Dn.sep))throw new Error("path escapes project directory");let n=await xd.stat(s);if(!n.isFile())throw new Error("not a file");let i=n.size>SD,r=await xd.open(s,"r");try{let a=Buffer.alloc(Math.min(n.size,SD));return await r.read(a,0,a.length,0),{path:e.split(Dn.sep).join("/"),content:a.toString("utf8"),truncated:i}}finally{await r.close()}}var dK,pk,uK,SD,yk=A(()=>{"use strict";dK=new Set(["node_modules",".git","dist","build","bundle",".next","coverage","vendor"]),pk=300,uK=5,SD=1024*1024;m(mk,"isMarkdown");m(hK,"listProjectDocs");m(pK,"readProjectDoc")});var ID={};Le(ID,{erwarteteFristMs:()=>AD,formatiereDauer:()=>Tn,fuehreProbenAus:()=>fK});function AD(l){return l.art==="taeglich"?26*36e5:l.art==="woechentlich"?8*864e5:Math.max(30*6e4,2*l.minuten*6e4)}function Tn(l){let e=Math.round(l/6e4);if(e<60)return`${e} min`;let t=Math.round(e/60);return t<48?`${t} h`:`${Math.round(t/24)} Tage`}async function fK(l){let e=(l.now??(()=>new Date))(),t=[];if(l.tiers)for(let n of l.tiers.konfigurierteTiers()){if(n==="embeddings")continue;let i=await l.tiers.probeTier(n);t.push({art:"tier",name:n,ok:i.ok,klasse:i.klasse,detail:i.ok?`${i.provider}/${i.model} antwortet (${i.dauerMs} ms)`:`${i.provider}/${i.model}: ${i.klasse??"fehler"} \u2014 ${(i.fehler??"").slice(0,120)}`})}if(l.embed)try{await l.embed(),t.push({art:"tier",name:"embeddings",ok:!0,detail:"Embedding-Provider antwortet"})}catch(n){t.push({art:"tier",name:"embeddings",ok:!1,klasse:"unbekannt",detail:`Embedding fehlgeschlagen \u2014 ${(n.message??"").slice(0,120)}`})}let s=new Set(l.ausgenommen??[]);for(let n of l.jobs()){if(s.has(n.key))continue;let i=AD(n.takt),r=await l.letzterLauf(n.key);if(!r){let o=l.registerGestartetAm?e.getTime()-Date.parse(l.registerGestartetAm):1/0,c=o>i;t.push({art:"job",name:n.key,ok:!c,detail:c?`noch kein Lauf seit Registrierung vor ${Tn(o)}`:"noch kein Lauf f\xE4llig"});continue}let a=e.getTime()-Date.parse(r.startedAt);a>i?t.push({art:"job",name:n.key,ok:!1,detail:`letzter Lauf vor ${Tn(a)} (erwartet innerhalb ${Tn(i)})`}):r.ok===!1?t.push({art:"job",name:n.key,ok:!1,detail:`letzter Lauf vor ${Tn(a)} fehlgeschlagen`}):t.push({art:"job",name:n.key,ok:!0,detail:`letzter Lauf vor ${Tn(a)}`})}if(l.juengsteZeit)for(let n of Object.keys(vD))try{let i=await l.juengsteZeit(n);if(!i){t.push({art:"daten",name:n,ok:!1,detail:"keine Zeile"});continue}let r=e.getTime()-Date.parse(i),a=r<=vD[n];t.push({art:"daten",name:n,ok:a,detail:`j\xFCngste Zeile vor ${Tn(r)}`})}catch(i){t.push({art:"daten",name:n,ok:!1,detail:`Abfrage fehlgeschlagen \u2014 ${(i.message??"").slice(0,120)}`})}if(l.adapter)for(let n of l.adapter()){let i=n.status==="connected",r=n.getrenntSeitMs?` seit ${Tn(e.getTime()-n.getrenntSeitMs)}`:"";t.push({art:"adapter",name:n.platform,ok:i,detail:i?"verbunden":`nicht verbunden (${n.status})${r}`})}return t}var vD,wk=A(()=>{"use strict";m(AD,"erwarteteFristMs");m(Tn,"formatiereDauer");vD={activity_log:24*36e5,llm_usage:48*36e5,alfred_insights:3*864e5};m(fK,"fuehreProbenAus")});var RD={};Le(RD,{DEGRADATION_SCHWELLE_MS:()=>Tk,DegradationsWaechter:()=>_k,bewerteAdapter:()=>wK,bewerteProben:()=>yK,bewertePuls:()=>gK,formatiereMeldungen:()=>TK});function vm(l){let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}.`}function gK(l,e){let t=[];for(let s of l){if(!Ed.istGestoert(s)||!s.gestoertSeit)continue;let n=e.getTime()-Date.parse(s.gestoertSeit);if(n<Tk)continue;let i=s.fehlerKlasse==="billing";if(!i&&!mK.has(s.tier))continue;let r=s.letzterErfolg?`letzter Erfolg ${vm(s.letzterErfolg)}`:"noch kein Erfolg seit Start",a=i?`Seit ${vm(s.gestoertSeit)} ohne ${s.provider}-Guthaben (Tier ${s.tier}, ${s.model}) \u2014 l\xE4uft \xFCber den Fallback, ${r}`:`Tier ${s.tier} (${s.provider}/${s.model}) seit ${Tn(n)} nicht erreichbar (${s.fehlerKlasse??"fehler"}) \u2014 l\xE4uft \xFCber den Fallback, ${r}`;t.push({key:`tier:${s.tier}`,text:a})}return t}function yK(l){let e=[];for(let t of l)t.ok||t.art==="tier"||e.push({key:`${t.art}:${t.name}`,text:t.art==="job"?`Job ${t.name}: ${t.detail}`:t.art==="adapter"?`Adapter ${t.name}: ${t.detail}`:`Tabelle ${t.name}: ${t.detail}`});return e}function wK(l,e){let t=[];for(let s of l){if(s.status==="connected"||!s.getrenntSeitMs)continue;let n=e.getTime()-s.getrenntSeitMs;n<Tk||t.push({key:`adapter:${s.platform}`,text:`Adapter ${s.platform} seit ${Tn(n)} nicht verbunden (${s.status}) \u2014 Alfred versucht alle 10 min neu`})}return t}function _K(l){let[e,t]=l.split(":");return e==="tier"?`Tier ${t}`:e==="job"?`Job ${t}`:e==="daten"?`Tabelle ${t}`:l}function TK(l){let e=l.filter(n=>n.art==="warnung").map(n=>n.text),t=l.filter(n=>n.art==="entwarnung").map(n=>n.text),s=[];return e.length&&s.push(`\u26A0\uFE0F ${e.join(" \xB7 ")}`),t.length&&s.push(`\u2705 ${t.join(" \xB7 ")}`),s.length?s.join(`
|
|
8320
|
+
WHERE adapter_claims.expires_at < ? OR adapter_claims.node_id = ?`,[e,this.nodeId,t,s,t,this.nodeId])).changes>0?(this.claimedPlatforms.add(e),!0):await this.adapter.queryOne("SELECT node_id FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])?(this.claimedPlatforms.add(e),!0):!1}start(){this.renewTimer=setInterval(()=>this.renewClaims(),this.claimTtlMs/2),this.checkTimer=setInterval(()=>this.checkExpiredClaims(),15e3)}stop(){this.renewTimer&&clearInterval(this.renewTimer),this.checkTimer&&clearInterval(this.checkTimer),this.releaseClaims().catch(()=>{})}async renewClaims(){if(this.claimedPlatforms.size===0||this.adapter.type==="sqlite")return;let e=new Date(Date.now()+this.claimTtlMs).toISOString();for(let t of this.claimedPlatforms)try{await this.adapter.execute("UPDATE adapter_claims SET expires_at = ? WHERE platform = ? AND node_id = ?",[e,t,this.nodeId])}catch(s){this.logger.warn({err:s,platform:t},"Failed to renew adapter claim")}}knownPlatforms=new Set;registerPlatform(e){this.knownPlatforms.add(e)}async checkExpiredClaims(){if(this.adapter.type!=="sqlite")try{let e=new Date().toISOString();for(let t of this.knownPlatforms){if(this.claimedPlatforms.has(t))continue;let s=await this.adapter.queryOne("SELECT node_id, expires_at FROM adapter_claims WHERE platform = ?",[t]);(!s||s.expires_at<e)&&await this.tryClaim(t)&&(this.logger.info({platform:t,nodeId:this.nodeId},"Acquired adapter claim from dead node"),this.onClaimAcquired?.(t))}}catch(e){this.logger.debug({err:e},"Adapter claim check failed")}}async releaseClaims(){if(this.adapter.type!=="sqlite"){for(let e of this.claimedPlatforms)try{await this.adapter.execute("DELETE FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])}catch{}this.claimedPlatforms.clear()}}owns(e){return this.claimedPlatforms.has(e)}}});var TD={};Le(TD,{applyActionInputs:()=>aK,extractInputFields:()=>rK});function rK(l){let e=l?.inputFields;if(!Array.isArray(e))return[];let t=[];for(let s of e){if(!s||typeof s!="object")continue;let n=s.key,i=s.label,r=s.type;typeof n!="string"||n.length===0||t.push({key:n,label:typeof i=="string"&&i.length>0?i:n,type:r==="date"||r==="number"?r:"text"})}return t}function aK(l,e,t){if(e.length===0)return{ok:!0,params:l};let s=t??{},n={},i=[];for(let a of e){let o=s[a.key],c=o==null?"":String(o).trim();if(c.length===0){i.push(a.key);continue}n[a.key]=c}if(i.length>0)return{ok:!1,missing:i};let r=m(a=>{if(typeof a=="string")return a.replace(/\{\{\s*([a-zA-Z0-9_-]+)\s*\}\}/g,(o,c)=>n[c]??o);if(Array.isArray(a))return a.map(r);if(a&&typeof a=="object"){let o={};for(let[c,d]of Object.entries(a))o[c]=r(d);return o}return a},"substitute");return{ok:!0,params:r(l)}}var ED=A(()=>{"use strict";m(rK,"extractInputFields");m(aK,"applyActionInputs")});var kD={};Le(kD,{blockingItemIds:()=>lK,isItemBlocked:()=>cK,wouldCreateDependencyCycle:()=>oK});function oK(l,e,t){if(t.includes(e))return!0;let s=new Map(l.map(r=>[r.id,r])),n=new Set,i=[...t];for(;i.length>0;){let r=i.pop();if(r===e)return!0;if(n.has(r))continue;n.add(r);let a=s.get(r)?.dependsOn??[];for(let o of a)i.push(o)}return!1}function cK(l,e){let t=l.dependsOn??[];if(t.length===0)return!1;let s=new Map(e.map(n=>[n.id,n]));return t.some(n=>{let i=s.get(n);return i?i.status!=="done"&&i.status!=="cancelled":!1})}function lK(l,e){let t=l.dependsOn??[];if(t.length===0)return[];let s=new Map(e.map(n=>[n.id,n]));return t.filter(n=>{let i=s.get(n);return i?i.status!=="done"&&i.status!=="cancelled":!1})}var bD=A(()=>{"use strict";m(oK,"wouldCreateDependencyCycle");m(cK,"isItemBlocked");m(lK,"blockingItemIds")});var gk={};Le(gk,{listProjectDocs:()=>hK,readProjectDoc:()=>pK});import{promises as xd}from"node:fs";import{existsSync as fk}from"node:fs";import Dn from"node:path";function mk(l){return l.toLowerCase().endsWith(".md")}async function hK(l){if(!fk(l))throw new Error(`cwd does not exist: ${l}`);let e=[],t=m(async(i,r)=>{if(!(e.length>=pk))try{let a=await xd.stat(i);if(!a.isFile())return;e.push({path:r.split(Dn.sep).join("/"),sizeBytes:a.size,modifiedAt:a.mtime.toISOString()})}catch{}},"addFile");try{let i=await xd.readdir(l,{withFileTypes:!0});for(let r of i)r.isFile()&&mk(r.name)&&await t(Dn.join(l,r.name),r.name)}catch{}let s=m(async(i,r,a)=>{if(a>uK||e.length>=pk)return;let o;try{o=await xd.readdir(i,{withFileTypes:!0})}catch{return}for(let c of o){if(e.length>=pk)return;if(c.name.startsWith(".")||dK.has(c.name))continue;let d=Dn.join(i,c.name),u=r?Dn.join(r,c.name):c.name;c.isDirectory()?await s(d,u,a+1):c.isFile()&&mk(c.name)&&await t(d,u)}},"walk"),n=Dn.join(l,"docs");return fk(n)&&await s(n,"docs",1),e.sort((i,r)=>{let a=i.path.toLowerCase()==="readme.md"?0:1,o=r.path.toLowerCase()==="readme.md"?0:1;return a!==o?a-o:i.path.localeCompare(r.path)}),e}async function pK(l,e){if(!fk(l))throw new Error(`cwd does not exist: ${l}`);if(!e||typeof e!="string")throw new Error("path required");if(!mk(e))throw new Error("only .md files are readable");if(Dn.isAbsolute(e))throw new Error("absolute paths are not allowed");let t=Dn.resolve(l),s=Dn.resolve(t,e);if(s!==t&&!s.startsWith(t+Dn.sep))throw new Error("path escapes project directory");let n=await xd.stat(s);if(!n.isFile())throw new Error("not a file");let i=n.size>SD,r=await xd.open(s,"r");try{let a=Buffer.alloc(Math.min(n.size,SD));return await r.read(a,0,a.length,0),{path:e.split(Dn.sep).join("/"),content:a.toString("utf8"),truncated:i}}finally{await r.close()}}var dK,pk,uK,SD,yk=A(()=>{"use strict";dK=new Set(["node_modules",".git","dist","build","bundle",".next","coverage","vendor"]),pk=300,uK=5,SD=1024*1024;m(mk,"isMarkdown");m(hK,"listProjectDocs");m(pK,"readProjectDoc")});var ID={};Le(ID,{erwarteteFristMs:()=>AD,formatiereDauer:()=>Tn,fuehreProbenAus:()=>fK});function AD(l){return l.art==="taeglich"?26*36e5:l.art==="woechentlich"?8*864e5:Math.max(30*6e4,2*l.minuten*6e4)}function Tn(l){let e=Math.round(l/6e4);if(e<60)return`${e} min`;let t=Math.round(e/60);return t<48?`${t} h`:`${Math.round(t/24)} Tage`}async function fK(l){let e=(l.now??(()=>new Date))(),t=[];if(l.tiers)for(let n of l.tiers.konfigurierteTiers()){if(n==="embeddings")continue;let i=await l.tiers.probeTier(n);t.push({art:"tier",name:n,ok:i.ok,klasse:i.klasse,detail:i.ok?`${i.provider}/${i.model} antwortet (${i.dauerMs} ms)`:`${i.provider}/${i.model}: ${i.klasse??"fehler"} \u2014 ${(i.fehler??"").slice(0,120)}`})}if(l.embed)try{await l.embed(),t.push({art:"tier",name:"embeddings",ok:!0,detail:"Embedding-Provider antwortet"})}catch(n){t.push({art:"tier",name:"embeddings",ok:!1,klasse:"unbekannt",detail:`Embedding fehlgeschlagen \u2014 ${(n.message??"").slice(0,120)}`})}let s=new Set(l.ausgenommen??[]);for(let n of l.jobs()){if(s.has(n.key))continue;let i=AD(n.takt),r=await l.letzterLauf(n.key);if(!r){let o=l.registerGestartetAm?e.getTime()-Date.parse(l.registerGestartetAm):1/0,c=o>i;t.push({art:"job",name:n.key,ok:!c,detail:c?`noch kein Lauf seit Registrierung vor ${Tn(o)}`:"noch kein Lauf f\xE4llig"});continue}let a=e.getTime()-Date.parse(r.startedAt);a>i?t.push({art:"job",name:n.key,ok:!1,detail:`letzter Lauf vor ${Tn(a)} (erwartet innerhalb ${Tn(i)})`}):r.ok===!1?t.push({art:"job",name:n.key,ok:!1,detail:`letzter Lauf vor ${Tn(a)} fehlgeschlagen`}):t.push({art:"job",name:n.key,ok:!0,detail:`letzter Lauf vor ${Tn(a)}`})}if(l.juengsteZeit)for(let n of Object.keys(vD))try{let i=await l.juengsteZeit(n);if(!i){t.push({art:"daten",name:n,ok:!1,detail:"keine Zeile"});continue}let r=e.getTime()-Date.parse(i),a=r<=vD[n];t.push({art:"daten",name:n,ok:a,detail:`j\xFCngste Zeile vor ${Tn(r)}`})}catch(i){t.push({art:"daten",name:n,ok:!1,detail:`Abfrage fehlgeschlagen \u2014 ${(i.message??"").slice(0,120)}`})}if(l.adapter)for(let n of l.adapter()){let i=n.status==="connected",r=n.getrenntSeitMs?` seit ${Tn(e.getTime()-n.getrenntSeitMs)}`:"";t.push({art:"adapter",name:n.platform,ok:i,detail:i?"verbunden":`nicht verbunden (${n.status})${r}`})}return t}var vD,wk=A(()=>{"use strict";m(AD,"erwarteteFristMs");m(Tn,"formatiereDauer");vD={activity_log:24*36e5,llm_usage:48*36e5,alfred_insights:3*864e5,messwerte:3*36e5};m(fK,"fuehreProbenAus")});var RD={};Le(RD,{DEGRADATION_SCHWELLE_MS:()=>Tk,DegradationsWaechter:()=>_k,bewerteAdapter:()=>wK,bewerteProben:()=>yK,bewertePuls:()=>gK,formatiereMeldungen:()=>TK});function vm(l){let e=new Date(l);return`${String(e.getDate()).padStart(2,"0")}.${String(e.getMonth()+1).padStart(2,"0")}.`}function gK(l,e){let t=[];for(let s of l){if(!Ed.istGestoert(s)||!s.gestoertSeit)continue;let n=e.getTime()-Date.parse(s.gestoertSeit);if(n<Tk)continue;let i=s.fehlerKlasse==="billing";if(!i&&!mK.has(s.tier))continue;let r=s.letzterErfolg?`letzter Erfolg ${vm(s.letzterErfolg)}`:"noch kein Erfolg seit Start",a=i?`Seit ${vm(s.gestoertSeit)} ohne ${s.provider}-Guthaben (Tier ${s.tier}, ${s.model}) \u2014 l\xE4uft \xFCber den Fallback, ${r}`:`Tier ${s.tier} (${s.provider}/${s.model}) seit ${Tn(n)} nicht erreichbar (${s.fehlerKlasse??"fehler"}) \u2014 l\xE4uft \xFCber den Fallback, ${r}`;t.push({key:`tier:${s.tier}`,text:a})}return t}function yK(l){let e=[];for(let t of l)t.ok||t.art==="tier"||e.push({key:`${t.art}:${t.name}`,text:t.art==="job"?`Job ${t.name}: ${t.detail}`:t.art==="adapter"?`Adapter ${t.name}: ${t.detail}`:`Tabelle ${t.name}: ${t.detail}`});return e}function wK(l,e){let t=[];for(let s of l){if(s.status==="connected"||!s.getrenntSeitMs)continue;let n=e.getTime()-s.getrenntSeitMs;n<Tk||t.push({key:`adapter:${s.platform}`,text:`Adapter ${s.platform} seit ${Tn(n)} nicht verbunden (${s.status}) \u2014 Alfred versucht alle 10 min neu`})}return t}function _K(l){let[e,t]=l.split(":");return e==="tier"?`Tier ${t}`:e==="job"?`Job ${t}`:e==="daten"?`Tabelle ${t}`:l}function TK(l){let e=l.filter(n=>n.art==="warnung").map(n=>n.text),t=l.filter(n=>n.art==="entwarnung").map(n=>n.text),s=[];return e.length&&s.push(`\u26A0\uFE0F ${e.join(" \xB7 ")}`),t.length&&s.push(`\u2705 ${t.join(" \xB7 ")}`),s.length?s.join(`
|
|
8321
8321
|
`):void 0}var Tk,mK,_k,ND=A(()=>{"use strict";gT();wk();yT();Tk=60*6e4,mK=new Set(["default","strong"]);m(vm,"datumKurz");m(gK,"bewertePuls");m(yK,"bewerteProben");m(wK,"bewerteAdapter");_k=class{static{m(this,"DegradationsWaechter")}deps;offen=new Map;constructor(e){this.deps=e}async lade(){if(this.deps.persistenz)try{for(let e of await this.deps.persistenz.ladeMeldungen())this.offen.set(e.key,{offenSeit:e.offenSeit,zuletztGemeldet:e.zuletztGemeldet,text:e.text??""})}catch(e){this.deps.logger.warn({err:e.message},"Lebenszeichen: W\xE4chter-Zustand konnte nicht geladen werden")}}offeneZustaende(){return[...this.offen.entries()].map(([e,t])=>({key:e,...t}))}async abgleich(e,t={wiederholen:!1}){let s=(this.deps.now??(()=>new Date))(),n=jo(s),i=s.toISOString(),r=[],a=new Map(e.map(c=>[c.key,c])),o=m(c=>!t.nurBereiche||t.nurBereiche.some(d=>c.startsWith(`${d}:`)),"imBereich");for(let c of e){let d=this.offen.get(c.key);if(!d){let h={offenSeit:i,zuletztGemeldet:i,text:c.text};this.offen.set(c.key,h),r.push({key:c.key,art:"warnung",text:c.text}),await this.deps.persistenz?.speichereMeldung({key:c.key,...h}).catch(()=>{});continue}d.text=c.text;let u=d.zuletztGemeldet?jo(new Date(d.zuletztGemeldet))===n:!1;t.wiederholen&&!u&&(d.zuletztGemeldet=i,r.push({key:c.key,art:"warnung",text:`${c.text} (seit ${vm(d.offenSeit)})`}),await this.deps.persistenz?.speichereMeldung({key:c.key,...d}).catch(()=>{}))}for(let[c,d]of[...this.offen.entries()])a.has(c)||!o(c)||(this.offen.delete(c),r.push({key:c,art:"entwarnung",text:`${_K(c)} wieder in Ordnung (war offen seit ${vm(d.offenSeit)})`}),await this.deps.persistenz?.loescheMeldung(c).catch(()=>{}));return r}};m(_K,"beschreibeKey");m(TK,"formatiereMeldungen")});var OD={};Le(OD,{deuteHaus:()=>EK,heimZonenAus:()=>CD,istZuhause:()=>LD,klassifiziereHausEreignis:()=>kk});function CD(l){let e=new Set(["home"]),t=l.filter(o=>o.entity_id.startsWith("zone.")),s=t.find(o=>o.entity_id==="zone.home"),n=Number(s?.attributes?.latitude),i=Number(s?.attributes?.longitude),r=Number(s?.attributes?.radius??100);if(!s||!Number.isFinite(n)||!Number.isFinite(i))return e;let a=Math.PI/180;for(let o of t){let c=Number(o.attributes?.latitude),d=Number(o.attributes?.longitude);if(!Number.isFinite(c)||!Number.isFinite(d))continue;let u=(d-i)*a*Math.cos((c+n)/2*a),h=(c-n)*a;Math.sqrt(u*u+h*h)*6371e3<=r&&(e.add(String(o.attributes?.friendly_name??"").trim()),e.add(o.entity_id.slice(5)))}return e.delete(""),e}function LD(l,e){return l==="home"||e.has(l)}function EK(l,e=new Date){let t=[],s=[],n=l.filter(h=>h.state!=="unavailable"&&h.state!=="unknown"),i=CD(l),r=n.filter(h=>h.entity_id.startsWith("person.")).map(h=>({name:h.entity_id.slice(7),zuhause:LD(h.state,i)})),a=r.length>0&&r.every(h=>!h.zuhause);r.length&&t.push(`**Anwesenheit:** ${r.map(h=>`${h.name}: ${h.zuhause?"zuhause":"abwesend"}`).join(", ")}${a?" \u21B3 niemand zu Hause":""}`);let o=n.filter(h=>h.entity_id.startsWith("binary_sensor.")),c=m(h=>String(h.attributes?.device_class??""),"dc");for(let h of o.filter(p=>(c(p)==="smoke"||c(p)==="carbon_monoxide")&&p.state==="on"))t.push(`**\u26A0\uFE0F ${c(h)==="smoke"?"RAUCH":"CO"}:** ${Fi(h)} meldet ${c(h)==="smoke"?"Rauch":"Kohlenmonoxid"} seit ${Md(h.last_changed)} \u2192 SOFORT pr\xFCfen`),s.push(`haus:${c(h)==="smoke"?"rauch":"co"}:${h.entity_id}`);for(let h of o.filter(p=>c(p)==="moisture"&&p.state==="on"&&!/rain|regen|wetter/i.test(p.entity_id+Fi(p))))t.push(`**\u26A0\uFE0F WASSER:** ${Fi(h)} meldet Feuchtigkeit seit ${Md(h.last_changed)} \u2192 pr\xFCfen`),s.push(`haus:wasser:${h.entity_id}`);let d=o.filter(h=>Ek.has(c(h))&&h.state==="on");if(d.length){let h=d.map(p=>`${Fi(p).replace(/ Tür$/,"")} (seit ${Md(p.last_changed)})`);if(a){t.push(`**\u26A0\uFE0F Offen bei Abwesenheit:** ${h.join(", ")} \u2192 pr\xFCfen`);for(let p of d)s.push(`haus:offen-bei-abwesenheit:${p.entity_id}`)}else t.push(`**Offen:** ${h.join(", ")} \u21B3 NORMAL (jemand zu Hause)`)}else o.some(h=>Ek.has(c(h)))&&t.push("**T\xFCren/Fenster:** alle geschlossen \u21B3 NORMAL");let u=o.filter(h=>(c(h)==="occupancy"||c(h)==="motion")&&h.state==="on"&&!$D.test(h.entity_id+Fi(h)));if(a&&u.length){t.push(`**\u26A0\uFE0F Bewegung bei Abwesenheit:** ${u.map(h=>`${Fi(h)} (${Md(h.last_changed)})`).join(", ")} \u2192 pr\xFCfen`);for(let h of u)s.push(`haus:bewegung-bei-abwesenheit:${h.entity_id}`)}for(let h of n.filter(p=>p.entity_id.startsWith("alarm_control_panel.")))h.state==="triggered"?(t.push(`**\u26A0\uFE0F ALARM:** ${Fi(h)} ausgel\xF6st seit ${Md(h.last_changed)}`),s.push(`haus:alarm:${h.entity_id}`)):t.push(`**Alarmanlage:** ${Fi(h)} ${h.state.replace(/_/g," ")} \u21B3 ${a&&h.state==="disarmed"?"Hinweis: niemand zu Hause, nicht scharf":"NORMAL"}`);return{zeilen:t,auffaellig:s,alleAbwesend:a,personen:r,heimZonen:i}}function kk(l,e){if(!e||e.state==="unavailable"||e.state==="unknown"||l&&l.state===e.state)return;let t=String(e.attributes?.device_class??"");if(e.entity_id.startsWith("person."))return{typ:"anwesenheit",cooldownMin:30};if(e.entity_id.startsWith("alarm_control_panel.")&&e.state==="triggered")return{typ:"alarm",cooldownMin:10};if(e.entity_id.startsWith("binary_sensor.")){if(t==="smoke"&&e.state==="on")return{typ:"rauch",cooldownMin:10};if(t==="carbon_monoxide"&&e.state==="on")return{typ:"co",cooldownMin:10};if(t==="moisture"&&e.state==="on"&&!/rain|regen|wetter/i.test(e.entity_id))return{typ:"wasser",cooldownMin:30};if(Ek.has(t))return{typ:"oeffnung",cooldownMin:30};if((t==="occupancy"||t==="motion")&&e.state==="on"&&!$D.test(e.entity_id))return{typ:"bewegung",cooldownMin:60}}}var Ek,$D,Md,Fi,bk=A(()=>{"use strict";Ek=new Set(["door","window","opening","garage_door"]),$D=/doorbell|ptz|g4_|g5_|camera|kamera/i,Md=m(l=>{if(!l)return"";let e=new Date(l);return`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},"zeitKurz"),Fi=m(l=>l.attributes?.friendly_name?.replace(/\s+/g," ").trim()||l.entity_id,"name");m(CD,"heimZonenAus");m(LD,"istZuhause");m(EK,"deuteHaus");m(kk,"klassifiziereHausEreignis")});var MD={};Le(MD,{HaEreignisQuelle:()=>Sk,verarbeiteNachricht:()=>xD,wsUrlAus:()=>DD});function DD(l){return l.replace(/\/+$/,"").replace(/^http/,"ws")+"/api/websocket"}function xD(l,e){let t;try{t=JSON.parse(l)}catch{return{art:"sonst"}}if(t.type==="auth_required"||t.type==="auth_ok"||t.type==="auth_invalid")return{art:t.type};if(t.type!=="event"||t.event?.event_type!=="state_changed")return{art:"sonst"};let s=t.event.data?.new_state??void 0,n=t.event.data?.old_state??void 0;if(!s?.entity_id)return{art:"sonst"};let i=n??e.get(s.entity_id);e.set(s.entity_id,s);let r=kk(i,s);return r?{art:"ereignis",ereignis:{typ:r.typ,entity:s,vorher:i,cooldownMin:r.cooldownMin}}:{art:"sonst"}}var Sk,PD=A(()=>{"use strict";ze();bk();m(DD,"wsUrlAus");m(xD,"verarbeiteNachricht");Sk=class{static{m(this,"HaEreignisQuelle")}deps;ws;verbunden=!1;reconnectTimer;reconnectFaelligAt;letztesEreignisAt;versuche=0;letzte=new Map;gestoppt=!1;zuletztGemeldet=new Map;ereignisse=0;constructor(e){this.deps=e}start(){this.gestoppt=!1,this.verbinde()}stop(){this.gestoppt=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer);try{this.ws?.close()}catch{}this.ws=void 0,this.verbunden=!1}status(){let e=m(t=>t?new Date(t).toISOString():void 0,"iso");return{verbunden:this.verbunden,reconnectFaelligAt:e(this.reconnectFaelligAt),ereignisse:this.ereignisse,nachrichten:this.nachrichten,letztesEreignisAt:e(this.letztesEreignisAt)}}ensureConnected(){let e=Da({enabled:!this.gestoppt,aktiv:this.verbunden,reconnectFaelligAt:this.reconnectFaelligAt,letztesEreignisAt:this.letztesEreignisAt});if(e==="neustart"){this.deps.logger.warn({},"v1177 HA-Ereignisse: Verbindung h\xE4ngt \u2014 Neustart");try{this.ws?.close()}catch{}this.ws=void 0,this.verbunden=!1,this.versuche=0,this.verbinde()}return e}verbinde(){if(this.gestoppt)return;this.reconnectFaelligAt=void 0;let e=DD(this.deps.baseUrl);try{let t=this.deps.wsFabrik?this.deps.wsFabrik(e):new globalThis.WebSocket(e);this.ws=t,t.onopen=()=>{this.letztesEreignisAt=Date.now(),this.deps.logger.debug({url:e},"v1177 HA-Ereignisse: Socket offen, warte auf auth_required")},t.onmessage=s=>{this.nachricht(String(s.data))},t.onerror=s=>{this.letztesEreignisAt=Date.now(),this.deps.logger.warn({err:String(s?.message??"websocket error")},"v1177 HA-Ereignisse: Fehler")},t.onclose=()=>{this.letztesEreignisAt=Date.now();let s=this.verbunden;if(this.verbunden=!1,this.ws=void 0,this.gestoppt)return;this.versuche++;let n=Math.min(3e4*Math.pow(2,Math.min(this.versuche-1,5)),10*6e4);this.reconnectFaelligAt=Date.now()+n,this.deps.logger[s?"warn":"info"]({inSek:Math.round(n/1e3),versuch:this.versuche},"v1177 HA-Ereignisse: Verbindung geschlossen, Reconnect geplant"),this.reconnectTimer=setTimeout(()=>this.verbinde(),n),this.reconnectTimer.unref?.()}}catch(t){this.deps.logger.warn({err:t.message},"v1177 HA-Ereignisse: Verbindungsaufbau fehlgeschlagen"),this.versuche++;let s=Math.min(3e4*Math.pow(2,Math.min(this.versuche-1,5)),10*6e4);this.reconnectFaelligAt=Date.now()+s,this.reconnectTimer=setTimeout(()=>this.verbinde(),s)}}nachrichten=0;async nachricht(e){this.letztesEreignisAt=Date.now(),e.includes('"state_changed"')&&this.nachrichten++;let t=xD(e,this.letzte);if(t.art==="auth_required"){this.ws?.send(JSON.stringify({type:"auth",access_token:this.deps.accessToken}));return}if(t.art==="auth_ok"){this.verbunden=!0,this.versuche=0,this.ws?.send(JSON.stringify({id:1,type:"subscribe_events",event_type:"state_changed"})),this.deps.logger.info({},"v1177 HA-Ereignisse: verbunden, state_changed abonniert");return}if(t.art==="auth_invalid"){this.deps.logger.warn({},"v1177 HA-Ereignisse: Token abgelehnt"),this.ws?.close();return}if(t.art==="sonst"&&e.includes('"type":"result"')){try{let i=JSON.parse(e);this.deps.logger[i.success?"info":"warn"]({id:i.id,success:i.success,error:i.error},"v1178 HA-Ereignisse: Antwort auf Abonnement")}catch{}return}if(t.art!=="ereignis"||!t.ereignis)return;let s=`${t.ereignis.entity.entity_id}:${t.ereignis.entity.state}`,n=this.zuletztGemeldet.get(s)??0;if(!(Date.now()-n<6e4)){this.zuletztGemeldet.set(s,Date.now()),this.ereignisse++;try{await this.deps.onEreignis(t.ereignis)}catch(i){this.deps.logger.warn({err:i.message,entity:t.ereignis.entity.entity_id},"v1177 HA-Ereignis nicht verarbeitet")}}}}});var FD={};Le(FD,{ChatSessionRunbookReflector:()=>vk});function UD(l){return new Set(l.toLowerCase().replace(/[^a-z0-9äöüß]+/g," ").split(" ").map(e=>e.trim()).filter(e=>e.length>=3&&!kK.has(e)))}var kK,vk,jD=A(()=>{"use strict";kK=new Set(["der","die","das","den","dem","des","und","oder","aber","auch","in","im","auf","an","am","mit","von","vom","zu","zum","zur","fuer","f\xFCr","aus","bei","nach","ueber","\xFCber","um","unter","ein","eine","einen","einer","eines","soll","sollen","kann","koennen","k\xF6nnen","will","wird","werden","ist","sind","war","waren","sein","and","or","the","to","of","for","with","on","in","at","by","is","are","was","were","be"]);m(UD,"normalizeTitle");vk=class l{static{m(this,"ChatSessionRunbookReflector")}adapter;conversationRepo;runbookRepo;memoryRepo;confirmationQueue;llm;logger;ownerPlatform;ownerChatId;timer;tickRunning=!1;static QUIET_MINUTES=30;static MIN_MESSAGES=6;static POLL_INTERVAL_MS=300*1e3;static MARKER_PREFIX="_internal_runbook_processed:";static BACKFILL_MARKER="_internal_runbook_reflector_backfilled";static MAX_CANDIDATES_PER_TICK=3;static SESSION_AGE_DAYS=7;static MARKER_TTL_MS=1440*60*1e3;static CONFIRM_THRESHOLD=.9;static DRAFT_THRESHOLD=.65;constructor(e,t,s,n,i,r,a,o,c){this.adapter=e,this.conversationRepo=t,this.runbookRepo=s,this.memoryRepo=n,this.confirmationQueue=i,this.llm=r,this.logger=a,this.ownerPlatform=o,this.ownerChatId=c}start(){this.timer||(this.timer=setInterval(()=>{if(this.tickRunning){this.logger.debug("Runbook-reflector: previous tick still running, skipping");return}this.tickRunning=!0,this.tick().catch(e=>this.logger.warn({err:e},"Runbook-reflector tick failed")).finally(()=>{this.tickRunning=!1})},l.POLL_INTERVAL_MS),this.logger.info("Chat-session runbook reflector started"))}stop(){this.timer&&(clearInterval(this.timer),this.timer=void 0)}async tick(){let e=Date.now(),t=new Date(e-l.QUIET_MINUTES*6e4).toISOString(),s=new Date(e-l.SESSION_AGE_DAYS*24*60*6e4).toISOString(),n=await this.adapter.query(`SELECT c.id AS conversation_id, c.user_id, c.platform, c.chat_id,
|
|
8322
8322
|
MAX(m.created_at) AS last_message_at,
|
|
8323
8323
|
COUNT(m.id) AS message_count,
|
|
@@ -8483,7 +8483,7 @@ Hat der Agent gegen eine bestehende Konvention versto\xDFen? STRENG JSON: {"viol
|
|
|
8483
8483
|
HAVING SUM(n) > 50
|
|
8484
8484
|
`,[this.ownerMasterUserId]);this.legacyDataUids=X.map(W=>String(W.user_id)).filter(Boolean),this.legacyDataUids.length>0&&this.logger.info({legacyUids:this.legacyDataUids,count:this.legacyDataUids.length},"v694 Legacy data UIDs discovered \u2014 will be merged into owner sweeps")}catch(X){this.logger.debug({err:X},"v694 Legacy-UID discovery skipped")}}let M=(()=>{let ie=this.config.email?.accounts?.[0]?.microsoft??this.config.email?.microsoft??this.config.calendar?.microsoft??this.config.contacts?.microsoft??this.config.todo;if(ie?.clientId&&ie?.clientSecret)return{clientId:ie.clientId,clientSecret:ie.clientSecret,tenantId:ie.tenantId}})(),P={};this.config.calendar?.microsoft&&(P.calendar={provider:"microsoft",microsoft:this.config.calendar.microsoft}),this.config.contacts?.microsoft&&(P.contacts={provider:"microsoft",microsoft:this.config.contacts.microsoft});let Q=this.config.email?.accounts?.[0]?.microsoft??this.config.email?.microsoft;Q&&(P.email={provider:"microsoft",microsoft:Q}),this.config.todo?.clientId&&(P.todo={...this.config.todo}),R.register(new J(O,M,Object.keys(P).length>0?P:void 0)),this.logger.info("User management skill registered"),re.setAlfredUserLookup(O);let{SharingSkill:ue}=await Promise.resolve().then(()=>(ze(),Ze)),{SharedResourceRepository:le}=await Promise.resolve().then(()=>(nt(),it)),ee=new le(e);R.register(new ue(ee,O)),Ce.sharedResourceRepo=ee,j.sharedResourceRepo=ee,F.sharedResourceRepo=ee,this.logger.info("Sharing skill registered");let je=d;this.webAuthCallback={loginWithCode:m(async ie=>{let he=`web-pending-${Date.now()}`,ne=await O.consumeInviteCode(ie,"api",he);if(!ne)return{success:!1,error:"Ung\xFCltiger oder abgelaufener Code"};let ve=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,q=new Date(Date.now()+720*60*6e4).toISOString();return await je.createSession(ve,ne.id,"web-session",q),{success:!0,userId:ne.id,username:ne.username,role:ne.role,token:ve}},"loginWithCode"),getUserByToken:m(async ie=>{let he=await je.findByToken(ie);if(!he||new Date(he.expiresAt)<new Date)return null;let ne=await O.getById(he.userId);return ne?{userId:ne.id,username:ne.username,role:ne.role}:null},"getUserByToken")}}if(this.config.database?.enabled){let{DatabaseSkill:x}=await Promise.resolve().then(()=>(ze(),Ze)),{DatabaseConnectionRepository:J}=await Promise.resolve().then(()=>(nt(),it)),O=new J(e),M=new x(this.config.database,O);if(this.config.database.connections)for(let P of this.config.database.connections)await O.getByName(P.name)||await O.create({name:P.name,type:P.type,host:P.host,port:P.port,databaseName:P.database,username:P.username,authConfig:P.password?{password:P.password}:void 0,options:{readOnly:P.options?.readOnly??!0,rowLimit:P.options?.rowLimit,timeoutMs:P.options?.timeoutMs}});R.register(M),this.logger.info("Database skill registered")}if(this.config.backup?.enabled){let{SystemBackupSkill:x}=await Promise.resolve().then(()=>(ze(),Ze)),J=await Promise.resolve().then(()=>(am(),rm)).catch(()=>({default:{version:"unknown"}})),O=new x(this.config.backup,e,this.config.cluster?.nodeId??"single",J.default.version??"unknown",this.config.fileStore);R.register(O),this.logger.info("System Backup skill registered")}if(this.config.commvault?.enabled){let{CommvaultSkill:x}=await Promise.resolve().then(()=>(ze(),Ze)),J=new x(this.config.commvault);if(this.config.cmdb?.autoIncidentFromMonitor){let O=R.get("itsm");O&&J.setItsmCallback(async M=>O.execute(M,{alfredUserId:this.ownerMasterUserId}))}R.register(J),this.logger.info("Commvault skill registered")}if(this.config.mikrotik?.enabled&&this.config.cmdb?.autoIncidentFromMonitor){let x=R.get("mikrotik"),J=R.get("itsm");x&&J&&x.setItsmCallback(async O=>J.execute(O,{alfredUserId:this.ownerMasterUserId}))}if(this.config.youtube?.apiKey){let{YouTubeSkill:x}=await Promise.resolve().then(()=>(ze(),Ze));R.register(new x(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:R.getAll().map(x=>x.metadata.name)},"Skills registered"),this.config.speech&&(this.config.speech.sttProvider==="mistral"&&!this.config.speech.sttApiKey&&_e&&(this.config.speech.sttApiKey=_e),this.config.speech.ttsProvider==="mistral"&&!this.config.speech.ttsApiKey&&_e&&(this.config.speech.ttsApiKey=_e));let dt;if(this.config.speech?.apiKey){dt=new zl(this.config.speech,this.logger.child({component:"speech"})),dt.setUsageCallback((O,M)=>{v.record("stt",O,M).catch(()=>{})});let x=this.config.speech.sttProvider??this.config.speech.provider;this.logger.info({provider:x},"Speech-to-text initialized");let J=this.adapters.get("api");J&&"setTranscribeCallback"in J&&(J.setTranscribeCallback(async(O,M)=>dt.transcribe(O,M)),this.logger.info("Transcribe API endpoint registered (/api/transcribe)"))}if(this.config.speech?.ttsEnabled){let x=new Hl(this.config.speech,this.logger.child({component:"tts"}));x.setSkillState(r),x.setUsageCallback((O,M)=>{v.record("tts",O,M).catch(()=>{})}),this.speechSynthesizerRef=x,R.register(new ro(x));let J=this.config.speech.ttsProvider??"openai";this.logger.info({provider:J},"Text-to-speech skill registered")}{let x=this.config.speech,J=x?.ttsProvider==="mistral"&&x.voiceManagement!==!1,O=x?.ttsApiKey??_e;if(J&&O&&i){let M,P="localhost",Q=Ik.networkInterfaces();for(let ee of Object.values(Q))if(ee){for(let je of ee)if(je.family==="IPv4"&&!je.internal){P=je.address;break}if(P!=="localhost")break}let ue=this.config.api?.port??3420,le=this.config.api?.tls?.enabled?ue+2:ue;M=`http://${P}:${le}`,R.register(new Io(O,"https://api.mistral.ai/v1","voxtral-mini-tts-2603",i,R,M,r)),this.logger.info({announceBaseUrl:M},"Voice management skill registered")}}let ht=this.detectImageGenProvider();if(ht){let x,J=m(async()=>{if(x&&Date.now()-x.at<6e5)return x.key;let M;for(let P of["default","strong","fast","embeddings","local"]){let Q=this.config.llm[P];if(Q?.provider==="google"&&Q.apiKey){M=Q.apiKey;break}}if(!M&&this.socialRepo&&this.envRepoRef&&this.envCryptoRef&&this.ownerMasterUserId)try{let P=await this.socialRepo.listChannels(this.ownerMasterUserId,"active");for(let Q of P){if(!Q.projectId)continue;let ue=typeof Q.config.env_stage=="string"?Q.config.env_stage:"social",le=await this.envRepoRef.get(Q.projectId,ue);if(!le)continue;let ee=this.envCryptoRef.decrypt(le.varsEncrypted,le.iv,le.authTag);if(ee.GOOGLE_API_KEY){M=ee.GOOGLE_API_KEY;break}}}catch{}return x={key:M,at:Date.now()},M},"googleKeyProvider"),O=new Xl({...ht,googleKeyProvider:J},this.logger.child({component:"image-gen"}));R.register(new ao(O)),this.logger.info({provider:ht.provider},"Image generation skill registered")}try{let x=new Wl(this.logger.child({component:"transit"}));R.register(new po(x)),this.logger.info("Public transit skill registered")}catch(x){this.logger.warn({err:x},"Failed to register transit skill")}let Qe;if(this.config.fileStore){let{createFileStore:x}=await Promise.resolve().then(()=>(nt(),it));Qe=x(this.config.fileStore),this.fileStoreRef=Qe,this.logger.info({backend:this.config.fileStore.backend},"File store initialized")}Qe&&this.projectAgentRunnerRef&&(this.projectAgentRunnerRef.setFileStore(Qe),this.logger.info("Project-agent runner connected to file-store for asset-bridge"));let Pe=new Rl(t),Gt=Dt.resolve(Dt.dirname(this.config.storage.path),"inbox");if(this.pipeline=new jl({llm:k,conversationManager:Pe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:R,skillSandbox:C,securityManager:T,memoryRepo:i,speechTranscriber:dt,inboxPath:Gt,fileStore:Qe,processedMessageRepo:this.config.cluster?.enabled?new(await Promise.resolve().then(()=>(nt(),it))).ProcessedMessageRepository(e):void 0,nodeId:this.config.cluster?.nodeId??"single",embeddingService:N,activeLearning:L,memoryRetriever:V,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:He,conversationSummarizer:D,personality:this.config.personality}),this.config.cluster?.enabled){if(e.type!=="postgres")throw new Error('HA Cluster erfordert storage.backend: "postgres". SQLite ist nicht f\xFCr Multi-Node geeignet.');if(!this.config.cluster.nodeId)throw new Error("HA Cluster erfordert cluster.nodeId. Jeder Node braucht eine eindeutige ID.");(!this.config.fileStore||this.config.fileStore.backend==="local")&&this.logger.warn('HA Cluster ohne S3/NFS FileStore \u2014 Datei-Uploads sind nur auf dem empfangenden Node sichtbar. Empfohlen: fileStore.backend: "s3" oder "nfs"');let{ClusterManager:x}=await Promise.resolve().then(()=>(AE(),GL));this.clusterManager=new x(this.config.cluster,this.logger.child({component:"cluster"})),await this.clusterManager.connect(),this.clusterManager.isConnected||this.logger.warn("Redis nicht erreichbar \u2014 Cross-Node Pub/Sub und Echtzeit-Heartbeat deaktiviert. PG-Heartbeat als Fallback aktiv.");let{PgMigrator:J,PG_MIGRATIONS:O}=await Promise.resolve().then(()=>(nt(),it));await new J(e).migrate(O);{let P=await Promise.resolve().then(()=>(am(),rm)).catch(()=>({default:{version:""}})),Q=["/",this.config.storage?.path,this.config.fileStore?.basePath,...(this.config.infra?.shares??[]).map(ue=>ue.mountPath)].filter(ue=>typeof ue=="string"&&ue.length>0);this.clusterManager.setNodeInfo({version:P.default.version??"",adapters:m(()=>[...this.adapters?.keys()??[]],"adapters"),diskPaths:Q})}this.clusterManager.startPgHeartbeat(e),this.logger.info({nodeId:this.config.cluster.nodeId},"Cluster manager initialized (Active-Active)")}this.reminderScheduler=new Bl(a,async(x,J,O,M)=>{let P=this.adapters.get(x);P?await P.sendMessage(J,O,M):this.logger.warn({platform:x,chatId:J},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(x=>s.getMasterUserId(x),"getMasterUserId"),getLinkedUsers:m(x=>s.getLinkedUsers(x),"getLinkedUsers"),findConversation:m((x,J)=>t.findByPlatformAndUser(x,J),"findConversation")},this.config.cluster?.nodeId??"single"),this.backgroundTaskRunner=new ql(R,C,u,this.adapters,s,this.logger.child({component:"background-tasks"}),f,y);let bt=new Jl(R,C,u,this.adapters,s,this.logger.child({component:"persistent-agents"}),f);this.backgroundTaskRunner.setPersistentRunner(bt),ye.setPersistentRunner(bt),this.proactiveScheduler=new Yl(h,R,C,k,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Pe,f,this.config.cluster?.nodeId??"single");let _t=new ea(e);this.watchRepo=_t;let ft=new go(_t,R);ft.setSkillSandbox(C),R.register(ft);let Lt=new ta(e);this.confirmationQueue=new Nl(Lt,R,C,this.adapters,this.logger.child({component:"confirmation-queue"}),f);let Ve=new aa(e),at=new Do(Ve,i,this.logger.child({component:"feedback"}));at.setLLM(k),k.supportsEmbeddings()&&at.setEmbeddingService(k),setTimeout(()=>{let x=this.tryOwner();x&&at.migrateCorrectionMemories(x).then(J=>this.logger.info({...J},"Feedback: correction-migration completed")).catch(J=>this.logger.debug({err:J},"Feedback: correction-migration failed (non-critical)"))},3e4),this.confirmationQueue.setFeedbackService(at),L&&L.setFeedbackService(at),this.projectRepo&&this.confirmationQueue.setProjectRepo(this.projectRepo),this.memoryRepo&&this.confirmationQueue.setMemoryRepo(this.memoryRepo),this.watchEngine=new kf(_t,R,C,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,f,y,k,this.config.cluster?.nodeId??"single");let yt=new ra(e),mt=new yo(yt,R);mt.setRunConfirmationCallback(async({chain:x,context:J})=>{if(!this.confirmationQueue)throw new Error("ConfirmationQueue not available");let O=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":J.platform??"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:O,source:"reasoning",sourceId:`workflow-run-${x.id.slice(0,8)}-${Date.now()}`,description:`Workflow '${x.name}' (${x.steps.length} Schritte) ausf\xFChren?`+(x.description?`
|
|
8485
8485
|
|
|
8486
|
-
${x.description}`:""),skillName:"workflow",skillParams:{action:"run",workflow_id:x.id,confirmed:!0},timeoutMinutes:60})}),R.register(mt);let Ut=new fd("./data/scripts",this.logger.child({component:"script-executor"})),Mt=new md(e,this.logger.child({component:"db-query-executor"})),Tt=new pd(yt,R,C,this.logger.child({component:"workflow-runner"}),f,y,Ut,Mt);mt.setRunner(Tt);let es=new gd(k,R,this.logger.child({component:"prompt-parser"}));mt.setPromptParser(es);{let x=new wd(R,C),J=new yd(yt,x,async(O,M)=>{let P=await yt.getById(O);if(!P)return;let{context:Q}=await(await Promise.resolve().then(()=>(wn(),ZR))).buildSkillContext(s,{userId:this.config.security?.ownerUserId??"",platform:"api",chatId:""});return Tt.run(P,Q,M)},this.logger.child({component:"trigger-manager"}));J.start(),this.triggerManager=J}let ct,Nt;{let x=this.config.security?.ownerUserId;if(x&&this.config.reasoning?.enabled!==!1){ct=new In(i,this.logger.child({component:"insight-tracker"}),r),this.insightTracker=ct;let J=new ii(e);Nt=new Nr(new ks(e),this.logger.child({component:"knowledge-graph"}),i,R,C,s,x,Be),this.embeddingServiceRef&&Nt.setEmbeddingService(this.embeddingServiceRef,this.embeddingRepoRef);let O=this.config.reasoning?.llmLinking;if(O?.enabled){let P=O.provider??"mistral",Q=this.config.mistralApiKey;if(!Q)for(let ue of["fast","default","strong"]){let le=this.config.llm[ue];if(le?.provider===P&&le.apiKey){Q=le.apiKey;break}}if(Q){let{LLMEntityLinker:ue}=await Promise.resolve().then(()=>(qL(),VL)),le=P==="openai"?"https://api.openai.com/v1":P==="anthropic"?"https://api.anthropic.com/v1":"https://api.mistral.ai/v1",ee=new ue(new ks(e),O,this.logger.child({component:"llm-entity-linker"}),Q,le);ee.setUsageCallback((je,ie,he,ne)=>{b.record(ie,he,ne,0,0,0).catch(()=>{})}),ee.setDocumentRepo(xe),Nt.setLLMLinker(ee),this.logger.info({provider:P,model:O.model??"mistral-small-latest"},"LLM entity linker enabled")}}let M;try{M=(await s.getProfile?.(this.ownerMasterUserId||x))?.timezone}catch{}try{b.setTimezone(M),v.setTimezone(M)}catch{}this.reasoningEngine=new Oo(Ge,B,_t,i,p,g,J,R,C,k,this.adapters,s,x,Be,this.config.reasoning,this.logger.child({component:"reasoning-engine"}),f,this.config.briefing?.location,Ve,this.confirmationQueue,this.config.cluster?.nodeId??"single",e,ct,void 0,Nt,yt,this.bmwTelematicRepo,o,this.reminderRepo,xe,M,t,this.runbookRepo,this.projectRepo)}}if(this.reasoningEngine){let{PlanRepository:x}=await Promise.resolve().then(()=>(nt(),it)),{PlanningAgent:J}=await Promise.resolve().then(()=>(YL(),JL)),O=new x(e),M=new J(O,k,{execute:m(async(P,Q,ue)=>{let le=R.get(P);return le?C.execute(le,Q,{userId:ue,masterUserId:ue}):{success:!1,error:`Skill "${P}" not found`}},"execute")},this.logger.child({component:"planning-agent"}));this.reasoningEngine.setPlanningAgent(M),this.reasoningEngine.collector?.setPlanningAgent&&this.reasoningEngine.collector.setPlanningAgent(M)}if(this.reasoningEngine&&this.insightsRepo&&this.ownerMasterUserId){let{NotificationRouter:x}=await Promise.resolve().then(()=>(eO(),QL)),J={};if(this.database)try{let O=await new ai(this.database.getAdapter()).get(this.ownerMasterUserId,"notifications","router-override");O&&(J=JSON.parse(O))}catch{}this.notificationRouter=new x(this.insightsRepo,this.adapters,{minUrgency:J.minUrgency??this.config.notifications?.minUrgency??"high",perSource:J.perSource??this.config.notifications?.perSource,devMode:J.devMode??this.config.notifications?.devMode??!1},this.logger.child({component:"notification-router"}),this.ownerMasterUserId),this.reasoningEngine.setNotificationRouter(this.notificationRouter),this.logger.info({minUrgency:this.config.notifications?.minUrgency??"high",devMode:this.config.notifications?.devMode??!1},"v927 notification router active")}else this.reasoningEngine&&!this.ownerMasterUserId&&this.logger.warn("v927 notification router NOT active (no ownerMasterUserId) \u2014 sending behaviour unchanged");Nt&&(this.pipeline.setKnowledgeGraphService(Nt),this.kgServiceRef=Nt,this.memorySkillRef&&this.memorySkillRef.setKgAnalyzeCallback(async x=>{let J=this.ownerMasterUserId??x,O=new ks(this.database.getAdapter());try{await Nt.syncMemoryEntities(J)}catch{}try{await Nt.buildCrossExtractorRelations(J)}catch{}try{await Nt.buildFamilyInference(J)}catch{}try{await Nt.buildGenericEntityLinks(J)}catch{}let M=Nt.getLLMLinker(),P={relations:0,newEntities:0,corrections:0};if(M)try{P=await M.run(J)}catch{}try{await Nt.maintenance(J)}catch(ue){this.logger.warn({err:ue.message},"KG maintenance in kg_analyze failed")}let Q=await O.getFullGraph(J);return{entities:Q.entities.length,relations:Q.relations.length,newEntities:P.newEntities,corrections:P.corrections}}));{let x=this.watchEngine.onWatchTriggered;this.watchEngine.onWatchTriggered=(J,O,M,P)=>{x?.(J,O,M,P),this.triggerManager&&this.triggerManager.onWatchTriggered(J,O).catch(()=>{}),P!=="feed_reader"&&this.reasoningEngine&&this.reasoningEngine.triggerOnEvent("watch_alert",`Watch "${J}" ausgel\xF6st: ${O}`,M).catch(Q=>this.logger.warn({err:Q},"Event-triggered reasoning failed"))}}if(this.reasoningEngine&&this.calendarWatcher&&(this.calendarWatcher.onEventNotified=x=>{this.reasoningEngine.triggerOnEvent("calendar_upcoming",`Termin in K\xFCrze: ${x.title}${x.location?` (${x.location})`:""}`,{eventId:x.id,title:x.title,location:x.location,start:x.start.toISOString()}).catch(J=>this.logger.warn({err:J},"Calendar-triggered reasoning failed"))}),this.reasoningEngine&&this.todoWatcher&&(this.todoWatcher.onTodoNotified=(x,J,O)=>{this.reasoningEngine.triggerOnEvent(`todo_${O}`,`Todo ${O==="overdue"?"\xFCberf\xE4llig":"bald f\xE4llig"}: ${J}`,{todoId:x,title:J,kind:O}).catch(M=>this.logger.warn({err:M},"Todo-triggered reasoning failed"))}),this.pipeline.setConfirmationQueue(this.confirmationQueue),this.todoRepo&&this.reminderRepo){let{QuickActionHandler:x}=await Promise.resolve().then(()=>(sO(),tO)),J=new x(this.todoRepo,this.reminderRepo,this.adapters,this.logger.child({component:"quick-actions"}));if(this.socialSkillRef&&this.ownerMasterUserId){let O=this.socialSkillRef,M={userId:this.ownerMasterUserId,masterUserId:this.ownerMasterUserId},P=m(Q=>async ue=>{let le=await O.execute({action:Q,item_id:ue},M);return{success:le.success,display:le.display,error:le.error}},"run");J.setSocialHandlers({approve:P("approve_content"),publish:P("publish_now"),reject:P("reject_content")})}this.pipeline.setQuickActions(J)}if(this.pipeline.setActivityLogger(f),this.pipeline.setSkillHealthTracker(y),this.pipeline.setOwnerMasterUserId&&this.pipeline.setOwnerMasterUserId(this.ownerMasterUserId),this.skillHealthRepo&&this.pipeline.setSkillHealthRepo(this.skillHealthRepo),ct&&this.pipeline.setInsightTracker(ct),this.pipeline.setProjectAgentResolver&&this.pipeline.setProjectAgentResolver((x,J)=>this.resolveCliAgent(x,J)),this.reasoningEngine&&this.pipeline.setReasoningEngine(this.reasoningEngine),this.interestsRepo){this.pipeline.setInterestsRepo(this.interestsRepo);let{TopicCollector:x}=await Promise.resolve().then(()=>(rO(),iO));this.topicCollector=new x(this.interestsRepo,this.skillRegistry,this.skillSandbox,this.logger.child({component:"topic-collector"}),{dbAdapter:this.database?.getAdapter(),nodeId:this.config.cluster?.nodeId,youtubeApiKey:this.config.youtube?.apiKey,llm:this.llmProvider??void 0}),this.topicCollector.start();let J=this.topicCollector;this.interestsSkillRef?.setCollector(P=>P?J.collectTopic(P):J.collectAll()),this.reasoningEngine?.setInterestsRepo(this.interestsRepo);let{SourceProvisioner:O}=await Promise.resolve().then(()=>(cO(),oO));this.sourceProvisioner=new O(this.interestsRepo,this.skillRegistry,this.skillSandbox,this.llmProvider,this.logger.child({component:"source-provisioner"}));let M=this.sourceProvisioner;if(this.interestsSkillRef?.setProvisioner(P=>M.provision(P)),this.ownerMasterUserId&&this.llmProvider){let P=this.ownerMasterUserId,{InterestDetector:Q}=await Promise.resolve().then(()=>(uO(),dO)),{TopicDigestBuilder:ue}=await Promise.resolve().then(()=>(fO(),pO)),le=this.database?new ks(this.database.getAdapter()):void 0,ee=this.memoryRepo;this.interestDetector=new Q(this.interestsRepo,this.insightsRepo,this.llmProvider,this.sourceProvisioner,async()=>{let he=le?(await le.getAllEntities(P)).filter(ve=>ve.layer==="personal").sort((ve,q)=>q.mentionCount-ve.mentionCount).slice(0,30).map(ve=>({name:ve.name,type:ve.entityType,mentions:ve.mentionCount})):[],ne=ee?await ee.getRecentForPrompt(P,15):[];return{entities:he,recentSummaries:ne.map(ve=>`${ve.key}: ${ve.value}`)}},this.logger.child({component:"interest-detector"}),P);let je={chatId:this.config.security?.ownerUserId??"",platform:this.config.telegram?.enabled?"telegram":"api"};this.topicDigestBuilder=new ue(this.interestsRepo,this.llmProvider,this.notificationRouter,this.logger.child({component:"topic-digest-builder"}),je);let{SourceMaintenance:ie}=await Promise.resolve().then(()=>(gO(),mO));this.sourceMaintenance=new ie(this.interestsRepo,this.sourceProvisioner,this.insightsRepo,this.logger.child({component:"source-maintenance"}),P),this.registriereJob({key:"interest-detect",beschreibung:"Interessen-Erkennung (Themen-Radar)",takt:{art:"taeglich",um:"05:15"},bereich:"global",slot:!0,run:m(async()=>(await this.interestDetector?.runDetection(),{ok:!0}),"run")}),this.registriereJob({key:"source-maintenance",beschreibung:"Quellen-Pflege: Feeds proben, ausmisten, nachbest\xFCcken",takt:{art:"woechentlich",tag:6,um:"05:45"},bereich:"global",slot:!0,run:m(async()=>(await this.sourceMaintenance?.runWeekly(),{ok:!0}),"run")}),this.registriereJob({key:"topic-digest",beschreibung:"Themen-Digest an den Owner",takt:{art:"taeglich",um:"06:30"},bereich:"global",slot:!0,run:m(async()=>(await this.topicDigestBuilder?.run(),{ok:!0}),"run")}),this.registriereJob({key:"stammdaten-sync",beschreibung:"Memory-Fakten \u2192 Knowledge Graph (idempotent)",takt:{art:"intervall",minuten:60},bereich:"global",run:m(async()=>{let he=this.tryOwner();if(!he||!this.database||!this.memoryRepo)return{ok:!0,zaehler:{uebersprungen:1}};let{StammdatenSync:ne}=await Promise.resolve().then(()=>(jE(),FE)),{KnowledgeGraphRepository:ve}=await Promise.resolve().then(()=>(nt(),it)),q=await new ne(new ve(this.database.getAdapter()),this.memoryRepo,this.logger.child({component:"stammdaten-sync"})).run(he);return{ok:!0,zaehler:{gesetzt:q.gesetzt,angelegt:q.angelegt}}},"run")}),this.registriereJob({key:"lern-telemetrie",beschreibung:"Lern-Telemetrie der Woche (Insight)",takt:{art:"woechentlich",tag:0,um:"19:15"},bereich:"global",slot:!0,run:m(async()=>{try{let he=this.tryOwner(),ne=this.database?.getAdapter();if(he&&ne&&this.insightsRepo){let ve=m(async W=>{try{let de=await ne.queryOne(W,[]);return Number(de?.n??0)}catch{return-1}},"zaehle"),q=[`Rezepte: ${await ve("SELECT count(*) n FROM learned_recipes")} gelernt, ${await ve("SELECT count(*) n FROM learned_recipes WHERE success_count > 0")} je benutzt`,`Runbooks: ${await ve("SELECT count(*) n FROM runbooks")}`,`Verhaltens-Muster: ${await ve("SELECT count(*) n FROM memories WHERE type = 'pattern'")}`,`Skill-Regeln: ${await ve("SELECT count(*) n FROM memories WHERE type = 'rule'")}`,`Action-Feedback-Events: ${await ve("SELECT count(*) n FROM feedback_events")}`,`Auto-extrahierte Workflows: ${await ve("SELECT count(*) n FROM workflow_chains WHERE auto_extracted = 1")}`,`Wissens-R\xFCckfragen gestellt: ${await ve("SELECT count(*) n FROM kg_questions")}`,`Watches: ${await ve("SELECT count(*) n FROM watches WHERE enabled = 1")} aktiv, ${await ve("SELECT count(*) n FROM watches WHERE last_triggered_at IS NOT NULL")} haben je getriggert`];try{let{summiereKennzahlMesswerte:W,berechneQuoten:de,formatiereKennzahlen:Oe,KENNZAHL_QUELLE:Xe}=await Promise.resolve().then(()=>(Ll(),ff)),st=new Date(Date.now()-7*864e5).toISOString(),G=(await ne.query("SELECT entity, wert FROM messwerte WHERE user_id = ? AND quelle = ? AND gemessen_at >= ?",[he,Xe,st])).map(Y=>({entity:Y.entity,wert:Y.wert===null?0:Number(Y.wert)})),pe=W(G),ae=m(Y=>G.filter(ce=>ce.entity==="kennzahl."+Y).reduce((ce,me)=>ce+me.wert,0),"summe"),De=de({insightsReagiert:ae("insightsReagiert"),insightsVerworfen:ae("insightsVerworfen"),insightsAbgelaufen:ae("insightsAbgelaufen"),vorgaengeAngelegt:pe.vorgaengeAngelegt??0,vorgaengeErledigt:ae("vorgaengeErledigt"),kostenUsd:ae("kostenUsd")});G.length>0&&q.push("",...Oe(pe,De,7));let{formatiereErledigungJeKategorie:we}=await Promise.resolve().then(()=>(Ll(),ff)),{VorgaengeRepository:Ae}=await Promise.resolve().then(()=>(nt(),it)),Z=await new Ae(ne).erledigungJeKategorie(he,28);Z.length>0&&q.push("",...we(Z,28))}catch(W){this.logger.debug({err:W.message},"v1183 Wochen-Kennzahlen nicht verf\xFCgbar")}let X=Math.floor(Date.now()/(168*36e5));await this.insightsRepo.upsertCandidate(he,{category:"lern-telemetrie",title:"\u{1F4CA} Lern-Telemetrie der Woche",body:q.join(`
|
|
8486
|
+
${x.description}`:""),skillName:"workflow",skillParams:{action:"run",workflow_id:x.id,confirmed:!0},timeoutMinutes:60})}),R.register(mt);let Ut=new fd("./data/scripts",this.logger.child({component:"script-executor"})),Mt=new md(e,this.logger.child({component:"db-query-executor"})),Tt=new pd(yt,R,C,this.logger.child({component:"workflow-runner"}),f,y,Ut,Mt);mt.setRunner(Tt);let es=new gd(k,R,this.logger.child({component:"prompt-parser"}));mt.setPromptParser(es);{let x=new wd(R,C),J=new yd(yt,x,async(O,M)=>{let P=await yt.getById(O);if(!P)return;let{context:Q}=await(await Promise.resolve().then(()=>(wn(),ZR))).buildSkillContext(s,{userId:this.config.security?.ownerUserId??"",platform:"api",chatId:""});return Tt.run(P,Q,M)},this.logger.child({component:"trigger-manager"}));J.start(),this.triggerManager=J}let ct,Nt;{let x=this.config.security?.ownerUserId;if(x&&this.config.reasoning?.enabled!==!1){ct=new In(i,this.logger.child({component:"insight-tracker"}),r),this.insightTracker=ct;let J=new ii(e);Nt=new Nr(new ks(e),this.logger.child({component:"knowledge-graph"}),i,R,C,s,x,Be),this.embeddingServiceRef&&Nt.setEmbeddingService(this.embeddingServiceRef,this.embeddingRepoRef);let O=this.config.reasoning?.llmLinking;if(O?.enabled){let P=O.provider??"mistral",Q=this.config.mistralApiKey;if(!Q)for(let ue of["fast","default","strong"]){let le=this.config.llm[ue];if(le?.provider===P&&le.apiKey){Q=le.apiKey;break}}if(Q){let{LLMEntityLinker:ue}=await Promise.resolve().then(()=>(qL(),VL)),le=P==="openai"?"https://api.openai.com/v1":P==="anthropic"?"https://api.anthropic.com/v1":"https://api.mistral.ai/v1",ee=new ue(new ks(e),O,this.logger.child({component:"llm-entity-linker"}),Q,le);ee.setUsageCallback((je,ie,he,ne)=>{b.record(ie,he,ne,0,0,0).catch(()=>{})}),ee.setDocumentRepo(xe),Nt.setLLMLinker(ee),this.logger.info({provider:P,model:O.model??"mistral-small-latest"},"LLM entity linker enabled")}}let M;try{M=(await s.getProfile?.(this.ownerMasterUserId||x))?.timezone}catch{}try{b.setTimezone(M),v.setTimezone(M)}catch{}this.reasoningEngine=new Oo(Ge,B,_t,i,p,g,J,R,C,k,this.adapters,s,x,Be,this.config.reasoning,this.logger.child({component:"reasoning-engine"}),f,this.config.briefing?.location,Ve,this.confirmationQueue,this.config.cluster?.nodeId??"single",e,ct,void 0,Nt,yt,this.bmwTelematicRepo,o,this.reminderRepo,xe,M,t,this.runbookRepo,this.projectRepo)}}if(this.reasoningEngine){let{PlanRepository:x}=await Promise.resolve().then(()=>(nt(),it)),{PlanningAgent:J}=await Promise.resolve().then(()=>(YL(),JL)),O=new x(e),M=new J(O,k,{execute:m(async(P,Q,ue)=>{let le=R.get(P);return le?C.execute(le,Q,{userId:ue,masterUserId:ue}):{success:!1,error:`Skill "${P}" not found`}},"execute")},this.logger.child({component:"planning-agent"}));this.reasoningEngine.setPlanningAgent(M),this.reasoningEngine.collector?.setPlanningAgent&&this.reasoningEngine.collector.setPlanningAgent(M)}if(this.reasoningEngine&&this.insightsRepo&&this.ownerMasterUserId){let{NotificationRouter:x}=await Promise.resolve().then(()=>(eO(),QL)),J={};if(this.database)try{let O=await new ai(this.database.getAdapter()).get(this.ownerMasterUserId,"notifications","router-override");O&&(J=JSON.parse(O))}catch{}this.notificationRouter=new x(this.insightsRepo,this.adapters,{minUrgency:J.minUrgency??this.config.notifications?.minUrgency??"high",perSource:J.perSource??this.config.notifications?.perSource,devMode:J.devMode??this.config.notifications?.devMode??!1},this.logger.child({component:"notification-router"}),this.ownerMasterUserId),this.reasoningEngine.setNotificationRouter(this.notificationRouter),this.logger.info({minUrgency:this.config.notifications?.minUrgency??"high",devMode:this.config.notifications?.devMode??!1},"v927 notification router active")}else this.reasoningEngine&&!this.ownerMasterUserId&&this.logger.warn("v927 notification router NOT active (no ownerMasterUserId) \u2014 sending behaviour unchanged");Nt&&(this.pipeline.setKnowledgeGraphService(Nt),this.kgServiceRef=Nt,this.memorySkillRef&&this.memorySkillRef.setKgAnalyzeCallback(async x=>{let J=this.ownerMasterUserId??x,O=new ks(this.database.getAdapter());try{await Nt.syncMemoryEntities(J)}catch{}try{await Nt.buildCrossExtractorRelations(J)}catch{}try{await Nt.buildFamilyInference(J)}catch{}try{await Nt.buildGenericEntityLinks(J)}catch{}let M=Nt.getLLMLinker(),P={relations:0,newEntities:0,corrections:0};if(M)try{P=await M.run(J)}catch{}try{await Nt.maintenance(J)}catch(ue){this.logger.warn({err:ue.message},"KG maintenance in kg_analyze failed")}let Q=await O.getFullGraph(J);return{entities:Q.entities.length,relations:Q.relations.length,newEntities:P.newEntities,corrections:P.corrections}}));{let x=this.watchEngine.onWatchTriggered;this.watchEngine.onWatchTriggered=(J,O,M,P)=>{x?.(J,O,M,P),this.triggerManager&&this.triggerManager.onWatchTriggered(J,O).catch(()=>{}),P!=="feed_reader"&&this.reasoningEngine&&this.reasoningEngine.triggerOnEvent("watch_alert",`Watch "${J}" ausgel\xF6st: ${O}`,M).catch(Q=>this.logger.warn({err:Q},"Event-triggered reasoning failed"))}}if(this.reasoningEngine&&this.calendarWatcher&&(this.calendarWatcher.onEventNotified=x=>{this.reasoningEngine.triggerOnEvent("calendar_upcoming",`Termin in K\xFCrze: ${x.title}${x.location?` (${x.location})`:""}`,{eventId:x.id,title:x.title,location:x.location,start:x.start.toISOString()}).catch(J=>this.logger.warn({err:J},"Calendar-triggered reasoning failed"))}),this.reasoningEngine&&this.todoWatcher&&(this.todoWatcher.onTodoNotified=(x,J,O)=>{this.reasoningEngine.triggerOnEvent(`todo_${O}`,`Todo ${O==="overdue"?"\xFCberf\xE4llig":"bald f\xE4llig"}: ${J}`,{todoId:x,title:J,kind:O}).catch(M=>this.logger.warn({err:M},"Todo-triggered reasoning failed"))}),this.pipeline.setConfirmationQueue(this.confirmationQueue),this.todoRepo&&this.reminderRepo){let{QuickActionHandler:x}=await Promise.resolve().then(()=>(sO(),tO)),J=new x(this.todoRepo,this.reminderRepo,this.adapters,this.logger.child({component:"quick-actions"}));if(this.socialSkillRef&&this.ownerMasterUserId){let O=this.socialSkillRef,M={userId:this.ownerMasterUserId,masterUserId:this.ownerMasterUserId},P=m(Q=>async ue=>{let le=await O.execute({action:Q,item_id:ue},M);return{success:le.success,display:le.display,error:le.error}},"run");J.setSocialHandlers({approve:P("approve_content"),publish:P("publish_now"),reject:P("reject_content")})}this.pipeline.setQuickActions(J)}if(this.pipeline.setActivityLogger(f),this.pipeline.setSkillHealthTracker(y),this.pipeline.setOwnerMasterUserId&&this.pipeline.setOwnerMasterUserId(this.ownerMasterUserId),this.skillHealthRepo&&this.pipeline.setSkillHealthRepo(this.skillHealthRepo),ct&&this.pipeline.setInsightTracker(ct),this.pipeline.setProjectAgentResolver&&this.pipeline.setProjectAgentResolver((x,J)=>this.resolveCliAgent(x,J)),this.reasoningEngine&&this.pipeline.setReasoningEngine(this.reasoningEngine),this.interestsRepo){this.pipeline.setInterestsRepo(this.interestsRepo);let{TopicCollector:x}=await Promise.resolve().then(()=>(rO(),iO));this.topicCollector=new x(this.interestsRepo,this.skillRegistry,this.skillSandbox,this.logger.child({component:"topic-collector"}),{dbAdapter:this.database?.getAdapter(),nodeId:this.config.cluster?.nodeId,youtubeApiKey:this.config.youtube?.apiKey,llm:this.llmProvider??void 0}),this.topicCollector.start();let J=this.topicCollector;this.interestsSkillRef?.setCollector(P=>P?J.collectTopic(P):J.collectAll()),this.reasoningEngine?.setInterestsRepo(this.interestsRepo);let{SourceProvisioner:O}=await Promise.resolve().then(()=>(cO(),oO));this.sourceProvisioner=new O(this.interestsRepo,this.skillRegistry,this.skillSandbox,this.llmProvider,this.logger.child({component:"source-provisioner"}));let M=this.sourceProvisioner;if(this.interestsSkillRef?.setProvisioner(P=>M.provision(P)),this.ownerMasterUserId&&this.llmProvider){let P=this.ownerMasterUserId,{InterestDetector:Q}=await Promise.resolve().then(()=>(uO(),dO)),{TopicDigestBuilder:ue}=await Promise.resolve().then(()=>(fO(),pO)),le=this.database?new ks(this.database.getAdapter()):void 0,ee=this.memoryRepo;this.interestDetector=new Q(this.interestsRepo,this.insightsRepo,this.llmProvider,this.sourceProvisioner,async()=>{let he=le?(await le.getAllEntities(P)).filter(ve=>ve.layer==="personal").sort((ve,q)=>q.mentionCount-ve.mentionCount).slice(0,30).map(ve=>({name:ve.name,type:ve.entityType,mentions:ve.mentionCount})):[],ne=ee?await ee.getRecentForPrompt(P,15):[];return{entities:he,recentSummaries:ne.map(ve=>`${ve.key}: ${ve.value}`)}},this.logger.child({component:"interest-detector"}),P);let je={chatId:this.config.security?.ownerUserId??"",platform:this.config.telegram?.enabled?"telegram":"api"};this.topicDigestBuilder=new ue(this.interestsRepo,this.llmProvider,this.notificationRouter,this.logger.child({component:"topic-digest-builder"}),je);let{SourceMaintenance:ie}=await Promise.resolve().then(()=>(gO(),mO));this.sourceMaintenance=new ie(this.interestsRepo,this.sourceProvisioner,this.insightsRepo,this.logger.child({component:"source-maintenance"}),P),this.registriereJob({key:"interest-detect",beschreibung:"Interessen-Erkennung (Themen-Radar)",takt:{art:"taeglich",um:"05:15"},bereich:"global",slot:!0,run:m(async()=>(await this.interestDetector?.runDetection(),{ok:!0}),"run")}),this.registriereJob({key:"source-maintenance",beschreibung:"Quellen-Pflege: Feeds proben, ausmisten, nachbest\xFCcken",takt:{art:"woechentlich",tag:6,um:"05:45"},bereich:"global",slot:!0,run:m(async()=>(await this.sourceMaintenance?.runWeekly(),{ok:!0}),"run")}),this.registriereJob({key:"topic-digest",beschreibung:"Themen-Digest an den Owner",takt:{art:"taeglich",um:"06:30"},bereich:"global",slot:!0,run:m(async()=>(await this.topicDigestBuilder?.run(),{ok:!0}),"run")}),this.registriereJob({key:"stammdaten-sync",beschreibung:"Memory-Fakten \u2192 Knowledge Graph (idempotent)",takt:{art:"intervall",minuten:60},bereich:"global",run:m(async()=>{let he=this.tryOwner();if(!he||!this.database||!this.memoryRepo)return{ok:!0,zaehler:{uebersprungen:1}};let{StammdatenSync:ne}=await Promise.resolve().then(()=>(jE(),FE)),{KnowledgeGraphRepository:ve}=await Promise.resolve().then(()=>(nt(),it)),q=await new ne(new ve(this.database.getAdapter()),this.memoryRepo,this.logger.child({component:"stammdaten-sync"})).run(he);return{ok:!0,zaehler:{gesetzt:q.gesetzt,angelegt:q.angelegt}}},"run")}),this.registriereJob({key:"lern-telemetrie",beschreibung:"Lern-Telemetrie der Woche (Insight)",takt:{art:"woechentlich",tag:0,um:"19:15"},bereich:"global",slot:!0,run:m(async()=>{try{let he=this.tryOwner(),ne=this.database?.getAdapter();if(he&&ne&&this.insightsRepo){let ve=m(async W=>{try{let de=await ne.queryOne(W,[]);return Number(de?.n??0)}catch{return-1}},"zaehle"),q=[`Rezepte: ${await ve("SELECT count(*) n FROM learned_recipes")} gelernt, ${await ve("SELECT count(*) n FROM learned_recipes WHERE success_count > 0")} je benutzt`,`Runbooks: ${await ve("SELECT count(*) n FROM runbooks")}`,`Verhaltens-Muster: ${await ve("SELECT count(*) n FROM memories WHERE type = 'pattern'")}`,`Skill-Regeln: ${await ve("SELECT count(*) n FROM memories WHERE type = 'rule'")}`,`Action-Feedback-Events: ${await ve("SELECT count(*) n FROM feedback_events")}`,`Auto-extrahierte Workflows: ${await ve("SELECT count(*) n FROM workflow_chains WHERE auto_extracted = 1")}`,`Wissens-R\xFCckfragen gestellt: ${await ve("SELECT count(*) n FROM kg_questions")}`,`Watches: ${await ve("SELECT count(*) n FROM watches WHERE enabled = 1")} aktiv, ${await ve("SELECT count(*) n FROM watches WHERE last_triggered_at IS NOT NULL")} haben je getriggert`];try{let{summiereKennzahlMesswerte:W,berechneQuoten:de,formatiereKennzahlen:Oe,KENNZAHL_QUELLE:Xe}=await Promise.resolve().then(()=>(Ll(),ff)),st=new Date(Date.now()-7*864e5).toISOString(),G=(await ne.query("SELECT entity, wert FROM messwerte WHERE user_id = ? AND quelle = ? AND gemessen_at >= ?",[he,Xe,st])).map(Y=>({entity:Y.entity,wert:Y.wert===null?0:Number(Y.wert)})),pe=W(G),ae=m(Y=>G.filter(ce=>ce.entity==="kennzahl."+Y).reduce((ce,me)=>ce+me.wert,0),"summe"),De=de({insightsReagiert:ae("insightsReagiert"),insightsVerworfen:ae("insightsVerworfen"),insightsAbgelaufen:ae("insightsAbgelaufen"),vorgaengeAngelegt:pe.vorgaengeAngelegt??0,vorgaengeErledigt:ae("vorgaengeErledigt"),kostenUsd:ae("kostenUsd")});G.length>0&&q.push("",...Oe(pe,De,7,ae("kostenUsd")));let{formatiereErledigungJeKategorie:we}=await Promise.resolve().then(()=>(Ll(),ff)),{VorgaengeRepository:Ae}=await Promise.resolve().then(()=>(nt(),it)),Z=await new Ae(ne).erledigungJeKategorie(he,28);Z.length>0&&q.push("",...we(Z,28))}catch(W){this.logger.debug({err:W.message},"v1183 Wochen-Kennzahlen nicht verf\xFCgbar")}let X=Math.floor(Date.now()/(168*36e5));await this.insightsRepo.upsertCandidate(he,{category:"lern-telemetrie",title:"\u{1F4CA} Lern-Telemetrie der Woche",body:q.join(`
|
|
8487
8487
|
`),confidence:.9,sourceData:{router:!0,urgency:"low"},dedupeKey:`lern-telemetrie:${X}`})}}catch(he){this.logger.debug({err:he},"v1147 Lern-Telemetrie fehlgeschlagen")}return{ok:!0}},"run")}),this.registriereJob({key:"vorausschau",beschreibung:"Vorausschau-Radar: Geburtstage und Termine der n\xE4chsten 7 Tage",takt:{art:"taeglich",um:"07:45"},bereich:"global",slot:!0,run:m(async()=>{try{let he=this.tryOwner();if(he&&this.database&&this.memoryRepo&&this.insightsRepo){let{VorausschauRadar:ne}=await Promise.resolve().then(()=>(bO(),kO)),{KnowledgeGraphRepository:ve}=await Promise.resolve().then(()=>(nt(),it));await new ne(new ve(this.database.getAdapter()),this.memoryRepo,this.insightsRepo,this.logger.child({component:"vorausschau"}),this.llmProvider).run(he)}else this.logger.warn("v1145 Vorausschau \xFCbersprungen \u2014 Owner/Repos nicht verf\xFCgbar")}catch(he){this.logger.warn({err:he},"v1145 Vorausschau-Radar failed")}return{ok:!0}},"run")}),this.registriereJob({key:"netzbetreiber-quartal",beschreibung:"Netzbetreiber-Recherche am 2. Tag jedes Quartals (sonst Leerlauf)",takt:{art:"taeglich",um:"04:00"},bereich:"global",run:m(async()=>{let he=new Date;if(process.env.ALFRED_GRID_KEY&&he.getDate()===2&&[0,3,6,9].includes(he.getMonth())){let ne=`${he.getFullYear()}-Q${Math.floor(he.getMonth()/3)+1}`;if(await this.claimDailySlot(`grid-recherche:${ne}`)){let ve=this.skillRegistry?.get("netzbetreiber");if(ve)try{let q=await ve.execute({action:"check_operators",limit:500},{userId:this.ownerMasterUserId??"",masterUserId:this.ownerMasterUserId??"",platform:"api",chatId:"grid-recherche",conversationId:"grid-recherche"});this.logger.info({ok:q.success,display:q.display?.slice(0,200)},"v1133 quartals-recherche netzbetreiber")}catch(q){this.logger.warn({err:q},"v1133 quartals-recherche failed")}}}return{ok:!0}},"run")})}}if(this.socialRepo&&this.socialSkillRef&&this.ownerMasterUserId){let{PublishingEngine:x}=await Promise.resolve().then(()=>(JE(),xO)),J=this.socialSkillRef,O=this.ownerMasterUserId,M={userId:O,masterUserId:O};if(this.publishingEngine=new x(this.socialRepo,async(P,Q)=>{let ue=await J.execute({action:"publish_now",item_id:P,...Q?.limitOverride?{limit_override:!0}:{}},M);return{success:ue.success,error:ue.error,display:ue.display,permanent:ue.data?.permanent===!0}},this.insightsRepo,this.notificationRouter,this.adapters,this.logger.child({component:"publishing-engine"}),{ownerUserId:O,chatId:this.config.security?.ownerUserId??"",platform:this.config.telegram?.enabled?"telegram":"api",dbAdapter:this.database?.getAdapter(),nodeId:this.config.cluster?.nodeId}),this.publishingEngine.start(),this.llmProvider){let{ContentStudio:P}=await Promise.resolve().then(()=>(qE(),DO)),{StoryDeduper:Q}=await Promise.resolve().then(()=>(PO(),MO)),ue=this.llmProvider,le=ue.supportsEmbeddings?.()?async W=>{let de=await ue.embed?.(W);return de?{embedding:de.embedding,model:de.model,dimensions:de.dimensions}:void 0}:void 0,ee=this.database?new Ji(this.database.getAdapter()):void 0,je=new Q(le,ee,this.llmProvider,this.logger.child({component:"story-dedup"}),O);this.contentStudio=new P(this.socialRepo,this.interestsRepo,this.insightsRepo,this.llmProvider,this.skillRegistry,this.skillSandbox,this.sourceProvisioner,this.logger.child({component:"content-studio"}),O,Dt.resolve(Dt.dirname(this.config.storage.path),"social-media"),je);let ie=this.contentStudio;J.setMediaDir(Dt.resolve(Dt.dirname(this.config.storage.path),"social-media")),J.setStudio(W=>ie.planFamilyFor(W)),J.setReplanner(W=>ie.replanChannel(W)),J.setInsightFn(async W=>{await this.insightsRepo?.upsertCandidate(O,{category:"social",title:W.title,body:W.body,confidence:.85,sourceData:{router:!0,urgency:"high"},dedupeKey:W.dedupeKey})}),J.setStoryPlanner((W,de,Oe)=>ie.planAdhocStory(W,de,Oe)),J.setOverlayRefresher(W=>ie.refreshOverlays(W)),J.setLibraryDeduper(()=>ie.dedupMediaLibrary()),J.setImageGenerator((W,de)=>ie.generateImageForItem(W,de)),ie.setVideoRenderer(async(W,de)=>{let Oe=await J.execute({action:"render_video",item_id:W,format:de},M);if(!Oe.success)throw new Error(Oe.error??"render_video fehlgeschlagen")});{let{SlideshowVideoRenderer:W}=await Promise.resolve().then(()=>(JO(),qO)),de=this.speechSynthesizerRef,Oe=new W(this.logger.child({component:"video-pipeline"}),{workDir:Dt.resolve(Dt.dirname(this.config.storage.path),"social-videos"),synthesize:de?(Fe,G)=>de.synthesize(Fe,O,G):void 0}),Xe=m(Fe=>{for(let G of["default","strong","fast","embeddings","local"]){let pe=this.config.llm[G];if(pe?.provider===Fe&&pe.apiKey)return pe.apiKey}},"llmKeyFor"),st=Dt.resolve(Dt.dirname(this.config.storage.path),"social-videos");J.setVideoTools({render:m(async(Fe,G,pe,ae)=>{let De=Fe.media.filter(Y=>Y.type==="image"&&!Y.pathOrUrl.startsWith("http")).map(Y=>Y.pathOrUrl);if(De.length===0)throw new Error("Keine lokalen Bilder am Item (http-URLs kann der Renderer nicht einlesen).");let we=Fe.body.split(/\n-{3,}\n/)[0]?.trim(),Ae;if(ae?.music&&typeof ae.music=="object")try{let{readdir:Y}=await import("node:fs/promises"),ce=Dt.resolve(Dt.dirname(this.config.storage.path),"reel-music"),me=(await Y(ce)).filter(Se=>/\.(mp3|m4a|aac|ogg|opus|wav|flac)$/i.test(Se)).sort();me.length>0&&(Ae=Dt.join(ce,me[Math.floor(Math.random()*me.length)]))}catch{}let Z=ae?.music&&typeof ae.music=="object"&&typeof ae.music.volume=="number"?ae.music.volume:void 0;return Oe.render({images:De,voiceoverText:we,format:pe,outBaseName:`${Fe.id.slice(0,8)}-${pe.replace(":","x")}`,...ae?.introImage?{introImage:ae.introImage}:{},...ae?.outroImage?{outroImage:ae.outroImage}:{},...Ae?{musicPath:Ae}:{},...Ae&&Z!==void 0?{musicVolume:Z}:{},...ae?.clips&&ae.clips.length>0?{clips:ae.clips}:{},...ae?.overlayImage?{overlayImage:ae.overlayImage}:{},...ae?.voiceId?{voiceId:ae.voiceId}:{}})},"render"),probe:m(Fe=>Oe.probeVideo(Fe),"probe"),analyze:m((Fe,G)=>Oe.analyzeHighlights(Fe,G),"analyze"),edit:m(Fe=>Oe.editVideo(Fe),"edit"),generateClip:m(async Fe=>{let{AiClipGenerator:G}=await Promise.resolve().then(()=>(eD(),QO)),ae=await new G(this.logger.child({component:"video-gen"}),{openai:Fe.secrets.OPENAI_API_KEY||Xe("openai"),runway:Fe.secrets.RUNWAY_API_SECRET,google:Fe.secrets.GOOGLE_API_KEY||Xe("google")}).generate(Fe.provider,{...Fe.imagePath?{imagePath:Fe.imagePath}:{},prompt:Fe.prompt,format:Fe.format,...Fe.model?{model:Fe.model}:{},workDir:st,outBaseName:`clip-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`});return{clipPath:ae.clipPath,durationSec:ae.durationSec}},"generateClip")})}setTimeout(()=>{J.resumeOrphanedReels(O).then(W=>{W>0&&this.logger.info({resumed:W},"v1115 verwaiste Auto-Reel-Renders nach Neustart wieder aufgenommen")}).catch(W=>this.logger.warn({err:W.message},"v1115 Auto-Reel-Wiederaufnahme fehlgeschlagen"))},9e4).unref();let he="",ne="",ve="",q="",X="";this.registriereJob({key:"content-studio-tick",beschreibung:"Content-Studio: News-Desk, Plan-Review, Kommentare, Analytics, Auth-Pr\xFCfung",takt:{art:"intervall",minuten:10},bereich:"global",timeoutMin:30,run:m(async()=>{let W=new Date,de=W.toISOString().slice(0,10),Oe=`${de}T${String(W.getHours()).padStart(2,"0")}`;if(X!==Oe){X=Oe;let Xe=0;if(await this.claimDailySlot(`social-newsdesk:${Oe}`))try{Xe=await ie.newsDesk(),Xe>0&&this.logger.info({items:Xe},"v994 news desk created breaking content")}catch(Fe){this.logger.warn({err:Fe},"v994 news desk failed")}if((W.getHours()%4===0||Xe>0)&&await this.claimDailySlot(`social-planreview:${Oe}`))try{await ie.planReview()}catch(Fe){this.logger.warn({err:Fe},"v995 plan review failed")}let st=m(async Fe=>{for(let G of Fe.byChannel){let pe=[];G.spamIgnored&&pe.push(`\u{1F9F9} ${G.spamIgnored} Spam-Kommentar(e) automatisch ausgeblendet.`),G.hassFlagged&&pe.push(`\u26A0\uFE0F ${G.hassFlagged} Kommentar(e) mit Beleidigung/Hetze ausgeblendet \u2014 auf der Plattform pr\xFCfen/l\xF6schen!`);for(let ae of G.suggestions??[])pe.push(`\u{1F4AC} Frage von ${ae.author??"anonym"}: \u201E${ae.text}"
|
|
8488
8488
|
\u2192 Vorschlag: \u201E${ae.draft}" \u2014 senden: reply_comment ${ae.id.slice(0,8)} (Text anpassbar) oder in der UI.`);await this.insightsRepo?.upsertCandidate(O,{category:"social",title:`Neue Kommentare auf ${G.channel}`,body:`${G.count} neue Kommentare eingesammelt.${pe.length?`
|
|
8489
8489
|
|