@madh-io/alfred-ai 0.14.6 → 0.14.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bundle/index.js +4 -4
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -1232,11 +1232,11 @@ Regeln:
1232
1232
  - Sprache: Deutsch (oder Sprache des Gespr\xE4chs)`,n}}});var fn,Va=T(()=>{"use strict";fn=class{static{m(this,"CalendarWatcher")}calendarProvider;notifRepo;adapters;defaultChatId;defaultPlatform;config;logger;activityLogger;timer=null;tickIntervalMs=6e4;minutesBefore;lastCleanup=0;constructor(e,t,s,r,n,o,i,a){this.calendarProvider=e,this.notifRepo=t,this.adapters=s,this.defaultChatId=r,this.defaultPlatform=n,this.config=o,this.logger=i,this.activityLogger=a,this.minutesBefore=o.minutesBefore??15}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info({minutesBefore:this.minutesBefore},"Calendar watcher started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Calendar watcher stopped")}async tick(){try{let e=Date.now();if(e-this.lastCleanup>36e5){let n=new Date(e-864e5).toISOString();this.notifRepo.cleanup(n),this.lastCleanup=e}let t=new Date,s=new Date(t.getTime()+this.minutesBefore*6e4),r=await this.calendarProvider.listEvents(t,s);for(let n of r)await this.processEvent(n)}catch(e){e instanceof Error&&(e.message.includes("Timeout")||e.message.includes("fetch failed")||e.message.includes("503")||e.message.includes("502")||e.message.includes("504"))?this.logger.warn({err:e},"Calendar watcher tick failed (transient)"):this.logger.error({err:e},"Calendar watcher tick failed")}}async processEvent(e){if(e.allDay||this.notifRepo.wasNotified(e.id,this.defaultChatId))return;let t=Date.now(),r=(e.start.getTime()-t)/6e4;if(r>this.minutesBefore||r<0)return;let n=[],o=Math.round(r),i=e.start.toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"});if(n.push(`\u{1F4C5} In ${o} Min: ${e.title}`),n.push(`Zeit: ${i} \u2013 ${e.end.toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"})}`),e.location&&n.push(`Ort: ${e.location}`),e.description){let c=e.description.replace(/<[^>]*>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&#\d+;/g,"").replace(/\s+/g," ").trim();c.length>0&&n.push(`
1233
1233
  ${c.slice(0,200)}`)}let a=this.adapters.get(this.defaultPlatform);if(a)try{await a.sendMessage(this.defaultChatId,n.join(`
1234
1234
  `)),this.notifRepo.markNotified(e.id,this.defaultChatId,this.defaultPlatform,e.start.toISOString()),this.logger.info({eventId:e.id,title:e.title},"Calendar vorlauf notification sent"),this.activityLogger?.logCalendarNotify({eventId:e.id,eventTitle:e.title,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(c){this.logger.error({err:c,eventId:e.id},"Failed to send calendar notification"),this.activityLogger?.logCalendarNotify({eventId:e.id,eventTitle:e.title,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:c instanceof Error?c.message:String(c)})}}}});var gn,Ya=T(()=>{"use strict";gn=class{static{m(this,"TodoWatcher")}todoRepo;notifRepo;adapters;defaultChatId;defaultPlatform;logger;activityLogger;timer=null;tickIntervalMs=6e4;minutesBefore;overdueCheck;lastOverdueCheck=0;constructor(e,t,s,r,n,o,i,a){this.todoRepo=e,this.notifRepo=t,this.adapters=s,this.defaultChatId=r,this.defaultPlatform=n,this.logger=i,this.activityLogger=a,this.minutesBefore=o.minutesBefore??30,this.overdueCheck=o.overdueCheck??!0}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info({minutesBefore:this.minutesBefore},"Todo watcher started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Todo watcher stopped")}async tick(){try{let e=new Date(Date.now()+this.minutesBefore*6e4),t=this.todoRepo.getDueInWindow(e.toISOString());for(let r of t)await this.notify(r.id,r.title,r.dueDate,r.list,r.priority,"upcoming");let s=Date.now();if(this.overdueCheck&&s-this.lastOverdueCheck>36e5){this.lastOverdueCheck=s;let r=this.todoRepo.getOverdue();for(let n of r)await this.notify(n.id,n.title,n.dueDate,n.list,n.priority,"overdue")}}catch(e){this.logger.error({err:e},"Todo watcher tick failed")}}async notify(e,t,s,r,n,o){let i=o==="overdue"?`todo:${o}:${e}:${new Date().toISOString().slice(0,10)}`:`todo:${o}:${e}`;if(this.notifRepo.wasNotified(i,this.defaultChatId))return;let c=new Date(s).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}),p=[`${o==="overdue"?"\u26A0\uFE0F":"\u2705"} **${o==="overdue"?"\xDCberf\xE4llig":"Bald f\xE4llig"}:** ${t}`,`F\xE4llig: ${c}`];r!=="default"&&p.push(`Liste: ${r}`),n!=="normal"&&p.push(`Priorit\xE4t: ${n}`);let h=this.adapters.get(this.defaultPlatform);if(!h)return;let g=o==="overdue"?new Date().toISOString():s;try{await h.sendMessage(this.defaultChatId,p.join(`
1235
- `)),this.notifRepo.markNotified(i,this.defaultChatId,this.defaultPlatform,g),this.logger.info({todoId:e,title:t,kind:o},"Todo reminder sent"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(f){this.logger.error({err:f,todoId:e},"Failed to send todo reminder"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:f instanceof Error?f.message:String(f)})}}}});var yn,Ja=T(()=>{"use strict";yn=class{static{m(this,"ActivityLogger")}repo;logger;constructor(e,t){this.repo=e,this.logger=t}logSkillExec(e){this.safe(()=>this.repo.log({eventType:"skill_exec",source:"user",userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.details}))}logWatchTrigger(e){this.safe(()=>this.repo.log({eventType:"watch_trigger",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.watchName,outcome:e.outcome,errorMessage:e.error,details:{value:e.value}}))}logWatchAction(e){this.safe(()=>this.repo.log({eventType:"watch_action",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{watchName:e.watchName}}))}logConfirmation(e){this.safe(()=>this.repo.log({eventType:"confirmation",source:e.source,sourceId:e.sourceId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{confirmationId:e.confirmationId,description:e.description}}))}logScheduledExec(e){this.safe(()=>this.repo.log({eventType:"scheduled_exec",source:"scheduled",sourceId:e.actionId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.actionName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.skillName?{skillName:e.skillName}:void 0}))}logBackgroundTask(e){this.safe(()=>this.repo.log({eventType:"background_task",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error}))}logCalendarNotify(e){this.safe(()=>this.repo.log({eventType:"calendar_notify",source:"system",sourceId:e.eventId,platform:e.platform,chatId:e.chatId,action:e.eventTitle,outcome:e.outcome,errorMessage:e.error}))}logWorkflowExec(e){this.safe(()=>this.repo.log({eventType:"workflow_exec",source:"workflow",sourceId:e.chainId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.chainName,outcome:e.outcome,errorMessage:e.error,details:{executionId:e.executionId,...e.details}}))}logAgentLifecycle(e){this.safe(()=>this.repo.log({eventType:"agent_lifecycle",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.event,outcome:"success",details:{skillName:e.skillName,...e.details}}))}logSkillHealth(e){this.safe(()=>this.repo.log({eventType:"skill_health",source:"system",action:e.skillName,outcome:e.outcome,details:e.details}))}safe(e){try{e()}catch(t){this.logger.warn({err:t},"Failed to write activity log entry")}}}});var Af,wn,Za=T(()=>{"use strict";Af=[{fails:20,durationMinutes:1440},{fails:10,durationMinutes:120},{fails:5,durationMinutes:30}],wn=class{static{m(this,"SkillHealthTracker")}healthRepo;logger;activityLogger;constructor(e,t,s){this.healthRepo=e,this.logger=t,this.activityLogger=s}isDisabled(e){try{return this.healthRepo.isDisabled(e)?this.healthRepo.getByName(e):void 0}catch{return}}recordSuccess(e){try{this.healthRepo.recordSuccess(e)}catch(t){this.logger.debug({err:t,skillName:e},"Failed to record skill success")}}recordFailure(e,t){try{let s=this.healthRepo.recordFailure(e,t);for(let r of Af)if(s.consecutiveFails>=r.fails&&!s.disabledUntil){let n=new Date(Date.now()+r.durationMinutes*6e4).toISOString();this.healthRepo.disable(e,n),this.logger.warn({skillName:e,consecutiveFails:s.consecutiveFails,disabledUntil:n},"Skill auto-disabled due to repeated failures"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"disabled",details:{consecutiveFails:s.consecutiveFails,disabledUntil:n,lastError:t}});break}}catch(s){this.logger.debug({err:s,skillName:e},"Failed to record skill failure")}}forceEnable(e){try{this.healthRepo.enable(e),this.logger.info({skillName:e},"Skill force-enabled by user"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"re-enabled",details:{reason:"force-enable"}})}catch(t){this.logger.warn({err:t,skillName:e},"Failed to force-enable skill")}}getDashboard(){try{return this.healthRepo.getAll()}catch{return[]}}checkReEnables(){try{let e=this.healthRepo.getAll(),t=new Date;for(let s of e)s.disabledUntil&&new Date(s.disabledUntil)<=t&&(this.healthRepo.enable(s.skillName),this.logger.info({skillName:s.skillName},"Skill auto-re-enabled after cooldown"),this.activityLogger?.logSkillHealth({skillName:s.skillName,outcome:"re-enabled",details:{reason:"cooldown-expired"}}))}catch(e){this.logger.warn({err:e},"Failed to check re-enables")}}}});var Tn,Qa=T(()=>{"use strict";So();Tn=class{static{m(this,"WorkflowRunner")}workflowRepo;skillRegistry;skillSandbox;logger;activityLogger;healthTracker;constructor(e,t,s,r,n,o){this.workflowRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.logger=r,this.activityLogger=n,this.healthTracker=o}async run(e,t,s){let r=this.workflowRepo.createExecution(e.id,e.steps.length),n=[],o=s??{};for(let i=0;i<e.steps.length;i++){let a=e.steps[i];if(this.healthTracker?.isDisabled(a.skillName)){let f=`Skill "${a.skillName}" is temporarily disabled`;if(a.onError==="skip"){n.push({skillName:a.skillName,success:!1,error:f});continue}return this.finishExecution(r.id,"failed",i,n,f),{executionId:r.id,status:"failed",stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:f}}let c=this.skillRegistry.get(a.skillName);if(!c){let f=`Skill "${a.skillName}" not found`;if(a.onError==="skip"){n.push({skillName:a.skillName,success:!1,error:f});continue}return this.finishExecution(r.id,"failed",i,n,f),{executionId:r.id,status:"failed",stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:f}}let d={prev:o,steps:n.map(f=>f.data)};s&&(d.trigger=s);let u=Wt(a.inputMapping,d),p=a.onError==="retry"?(a.maxRetries??1)+1:1,h,g=!1;for(let f=0;f<p;f++)try{let y=await this.skillSandbox.execute(c,u,t);if(y.success){o=y.data,n.push({skillName:a.skillName,success:!0,data:y.data}),this.healthTracker?.recordSuccess(a.skillName),g=!0;break}else h=y.error??"Unknown error",this.healthTracker?.recordFailure(a.skillName,h)}catch(y){h=y instanceof Error?y.message:String(y),this.healthTracker?.recordFailure(a.skillName,h)}if(!g){if(n.push({skillName:a.skillName,success:!1,error:h}),a.onError==="skip")continue;let f=i>0?"partial":"failed";return this.finishExecution(r.id,f,i,n,h),this.logWorkflow(e,r.id,f,i,h),{executionId:r.id,status:f,stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:h}}this.workflowRepo.updateExecution(r.id,{stepsCompleted:i+1,stepResults:JSON.stringify(n)})}return this.finishExecution(r.id,"completed",e.steps.length,n),this.logWorkflow(e,r.id,"completed",e.steps.length),{executionId:r.id,status:"completed",stepsCompleted:e.steps.length,totalSteps:e.steps.length,stepResults:n}}finishExecution(e,t,s,r,n){this.workflowRepo.updateExecution(e,{status:t,stepsCompleted:s,stepResults:JSON.stringify(r),error:n,completedAt:new Date().toISOString()})}logWorkflow(e,t,s,r,n){this.activityLogger?.logWorkflowExec({chainId:e.id,chainName:e.name,executionId:t,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:s==="completed"?"success":"error",error:n,details:{stepsCompleted:r,totalSteps:e.steps.length}})}}});import Rf from"node:crypto";var xf,Cf,_n,ec=T(()=>{"use strict";mt();xf=[7,12,18],Cf=1024,_n=class{static{m(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;tickTimer;lastRunHour=-1;enabled;schedule;tier;deduplicationHours;constructor(e,t,s,r,n,o,i,a,c,d,u,p,h,g,f,y,k){this.calendarProvider=e,this.todoRepo=t,this.watchRepo=s,this.memoryRepo=r,this.activityRepo=n,this.skillHealthRepo=o,this.notifRepo=i,this.skillRegistry=a,this.skillSandbox=c,this.llm=d,this.adapters=u,this.userRepo=p,this.defaultChatId=h,this.defaultPlatform=g,this.logger=y,this.activityLogger=k,this.enabled=f?.enabled!==!1,this.schedule=f?.schedule??"morning_noon_evening",this.tier=f?.tier??"fast",this.deduplicationHours=f?.deduplicationHours??12}start(){if(!this.enabled){this.logger.info("Reasoning engine disabled");return}this.tickTimer=setInterval(()=>this.tick(),6e4),this.logger.info({schedule:this.schedule,tier:this.tier},"Reasoning engine started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0)}shouldRun(){let e=new Date,t=e.getHours(),s=e.getMinutes();switch(this.schedule){case"morning_noon_evening":return!!(xf.includes(t)&&s===0&&this.lastRunHour!==t);case"hourly":return s===0&&this.lastRunHour!==t;case"half_hourly":return(s<=1||s>=30&&s<=31)&&this.lastRunHour!==t*100+(s<2?0:30);default:return!1}}markRun(){let e=new Date;this.schedule==="half_hourly"?this.lastRunHour=e.getHours()*100+e.getMinutes():this.lastRunHour=e.getHours()}async tick(){if(this.shouldRun()){this.markRun();try{this.logger.info("Reasoning pass starting");let e=Date.now(),t=await this.collectContext(),s=this.buildPrompt(t),n=(await this.llm.complete({messages:[{role:"user",content:s}],maxTokens:Cf,tier:this.tier})).content.trim(),o=Date.now()-e;if(!n||n==="KEINE_INSIGHTS"||n.length<10){this.logger.info({durationMs:o},"Reasoning pass: no insights"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o});return}let i=this.parseInsights(n),a=i.filter(u=>!this.wasRecentlySent(u));if(a.length===0){this.logger.info({durationMs:o,total:i.length},"Reasoning pass: all insights deduplicated");return}let c=`\u{1F4A1} **Alfred Insights**
1235
+ `)),this.notifRepo.markNotified(i,this.defaultChatId,this.defaultPlatform,g),this.logger.info({todoId:e,title:t,kind:o},"Todo reminder sent"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(f){this.logger.error({err:f,todoId:e},"Failed to send todo reminder"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:f instanceof Error?f.message:String(f)})}}}});var yn,Ja=T(()=>{"use strict";yn=class{static{m(this,"ActivityLogger")}repo;logger;constructor(e,t){this.repo=e,this.logger=t}logSkillExec(e){this.safe(()=>this.repo.log({eventType:"skill_exec",source:"user",userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.details}))}logWatchTrigger(e){this.safe(()=>this.repo.log({eventType:"watch_trigger",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.watchName,outcome:e.outcome,errorMessage:e.error,details:{value:e.value}}))}logWatchAction(e){this.safe(()=>this.repo.log({eventType:"watch_action",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{watchName:e.watchName}}))}logConfirmation(e){this.safe(()=>this.repo.log({eventType:"confirmation",source:e.source,sourceId:e.sourceId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{confirmationId:e.confirmationId,description:e.description}}))}logScheduledExec(e){this.safe(()=>this.repo.log({eventType:"scheduled_exec",source:"scheduled",sourceId:e.actionId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.actionName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.skillName?{skillName:e.skillName}:void 0}))}logBackgroundTask(e){this.safe(()=>this.repo.log({eventType:"background_task",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error}))}logCalendarNotify(e){this.safe(()=>this.repo.log({eventType:"calendar_notify",source:"system",sourceId:e.eventId,platform:e.platform,chatId:e.chatId,action:e.eventTitle,outcome:e.outcome,errorMessage:e.error}))}logWorkflowExec(e){this.safe(()=>this.repo.log({eventType:"workflow_exec",source:"workflow",sourceId:e.chainId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.chainName,outcome:e.outcome,errorMessage:e.error,details:{executionId:e.executionId,...e.details}}))}logAgentLifecycle(e){this.safe(()=>this.repo.log({eventType:"agent_lifecycle",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.event,outcome:"success",details:{skillName:e.skillName,...e.details}}))}logSkillHealth(e){this.safe(()=>this.repo.log({eventType:"skill_health",source:"system",action:e.skillName,outcome:e.outcome,details:e.details}))}safe(e){try{e()}catch(t){this.logger.warn({err:t},"Failed to write activity log entry")}}}});var Af,wn,Za=T(()=>{"use strict";Af=[{fails:20,durationMinutes:1440},{fails:10,durationMinutes:120},{fails:5,durationMinutes:30}],wn=class{static{m(this,"SkillHealthTracker")}healthRepo;logger;activityLogger;constructor(e,t,s){this.healthRepo=e,this.logger=t,this.activityLogger=s}isDisabled(e){try{return this.healthRepo.isDisabled(e)?this.healthRepo.getByName(e):void 0}catch{return}}recordSuccess(e){try{this.healthRepo.recordSuccess(e)}catch(t){this.logger.debug({err:t,skillName:e},"Failed to record skill success")}}recordFailure(e,t){try{let s=this.healthRepo.recordFailure(e,t);for(let r of Af)if(s.consecutiveFails>=r.fails&&!s.disabledUntil){let n=new Date(Date.now()+r.durationMinutes*6e4).toISOString();this.healthRepo.disable(e,n),this.logger.warn({skillName:e,consecutiveFails:s.consecutiveFails,disabledUntil:n},"Skill auto-disabled due to repeated failures"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"disabled",details:{consecutiveFails:s.consecutiveFails,disabledUntil:n,lastError:t}});break}}catch(s){this.logger.debug({err:s,skillName:e},"Failed to record skill failure")}}forceEnable(e){try{this.healthRepo.enable(e),this.logger.info({skillName:e},"Skill force-enabled by user"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"re-enabled",details:{reason:"force-enable"}})}catch(t){this.logger.warn({err:t,skillName:e},"Failed to force-enable skill")}}getDashboard(){try{return this.healthRepo.getAll()}catch{return[]}}checkReEnables(){try{let e=this.healthRepo.getAll(),t=new Date;for(let s of e)s.disabledUntil&&new Date(s.disabledUntil)<=t&&(this.healthRepo.enable(s.skillName),this.logger.info({skillName:s.skillName},"Skill auto-re-enabled after cooldown"),this.activityLogger?.logSkillHealth({skillName:s.skillName,outcome:"re-enabled",details:{reason:"cooldown-expired"}}))}catch(e){this.logger.warn({err:e},"Failed to check re-enables")}}}});var Tn,Qa=T(()=>{"use strict";So();Tn=class{static{m(this,"WorkflowRunner")}workflowRepo;skillRegistry;skillSandbox;logger;activityLogger;healthTracker;constructor(e,t,s,r,n,o){this.workflowRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.logger=r,this.activityLogger=n,this.healthTracker=o}async run(e,t,s){let r=this.workflowRepo.createExecution(e.id,e.steps.length),n=[],o=s??{};for(let i=0;i<e.steps.length;i++){let a=e.steps[i];if(this.healthTracker?.isDisabled(a.skillName)){let f=`Skill "${a.skillName}" is temporarily disabled`;if(a.onError==="skip"){n.push({skillName:a.skillName,success:!1,error:f});continue}return this.finishExecution(r.id,"failed",i,n,f),{executionId:r.id,status:"failed",stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:f}}let c=this.skillRegistry.get(a.skillName);if(!c){let f=`Skill "${a.skillName}" not found`;if(a.onError==="skip"){n.push({skillName:a.skillName,success:!1,error:f});continue}return this.finishExecution(r.id,"failed",i,n,f),{executionId:r.id,status:"failed",stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:f}}let d={prev:o,steps:n.map(f=>f.data)};s&&(d.trigger=s);let u=Wt(a.inputMapping,d),p=a.onError==="retry"?(a.maxRetries??1)+1:1,h,g=!1;for(let f=0;f<p;f++)try{let y=await this.skillSandbox.execute(c,u,t);if(y.success){o=y.data,n.push({skillName:a.skillName,success:!0,data:y.data}),this.healthTracker?.recordSuccess(a.skillName),g=!0;break}else h=y.error??"Unknown error",this.healthTracker?.recordFailure(a.skillName,h)}catch(y){h=y instanceof Error?y.message:String(y),this.healthTracker?.recordFailure(a.skillName,h)}if(!g){if(n.push({skillName:a.skillName,success:!1,error:h}),a.onError==="skip")continue;let f=i>0?"partial":"failed";return this.finishExecution(r.id,f,i,n,h),this.logWorkflow(e,r.id,f,i,h),{executionId:r.id,status:f,stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:h}}this.workflowRepo.updateExecution(r.id,{stepsCompleted:i+1,stepResults:JSON.stringify(n)})}return this.finishExecution(r.id,"completed",e.steps.length,n),this.logWorkflow(e,r.id,"completed",e.steps.length),{executionId:r.id,status:"completed",stepsCompleted:e.steps.length,totalSteps:e.steps.length,stepResults:n}}finishExecution(e,t,s,r,n){this.workflowRepo.updateExecution(e,{status:t,stepsCompleted:s,stepResults:JSON.stringify(r),error:n,completedAt:new Date().toISOString()})}logWorkflow(e,t,s,r,n){this.activityLogger?.logWorkflowExec({chainId:e.id,chainName:e.name,executionId:t,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:s==="completed"?"success":"error",error:n,details:{stepsCompleted:r,totalSteps:e.steps.length}})}}});import Rf from"node:crypto";var xf,Cf,_n,ec=T(()=>{"use strict";mt();xf=[7,12,18],Cf=1024,_n=class{static{m(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;defaultLocation;tickTimer;lastRunHour=-1;enabled;schedule;tier;deduplicationHours;constructor(e,t,s,r,n,o,i,a,c,d,u,p,h,g,f,y,k,S){this.calendarProvider=e,this.todoRepo=t,this.watchRepo=s,this.memoryRepo=r,this.activityRepo=n,this.skillHealthRepo=o,this.notifRepo=i,this.skillRegistry=a,this.skillSandbox=c,this.llm=d,this.adapters=u,this.userRepo=p,this.defaultChatId=h,this.defaultPlatform=g,this.logger=y,this.activityLogger=k,this.defaultLocation=S,this.enabled=f?.enabled!==!1,this.schedule=f?.schedule??"morning_noon_evening",this.tier=f?.tier??"fast",this.deduplicationHours=f?.deduplicationHours??12}start(){if(!this.enabled){this.logger.info("Reasoning engine disabled");return}this.tickTimer=setInterval(()=>this.tick(),6e4),this.logger.info({schedule:this.schedule,tier:this.tier},"Reasoning engine started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0)}shouldRun(){let e=new Date,t=e.getHours(),s=e.getMinutes();switch(this.schedule){case"morning_noon_evening":return!!(xf.includes(t)&&s===0&&this.lastRunHour!==t);case"hourly":return s===0&&this.lastRunHour!==t;case"half_hourly":return(s<=1||s>=30&&s<=31)&&this.lastRunHour!==t*100+(s<2?0:30);default:return!1}}markRun(){let e=new Date;this.schedule==="half_hourly"?this.lastRunHour=e.getHours()*100+e.getMinutes():this.lastRunHour=e.getHours()}async tick(){if(this.shouldRun()){this.markRun();try{this.logger.info("Reasoning pass starting");let e=Date.now(),t=await this.collectContext(),s=this.buildPrompt(t),n=(await this.llm.complete({messages:[{role:"user",content:s}],maxTokens:Cf,tier:this.tier})).content.trim(),o=Date.now()-e;if(!n||n==="KEINE_INSIGHTS"||n.length<10){this.logger.info({durationMs:o},"Reasoning pass: no insights"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o});return}let i=this.parseInsights(n),a=i.filter(u=>!this.wasRecentlySent(u));if(a.length===0){this.logger.info({durationMs:o,total:i.length},"Reasoning pass: all insights deduplicated");return}let c=`\u{1F4A1} **Alfred Insights**
1236
1236
 
1237
1237
  ${a.join(`
1238
1238
 
1239
- `)}`,d=this.adapters.get(this.defaultPlatform);if(d){await d.sendMessage(this.defaultChatId,c);for(let u of a)this.markSent(u);this.logger.info({durationMs:o,insights:a.length},"Reasoning pass: insights sent")}this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o})}catch(e){this.logger.error({err:e},"Reasoning pass failed"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"error",error:e instanceof Error?e.message:String(e)})}}}async collectContext(){let e=new Date,t=e.toLocaleString("de-AT",{weekday:"long",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit"}),[s,r,n]=await Promise.all([this.fetchCalendar(e),this.fetchSkillData("weather",{}),this.fetchSkillData("energy_price",{action:"current"})]),o=this.fetchTodos(),i=this.fetchWatches(),a=this.fetchMemories(),c=this.fetchActivity(),d=this.fetchSkillHealth();return{dateTime:t,events:s,todos:o,watches:i,memories:a,activity:c,weather:r,energy:n,skillHealth:d}}async fetchCalendar(e){if(!this.calendarProvider)return"(Kalender nicht konfiguriert)";try{let t=e,s=new Date(e.getTime()+1440*60*1e3),r=await this.calendarProvider.listEvents(t,s);return r.length===0?"Keine Termine in den n\xE4chsten 24h.":r.map(n=>{let o=n.start instanceof Date?n.start.toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}):String(n.start),i=n.location?` (${n.location})`:"";return`- ${o}: ${n.title??"Termin"}${i}`}).join(`
1239
+ `)}`,d=this.adapters.get(this.defaultPlatform);if(d){await d.sendMessage(this.defaultChatId,c);for(let u of a)this.markSent(u);this.logger.info({durationMs:o,insights:a.length},"Reasoning pass: insights sent")}this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o})}catch(e){this.logger.error({err:e},"Reasoning pass failed"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"error",error:e instanceof Error?e.message:String(e)})}}}async collectContext(){let e=new Date,t=e.toLocaleString("de-AT",{weekday:"long",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit"}),[s,r,n]=await Promise.all([this.fetchCalendar(e),this.fetchSkillData("weather",{action:"current",...this.defaultLocation?{location:this.defaultLocation}:{}}),this.fetchSkillData("energy_price",{action:"current"})]),o=this.fetchTodos(),i=this.fetchWatches(),a=this.fetchMemories(),c=this.fetchActivity(),d=this.fetchSkillHealth();return{dateTime:t,events:s,todos:o,watches:i,memories:a,activity:c,weather:r,energy:n,skillHealth:d}}async fetchCalendar(e){if(!this.calendarProvider)return"(Kalender nicht konfiguriert)";try{let t=e,s=new Date(e.getTime()+1440*60*1e3),r=await this.calendarProvider.listEvents(t,s);return r.length===0?"Keine Termine in den n\xE4chsten 24h.":r.map(n=>{let o=n.start instanceof Date?n.start.toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}):String(n.start),i=n.location?` (${n.location})`:"";return`- ${o}: ${n.title??"Termin"}${i}`}).join(`
1240
1240
  `)}catch(t){return this.logger.warn({err:t},"Reasoning: calendar fetch failed"),"(Kalender-Abfrage fehlgeschlagen)"}}async fetchSkillData(e,t){let s=this.skillRegistry.get(e);if(!s)return`(${e} nicht verf\xFCgbar)`;try{let{context:r}=$e(this.userRepo,{userId:this.defaultChatId,platform:this.defaultPlatform,chatId:this.defaultChatId,chatType:"dm"}),n=await this.skillSandbox.execute(s,t,r);return n.success?n.display??JSON.stringify(n.data):`(${e}: ${n.error})`}catch(r){return this.logger.warn({err:r,skillName:e},"Reasoning: skill fetch failed"),`(${e}-Abfrage fehlgeschlagen)`}}fetchTodos(){try{let e=this.todoRepo.getOverdue(),t=new Date(Date.now()+1440*60*1e3).toISOString(),s=this.todoRepo.getDueInWindow(t),r=this.todoRepo.list(this.defaultChatId),n=[];if(e.length>0){n.push(`\xDCberf\xE4llig (${e.length}):`);for(let o of e.slice(0,10))n.push(` - [${o.priority}] ${o.title} (f\xE4llig: ${o.dueDate})`)}if(s.length>0){n.push(`Bald f\xE4llig (${s.length}):`);for(let o of s.slice(0,10))n.push(` - [${o.priority}] ${o.title} (f\xE4llig: ${o.dueDate})`)}return r.length>0&&n.push(`Gesamt offene Todos: ${r.length}`),n.length>0?n.join(`
1241
1241
  `):"Keine offenen Todos."}catch(e){return this.logger.warn({err:e},"Reasoning: todo fetch failed"),"(Todo-Abfrage fehlgeschlagen)"}}fetchWatches(){try{let e=this.watchRepo.getEnabled();return e.length===0?"Keine aktiven Watches.":e.map(t=>{let s=t.lastValue?(()=>{try{let n=JSON.parse(t.lastValue);return typeof n=="object"?JSON.stringify(n).slice(0,200):String(n)}catch{return t.lastValue.slice(0,200)}})():"noch kein Ergebnis",r=t.lastTriggeredAt?`letzter Alert: ${new Date(t.lastTriggeredAt).toLocaleString("de-AT")}`:"noch nie ausgel\xF6st";return`- "${t.name}" (${t.skillName}, alle ${t.intervalMinutes} Min) \u2192 ${r}
1242
1242
  Letzter Wert: ${s}`}).join(`
@@ -1300,7 +1300,7 @@ Alfred: ${t}
1300
1300
  `),this.prompt(),r}async editMessage(e,t,s,r){rc.clearLine(process.stdout,0),rc.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import Pf from"node:http";import No from"node:crypto";var Bu,Do,Hu=T(()=>{"use strict";ot();Bu=1048576,Do=class extends ge{static{m(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;webhooks=new Map;constructor(e,t,s){if(super(),this.port=e,this.host=t,this.apiToken=s?.apiToken,this.corsOrigin=s?.corsOrigin??"http://localhost:3420",this.healthCheckFn=s?.healthCheck,this.metricsFn=s?.metricsCallback,s?.webhooks)for(let r of s.webhooks)this.webhooks.set(r.name,r)}addWebhook(e){this.webhooks.set(e.name,e)}async connect(){this.status="connecting",this.server=Pf.createServer((e,t)=>{this.handleRequest(e,t)}),await new Promise((e,t)=>{this.server.listen(this.port,this.host,()=>{e()}),this.server.once("error",t)}),this.status="connected",this.emit("connected")}async disconnect(){for(let[e,t]of this.streams)this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e);this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),r}async editMessage(e,t,s,r){let n=this.streams.get(e);n&&this.writeSseEvent(n,"status",{type:"status",text:s})}async deleteMessage(e,t){}async sendPhoto(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,r){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:r}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"voice",data:t.toString("base64"),caption:s}),`api-voice-${++this.messageCounter}`}endStream(e){let t=this.streams.get(e);t&&(this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e))}handleRequest(e,t){if(t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Access-Control-Allow-Origin",this.corsOrigin),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.method==="OPTIONS"){t.writeHead(204),t.end();return}let s=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`);if(s.pathname==="/api/health"&&e.method==="GET")this.handleHealth(t);else if(s.pathname==="/api/metrics"&&e.method==="GET")this.handleMetrics(t);else if(s.pathname==="/api/message"&&e.method==="POST")this.handleMessage(e,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let r=s.pathname.slice(13);this.handleWebhook(e,t,r)}else t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}))}checkAuth(e,t){if(!this.apiToken)return!0;let s=e.headers.authorization,r=`Bearer ${this.apiToken}`;return!s||s.length!==r.length||!No.timingSafeEqual(Buffer.from(s),Buffer.from(r))?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleHealth(e){let t=this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",r=s==="ok"?200:503;e.writeHead(r,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(this.metricsFn())):this.handleHealth(e)}handleMessage(e,t){if(!this.checkAuth(e,t))return;let s="",r=0,n=!1;e.on("data",o=>{if(!n){if(r+=o.length,r>Bu){n=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}s+=o.toString()}}),e.on("end",()=>{if(!n)try{let o=JSON.parse(s),i=o.text;if(!i||typeof i!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:'Missing or invalid "text" field'}));return}let a=o.chatId??`api-chat-${No.randomUUID()}`,c=o.userId??"api-user",d=this.streams.get(a);d&&(this.writeSseEvent(d,"done",{type:"done"}),d.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this.streams.set(a,t),e.on("close",()=>{this.streams.delete(a)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:a,chatType:"dm",userId:c,userName:c,displayName:"API User",text:i,timestamp:new Date};this.emit("message",u)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON body"}))}})}handleWebhook(e,t,s){let r=this.webhooks.get(s);if(!r){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`Webhook "${s}" not found`}));return}let n="",o=0,i=!1;e.on("data",a=>{if(!i){if(o+=a.length,o>Bu){i=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}n+=a.toString()}}),e.on("end",async()=>{if(i)return;let a=e.headers["x-webhook-signature"];if(!a){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing X-Webhook-Signature header"}));return}let c=No.createHmac("sha256",r.secret).update(n).digest(),d=Buffer.from(a,"hex");if(d.length!==c.length||!No.timingSafeEqual(d,c)){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid signature"}));return}try{let u=JSON.parse(n);await r.callback(u),t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({ok:!0}))}catch(u){t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:u instanceof Error?u.message:"Internal error"}))}})}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
1301
1301
  data: ${JSON.stringify(s)}
1302
1302
 
1303
- `)}}});var pt={};he(pt,{CLIAdapter:()=>Lo,DiscordAdapter:()=>Ao,HttpAdapter:()=>Do,MatrixAdapter:()=>Ro,MessagingAdapter:()=>ge,SignalAdapter:()=>Co,TelegramAdapter:()=>$o,WhatsAppAdapter:()=>xo});var ht=T(()=>{"use strict";ot();Mu();Ou();Pu();Uu();Fu();ju();Hu()});import kn from"node:fs";import Mo from"node:path";import Uf from"js-yaml";var zt,Wu=T(()=>{"use strict";bi();Ii();tt();ji();qn();se();Ia();Ra();xa();Ca();La();Na();Da();Ma();Oa();Pa();Ua();Fa();ja();Nu();Ha();Ga();Xa();Ka();Va();Ya();Ja();Za();Qa();ec();zt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new sn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=tr("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new At(this.config.storage.path);let e=this.database.getDb(),t=new rr(e),s=new nr(e);this.userRepo=s;let r=new Rt(e);this.auditRepo=r;let n=new or(e);this.memoryRepo=n;let o=new ir(e),i=new ar(e),a=new cr(e),c=new lr(e),d=new dr(e),u=new ur(e);this.scheduledActionRepo=u;let p=new Ct(e);this.activityRepo=p;let h=new yn(p,this.logger.child({component:"activity"})),g=new wr(e),f=new wn(g,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=f,this.logger.info("Storage initialized");let y=new Rr,k=this.loadSecurityRules();y.loadRules(k);let S=new xr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:k.length},"Security engine initialized");let b=Ui(this.config.llm,this.logger.child({component:"llm"}));await b.initialize(),this.llmProvider=b;let C=new yr(e);this.usageRepo=C,b.setPersist((v,M,V,Y,ye,me)=>{C.record(v,M,V,Y,ye,me)});let D=new rn(b,a,this.logger.child({component:"embeddings"})),P=this.config.activeLearning?.enabled!==!1,Q,ae;P&&(Q=new mn({llm:b,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:D,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),ae=new pn(n,this.logger.child({component:"memory-retriever"}),D),this.logger.info("Active learning & memory retriever initialized"));let j=new gr(e);this.summaryRepo=j;let z=new hn(b,j,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let re=new Qt(this.logger.child({component:"sandbox"})),N=this.skillRegistry=new Zt;N.register(new es),N.register(new ts),N.register(new ss(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),N.register(new rs(o)),N.register(new ns(i));let ie=new pr(e);if(N.register(new Es(ie)),N.register(new os),N.register(new is),N.register(new as(n,D)),N.register(new cs(b,N,re,S)),this.config.email?.accounts?.length){let v=new Map;for(let V of this.config.email.accounts)try{V.provider==="microsoft"&&!V.microsoft?.clientId&&this.config.calendar?.microsoft&&(V.microsoft={...this.config.calendar.microsoft});let Y=await Cr(V);v.set(V.name,Y),this.logger.info({account:V.name,provider:V.provider??"imap-smtp"},"Email account initialized")}catch(Y){this.logger.warn({err:Y,account:V.name},"Email account initialization failed, skipping")}let M=v.size>0?new dt(v):new dt;M.setLLM(b),N.register(M)}else{let v=new dt;v.setLLM(b),N.register(v)}N.register(new ls),N.register(new ds);let ce=new $s;ce.setReloadCallback(v=>this.reloadService(v)),N.register(ce),N.register(new ms),N.register(new ps),N.register(new hs),N.register(new fs(s)),N.register(new gs(s,c,this.adapters,(v,M)=>t.findByPlatformAndUser(v,M)));let J=new ys(d);N.register(J),N.register(new ws(u));let B=new mr(e),ue=new nn(B,D,this.logger.child({component:"documents"}));N.register(new Ts(B,ue,D));let Xe,ne;if(this.config.calendar)try{ne=await Dr(this.config.calendar),Xe=new Mt(ne),N.register(Xe),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(v){this.logger.warn({err:v},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Xe,ne&&this.config.calendar?.vorlauf?.enabled){let v=new xt(e),M=this.config.security?.ownerUserId;M&&(this.calendarWatcher=new fn(ne,v,this.adapters,M,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let v=this.config.security?.ownerUserId;if(v){let M=new xt(e);this.todoWatcher=new gn(ie,M,this.adapters,v,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:v}=await Promise.resolve().then(()=>(se(),oe));this.mcpManager=new v(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let M of this.mcpManager.getSkills())N.register(M);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},b)),this.logger.info({agents:this.config.codeAgents.agents.map(M=>M.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:v,createContactsProvider:M}=await Promise.resolve().then(()=>(se(),oe)),V=await M(this.config.contacts);N.register(new v(V)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(v){this.logger.warn({err:v},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant,proxmoxBackup:this.config.proxmoxBackup})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(N,this.config,n)),this.logger.info("Briefing skill registered")}N.register(new Rs(n)),this.logger.info("Feed reader skill registered"),this.logger.info({skills:N.getAll().map(v=>v.metadata.name)},"Skills registered");let be;if(this.config.speech?.apiKey&&(be=new Zr(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let v=new Qr(this.config.speech,this.logger.child({component:"tts"}));N.register(new _s(v)),this.logger.info("Text-to-speech skill registered")}let de=this.detectImageGenProvider();if(de){let v=new en(de,this.logger.child({component:"image-gen"}));N.register(new ks(v)),this.logger.info({provider:de.provider},"Image generation skill registered")}try{let v=new tn(this.logger.child({component:"transit"}));N.register(new Ss(v)),this.logger.info("Public transit skill registered")}catch(v){this.logger.warn({err:v},"Failed to register transit skill")}let Me=new Vr(t),Ye=Mo.resolve(Mo.dirname(this.config.storage.path),"inbox");this.pipeline=new Yr({llm:b,conversationManager:Me,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:N,skillSandbox:re,securityManager:S,memoryRepo:n,speechTranscriber:be,inboxPath:Ye,embeddingService:D,activeLearning:Q,memoryRetriever:ae,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:ue,conversationSummarizer:z}),this.reminderScheduler=new Jr(o,async(v,M,V)=>{let Y=this.adapters.get(v);Y?await Y.sendMessage(M,V):this.logger.warn({platform:v,chatId:M},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(v=>s.getMasterUserId(v),"getMasterUserId"),getLinkedUsers:m(v=>s.getLinkedUsers(v),"getLinkedUsers"),findConversation:m((v,M)=>t.findByPlatformAndUser(v,M),"findConversation")}),this.backgroundTaskRunner=new on(N,re,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,f);let Ke=new an(N,re,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ke),J.setPersistentRunner(Ke),this.proactiveScheduler=new cn(u,N,re,b,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Me,h);let Je=new hr(e);this.watchRepo=Je,N.register(new Is(Je,N));let Ne=new fr(e);this.confirmationQueue=new dn(Ne,N,re,this.adapters,this.logger.child({component:"confirmation-queue"}),h),this.watchEngine=new vo(Je,N,re,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,f,b);let gt=new Tr(e),yt=new As(gt);N.register(yt);let at=new Tn(gt,N,re,this.logger.child({component:"workflow-runner"}),h,f);yt.setRunner(at);{let v=this.config.security?.ownerUserId;if(v&&this.config.reasoning?.enabled!==!1){let M=new xt(e);this.reasoningEngine=new _n(ne,ie,Je,n,p,g,M,N,re,b,this.adapters,s,v,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(f),await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("telegram",new t(e.telegram.token)),this.logger.info("Telegram adapter registered")}if(e.discord?.enabled&&e.discord.token){let{DiscordAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("discord",new t(e.discord.token)),this.logger.info("Discord adapter registered")}if(e.whatsapp?.enabled){let{WhatsAppAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("whatsapp",new t(e.whatsapp.dataPath)),this.logger.info("WhatsApp adapter registered")}if(e.matrix?.enabled&&e.matrix.accessToken){let{MatrixAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("matrix",new t(e.matrix.homeserverUrl,e.matrix.accessToken,e.matrix.userId)),this.logger.info("Matrix adapter registered")}if(e.signal?.enabled&&e.signal.phoneNumber){let{SignalAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("signal",new t(e.signal.apiUrl,e.signal.phoneNumber)),this.logger.info("Signal adapter registered")}if(e.api?.enabled!==!1){let{HttpAdapter:t}=await Promise.resolve().then(()=>(ht(),pt)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>{let n;try{let o=this.config.storage.path,i=kn.statSync(o);n={path:o,sizeBytes:i.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([o,i])=>[o,i.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:this.watchRepo?.countEnabled()??0,schedulersActive:this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback")})),this.logger.info({port:s,host:r},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:m(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let o=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,o)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:this.auditRepo?.cleanup(90)??0,summaries:this.summaryRepo?.cleanup(180)??0,activity:this.activityRepo?.cleanup(90)??0,usage:this.usageRepo?.cleanup(365)??0,expiredMemories:this.memoryRepo?.cleanupExpired()??0};(e.audit||e.summaries||e.activity||e.usage)&&this.logger.info(e,"Startup DB cleanup completed")}catch(e){this.logger.warn({err:e},"Startup DB cleanup failed")}this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.adapters.size===0&&this.logger.warn("No messaging adapters enabled. Configure at least one platform."),this.logger.info(`Alfred is running with ${this.adapters.size} adapter(s)`)}async startWithCLI(){this.adapters.clear();let{CLIAdapter:e}=await Promise.resolve().then(()=>(ht(),pt)),t=new e;this.adapters.set("cli",t),t.on("disconnected",()=>{this.stop().then(()=>process.exit(0))}),await this.start()}async stop(){this.logger.info("Stopping Alfred..."),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(r=>setTimeout(r,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(r){this.logger.error({platform:t,err:r},"Failed to disconnect adapter")}try{this.database&&(this.database.getDb().pragma("wal_checkpoint(TRUNCATE)"),this.database.close())}catch{}this.logger.info("Alfred stopped")}async reloadService(e){try{ki();let t=new pe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(se(),oe)),n=await r(t.contacts);this.skillRegistry.register(new s(n)),this.config.contacts=t.contacts,this.logger.info({provider:t.contacts.provider},"Contacts skill hot-reloaded")}if(e==="docker"&&t.docker){let{DockerSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),o=this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${o.totalCostUsd}`),e.push("# HELP alfred_llm_today_calls Total LLM calls today (persisted)"),e.push("# TYPE alfred_llm_today_calls gauge"),e.push(`alfred_llm_today_calls ${o.totalCalls}`)}return e.push(""),e.join(`
1303
+ `)}}});var pt={};he(pt,{CLIAdapter:()=>Lo,DiscordAdapter:()=>Ao,HttpAdapter:()=>Do,MatrixAdapter:()=>Ro,MessagingAdapter:()=>ge,SignalAdapter:()=>Co,TelegramAdapter:()=>$o,WhatsAppAdapter:()=>xo});var ht=T(()=>{"use strict";ot();Mu();Ou();Pu();Uu();Fu();ju();Hu()});import kn from"node:fs";import Mo from"node:path";import Uf from"js-yaml";var zt,Wu=T(()=>{"use strict";bi();Ii();tt();ji();qn();se();Ia();Ra();xa();Ca();La();Na();Da();Ma();Oa();Pa();Ua();Fa();ja();Nu();Ha();Ga();Xa();Ka();Va();Ya();Ja();Za();Qa();ec();zt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new sn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=tr("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new At(this.config.storage.path);let e=this.database.getDb(),t=new rr(e),s=new nr(e);this.userRepo=s;let r=new Rt(e);this.auditRepo=r;let n=new or(e);this.memoryRepo=n;let o=new ir(e),i=new ar(e),a=new cr(e),c=new lr(e),d=new dr(e),u=new ur(e);this.scheduledActionRepo=u;let p=new Ct(e);this.activityRepo=p;let h=new yn(p,this.logger.child({component:"activity"})),g=new wr(e),f=new wn(g,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=f,this.logger.info("Storage initialized");let y=new Rr,k=this.loadSecurityRules();y.loadRules(k);let S=new xr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:k.length},"Security engine initialized");let b=Ui(this.config.llm,this.logger.child({component:"llm"}));await b.initialize(),this.llmProvider=b;let C=new yr(e);this.usageRepo=C,b.setPersist((v,M,V,Y,ye,me)=>{C.record(v,M,V,Y,ye,me)});let D=new rn(b,a,this.logger.child({component:"embeddings"})),P=this.config.activeLearning?.enabled!==!1,Q,ae;P&&(Q=new mn({llm:b,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:D,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),ae=new pn(n,this.logger.child({component:"memory-retriever"}),D),this.logger.info("Active learning & memory retriever initialized"));let j=new gr(e);this.summaryRepo=j;let z=new hn(b,j,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let re=new Qt(this.logger.child({component:"sandbox"})),N=this.skillRegistry=new Zt;N.register(new es),N.register(new ts),N.register(new ss(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),N.register(new rs(o)),N.register(new ns(i));let ie=new pr(e);if(N.register(new Es(ie)),N.register(new os),N.register(new is),N.register(new as(n,D)),N.register(new cs(b,N,re,S)),this.config.email?.accounts?.length){let v=new Map;for(let V of this.config.email.accounts)try{V.provider==="microsoft"&&!V.microsoft?.clientId&&this.config.calendar?.microsoft&&(V.microsoft={...this.config.calendar.microsoft});let Y=await Cr(V);v.set(V.name,Y),this.logger.info({account:V.name,provider:V.provider??"imap-smtp"},"Email account initialized")}catch(Y){this.logger.warn({err:Y,account:V.name},"Email account initialization failed, skipping")}let M=v.size>0?new dt(v):new dt;M.setLLM(b),N.register(M)}else{let v=new dt;v.setLLM(b),N.register(v)}N.register(new ls),N.register(new ds);let ce=new $s;ce.setReloadCallback(v=>this.reloadService(v)),N.register(ce),N.register(new ms),N.register(new ps),N.register(new hs),N.register(new fs(s)),N.register(new gs(s,c,this.adapters,(v,M)=>t.findByPlatformAndUser(v,M)));let J=new ys(d);N.register(J),N.register(new ws(u));let B=new mr(e),ue=new nn(B,D,this.logger.child({component:"documents"}));N.register(new Ts(B,ue,D));let Xe,ne;if(this.config.calendar)try{ne=await Dr(this.config.calendar),Xe=new Mt(ne),N.register(Xe),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(v){this.logger.warn({err:v},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Xe,ne&&this.config.calendar?.vorlauf?.enabled){let v=new xt(e),M=this.config.security?.ownerUserId;M&&(this.calendarWatcher=new fn(ne,v,this.adapters,M,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let v=this.config.security?.ownerUserId;if(v){let M=new xt(e);this.todoWatcher=new gn(ie,M,this.adapters,v,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:v}=await Promise.resolve().then(()=>(se(),oe));this.mcpManager=new v(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let M of this.mcpManager.getSkills())N.register(M);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},b)),this.logger.info({agents:this.config.codeAgents.agents.map(M=>M.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:v,createContactsProvider:M}=await Promise.resolve().then(()=>(se(),oe)),V=await M(this.config.contacts);N.register(new v(V)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(v){this.logger.warn({err:v},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant,proxmoxBackup:this.config.proxmoxBackup})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(N,this.config,n)),this.logger.info("Briefing skill registered")}N.register(new Rs(n)),this.logger.info("Feed reader skill registered"),this.logger.info({skills:N.getAll().map(v=>v.metadata.name)},"Skills registered");let be;if(this.config.speech?.apiKey&&(be=new Zr(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let v=new Qr(this.config.speech,this.logger.child({component:"tts"}));N.register(new _s(v)),this.logger.info("Text-to-speech skill registered")}let de=this.detectImageGenProvider();if(de){let v=new en(de,this.logger.child({component:"image-gen"}));N.register(new ks(v)),this.logger.info({provider:de.provider},"Image generation skill registered")}try{let v=new tn(this.logger.child({component:"transit"}));N.register(new Ss(v)),this.logger.info("Public transit skill registered")}catch(v){this.logger.warn({err:v},"Failed to register transit skill")}let Me=new Vr(t),Ye=Mo.resolve(Mo.dirname(this.config.storage.path),"inbox");this.pipeline=new Yr({llm:b,conversationManager:Me,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:N,skillSandbox:re,securityManager:S,memoryRepo:n,speechTranscriber:be,inboxPath:Ye,embeddingService:D,activeLearning:Q,memoryRetriever:ae,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:ue,conversationSummarizer:z}),this.reminderScheduler=new Jr(o,async(v,M,V)=>{let Y=this.adapters.get(v);Y?await Y.sendMessage(M,V):this.logger.warn({platform:v,chatId:M},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(v=>s.getMasterUserId(v),"getMasterUserId"),getLinkedUsers:m(v=>s.getLinkedUsers(v),"getLinkedUsers"),findConversation:m((v,M)=>t.findByPlatformAndUser(v,M),"findConversation")}),this.backgroundTaskRunner=new on(N,re,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,f);let Ke=new an(N,re,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ke),J.setPersistentRunner(Ke),this.proactiveScheduler=new cn(u,N,re,b,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Me,h);let Je=new hr(e);this.watchRepo=Je,N.register(new Is(Je,N));let Ne=new fr(e);this.confirmationQueue=new dn(Ne,N,re,this.adapters,this.logger.child({component:"confirmation-queue"}),h),this.watchEngine=new vo(Je,N,re,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,f,b);let gt=new Tr(e),yt=new As(gt);N.register(yt);let at=new Tn(gt,N,re,this.logger.child({component:"workflow-runner"}),h,f);yt.setRunner(at);{let v=this.config.security?.ownerUserId;if(v&&this.config.reasoning?.enabled!==!1){let M=new xt(e);this.reasoningEngine=new _n(ne,ie,Je,n,p,g,M,N,re,b,this.adapters,s,v,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h,this.config.briefing?.location)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(f),await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("telegram",new t(e.telegram.token)),this.logger.info("Telegram adapter registered")}if(e.discord?.enabled&&e.discord.token){let{DiscordAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("discord",new t(e.discord.token)),this.logger.info("Discord adapter registered")}if(e.whatsapp?.enabled){let{WhatsAppAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("whatsapp",new t(e.whatsapp.dataPath)),this.logger.info("WhatsApp adapter registered")}if(e.matrix?.enabled&&e.matrix.accessToken){let{MatrixAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("matrix",new t(e.matrix.homeserverUrl,e.matrix.accessToken,e.matrix.userId)),this.logger.info("Matrix adapter registered")}if(e.signal?.enabled&&e.signal.phoneNumber){let{SignalAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("signal",new t(e.signal.apiUrl,e.signal.phoneNumber)),this.logger.info("Signal adapter registered")}if(e.api?.enabled!==!1){let{HttpAdapter:t}=await Promise.resolve().then(()=>(ht(),pt)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>{let n;try{let o=this.config.storage.path,i=kn.statSync(o);n={path:o,sizeBytes:i.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([o,i])=>[o,i.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:this.watchRepo?.countEnabled()??0,schedulersActive:this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback")})),this.logger.info({port:s,host:r},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:m(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let o=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,o)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:this.auditRepo?.cleanup(90)??0,summaries:this.summaryRepo?.cleanup(180)??0,activity:this.activityRepo?.cleanup(90)??0,usage:this.usageRepo?.cleanup(365)??0,expiredMemories:this.memoryRepo?.cleanupExpired()??0};(e.audit||e.summaries||e.activity||e.usage)&&this.logger.info(e,"Startup DB cleanup completed")}catch(e){this.logger.warn({err:e},"Startup DB cleanup failed")}this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.adapters.size===0&&this.logger.warn("No messaging adapters enabled. Configure at least one platform."),this.logger.info(`Alfred is running with ${this.adapters.size} adapter(s)`)}async startWithCLI(){this.adapters.clear();let{CLIAdapter:e}=await Promise.resolve().then(()=>(ht(),pt)),t=new e;this.adapters.set("cli",t),t.on("disconnected",()=>{this.stop().then(()=>process.exit(0))}),await this.start()}async stop(){this.logger.info("Stopping Alfred..."),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(r=>setTimeout(r,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(r){this.logger.error({platform:t,err:r},"Failed to disconnect adapter")}try{this.database&&(this.database.getDb().pragma("wal_checkpoint(TRUNCATE)"),this.database.close())}catch{}this.logger.info("Alfred stopped")}async reloadService(e){try{ki();let t=new pe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(se(),oe)),n=await r(t.contacts);this.skillRegistry.register(new s(n)),this.config.contacts=t.contacts,this.logger.info({provider:t.contacts.provider},"Contacts skill hot-reloaded")}if(e==="docker"&&t.docker){let{DockerSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),o=this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${o.totalCostUsd}`),e.push("# HELP alfred_llm_today_calls Total LLM calls today (persisted)"),e.push("# TYPE alfred_llm_today_calls gauge"),e.push(`alfred_llm_today_calls ${o.totalCalls}`)}return e.push(""),e.join(`
1304
1304
  `)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async a=>{if(a!==n){n=a;try{r?await t.editMessage(s.chatId,r,a):r=await t.sendMessage(s.chatId,a)}catch(c){this.logger.debug({err:c,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o);if(i.text){let a=this.formatter.format(i.text,s.platform),c=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,c)}catch(d){this.logger.debug({err:d,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,a.text,c)}else await t.sendMessage(s.chatId,a.text,c)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let u=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,u.text)}}if(i.attachments)for(let a of i.attachments)try{let c=a.mimeType?.startsWith("image/")??!1,d=a.mimeType==="audio/ogg"||a.mimeType==="audio/opus";c?await t.sendPhoto(s.chatId,a.data,a.fileName):d?await t.sendVoice(s.chatId,a.data):await t.sendFile(s.chatId,a.data,a.fileName)}catch(c){this.logger.warn({err:c,fileName:a.fileName,chatId:s.chatId},"Failed to send attachment")}t.endStream(s.chatId)}catch(r){this.logger.error({platform:e,err:r,chatId:s.chatId},"Failed to handle message");try{await t.sendMessage(s.chatId,"Sorry, I encountered an error processing your message. Please try again.")}catch(n){this.logger.error({err:n},"Failed to send error message")}t.endStream(s.chatId)}}),t.on("error",s=>{this.logger.error({platform:e,err:s},"Adapter error")}),t.on("connected",()=>{this.logger.info({platform:e},"Adapter connected")}),t.on("disconnected",()=>{this.logger.warn({platform:e},"Adapter disconnected")})}detectImageGenProvider(){let e=["default","strong","fast","embeddings","local"];for(let t of["openai","google"])for(let s of e){let r=this.config.llm[s];if(r?.provider===t&&r.apiKey)return{provider:t,apiKey:r.apiKey,baseUrl:r.baseUrl}}}loadSecurityRules(){let e=Mo.resolve(this.config.security.rulesPath),t=[];if(!kn.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!kn.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=kn.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=Mo.join(e,n),i=kn.readFileSync(o,"utf-8"),a=Uf.load(i);if(a?.rules&&Array.isArray(a.rules)){let d=new rt().loadFromObject({rules:a.rules});t.push(...d),this.logger.info({file:n,count:d.length},"Loaded security rules")}}catch(o){this.logger.error({err:o,file:n},"Failed to load security rules file")}return t}}});var zu=T(()=>{"use strict"});var nc=T(()=>{"use strict";Wu();Ra();Ia();xa();Ca();La();Ma();Oa();Ua();Fa();ja();mt();Pa();Na();Da();Ga();Xa();qa();zu();za();Ka();bo();Ha();Va();Ya();Ja();So();Za();Qa();ec()});import Oo from"node:fs";import qu from"node:path";import Ff from"node:os";function Gu(){try{let l=Oo.readFileSync(oc,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Xu(l){try{let e=qu.dirname(oc);Oo.existsSync(e)||Oo.mkdirSync(e,{recursive:!0}),Oo.writeFileSync(oc,JSON.stringify(l,null,2),"utf-8")}catch{}}async function qt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),Bf);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function Ku(l,e,t){switch(l){case"anthropic":{let s=await qt("https://api.anthropic.com/v1/models",{headers:{"x-api-key":e??"","anthropic-version":"2023-06-01"}});return s.ok?((await s.json()).data??[]).map(n=>({id:n.id,name:n.display_name})):[]}case"openai":{let s=t?`${t.replace(/\/+$/,"")}/models`:"https://api.openai.com/v1/models",r=await qt(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await qt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await qt("https://api.mistral.ai/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(n=>({id:n.id,name:n.name})):[]}case"openrouter":{let s=await qt("https://openrouter.ai/api/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(n=>({id:n.id,name:n.name})):[]}case"ollama":{let s=(t??"http://localhost:11434").replace(/\/+$/,""),r=await qt(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await qt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function ic(l,e,t){let s=Gu(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<jf)return r.models;try{let n=await Ku(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Xu(s),n}catch{}return r?r.models:[]}function Po(l,e,t){Ku(l,e,t).then(s=>{if(s.length>0){let r=Gu();r.providers[l]={fetchedAt:Date.now(),models:s},Xu(r)}}).catch(()=>{})}function ac(l,e){let t=new Set,s=[];for(let r of l)if(!t.has(r.id)){t.add(r.id);let n=e.find(o=>o.id===r.id);s.push({id:r.id,name:r.name,desc:n?.desc})}for(let r of e)t.has(r.id)||(t.add(r.id),s.push({id:r.id,desc:r.desc}));return s}var jf,Bf,oc,cc=T(()=>{"use strict";jf=1440*60*1e3,Bf=5e3,oc=qu.join(Ff.homedir(),".alfred","model-cache.json");m(Gu,"readCache");m(Xu,"writeCache");m(qt,"fetchWithTimeout");m(Ku,"fetchModelsFromAPI");m(ic,"getModels");m(Po,"refreshCacheInBackground");m(ac,"mergeModels")});var Vu={};he(Vu,{startCommand:()=>Hf});async function Hf(){let l=new pe,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=tr("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new zt(e),r=!1,n=m(async o=>{if(!r){r=!0,t.info({signal:o},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(i){t.error({error:i},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",o=>{t.fatal({error:o},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",o=>{t.fatal({reason:o},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let o=e.llm;o?.default?.provider?Po(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&Po(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&Po(a.provider,a.apiKey,a.baseUrl)}}catch(o){let i=o instanceof Error?o:new Error(String(o));t.fatal({err:i},"Failed to start Alfred"),process.exit(1)}}var Yu=T(()=>{"use strict";tt();bi();nc();cc();m(Hf,"startCommand")});var Zu={};he(Zu,{chatCommand:()=>qf});import Ju from"node:http";import En from"node:readline";function Wf(l,e){return new Promise(t=>{let s=Ju.get(`http://${l}:${e}/api/health`,{timeout:2e3},r=>{let n="";r.on("data",o=>{n+=o.toString()}),r.on("end",()=>{try{let o=JSON.parse(n);t(o.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function zf(l,e){let t=En.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
1305
1305
  Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
1306
1306
  `),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
@@ -1435,7 +1435,7 @@ ${Zf}${K} _ _ _____ ____ _____ ____
1435
1435
  / ___ \\| |___| _| | _ <| |___| |_| |
1436
1436
  /_/ \\_\\_____|_| |_| \\_\\_____|____/ ${A}
1437
1437
  ${ft} Personal AI Assistant \u2014 Setup Wizard${A}
1438
- `)}var A,K,ft,Uo,F,Fo,Jf,Zf,it,Ds,em,rm=T(()=>{"use strict";cc();A="\x1B[0m",K="\x1B[1m",ft="\x1B[2m",Uo="\x1B[32m",F="\x1B[33m",Fo="\x1B[36m",Jf="\x1B[31m",Zf="\x1B[35m";m(U,"green");m(Qf,"yellow");m(_e,"cyan");m(tm,"red");m(L,"bold");m(E,"dim");m(ke,"maskKey");it=[{name:"anthropic",label:"Anthropic (Claude) \u2014 recommended",defaultModel:"claude-sonnet-4-20250514",envKeyName:"ALFRED_ANTHROPIC_API_KEY",needsApiKey:!0,models:[{id:"claude-sonnet-4-20250514",desc:"Sonnet 4 \u2014 fast, smart, recommended"},{id:"claude-opus-4-20250514",desc:"Opus 4 \u2014 most capable, slower"},{id:"claude-haiku-4-5-20251001",desc:"Haiku 4.5 \u2014 fastest, cheapest"}]},{name:"openai",label:"OpenAI (GPT)",defaultModel:"gpt-4o",envKeyName:"ALFRED_OPENAI_API_KEY",needsApiKey:!0,models:[{id:"gpt-4o",desc:"GPT-4o \u2014 flagship, 128k context"},{id:"gpt-4o-mini",desc:"GPT-4o Mini \u2014 fast, cheap, 128k context"},{id:"o3-mini",desc:"o3-mini \u2014 reasoning, 200k context"}]},{name:"openrouter",label:"OpenRouter (multiple providers)",defaultModel:"anthropic/claude-sonnet-4-20250514",envKeyName:"ALFRED_OPENROUTER_API_KEY",needsApiKey:!0,baseUrl:"https://openrouter.ai/api/v1"},{name:"ollama",label:"Ollama (local, no API key needed)",defaultModel:"llama3.2",envKeyName:"",needsApiKey:!1,baseUrl:"http://localhost:11434"},{name:"openwebui",label:"OpenWebUI (local OpenAI-compatible UI)",defaultModel:"llama3.2",envKeyName:"ALFRED_OPENWEBUI_API_KEY",needsApiKey:!0,baseUrl:"http://localhost:3000/api/v1"},{name:"google",label:"Google (Gemini)",defaultModel:"gemini-2.0-flash",envKeyName:"ALFRED_GOOGLE_API_KEY",needsApiKey:!0,models:[{id:"gemini-2.0-flash",desc:"Flash 2.0 \u2014 fast, 1M context"},{id:"gemini-2.0-pro",desc:"Pro 2.0 \u2014 capable, 1M context"},{id:"gemini-1.5-pro",desc:"Pro 1.5 \u2014 2M context"},{id:"gemini-1.5-flash",desc:"Flash 1.5 \u2014 fast, 1M context"}]},{name:"mistral",label:"Mistral AI",defaultModel:"mistral-small-latest",envKeyName:"ALFRED_MISTRAL_API_KEY",needsApiKey:!0,models:[{id:"mistral-small-latest",desc:"Small 3.2 \u2014 fast, 128k context, best value"},{id:"mistral-medium-latest",desc:"Medium 3.1 \u2014 balanced, 128k context"},{id:"mistral-large-latest",desc:"Large 3 \u2014 flagship, 256k context"},{id:"codestral-latest",desc:"Codestral \u2014 code-optimized, 256k context"},{id:"magistral-medium-latest",desc:"Magistral Medium \u2014 reasoning, 40k context"},{id:"magistral-small-latest",desc:"Magistral Small \u2014 reasoning (light), 40k context"},{id:"ministral-8b-latest",desc:"Ministral 8B \u2014 edge/tiny, 128k context"}]}],Ds=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];m(eg,"findCommand");em=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];m(tg,"loadExistingConfig");m(sg,"setupCommand");m(H,"askWithDefault");m(Le,"askRequired");m(bn,"askNumber");m(rg,"printBanner")});var om={};he(om,{configCommand:()=>ag});function og(l){let e=l.toLowerCase();return ng.some(t=>e.includes(t))}function ig(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function nm(l){let e={};for(let[t,s]of Object.entries(l))og(t)?e[t]=ig(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=nm(s):e[t]=s;return e}async function ag(){let l=new pe,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=nm(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var ng,im=T(()=>{"use strict";tt();ng=["token","apikey","api_key","accesstoken","secret","password"];m(og,"isSensitiveKey");m(ig,"redactValue");m(nm,"redactObject");m(ag,"configCommand")});var cm={};he(cm,{rulesCommand:()=>lg});import jo from"node:fs";import am from"node:path";import cg from"js-yaml";async function lg(){let l=new pe,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=am.resolve(e.security.rulesPath);if(!jo.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}jo.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=jo.readdirSync(t).filter(a=>a.endsWith(".yml")||a.endsWith(".yaml"));if(r.length===0){console.log(`No YAML rule files found in: ${t}`);return}let n=new rt,o=[],i=[];for(let a of r){let c=am.join(t,a);try{let d=jo.readFileSync(c,"utf-8"),u=cg.load(d),p=n.loadFromObject(u);o.push(...p)}catch(d){i.push(` ${a}: ${d.message}`)}}if(console.log("Alfred \u2014 Security Rules"),console.log("======================="),console.log(`Rules directory: ${t}`),console.log(`Rule files found: ${r.length}`),console.log(`Total rules loaded: ${o.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(o.length!==0){o.sort((a,c)=>a.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of o){let c=a.rateLimit?` | rate-limit: ${a.rateLimit.maxInvocations}/${a.rateLimit.windowSeconds}s`:"";console.log(` [${a.priority}] ${a.id}`),console.log(` effect: ${a.effect} | scope: ${a.scope}`),console.log(` actions: ${a.actions.join(", ")}`),console.log(` risk levels: ${a.riskLevels.join(", ")}${c}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var lm=T(()=>{"use strict";tt();qn();m(lg,"rulesCommand")});var dm={};he(dm,{statusCommand:()=>ug});import Sn from"node:fs";import dc from"node:path";import dg from"js-yaml";async function ug(){let l=new pe,e;try{e=l.loadConfig()}catch(c){console.error("Failed to load configuration:",c.message),process.exit(1)}console.log("Alfred \u2014 Status"),console.log("================"),console.log("");let t=[{name:"Telegram",enabled:e.telegram.enabled,configured:!!e.telegram.token},{name:"Discord",enabled:!!e.discord?.enabled,configured:!!e.discord?.token},{name:"WhatsApp",enabled:!!e.whatsapp?.enabled,configured:!!e.whatsapp?.dataPath},{name:"Matrix",enabled:!!e.matrix?.enabled,configured:!!e.matrix?.accessToken},{name:"Signal",enabled:!!e.signal?.enabled,configured:!!e.signal?.phoneNumber}];console.log("Messaging Adapters:");for(let c of t){let d=c.enabled?"enabled":c.configured?"configured (disabled)":"not configured",u=c.enabled?"+":"-";console.log(` [${u}] ${c.name}: ${d}`)}console.log(""),console.log("LLM Provider:");let s=e.llm.default;console.log(` Provider: ${s.provider}`),console.log(` Model: ${s.model}`),console.log(` API Key: ${s.apiKey?"set":"not set"}`),s.baseUrl&&console.log(` Base URL: ${s.baseUrl}`);for(let c of["strong","fast","embeddings","local"]){let d=e.llm[c];d&&console.log(` ${c}: ${d.provider}/${d.model}`)}console.log(""),console.log("Storage:");let r=dc.resolve(e.storage.path),n=Sn.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=dc.resolve(e.security.rulesPath),i=0,a=0;if(Sn.existsSync(o)&&Sn.statSync(o).isDirectory()){let c=Sn.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new rt;for(let u of c){let p=dc.join(o,u);try{let h=Sn.readFileSync(p,"utf-8"),g=dg.load(h),f=d.loadFromObject(g);i+=f.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${o}`),console.log(` Rule files: ${a}`),console.log(` Rules loaded: ${i}`),console.log(` Default effect: ${e.security.defaultEffect}`),e.security.ownerUserId&&console.log(` Owner user ID: ${e.security.ownerUserId}`),console.log(""),console.log("Logger:"),console.log(` Level: ${e.logger.level}`),console.log(` Pretty: ${e.logger.pretty}`)}var um=T(()=>{"use strict";tt();qn();m(ug,"statusCommand")});var hm={};he(hm,{authCommand:()=>Ig});import{createServer as mg}from"node:http";import{exec as pg}from"node:child_process";import{readFileSync as hg,writeFileSync as fg,existsSync as gg}from"node:fs";import{createInterface as yg}from"node:readline";import{resolve as wg}from"node:path";async function uc(l){let e=yg({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function _g(){let l={};try{let s=new pe().loadConfig();for(let o of["email","calendar","contacts"]){let i=s[o];if(!i)continue;let a=i.microsoft;a&&(!l.clientId&&a.clientId&&(l.clientId=a.clientId),!l.clientSecret&&a.clientSecret&&(l.clientSecret=a.clientSecret),!l.tenantId&&a.tenantId&&(l.tenantId=a.tenantId))}let r=s.todo;r&&(!l.clientId&&r.clientId&&(l.clientId=r.clientId),!l.clientSecret&&r.clientSecret&&(l.clientSecret=r.clientSecret),!l.tenantId&&r.tenantId&&(l.tenantId=r.tenantId));let n=s.email;if(n?.accounts&&Array.isArray(n.accounts))for(let o of n.accounts){let i=o.microsoft;i&&(!l.clientId&&i.clientId&&(l.clientId=i.clientId),!l.clientSecret&&i.clientSecret&&(l.clientSecret=i.clientSecret),!l.tenantId&&i.tenantId&&(l.tenantId=i.tenantId))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS","ALFRED_MICROSOFT_TODO"];for(let t of e)l.clientId||(l.clientId=process.env[`${t}_CLIENT_ID`]),l.clientSecret||(l.clientSecret=process.env[`${t}_CLIENT_SECRET`]),l.tenantId||(l.tenantId=process.env[`${t}_TENANT_ID`]);return l}async function kg(){let l=_g(),e=l.clientId||await uc(" Client ID: "),t=l.clientSecret||await uc(" Client Secret: "),s=l.tenantId||await uc(' Tenant ID (oder "common"): ');return(!e||!t||!s)&&(console.error("Fehler: Client ID, Client Secret und Tenant ID werden ben\xF6tigt."),process.exit(1)),{clientId:e,clientSecret:t,tenantId:s}}function Eg(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:mm,response_mode:"query",scope:pm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function bg(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:mm,grant_type:"authorization_code",scope:pm}),s=await fetch(`https://login.microsoftonline.com/${e.tenantId}/oauth2/v2.0/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t});if(!s.ok){let n=await s.text();throw new Error(`Token-Austausch fehlgeschlagen (${s.status}): ${n}`)}let r=await s.json();if(!r.refresh_token)throw new Error('Kein Refresh Token in der Antwort. Stelle sicher, dass "offline_access" als Scope erlaubt ist.');return r.refresh_token}function Sg(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&pg(t,()=>{})}function vg(l,e){let t=wg(process.cwd(),".env"),s=[];gg(t)&&(s=hg(t,"utf-8").split(`
1438
+ `)}var A,K,ft,Uo,F,Fo,Jf,Zf,it,Ds,em,rm=T(()=>{"use strict";cc();A="\x1B[0m",K="\x1B[1m",ft="\x1B[2m",Uo="\x1B[32m",F="\x1B[33m",Fo="\x1B[36m",Jf="\x1B[31m",Zf="\x1B[35m";m(U,"green");m(Qf,"yellow");m(_e,"cyan");m(tm,"red");m(L,"bold");m(E,"dim");m(ke,"maskKey");it=[{name:"anthropic",label:"Anthropic (Claude) \u2014 recommended",defaultModel:"claude-sonnet-4-20250514",envKeyName:"ALFRED_ANTHROPIC_API_KEY",needsApiKey:!0,models:[{id:"claude-sonnet-4-20250514",desc:"Sonnet 4 \u2014 fast, smart, recommended"},{id:"claude-opus-4-20250514",desc:"Opus 4 \u2014 most capable, slower"},{id:"claude-haiku-4-5-20251001",desc:"Haiku 4.5 \u2014 fastest, cheapest"}]},{name:"openai",label:"OpenAI (GPT)",defaultModel:"gpt-4o",envKeyName:"ALFRED_OPENAI_API_KEY",needsApiKey:!0,models:[{id:"gpt-4o",desc:"GPT-4o \u2014 flagship, 128k context"},{id:"gpt-4o-mini",desc:"GPT-4o Mini \u2014 fast, cheap, 128k context"},{id:"o3-mini",desc:"o3-mini \u2014 reasoning, 200k context"}]},{name:"openrouter",label:"OpenRouter (multiple providers)",defaultModel:"anthropic/claude-sonnet-4-20250514",envKeyName:"ALFRED_OPENROUTER_API_KEY",needsApiKey:!0,baseUrl:"https://openrouter.ai/api/v1"},{name:"ollama",label:"Ollama (local, no API key needed)",defaultModel:"llama3.2",envKeyName:"",needsApiKey:!1,baseUrl:"http://localhost:11434"},{name:"openwebui",label:"OpenWebUI (local OpenAI-compatible UI)",defaultModel:"llama3.2",envKeyName:"ALFRED_OPENWEBUI_API_KEY",needsApiKey:!0,baseUrl:"http://localhost:3000/api/v1"},{name:"google",label:"Google (Gemini)",defaultModel:"gemini-2.0-flash",envKeyName:"ALFRED_GOOGLE_API_KEY",needsApiKey:!0,models:[{id:"gemini-2.0-flash",desc:"Flash 2.0 \u2014 fast, 1M context"},{id:"gemini-2.0-pro",desc:"Pro 2.0 \u2014 capable, 1M context"},{id:"gemini-1.5-pro",desc:"Pro 1.5 \u2014 2M context"},{id:"gemini-1.5-flash",desc:"Flash 1.5 \u2014 fast, 1M context"}]},{name:"mistral",label:"Mistral AI",defaultModel:"mistral-small-latest",envKeyName:"ALFRED_MISTRAL_API_KEY",needsApiKey:!0,models:[{id:"mistral-small-latest",desc:"Small 3.2 \u2014 fast, 128k context, best value"},{id:"mistral-medium-latest",desc:"Medium 3.1 \u2014 balanced, 128k context"},{id:"mistral-large-latest",desc:"Large 3 \u2014 flagship, 256k context"},{id:"codestral-latest",desc:"Codestral \u2014 code-optimized, 256k context"},{id:"magistral-medium-latest",desc:"Magistral Medium \u2014 reasoning, 40k context"},{id:"magistral-small-latest",desc:"Magistral Small \u2014 reasoning (light), 40k context"},{id:"ministral-8b-latest",desc:"Ministral 8B \u2014 edge/tiny, 128k context"}]}],Ds=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];m(eg,"findCommand");em=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["exec","--dangerously-bypass-approvals-and-sandbox","{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];m(tg,"loadExistingConfig");m(sg,"setupCommand");m(H,"askWithDefault");m(Le,"askRequired");m(bn,"askNumber");m(rg,"printBanner")});var om={};he(om,{configCommand:()=>ag});function og(l){let e=l.toLowerCase();return ng.some(t=>e.includes(t))}function ig(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function nm(l){let e={};for(let[t,s]of Object.entries(l))og(t)?e[t]=ig(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=nm(s):e[t]=s;return e}async function ag(){let l=new pe,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=nm(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var ng,im=T(()=>{"use strict";tt();ng=["token","apikey","api_key","accesstoken","secret","password"];m(og,"isSensitiveKey");m(ig,"redactValue");m(nm,"redactObject");m(ag,"configCommand")});var cm={};he(cm,{rulesCommand:()=>lg});import jo from"node:fs";import am from"node:path";import cg from"js-yaml";async function lg(){let l=new pe,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=am.resolve(e.security.rulesPath);if(!jo.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}jo.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=jo.readdirSync(t).filter(a=>a.endsWith(".yml")||a.endsWith(".yaml"));if(r.length===0){console.log(`No YAML rule files found in: ${t}`);return}let n=new rt,o=[],i=[];for(let a of r){let c=am.join(t,a);try{let d=jo.readFileSync(c,"utf-8"),u=cg.load(d),p=n.loadFromObject(u);o.push(...p)}catch(d){i.push(` ${a}: ${d.message}`)}}if(console.log("Alfred \u2014 Security Rules"),console.log("======================="),console.log(`Rules directory: ${t}`),console.log(`Rule files found: ${r.length}`),console.log(`Total rules loaded: ${o.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(o.length!==0){o.sort((a,c)=>a.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of o){let c=a.rateLimit?` | rate-limit: ${a.rateLimit.maxInvocations}/${a.rateLimit.windowSeconds}s`:"";console.log(` [${a.priority}] ${a.id}`),console.log(` effect: ${a.effect} | scope: ${a.scope}`),console.log(` actions: ${a.actions.join(", ")}`),console.log(` risk levels: ${a.riskLevels.join(", ")}${c}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var lm=T(()=>{"use strict";tt();qn();m(lg,"rulesCommand")});var dm={};he(dm,{statusCommand:()=>ug});import Sn from"node:fs";import dc from"node:path";import dg from"js-yaml";async function ug(){let l=new pe,e;try{e=l.loadConfig()}catch(c){console.error("Failed to load configuration:",c.message),process.exit(1)}console.log("Alfred \u2014 Status"),console.log("================"),console.log("");let t=[{name:"Telegram",enabled:e.telegram.enabled,configured:!!e.telegram.token},{name:"Discord",enabled:!!e.discord?.enabled,configured:!!e.discord?.token},{name:"WhatsApp",enabled:!!e.whatsapp?.enabled,configured:!!e.whatsapp?.dataPath},{name:"Matrix",enabled:!!e.matrix?.enabled,configured:!!e.matrix?.accessToken},{name:"Signal",enabled:!!e.signal?.enabled,configured:!!e.signal?.phoneNumber}];console.log("Messaging Adapters:");for(let c of t){let d=c.enabled?"enabled":c.configured?"configured (disabled)":"not configured",u=c.enabled?"+":"-";console.log(` [${u}] ${c.name}: ${d}`)}console.log(""),console.log("LLM Provider:");let s=e.llm.default;console.log(` Provider: ${s.provider}`),console.log(` Model: ${s.model}`),console.log(` API Key: ${s.apiKey?"set":"not set"}`),s.baseUrl&&console.log(` Base URL: ${s.baseUrl}`);for(let c of["strong","fast","embeddings","local"]){let d=e.llm[c];d&&console.log(` ${c}: ${d.provider}/${d.model}`)}console.log(""),console.log("Storage:");let r=dc.resolve(e.storage.path),n=Sn.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=dc.resolve(e.security.rulesPath),i=0,a=0;if(Sn.existsSync(o)&&Sn.statSync(o).isDirectory()){let c=Sn.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new rt;for(let u of c){let p=dc.join(o,u);try{let h=Sn.readFileSync(p,"utf-8"),g=dg.load(h),f=d.loadFromObject(g);i+=f.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${o}`),console.log(` Rule files: ${a}`),console.log(` Rules loaded: ${i}`),console.log(` Default effect: ${e.security.defaultEffect}`),e.security.ownerUserId&&console.log(` Owner user ID: ${e.security.ownerUserId}`),console.log(""),console.log("Logger:"),console.log(` Level: ${e.logger.level}`),console.log(` Pretty: ${e.logger.pretty}`)}var um=T(()=>{"use strict";tt();qn();m(ug,"statusCommand")});var hm={};he(hm,{authCommand:()=>Ig});import{createServer as mg}from"node:http";import{exec as pg}from"node:child_process";import{readFileSync as hg,writeFileSync as fg,existsSync as gg}from"node:fs";import{createInterface as yg}from"node:readline";import{resolve as wg}from"node:path";async function uc(l){let e=yg({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function _g(){let l={};try{let s=new pe().loadConfig();for(let o of["email","calendar","contacts"]){let i=s[o];if(!i)continue;let a=i.microsoft;a&&(!l.clientId&&a.clientId&&(l.clientId=a.clientId),!l.clientSecret&&a.clientSecret&&(l.clientSecret=a.clientSecret),!l.tenantId&&a.tenantId&&(l.tenantId=a.tenantId))}let r=s.todo;r&&(!l.clientId&&r.clientId&&(l.clientId=r.clientId),!l.clientSecret&&r.clientSecret&&(l.clientSecret=r.clientSecret),!l.tenantId&&r.tenantId&&(l.tenantId=r.tenantId));let n=s.email;if(n?.accounts&&Array.isArray(n.accounts))for(let o of n.accounts){let i=o.microsoft;i&&(!l.clientId&&i.clientId&&(l.clientId=i.clientId),!l.clientSecret&&i.clientSecret&&(l.clientSecret=i.clientSecret),!l.tenantId&&i.tenantId&&(l.tenantId=i.tenantId))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS","ALFRED_MICROSOFT_TODO"];for(let t of e)l.clientId||(l.clientId=process.env[`${t}_CLIENT_ID`]),l.clientSecret||(l.clientSecret=process.env[`${t}_CLIENT_SECRET`]),l.tenantId||(l.tenantId=process.env[`${t}_TENANT_ID`]);return l}async function kg(){let l=_g(),e=l.clientId||await uc(" Client ID: "),t=l.clientSecret||await uc(" Client Secret: "),s=l.tenantId||await uc(' Tenant ID (oder "common"): ');return(!e||!t||!s)&&(console.error("Fehler: Client ID, Client Secret und Tenant ID werden ben\xF6tigt."),process.exit(1)),{clientId:e,clientSecret:t,tenantId:s}}function Eg(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:mm,response_mode:"query",scope:pm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function bg(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:mm,grant_type:"authorization_code",scope:pm}),s=await fetch(`https://login.microsoftonline.com/${e.tenantId}/oauth2/v2.0/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t});if(!s.ok){let n=await s.text();throw new Error(`Token-Austausch fehlgeschlagen (${s.status}): ${n}`)}let r=await s.json();if(!r.refresh_token)throw new Error('Kein Refresh Token in der Antwort. Stelle sicher, dass "offline_access" als Scope erlaubt ist.');return r.refresh_token}function Sg(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&pg(t,()=>{})}function vg(l,e){let t=wg(process.cwd(),".env"),s=[];gg(t)&&(s=hg(t,"utf-8").split(`
1439
1439
  `));let r={ALFRED_EMAIL_PROVIDER:"microsoft",ALFRED_CALENDAR_PROVIDER:"microsoft",ALFRED_CONTACTS_PROVIDER:"microsoft",ALFRED_MICROSOFT_EMAIL_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_EMAIL_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:e,ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_CALENDAR_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:e,ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_CONTACTS_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:e,ALFRED_MICROSOFT_TODO_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_TODO_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_TODO_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:e},n=new Set(Object.keys(r));for(let i=0;i<s.length;i++){let a=s[i].match(/^#?\s*([A-Z_]+)=/);a&&n.has(a[1])&&(s[i]=`${a[1]}=${r[a[1]]}`,n.delete(a[1]))}if(n.size>0){s.length>0&&s[s.length-1]!==""&&s.push("");for(let i of n)s.push(`${i}=${r[i]}`)}let o=s.join(`
1440
1440
  `).replace(/\n*$/,`
1441
1441
  `);fg(t,o)}function $g(l){return new Promise((e,t)=>{let s=mg(async(r,n)=>{let o=new URL(r.url??"/","http://localhost:3000");if(o.pathname!=="/callback"){n.writeHead(404),n.end("Not found");return}let i=o.searchParams.get("code"),a=o.searchParams.get("error");if(a){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>Fehler: ${a}</h1><p>${o.searchParams.get("error_description")??""}</p>`),s.close(),t(new Error(`OAuth-Fehler: ${a}`));return}if(!i){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>Fehler: Kein Auth-Code erhalten</h1>");return}try{let c=await bg(i,l);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(Tg),s.close(),e(c)}catch(c){n.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>Fehler beim Token-Austausch</h1><p>${c.message}</p>`),s.close(),t(c)}});s.listen(3e3,()=>{console.log(" Callback-Server gestartet auf http://localhost:3000")}),s.on("error",r=>{t(new Error(`Server konnte nicht gestartet werden: ${r.message}`))})})}async function Ig(l){l||(console.error("Usage: alfred auth <provider>"),console.error(" Unterst\xFCtzte Provider: microsoft"),process.exit(1)),l!=="microsoft"&&(console.error(`Unbekannter Provider: ${l}`),console.error(" Unterst\xFCtzte Provider: microsoft"),process.exit(1)),console.log(""),console.log(" Microsoft 365 OAuth \u2014 Automatischer Token-Flow"),console.log(" ================================================"),console.log("");let e=await kg(),t=Eg(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),Sg(t);try{let s=await $g(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),vg(e,s),console.log(" .env aktualisiert (Email, Calendar, Contacts, To Do)."),console.log(""),console.log(" Fertig! Du kannst Alfred jetzt mit Microsoft 365 nutzen."),console.log("")}catch(s){console.error(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madh-io/alfred-ai",
3
- "version": "0.14.6",
3
+ "version": "0.14.7",
4
4
  "description": "Alfred — Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",
5
5
  "type": "module",
6
6
  "bin": {