@madh-io/alfred-ai 0.17.1 → 0.17.3

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 +103 -103
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0}),io=(l=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(l,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):l)(function(l){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+l+'" is not supported')});var T=(l,e)=>()=>(l&&(e=l(l=0)),e);var me=(l,e)=>{for(var t in e)hl(l,t,{get:e[t],enumerable:!0})};import{z as w}from"zod";var gl,yl,wl,Tl,_l,kl,bl,El,Pt,zm,qm,Gm,fl,Km,Xm,Vm,Ym,Jm,Zm,Qm,eh,th,sh,rh,nh,oh,ih,ah,ch,lh,dh,uh,ph,mh,hh,fh,gh,yh,wh,Th,_h,kh,bh,Eh,Sh,$h,vh,Ah,Ih,Rh,xh,Xi,Vi=T(()=>{"use strict";gl=w.object({token:w.string().optional(),enabled:w.boolean()}),yl=w.object({token:w.string().optional(),enabled:w.boolean()}),wl=w.object({enabled:w.boolean(),dataPath:w.string()}),Tl=w.object({homeserverUrl:w.string(),accessToken:w.string().optional(),userId:w.string().optional(),enabled:w.boolean()}),_l=w.object({apiUrl:w.string(),phoneNumber:w.string().optional(),enabled:w.boolean()}),kl=w.object({path:w.string()}),bl=w.object({level:w.enum(["trace","debug","info","warn","error","fatal"]),pretty:w.boolean(),auditLogPath:w.string().optional()}),El=w.object({rulesPath:w.string(),defaultEffect:w.enum(["allow","deny"]),ownerUserId:w.string().optional()}),Pt=w.object({provider:w.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:w.string().optional(),baseUrl:w.string().optional(),model:w.string(),temperature:w.number().optional(),maxTokens:w.number().optional()}),zm=w.object({default:Pt,strong:Pt.optional(),fast:Pt.optional(),embeddings:Pt.optional(),local:Pt.optional()}).passthrough(),qm=w.union([Pt,zm]),Gm=w.object({provider:w.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:w.string().optional(),baseUrl:w.string().optional()}),fl=w.object({name:w.string().optional(),provider:w.enum(["imap-smtp","microsoft"]).optional(),imap:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),smtp:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),auth:w.object({user:w.string(),pass:w.string()}).optional(),microsoft:w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}).optional()}),Km=w.union([w.object({accounts:w.array(fl)}),fl]),Xm=w.object({provider:w.enum(["openai","groq","google"]),apiKey:w.string(),baseUrl:w.string().optional(),ttsEnabled:w.boolean().optional(),ttsModel:w.string().optional(),ttsVoice:w.string().optional()}),Vm=w.object({serverUrl:w.string(),username:w.string(),password:w.string()}),Ym=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),Jm=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Zm=w.object({provider:w.enum(["caldav","google","microsoft"]),caldav:Vm.optional(),google:Ym.optional(),microsoft:Jm.optional(),vorlauf:w.object({enabled:w.boolean(),minutesBefore:w.coerce.number().min(1).max(120).default(15),enrichWithRoute:w.boolean().optional(),enrichWithMemories:w.boolean().optional()}).optional()}),Qm=w.object({name:w.string(),command:w.string().optional(),args:w.array(w.string()).optional(),env:w.record(w.string()).optional(),url:w.string().optional()}),eh=w.object({servers:w.array(Qm)}),th=w.object({enabled:w.boolean(),allowedLanguages:w.array(w.enum(["javascript","python"])).optional(),maxTimeoutMs:w.number().optional(),allowNetwork:w.boolean().optional()}),sh=w.object({enabled:w.boolean().optional(),minMessageLength:w.number().optional(),minConfidence:w.number().min(0).max(1).optional(),maxExtractionsPerMinute:w.number().optional()}),rh=w.object({enabled:w.boolean().optional(),cert:w.string().optional(),key:w.string().optional()}),nh=w.object({enabled:w.boolean(),port:w.coerce.number().int().min(1).max(65535),host:w.string(),token:w.string().optional(),corsOrigin:w.string().optional(),webUi:w.boolean().optional(),tls:rh.optional()}),oh=w.object({name:w.string(),command:w.string(),argsTemplate:w.array(w.string()),promptVia:w.enum(["arg","stdin"]).default("arg"),env:w.record(w.string()).optional(),cwd:w.string().optional(),timeoutMs:w.number().max(9e5).optional()}),ih=w.object({token:w.string(),baseUrl:w.string().optional()}),ah=w.object({token:w.string(),baseUrl:w.string().optional()}),ch=w.object({provider:w.enum(["github","gitlab"]),baseBranch:w.string().optional(),github:ih.optional(),gitlab:ah.optional()}),lh=w.object({enabled:w.boolean(),agents:w.array(oh),forge:ch.optional()}),dh=w.object({name:w.string(),buildCommands:w.array(w.string()),testCommands:w.array(w.string()),description:w.string().optional()}),uh=w.object({enabled:w.boolean(),templates:w.array(dh).optional(),defaultMaxDurationHours:w.number().optional(),defaultProgressEveryN:w.number().optional(),maxFixAttemptsPerIteration:w.number().optional(),buildCommandTimeoutMs:w.number().optional()}),ph=w.object({apiKey:w.string(),supadata:w.object({enabled:w.boolean().optional(),apiKey:w.string().optional()}).optional()}),mh=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),verifyTls:w.boolean().optional(),defaultNode:w.string().optional()}),hh=w.object({baseUrl:w.string(),apiKey:w.string().optional(),username:w.string().optional(),password:w.string().optional(),site:w.string().optional(),verifyTls:w.boolean().optional()}),fh=w.object({baseUrl:w.string(),accessToken:w.string(),verifyTls:w.boolean().optional()}),gh=w.object({serverUrl:w.string(),username:w.string(),password:w.string(),addressBookPath:w.string().optional()}),yh=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),wh=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Th=w.object({provider:w.enum(["carddav","google","microsoft"]),carddav:gh.optional(),google:yh.optional(),microsoft:wh.optional()}),_h=w.object({socketPath:w.string().optional(),host:w.string().optional(),verifyTls:w.boolean().optional()}),kh=w.object({clientId:w.string()}),bh=w.object({apiKey:w.string()}),Eh=w.object({gridName:w.string().optional(),gridUsageCt:w.coerce.number().optional(),gridLossCt:w.coerce.number().optional(),gridCapacityFee:w.coerce.number().optional(),gridMeterFee:w.coerce.number().optional()}),Sh=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),$h=w.object({maxHistoryMessages:w.number().min(10).max(500).optional()}).optional(),vh=w.object({name:w.string(),secret:w.string(),watchId:w.string().optional(),chatId:w.string().optional(),platform:w.string().optional()}),Ah=w.object({ebay:w.object({appId:w.string(),certId:w.string()}).optional()}),Ih=w.object({location:w.string().optional(),homeAddress:w.string().optional(),officeAddress:w.string().optional(),homeAssistant:w.object({entities:w.array(w.string()).optional(),domains:w.array(w.string()).optional()}).optional()}),Rh=w.object({enabled:w.boolean().optional(),schedule:w.enum(["morning_noon_evening","hourly","half_hourly"]).optional(),tier:w.enum(["fast","default"]).optional(),deduplicationHours:w.number().optional()}),xh=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),maxAgeHours:w.coerce.number().optional(),verifyTls:w.boolean().optional()}),Xi=w.object({name:w.string(),telegram:gl,discord:yl.optional(),whatsapp:wl.optional(),matrix:Tl.optional(),signal:_l.optional(),llm:qm,storage:kl,logger:bl,security:El,search:Gm.optional(),email:Km.optional(),speech:Xm.optional(),calendar:Zm.optional(),mcp:eh.optional(),codeSandbox:th.optional(),activeLearning:sh.optional(),api:nh.optional(),codeAgents:lh.optional(),projectAgents:uh.optional(),youtube:ph.optional(),proxmox:mh.optional(),unifi:hh.optional(),homeassistant:fh.optional(),contacts:Th.optional(),docker:_h.optional(),bmw:kh.optional(),routing:bh.optional(),todo:Sh.optional(),energy:Eh.optional(),marketplace:Ah.optional(),briefing:Ih.optional(),reasoning:Rh.optional(),webhooks:w.array(vh).optional(),proxmoxBackup:xh.optional(),conversation:$h})});var Yi,Ji=T(()=>{"use strict";Yi={name:"Alfred",telegram:{token:"",enabled:!1},discord:{token:"",enabled:!1},whatsapp:{enabled:!1,dataPath:"./data/whatsapp"},matrix:{homeserverUrl:"https://matrix.org",accessToken:"",userId:"",enabled:!1},signal:{apiUrl:"http://localhost:8080",phoneNumber:"",enabled:!1},llm:{provider:"anthropic",model:"claude-sonnet-4-20250514",temperature:.7,maxTokens:4096},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0},security:{rulesPath:"./config/rules",defaultEffect:"deny"},api:{enabled:!0,port:3420,host:"127.0.0.1"},conversation:{maxHistoryMessages:100}}});import Sl from"node:fs";import Zi from"node:path";import{config as $l}from"dotenv";import Ch from"js-yaml";function vl(l,e){let t={...l};for(let s of Object.keys(e)){let r=e[s],n=t[s];r!=null&&typeof r=="object"&&!Array.isArray(r)&&n!==null&&n!==void 0&&typeof n=="object"&&!Array.isArray(n)?t[s]=vl(n,r):t[s]=r}return t}function Lh(l){let e=l.toLowerCase();return e==="true"?!0:e==="false"?!1:l}function Dh(l){let e={...l};for(let[t,s]of Object.entries(Nh)){let r=process.env[t];if(r===void 0)continue;let n=e;for(let o=0;o<s.length-1;o++){let i=s[o];(n[i]===void 0||n[i]===null||typeof n[i]!="object")&&(n[i]={}),n[i]={...n[i]},n=n[i]}n[s[s.length-1]]=Lh(r)}return e}function Qi(){$l({override:!0})}function Mh(l){let e=Zi.resolve(l),t=process.platform==="win32"?["C:\\Windows","C:\\Program Files","C:\\Program Files (x86)"]:["/etc","/bin","/proc","/sys","/dev","/boot"];for(let s of t)if(e.startsWith(s+Zi.sep)||e.startsWith(s+"/")||e===s)throw new Error(`Storage path "${e}" is in forbidden directory ${s}`)}var Nh,fe,Al=T(()=>{"use strict";Vi();Ji();p(vl,"deepMerge");Nh={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_TELEGRAM_ENABLED:["telegram","enabled"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_DISCORD_ENABLED:["discord","enabled"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_MATRIX_ENABLED:["matrix","enabled"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],ALFRED_SIGNAL_ENABLED:["signal","enabled"],ALFRED_ANTHROPIC_API_KEY:["llm","apiKey"],ALFRED_OPENAI_API_KEY:["llm","apiKey"],ALFRED_GOOGLE_API_KEY:["llm","apiKey"],ALFRED_OPENROUTER_API_KEY:["llm","apiKey"],ALFRED_OPENWEBUI_API_KEY:["llm","apiKey"],ALFRED_LLM_PROVIDER:["llm","provider"],ALFRED_LLM_MODEL:["llm","model"],ALFRED_LLM_BASE_URL:["llm","baseUrl"],ALFRED_LLM_STRONG_PROVIDER:["llm","strong","provider"],ALFRED_LLM_STRONG_MODEL:["llm","strong","model"],ALFRED_LLM_STRONG_API_KEY:["llm","strong","apiKey"],ALFRED_LLM_FAST_PROVIDER:["llm","fast","provider"],ALFRED_LLM_FAST_MODEL:["llm","fast","model"],ALFRED_LLM_FAST_API_KEY:["llm","fast","apiKey"],ALFRED_LLM_EMBEDDINGS_PROVIDER:["llm","embeddings","provider"],ALFRED_LLM_EMBEDDINGS_MODEL:["llm","embeddings","model"],ALFRED_LLM_EMBEDDINGS_API_KEY:["llm","embeddings","apiKey"],ALFRED_LLM_LOCAL_PROVIDER:["llm","local","provider"],ALFRED_LLM_LOCAL_MODEL:["llm","local","model"],ALFRED_LLM_LOCAL_BASE_URL:["llm","local","baseUrl"],ALFRED_STORAGE_PATH:["storage","path"],ALFRED_LOG_LEVEL:["logger","level"],ALFRED_OWNER_USER_ID:["security","ownerUserId"],ALFRED_SEARCH_PROVIDER:["search","provider"],ALFRED_SEARCH_API_KEY:["search","apiKey"],ALFRED_SEARCH_BASE_URL:["search","baseUrl"],ALFRED_EMAIL_PROVIDER:["email","provider"],ALFRED_EMAIL_USER:["email","auth","user"],ALFRED_EMAIL_PASS:["email","auth","pass"],ALFRED_MICROSOFT_EMAIL_CLIENT_ID:["email","microsoft","clientId"],ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:["email","microsoft","clientSecret"],ALFRED_MICROSOFT_EMAIL_TENANT_ID:["email","microsoft","tenantId"],ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:["email","microsoft","refreshToken"],ALFRED_SPEECH_PROVIDER:["speech","provider"],ALFRED_SPEECH_API_KEY:["speech","apiKey"],ALFRED_SPEECH_BASE_URL:["speech","baseUrl"],ALFRED_CALENDAR_PROVIDER:["calendar","provider"],ALFRED_CALDAV_SERVER_URL:["calendar","caldav","serverUrl"],ALFRED_CALDAV_USERNAME:["calendar","caldav","username"],ALFRED_CALDAV_PASSWORD:["calendar","caldav","password"],ALFRED_GOOGLE_CALENDAR_CLIENT_ID:["calendar","google","clientId"],ALFRED_GOOGLE_CALENDAR_CLIENT_SECRET:["calendar","google","clientSecret"],ALFRED_GOOGLE_CALENDAR_REFRESH_TOKEN:["calendar","google","refreshToken"],ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:["calendar","microsoft","clientId"],ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:["calendar","microsoft","clientSecret"],ALFRED_MICROSOFT_CALENDAR_TENANT_ID:["calendar","microsoft","tenantId"],ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:["calendar","microsoft","refreshToken"],ALFRED_FORGE_PROVIDER:["codeAgents","forge","provider"],ALFRED_FORGE_BASE_BRANCH:["codeAgents","forge","baseBranch"],ALFRED_GITHUB_TOKEN:["codeAgents","forge","github","token"],ALFRED_GITHUB_BASE_URL:["codeAgents","forge","github","baseUrl"],ALFRED_GITLAB_TOKEN:["codeAgents","forge","gitlab","token"],ALFRED_GITLAB_BASE_URL:["codeAgents","forge","gitlab","baseUrl"],ALFRED_PROXMOX_BASE_URL:["proxmox","baseUrl"],ALFRED_PROXMOX_TOKEN_ID:["proxmox","tokenId"],ALFRED_PROXMOX_TOKEN_SECRET:["proxmox","tokenSecret"],ALFRED_PROXMOX_VERIFY_TLS:["proxmox","verifyTls"],ALFRED_UNIFI_BASE_URL:["unifi","baseUrl"],ALFRED_UNIFI_API_KEY:["unifi","apiKey"],ALFRED_UNIFI_USERNAME:["unifi","username"],ALFRED_UNIFI_PASSWORD:["unifi","password"],ALFRED_UNIFI_SITE:["unifi","site"],ALFRED_UNIFI_VERIFY_TLS:["unifi","verifyTls"],ALFRED_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],ALFRED_HOMEASSISTANT_VERIFY_TLS:["homeassistant","verifyTls"],ALFRED_CONTACTS_PROVIDER:["contacts","provider"],ALFRED_CARDDAV_CONTACTS_SERVER_URL:["contacts","carddav","serverUrl"],ALFRED_CARDDAV_CONTACTS_USERNAME:["contacts","carddav","username"],ALFRED_CARDDAV_CONTACTS_PASSWORD:["contacts","carddav","password"],ALFRED_GOOGLE_CONTACTS_CLIENT_ID:["contacts","google","clientId"],ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET:["contacts","google","clientSecret"],ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN:["contacts","google","refreshToken"],ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:["contacts","microsoft","clientId"],ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:["contacts","microsoft","clientSecret"],ALFRED_MICROSOFT_CONTACTS_TENANT_ID:["contacts","microsoft","tenantId"],ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:["contacts","microsoft","refreshToken"],ALFRED_DOCKER_SOCKET_PATH:["docker","socketPath"],ALFRED_DOCKER_HOST:["docker","host"],ALFRED_DOCKER_VERIFY_TLS:["docker","verifyTls"],ALFRED_BMW_CLIENT_ID:["bmw","clientId"],ALFRED_YOUTUBE_API_KEY:["youtube","apiKey"],ALFRED_SUPADATA_API_KEY:["youtube","supadata","apiKey"],ALFRED_ROUTING_API_KEY:["routing","apiKey"],ALFRED_MICROSOFT_TODO_CLIENT_ID:["todo","clientId"],ALFRED_MICROSOFT_TODO_CLIENT_SECRET:["todo","clientSecret"],ALFRED_MICROSOFT_TODO_TENANT_ID:["todo","tenantId"],ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:["todo","refreshToken"],ALFRED_ENERGY_GRID_NAME:["energy","gridName"],ALFRED_ENERGY_GRID_USAGE_CT:["energy","gridUsageCt"],ALFRED_ENERGY_GRID_LOSS_CT:["energy","gridLossCt"],ALFRED_ENERGY_GRID_CAPACITY_FEE:["energy","gridCapacityFee"],ALFRED_ENERGY_GRID_METER_FEE:["energy","gridMeterFee"],ALFRED_PBS_BASE_URL:["proxmoxBackup","baseUrl"],ALFRED_PBS_TOKEN_ID:["proxmoxBackup","tokenId"],ALFRED_PBS_TOKEN_SECRET:["proxmoxBackup","tokenSecret"],ALFRED_PBS_MAX_AGE_HOURS:["proxmoxBackup","maxAgeHours"],ALFRED_PBS_VERIFY_TLS:["proxmoxBackup","verifyTls"],ALFRED_EBAY_APP_ID:["marketplace","ebay","appId"],ALFRED_EBAY_CERT_ID:["marketplace","ebay","certId"],ALFRED_BRIEFING_LOCATION:["briefing","location"],ALFRED_BRIEFING_HOME_ADDRESS:["briefing","homeAddress"],ALFRED_BRIEFING_OFFICE_ADDRESS:["briefing","officeAddress"],ALFRED_REASONING_ENABLED:["reasoning","enabled"],ALFRED_REASONING_SCHEDULE:["reasoning","schedule"],ALFRED_REASONING_TIER:["reasoning","tier"]};p(Lh,"coerceEnvValue");p(Dh,"applyEnvOverrides");p(Qi,"reloadDotenv");fe=class{static{p(this,"ConfigLoader")}loadConfig(e){$l();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Zi.resolve(t);if(Sl.existsSync(r)){let f=Sl.readFileSync(r,"utf-8"),g=Ch.load(f);g&&typeof g=="object"&&(s=g)}let n=vl(Yi,s),o=Dh(n),i=["strong","fast","embeddings","local"],a=o.llm;if(a&&"provider"in a&&i.some(g=>a[g]&&typeof a[g]=="object")){let g={};for(let[_,S]of Object.entries(a))!i.includes(_)&&_!=="default"&&(g[_]=S);let y={default:g};for(let _ of i)a[_]&&(y[_]=a[_]);o.llm=y}let c=Xi.parse(o),d=c.llm;d&&"provider"in d&&(c.llm={default:d});let u=c.llm;if(u&&typeof u=="object"){let f=u.apiKey??u.default?.apiKey;if(f)for(let g of["default","strong","fast","embeddings","local"]){let y=u[g];y&&!y.apiKey&&(y.apiKey=f)}}let m=c.email;if(m&&!("accounts"in m))c.email={accounts:[{name:"default",...m}]};else if(m&&"accounts"in m&&"microsoft"in m){let f=m.microsoft;if(f){let y=m.accounts.find(_=>_.provider==="microsoft");if(y){let _=y.microsoft??{};y.microsoft={..._,...f}}delete m.microsoft}}let h=c.storage;return h?.path&&typeof h.path=="string"&&Mh(h.path),c}};p(Mh,"validateStoragePath")});var ot=T(()=>{"use strict";Vi();Ji();Al()});import ea from"pino";function Ir(l,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=ea.transport({target:"pino-pretty",options:{colorize:!0}});return ea({name:l,level:t,redact:Il},r)}return ea({name:l,level:t,redact:Il})}var Il,Rl=T(()=>{"use strict";Il={paths:["**.apiKey","**.token","**.password","**.secret","**.accessToken","**.refreshToken","**.clientSecret","**.Authorization","**.authorization","**.bearer","**.credential","**.jwt","**.x-api-key","**.x-auth-token"],censor:"[REDACTED]"};p(Ir,"createLogger")});import bw from"pino";var xl=T(()=>{"use strict"});var ta=T(()=>{"use strict";Rl();xl()});var Ut,ao=T(()=>{"use strict";Ut=class{static{p(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
2
+ var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0}),ao=(l=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(l,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):l)(function(l){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+l+'" is not supported')});var T=(l,e)=>()=>(l&&(e=l(l=0)),e);var me=(l,e)=>{for(var t in e)hl(l,t,{get:e[t],enumerable:!0})};import{z as w}from"zod";var gl,yl,wl,Tl,_l,kl,bl,El,Pt,zm,qm,Gm,fl,Km,Xm,Vm,Ym,Jm,Zm,Qm,eh,th,sh,rh,nh,oh,ih,ah,ch,lh,dh,uh,ph,mh,hh,fh,gh,yh,wh,Th,_h,kh,bh,Eh,Sh,$h,vh,Ah,Ih,Rh,xh,Xi,Vi=T(()=>{"use strict";gl=w.object({token:w.string().optional(),enabled:w.boolean()}),yl=w.object({token:w.string().optional(),enabled:w.boolean()}),wl=w.object({enabled:w.boolean(),dataPath:w.string()}),Tl=w.object({homeserverUrl:w.string(),accessToken:w.string().optional(),userId:w.string().optional(),enabled:w.boolean()}),_l=w.object({apiUrl:w.string(),phoneNumber:w.string().optional(),enabled:w.boolean()}),kl=w.object({path:w.string()}),bl=w.object({level:w.enum(["trace","debug","info","warn","error","fatal"]),pretty:w.boolean(),auditLogPath:w.string().optional()}),El=w.object({rulesPath:w.string(),defaultEffect:w.enum(["allow","deny"]),ownerUserId:w.string().optional()}),Pt=w.object({provider:w.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:w.string().optional(),baseUrl:w.string().optional(),model:w.string(),temperature:w.number().optional(),maxTokens:w.number().optional()}),zm=w.object({default:Pt,strong:Pt.optional(),fast:Pt.optional(),embeddings:Pt.optional(),local:Pt.optional()}).passthrough(),qm=w.union([Pt,zm]),Gm=w.object({provider:w.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:w.string().optional(),baseUrl:w.string().optional()}),fl=w.object({name:w.string().optional(),provider:w.enum(["imap-smtp","microsoft"]).optional(),imap:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),smtp:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),auth:w.object({user:w.string(),pass:w.string()}).optional(),microsoft:w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}).optional()}),Km=w.union([w.object({accounts:w.array(fl)}),fl]),Xm=w.object({provider:w.enum(["openai","groq","google"]),apiKey:w.string(),baseUrl:w.string().optional(),ttsEnabled:w.boolean().optional(),ttsModel:w.string().optional(),ttsVoice:w.string().optional()}),Vm=w.object({serverUrl:w.string(),username:w.string(),password:w.string()}),Ym=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),Jm=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Zm=w.object({provider:w.enum(["caldav","google","microsoft"]),caldav:Vm.optional(),google:Ym.optional(),microsoft:Jm.optional(),vorlauf:w.object({enabled:w.boolean(),minutesBefore:w.coerce.number().min(1).max(120).default(15),enrichWithRoute:w.boolean().optional(),enrichWithMemories:w.boolean().optional()}).optional()}),Qm=w.object({name:w.string(),command:w.string().optional(),args:w.array(w.string()).optional(),env:w.record(w.string()).optional(),url:w.string().optional()}),eh=w.object({servers:w.array(Qm)}),th=w.object({enabled:w.boolean(),allowedLanguages:w.array(w.enum(["javascript","python"])).optional(),maxTimeoutMs:w.number().optional(),allowNetwork:w.boolean().optional()}),sh=w.object({enabled:w.boolean().optional(),minMessageLength:w.number().optional(),minConfidence:w.number().min(0).max(1).optional(),maxExtractionsPerMinute:w.number().optional()}),rh=w.object({enabled:w.boolean().optional(),cert:w.string().optional(),key:w.string().optional()}),nh=w.object({enabled:w.boolean(),port:w.coerce.number().int().min(1).max(65535),host:w.string(),token:w.string().optional(),corsOrigin:w.string().optional(),webUi:w.boolean().optional(),tls:rh.optional()}),oh=w.object({name:w.string(),command:w.string(),argsTemplate:w.array(w.string()),promptVia:w.enum(["arg","stdin"]).default("arg"),env:w.record(w.string()).optional(),cwd:w.string().optional(),timeoutMs:w.number().max(9e5).optional()}),ih=w.object({token:w.string(),baseUrl:w.string().optional()}),ah=w.object({token:w.string(),baseUrl:w.string().optional()}),ch=w.object({provider:w.enum(["github","gitlab"]),baseBranch:w.string().optional(),github:ih.optional(),gitlab:ah.optional()}),lh=w.object({enabled:w.boolean(),agents:w.array(oh),forge:ch.optional()}),dh=w.object({name:w.string(),buildCommands:w.array(w.string()),testCommands:w.array(w.string()),description:w.string().optional()}),uh=w.object({enabled:w.boolean(),templates:w.array(dh).optional(),defaultMaxDurationHours:w.number().optional(),defaultProgressEveryN:w.number().optional(),maxFixAttemptsPerIteration:w.number().optional(),buildCommandTimeoutMs:w.number().optional()}),ph=w.object({apiKey:w.string(),supadata:w.object({enabled:w.boolean().optional(),apiKey:w.string().optional()}).optional()}),mh=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),verifyTls:w.boolean().optional(),defaultNode:w.string().optional()}),hh=w.object({baseUrl:w.string(),apiKey:w.string().optional(),username:w.string().optional(),password:w.string().optional(),site:w.string().optional(),verifyTls:w.boolean().optional()}),fh=w.object({baseUrl:w.string(),accessToken:w.string(),verifyTls:w.boolean().optional()}),gh=w.object({serverUrl:w.string(),username:w.string(),password:w.string(),addressBookPath:w.string().optional()}),yh=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),wh=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Th=w.object({provider:w.enum(["carddav","google","microsoft"]),carddav:gh.optional(),google:yh.optional(),microsoft:wh.optional()}),_h=w.object({socketPath:w.string().optional(),host:w.string().optional(),verifyTls:w.boolean().optional()}),kh=w.object({clientId:w.string()}),bh=w.object({apiKey:w.string()}),Eh=w.object({gridName:w.string().optional(),gridUsageCt:w.coerce.number().optional(),gridLossCt:w.coerce.number().optional(),gridCapacityFee:w.coerce.number().optional(),gridMeterFee:w.coerce.number().optional()}),Sh=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),$h=w.object({maxHistoryMessages:w.number().min(10).max(500).optional()}).optional(),vh=w.object({name:w.string(),secret:w.string(),watchId:w.string().optional(),chatId:w.string().optional(),platform:w.string().optional()}),Ah=w.object({ebay:w.object({appId:w.string(),certId:w.string()}).optional()}),Ih=w.object({location:w.string().optional(),homeAddress:w.string().optional(),officeAddress:w.string().optional(),homeAssistant:w.object({entities:w.array(w.string()).optional(),domains:w.array(w.string()).optional()}).optional()}),Rh=w.object({enabled:w.boolean().optional(),schedule:w.enum(["morning_noon_evening","hourly","half_hourly"]).optional(),tier:w.enum(["fast","default"]).optional(),deduplicationHours:w.number().optional()}),xh=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),maxAgeHours:w.coerce.number().optional(),verifyTls:w.boolean().optional()}),Xi=w.object({name:w.string(),telegram:gl,discord:yl.optional(),whatsapp:wl.optional(),matrix:Tl.optional(),signal:_l.optional(),llm:qm,storage:kl,logger:bl,security:El,search:Gm.optional(),email:Km.optional(),speech:Xm.optional(),calendar:Zm.optional(),mcp:eh.optional(),codeSandbox:th.optional(),activeLearning:sh.optional(),api:nh.optional(),codeAgents:lh.optional(),projectAgents:uh.optional(),youtube:ph.optional(),proxmox:mh.optional(),unifi:hh.optional(),homeassistant:fh.optional(),contacts:Th.optional(),docker:_h.optional(),bmw:kh.optional(),routing:bh.optional(),todo:Sh.optional(),energy:Eh.optional(),marketplace:Ah.optional(),briefing:Ih.optional(),reasoning:Rh.optional(),webhooks:w.array(vh).optional(),proxmoxBackup:xh.optional(),conversation:$h})});var Yi,Ji=T(()=>{"use strict";Yi={name:"Alfred",telegram:{token:"",enabled:!1},discord:{token:"",enabled:!1},whatsapp:{enabled:!1,dataPath:"./data/whatsapp"},matrix:{homeserverUrl:"https://matrix.org",accessToken:"",userId:"",enabled:!1},signal:{apiUrl:"http://localhost:8080",phoneNumber:"",enabled:!1},llm:{provider:"anthropic",model:"claude-sonnet-4-20250514",temperature:.7,maxTokens:4096},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0},security:{rulesPath:"./config/rules",defaultEffect:"deny"},api:{enabled:!0,port:3420,host:"127.0.0.1"},conversation:{maxHistoryMessages:100}}});import Sl from"node:fs";import Zi from"node:path";import{config as $l}from"dotenv";import Ch from"js-yaml";function vl(l,e){let t={...l};for(let s of Object.keys(e)){let r=e[s],n=t[s];r!=null&&typeof r=="object"&&!Array.isArray(r)&&n!==null&&n!==void 0&&typeof n=="object"&&!Array.isArray(n)?t[s]=vl(n,r):t[s]=r}return t}function Lh(l){let e=l.toLowerCase();return e==="true"?!0:e==="false"?!1:l}function Dh(l){let e={...l};for(let[t,s]of Object.entries(Nh)){let r=process.env[t];if(r===void 0)continue;let n=e;for(let o=0;o<s.length-1;o++){let i=s[o];(n[i]===void 0||n[i]===null||typeof n[i]!="object")&&(n[i]={}),n[i]={...n[i]},n=n[i]}n[s[s.length-1]]=Lh(r)}return e}function Qi(){$l({override:!0})}function Mh(l){let e=Zi.resolve(l),t=process.platform==="win32"?["C:\\Windows","C:\\Program Files","C:\\Program Files (x86)"]:["/etc","/bin","/proc","/sys","/dev","/boot"];for(let s of t)if(e.startsWith(s+Zi.sep)||e.startsWith(s+"/")||e===s)throw new Error(`Storage path "${e}" is in forbidden directory ${s}`)}var Nh,fe,Al=T(()=>{"use strict";Vi();Ji();p(vl,"deepMerge");Nh={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_TELEGRAM_ENABLED:["telegram","enabled"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_DISCORD_ENABLED:["discord","enabled"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_MATRIX_ENABLED:["matrix","enabled"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],ALFRED_SIGNAL_ENABLED:["signal","enabled"],ALFRED_ANTHROPIC_API_KEY:["llm","apiKey"],ALFRED_OPENAI_API_KEY:["llm","apiKey"],ALFRED_GOOGLE_API_KEY:["llm","apiKey"],ALFRED_OPENROUTER_API_KEY:["llm","apiKey"],ALFRED_OPENWEBUI_API_KEY:["llm","apiKey"],ALFRED_LLM_PROVIDER:["llm","provider"],ALFRED_LLM_MODEL:["llm","model"],ALFRED_LLM_BASE_URL:["llm","baseUrl"],ALFRED_LLM_STRONG_PROVIDER:["llm","strong","provider"],ALFRED_LLM_STRONG_MODEL:["llm","strong","model"],ALFRED_LLM_STRONG_API_KEY:["llm","strong","apiKey"],ALFRED_LLM_FAST_PROVIDER:["llm","fast","provider"],ALFRED_LLM_FAST_MODEL:["llm","fast","model"],ALFRED_LLM_FAST_API_KEY:["llm","fast","apiKey"],ALFRED_LLM_EMBEDDINGS_PROVIDER:["llm","embeddings","provider"],ALFRED_LLM_EMBEDDINGS_MODEL:["llm","embeddings","model"],ALFRED_LLM_EMBEDDINGS_API_KEY:["llm","embeddings","apiKey"],ALFRED_LLM_LOCAL_PROVIDER:["llm","local","provider"],ALFRED_LLM_LOCAL_MODEL:["llm","local","model"],ALFRED_LLM_LOCAL_BASE_URL:["llm","local","baseUrl"],ALFRED_STORAGE_PATH:["storage","path"],ALFRED_LOG_LEVEL:["logger","level"],ALFRED_OWNER_USER_ID:["security","ownerUserId"],ALFRED_SEARCH_PROVIDER:["search","provider"],ALFRED_SEARCH_API_KEY:["search","apiKey"],ALFRED_SEARCH_BASE_URL:["search","baseUrl"],ALFRED_EMAIL_PROVIDER:["email","provider"],ALFRED_EMAIL_USER:["email","auth","user"],ALFRED_EMAIL_PASS:["email","auth","pass"],ALFRED_MICROSOFT_EMAIL_CLIENT_ID:["email","microsoft","clientId"],ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:["email","microsoft","clientSecret"],ALFRED_MICROSOFT_EMAIL_TENANT_ID:["email","microsoft","tenantId"],ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:["email","microsoft","refreshToken"],ALFRED_SPEECH_PROVIDER:["speech","provider"],ALFRED_SPEECH_API_KEY:["speech","apiKey"],ALFRED_SPEECH_BASE_URL:["speech","baseUrl"],ALFRED_CALENDAR_PROVIDER:["calendar","provider"],ALFRED_CALDAV_SERVER_URL:["calendar","caldav","serverUrl"],ALFRED_CALDAV_USERNAME:["calendar","caldav","username"],ALFRED_CALDAV_PASSWORD:["calendar","caldav","password"],ALFRED_GOOGLE_CALENDAR_CLIENT_ID:["calendar","google","clientId"],ALFRED_GOOGLE_CALENDAR_CLIENT_SECRET:["calendar","google","clientSecret"],ALFRED_GOOGLE_CALENDAR_REFRESH_TOKEN:["calendar","google","refreshToken"],ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:["calendar","microsoft","clientId"],ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:["calendar","microsoft","clientSecret"],ALFRED_MICROSOFT_CALENDAR_TENANT_ID:["calendar","microsoft","tenantId"],ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:["calendar","microsoft","refreshToken"],ALFRED_FORGE_PROVIDER:["codeAgents","forge","provider"],ALFRED_FORGE_BASE_BRANCH:["codeAgents","forge","baseBranch"],ALFRED_GITHUB_TOKEN:["codeAgents","forge","github","token"],ALFRED_GITHUB_BASE_URL:["codeAgents","forge","github","baseUrl"],ALFRED_GITLAB_TOKEN:["codeAgents","forge","gitlab","token"],ALFRED_GITLAB_BASE_URL:["codeAgents","forge","gitlab","baseUrl"],ALFRED_PROXMOX_BASE_URL:["proxmox","baseUrl"],ALFRED_PROXMOX_TOKEN_ID:["proxmox","tokenId"],ALFRED_PROXMOX_TOKEN_SECRET:["proxmox","tokenSecret"],ALFRED_PROXMOX_VERIFY_TLS:["proxmox","verifyTls"],ALFRED_UNIFI_BASE_URL:["unifi","baseUrl"],ALFRED_UNIFI_API_KEY:["unifi","apiKey"],ALFRED_UNIFI_USERNAME:["unifi","username"],ALFRED_UNIFI_PASSWORD:["unifi","password"],ALFRED_UNIFI_SITE:["unifi","site"],ALFRED_UNIFI_VERIFY_TLS:["unifi","verifyTls"],ALFRED_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],ALFRED_HOMEASSISTANT_VERIFY_TLS:["homeassistant","verifyTls"],ALFRED_CONTACTS_PROVIDER:["contacts","provider"],ALFRED_CARDDAV_CONTACTS_SERVER_URL:["contacts","carddav","serverUrl"],ALFRED_CARDDAV_CONTACTS_USERNAME:["contacts","carddav","username"],ALFRED_CARDDAV_CONTACTS_PASSWORD:["contacts","carddav","password"],ALFRED_GOOGLE_CONTACTS_CLIENT_ID:["contacts","google","clientId"],ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET:["contacts","google","clientSecret"],ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN:["contacts","google","refreshToken"],ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:["contacts","microsoft","clientId"],ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:["contacts","microsoft","clientSecret"],ALFRED_MICROSOFT_CONTACTS_TENANT_ID:["contacts","microsoft","tenantId"],ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:["contacts","microsoft","refreshToken"],ALFRED_DOCKER_SOCKET_PATH:["docker","socketPath"],ALFRED_DOCKER_HOST:["docker","host"],ALFRED_DOCKER_VERIFY_TLS:["docker","verifyTls"],ALFRED_BMW_CLIENT_ID:["bmw","clientId"],ALFRED_YOUTUBE_API_KEY:["youtube","apiKey"],ALFRED_SUPADATA_API_KEY:["youtube","supadata","apiKey"],ALFRED_ROUTING_API_KEY:["routing","apiKey"],ALFRED_MICROSOFT_TODO_CLIENT_ID:["todo","clientId"],ALFRED_MICROSOFT_TODO_CLIENT_SECRET:["todo","clientSecret"],ALFRED_MICROSOFT_TODO_TENANT_ID:["todo","tenantId"],ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:["todo","refreshToken"],ALFRED_ENERGY_GRID_NAME:["energy","gridName"],ALFRED_ENERGY_GRID_USAGE_CT:["energy","gridUsageCt"],ALFRED_ENERGY_GRID_LOSS_CT:["energy","gridLossCt"],ALFRED_ENERGY_GRID_CAPACITY_FEE:["energy","gridCapacityFee"],ALFRED_ENERGY_GRID_METER_FEE:["energy","gridMeterFee"],ALFRED_PBS_BASE_URL:["proxmoxBackup","baseUrl"],ALFRED_PBS_TOKEN_ID:["proxmoxBackup","tokenId"],ALFRED_PBS_TOKEN_SECRET:["proxmoxBackup","tokenSecret"],ALFRED_PBS_MAX_AGE_HOURS:["proxmoxBackup","maxAgeHours"],ALFRED_PBS_VERIFY_TLS:["proxmoxBackup","verifyTls"],ALFRED_EBAY_APP_ID:["marketplace","ebay","appId"],ALFRED_EBAY_CERT_ID:["marketplace","ebay","certId"],ALFRED_BRIEFING_LOCATION:["briefing","location"],ALFRED_BRIEFING_HOME_ADDRESS:["briefing","homeAddress"],ALFRED_BRIEFING_OFFICE_ADDRESS:["briefing","officeAddress"],ALFRED_REASONING_ENABLED:["reasoning","enabled"],ALFRED_REASONING_SCHEDULE:["reasoning","schedule"],ALFRED_REASONING_TIER:["reasoning","tier"]};p(Lh,"coerceEnvValue");p(Dh,"applyEnvOverrides");p(Qi,"reloadDotenv");fe=class{static{p(this,"ConfigLoader")}loadConfig(e){$l();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Zi.resolve(t);if(Sl.existsSync(r)){let f=Sl.readFileSync(r,"utf-8"),g=Ch.load(f);g&&typeof g=="object"&&(s=g)}let n=vl(Yi,s),o=Dh(n),i=["strong","fast","embeddings","local"],a=o.llm;if(a&&"provider"in a&&i.some(g=>a[g]&&typeof a[g]=="object")){let g={};for(let[_,S]of Object.entries(a))!i.includes(_)&&_!=="default"&&(g[_]=S);let y={default:g};for(let _ of i)a[_]&&(y[_]=a[_]);o.llm=y}let c=Xi.parse(o),d=c.llm;d&&"provider"in d&&(c.llm={default:d});let u=c.llm;if(u&&typeof u=="object"){let f=u.apiKey??u.default?.apiKey;if(f)for(let g of["default","strong","fast","embeddings","local"]){let y=u[g];y&&!y.apiKey&&(y.apiKey=f)}}let m=c.email;if(m&&!("accounts"in m))c.email={accounts:[{name:"default",...m}]};else if(m&&"accounts"in m&&"microsoft"in m){let f=m.microsoft;if(f){let y=m.accounts.find(_=>_.provider==="microsoft");if(y){let _=y.microsoft??{};y.microsoft={..._,...f}}delete m.microsoft}}let h=c.storage;return h?.path&&typeof h.path=="string"&&Mh(h.path),c}};p(Mh,"validateStoragePath")});var ot=T(()=>{"use strict";Vi();Ji();Al()});import ea from"pino";function Ir(l,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=ea.transport({target:"pino-pretty",options:{colorize:!0}});return ea({name:l,level:t,redact:Il},r)}return ea({name:l,level:t,redact:Il})}var Il,Rl=T(()=>{"use strict";Il={paths:["**.apiKey","**.token","**.password","**.secret","**.accessToken","**.refreshToken","**.clientSecret","**.Authorization","**.authorization","**.bearer","**.credential","**.jwt","**.x-api-key","**.x-auth-token"],censor:"[REDACTED]"};p(Ir,"createLogger")});import bw from"pino";var xl=T(()=>{"use strict"});var ta=T(()=>{"use strict";Rl();xl()});var Ut,co=T(()=>{"use strict";Ut=class{static{p(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
3
3
  CREATE TABLE IF NOT EXISTS _migrations (
4
4
  version INTEGER PRIMARY KEY,
5
5
  description TEXT,
6
6
  applied_at TEXT NOT NULL
7
7
  )
8
- `)}getCurrentVersion(){return this.db.prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}migrate(e){let t=[...e].sort((r,n)=>r.version-n.version),s=this.getCurrentVersion();for(let r of t){if(r.version<=s)continue;this.db.transaction(()=>{r.up(this.db),this.db.prepare("INSERT INTO _migrations (version, description, applied_at) VALUES (?, ?, ?)").run(r.version,r.description,new Date().toISOString())})()}}getAppliedMigrations(){return this.db.prepare("SELECT version, applied_at FROM _migrations ORDER BY version ASC").all().map(t=>({version:t.version,appliedAt:t.applied_at}))}}});var co,sa=T(()=>{"use strict";ao();co=[{version:1,description:"Initial schema \u2014 conversations, messages, users, audit_log",up(l){}},{version:2,description:"Add plugin_skills table for tracking loaded external plugins",up(l){l.exec(`
8
+ `)}getCurrentVersion(){return this.db.prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}migrate(e){let t=[...e].sort((r,n)=>r.version-n.version),s=this.getCurrentVersion();for(let r of t){if(r.version<=s)continue;this.db.transaction(()=>{r.up(this.db),this.db.prepare("INSERT INTO _migrations (version, description, applied_at) VALUES (?, ?, ?)").run(r.version,r.description,new Date().toISOString())})()}}getAppliedMigrations(){return this.db.prepare("SELECT version, applied_at FROM _migrations ORDER BY version ASC").all().map(t=>({version:t.version,appliedAt:t.applied_at}))}}});var lo,sa=T(()=>{"use strict";co();lo=[{version:1,description:"Initial schema \u2014 conversations, messages, users, audit_log",up(l){}},{version:2,description:"Add plugin_skills table for tracking loaded external plugins",up(l){l.exec(`
9
9
  CREATE TABLE IF NOT EXISTS plugin_skills (
10
10
  name TEXT PRIMARY KEY,
11
11
  file_path TEXT NOT NULL,
@@ -390,7 +390,7 @@ var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0})
390
390
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
391
391
  );
392
392
  CREATE INDEX IF NOT EXISTS idx_project_sessions_task ON project_agent_sessions(task_id);
393
- `)}}]});import Cl from"better-sqlite3";import Rr from"node:fs";import lo from"node:path";var ht,Nl=T(()=>{"use strict";ao();sa();ht=class{static{p(this,"Database")}db;constructor(e){let t=lo.dirname(e);Rr.mkdirSync(t,{recursive:!0});let s=Rr.statSync(e,{throwIfNoEntry:!1});if(s&&s.size>1e5){let r=lo.join(lo.dirname(e),"backups");Rr.mkdirSync(r,{recursive:!0});let n=lo.join(r,`alfred-${new Date().toISOString().slice(0,10)}.db`);if(!Rr.existsSync(n))try{let o=new Cl(e,{readonly:!0});try{o.pragma("wal_checkpoint(TRUNCATE)")}catch{}o.close(),Rr.copyFileSync(e,n)}catch(o){console.warn(`[Database] Backup failed: ${o instanceof Error?o.message:String(o)}`)}}this.db=new Cl(e),this.db.pragma("journal_mode = WAL"),this.db.pragma("foreign_keys = ON"),this.db.pragma("busy_timeout = 5000"),this.initTables(),this.runMigrations()}initTables(){this.db.exec(`
393
+ `)}}]});import Cl from"better-sqlite3";import Rr from"node:fs";import uo from"node:path";var ht,Nl=T(()=>{"use strict";co();sa();ht=class{static{p(this,"Database")}db;constructor(e){let t=uo.dirname(e);Rr.mkdirSync(t,{recursive:!0});let s=Rr.statSync(e,{throwIfNoEntry:!1});if(s&&s.size>1e5){let r=uo.join(uo.dirname(e),"backups");Rr.mkdirSync(r,{recursive:!0});let n=uo.join(r,`alfred-${new Date().toISOString().slice(0,10)}.db`);if(!Rr.existsSync(n))try{let o=new Cl(e,{readonly:!0});try{o.pragma("wal_checkpoint(TRUNCATE)")}catch{}o.close(),Rr.copyFileSync(e,n)}catch(o){console.warn(`[Database] Backup failed: ${o instanceof Error?o.message:String(o)}`)}}this.db=new Cl(e),this.db.pragma("journal_mode = WAL"),this.db.pragma("foreign_keys = ON"),this.db.pragma("busy_timeout = 5000"),this.initTables(),this.runMigrations()}initTables(){this.db.exec(`
394
394
  CREATE TABLE IF NOT EXISTS conversations (
395
395
  id TEXT PRIMARY KEY,
396
396
  platform TEXT NOT NULL,
@@ -440,7 +440,7 @@ var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0})
440
440
 
441
441
  CREATE UNIQUE INDEX IF NOT EXISTS idx_users_platform
442
442
  ON users(platform, platform_user_id);
443
- `)}runMigrations(){new Ut(this.db).migrate(co)}getDb(){return this.db}close(){this.db.close()}}});import Ll from"node:crypto";var ss,Dl=T(()=>{"use strict";ss=class{static{p(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),n={id:Ll.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
443
+ `)}runMigrations(){new Ut(this.db).migrate(lo)}getDb(){return this.db}close(){this.db.close()}}});import Ll from"node:crypto";var ss,Dl=T(()=>{"use strict";ss=class{static{p(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),n={id:Ll.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
444
444
  INSERT INTO conversations (id, platform, chat_id, user_id, created_at, updated_at)
445
445
  VALUES (?, ?, ?, ?, ?, ?)
446
446
  `).run(n.id,n.platform,n.chatId,n.userId,n.createdAt,n.updatedAt),n}findById(e){let t=this.db.prepare("SELECT * FROM conversations WHERE id = ?").get(e);if(t)return this.mapRow(t)}findByPlatformChat(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND chat_id = ?").get(e,t);if(s)return this.mapRow(s)}findByPlatformAndUser(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND user_id = ? ORDER BY updated_at DESC LIMIT 1").get(e,t);if(s)return this.mapRow(s)}addMessage(e,t,s,r){let n={id:Ll.randomUUID(),conversationId:e,role:t,content:s,toolCalls:r,createdAt:new Date().toISOString()};return this.db.prepare(`
@@ -502,7 +502,7 @@ var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0})
502
502
  UPDATE background_tasks
503
503
  SET status = 'cancelled', completed_at = datetime('now')
504
504
  WHERE id = ? AND status IN ('pending', 'running', 'checkpointed', 'resuming')
505
- `).run(e)}updatePersistentConfig(e,t){this.db.prepare("UPDATE background_tasks SET max_duration_hours = ? WHERE id = ?").run(t,e)}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at,agentState:e.agent_state,checkpointAt:e.checkpoint_at,resumeCount:e.resume_count??0,maxDurationHours:e.max_duration_hours}}}});var Wl=T(()=>{"use strict"});var zl=T(()=>{"use strict"});var ql=T(()=>{"use strict"});var Gl=T(()=>{"use strict"});var Kl=T(()=>{"use strict"});var Xl=T(()=>{"use strict"});var Vl=T(()=>{"use strict"});var Yl=T(()=>{"use strict"});function Wh(l,e){let t=l.trim().split(/\s+/);if(t.length!==5)return!1;let s=e.getMinutes(),r=e.getHours(),n=e.getDate(),o=e.getMonth()+1,i=e.getDay();return ds(t[0],s)&&ds(t[1],r)&&ds(t[2],n)&&ds(t[3],o)&&ds(t[4],i)}function uo(l,e,t=1440*6e4){let s=e.getTime()+t,r=new Date(e);for(r.setSeconds(0,0),r.setMinutes(r.getMinutes()+1);r.getTime()<=s;){if(Wh(l,r))return r;r.setMinutes(r.getMinutes()+1)}return null}function ds(l,e){if(l.includes(","))return l.split(",").some(n=>ds(n.trim(),e));if(l==="*")return!0;let t=/^\*\/(\d+)$/.exec(l);if(t){let n=parseInt(t[1],10);return n>0&&e%n===0}let s=/^(\d+)-(\d+)(?:\/(\d+))?$/.exec(l);if(s){let n=parseInt(s[1],10),o=parseInt(s[2],10),i=s[3]?parseInt(s[3],10):1;return e<n||e>o?!1:i>0&&(e-n)%i===0}let r=parseInt(l,10);return isNaN(r)?!1:e===r}var Jl=T(()=>{"use strict";p(Wh,"matchesCron");p(uo,"getNextCronDate");p(ds,"matchCronField")});var ra=T(()=>{"use strict";Wl();zl();ql();Gl();Kl();Xl();Vl();Yl();Jl()});import{randomUUID as zh}from"node:crypto";var us,Zl=T(()=>{"use strict";ra();us=class{static{p(this,"ScheduledActionRepository")}db;constructor(e){this.db=e}countEnabled(){return this.db.prepare("SELECT COUNT(*) as cnt FROM scheduled_actions WHERE enabled = 1").get().cnt}create(e){let t=new Date().toISOString(),s=zh(),r=this.calculateInitialNextRun(e.scheduleType,e.scheduleValue);return this.db.prepare(`
505
+ `).run(e)}updatePersistentConfig(e,t){this.db.prepare("UPDATE background_tasks SET max_duration_hours = ? WHERE id = ?").run(t,e)}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at,agentState:e.agent_state,checkpointAt:e.checkpoint_at,resumeCount:e.resume_count??0,maxDurationHours:e.max_duration_hours}}}});var Wl=T(()=>{"use strict"});var zl=T(()=>{"use strict"});var ql=T(()=>{"use strict"});var Gl=T(()=>{"use strict"});var Kl=T(()=>{"use strict"});var Xl=T(()=>{"use strict"});var Vl=T(()=>{"use strict"});var Yl=T(()=>{"use strict"});function Wh(l,e){let t=l.trim().split(/\s+/);if(t.length!==5)return!1;let s=e.getMinutes(),r=e.getHours(),n=e.getDate(),o=e.getMonth()+1,i=e.getDay();return ds(t[0],s)&&ds(t[1],r)&&ds(t[2],n)&&ds(t[3],o)&&ds(t[4],i)}function po(l,e,t=1440*6e4){let s=e.getTime()+t,r=new Date(e);for(r.setSeconds(0,0),r.setMinutes(r.getMinutes()+1);r.getTime()<=s;){if(Wh(l,r))return r;r.setMinutes(r.getMinutes()+1)}return null}function ds(l,e){if(l.includes(","))return l.split(",").some(n=>ds(n.trim(),e));if(l==="*")return!0;let t=/^\*\/(\d+)$/.exec(l);if(t){let n=parseInt(t[1],10);return n>0&&e%n===0}let s=/^(\d+)-(\d+)(?:\/(\d+))?$/.exec(l);if(s){let n=parseInt(s[1],10),o=parseInt(s[2],10),i=s[3]?parseInt(s[3],10):1;return e<n||e>o?!1:i>0&&(e-n)%i===0}let r=parseInt(l,10);return isNaN(r)?!1:e===r}var Jl=T(()=>{"use strict";p(Wh,"matchesCron");p(po,"getNextCronDate");p(ds,"matchCronField")});var ra=T(()=>{"use strict";Wl();zl();ql();Gl();Kl();Xl();Vl();Yl();Jl()});import{randomUUID as zh}from"node:crypto";var us,Zl=T(()=>{"use strict";ra();us=class{static{p(this,"ScheduledActionRepository")}db;constructor(e){this.db=e}countEnabled(){return this.db.prepare("SELECT COUNT(*) as cnt FROM scheduled_actions WHERE enabled = 1").get().cnt}create(e){let t=new Date().toISOString(),s=zh(),r=this.calculateInitialNextRun(e.scheduleType,e.scheduleValue);return this.db.prepare(`
506
506
  INSERT INTO scheduled_actions
507
507
  (id, user_id, platform, chat_id, name, description, schedule_type, schedule_value,
508
508
  skill_name, skill_input, prompt_template, enabled, next_run_at, created_at)
@@ -513,7 +513,7 @@ var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0})
513
513
  UPDATE scheduled_actions
514
514
  SET last_run_at = ?, next_run_at = ?
515
515
  WHERE id = ?
516
- `).run(t,s,e)}setEnabled(e,t){return this.db.prepare("UPDATE scheduled_actions SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM scheduled_actions WHERE id = ?").run(e).changes>0}calculateInitialNextRun(e,t){let s=new Date;switch(e){case"interval":{let r=parseInt(t,10);return isNaN(r)||r<=0?null:new Date(s.getTime()+r*6e4).toISOString()}case"once":return new Date(t).toISOString();case"cron":return uo(t,s)?.toISOString()??null;default:return null}}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as Ql}from"node:crypto";var ps,ed=T(()=>{"use strict";ps=class{static{p(this,"DocumentRepository")}db;constructor(e){this.db=e}createDocument(e,t,s,r,n){let o=Ql(),i=new Date().toISOString();return this.db.prepare("INSERT INTO documents (id, user_id, filename, mime_type, size_bytes, chunk_count, content_hash, created_at) VALUES (?, ?, ?, ?, ?, 0, ?, ?)").run(o,e,t,s,r,n??null,i),{id:o,userId:e,filename:t,mimeType:s,sizeBytes:r,chunkCount:0,contentHash:n,createdAt:i}}findByContentHash(e,t){let s=this.db.prepare("SELECT * FROM documents WHERE user_id = ? AND content_hash = ? ORDER BY chunk_count DESC LIMIT 1").get(e,t);return s?this.mapDocumentRow(s):void 0}updateChunkCount(e,t){this.db.prepare("UPDATE documents SET chunk_count = ? WHERE id = ?").run(t,e)}addChunk(e,t,s,r){let n=Ql(),o=new Date().toISOString();return this.db.prepare("INSERT INTO document_chunks (id, document_id, chunk_index, content, embedding_id, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(n,e,t,s,r??null,o),{id:n,documentId:e,chunkIndex:t,content:s,embeddingId:r,createdAt:o}}getDocument(e){let t=this.db.prepare("SELECT * FROM documents WHERE id = ?").get(e);return t?this.mapDocumentRow(t):void 0}getChunks(e){return this.db.prepare("SELECT * FROM document_chunks WHERE document_id = ? ORDER BY chunk_index ASC").all(e).map(s=>this.mapChunkRow(s))}listByUser(e){return this.db.prepare("SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapDocumentRow(s))}deleteDocument(e){this.db.transaction(()=>{let s=this.db.prepare("SELECT embedding_id FROM document_chunks WHERE document_id = ? AND embedding_id IS NOT NULL").all(e);if(s.length>0){let r=s.map(o=>o.embedding_id),n=r.map(()=>"?").join(", ");this.db.prepare(`DELETE FROM embeddings WHERE id IN (${n})`).run(...r)}this.db.prepare("DELETE FROM document_chunks WHERE document_id = ?").run(e),this.db.prepare("DELETE FROM documents WHERE id = ?").run(e)})()}getChunksByEmbeddingIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(", ");return this.db.prepare(`SELECT * FROM document_chunks WHERE embedding_id IN (${t}) ORDER BY chunk_index ASC`).all(...e).map(r=>this.mapChunkRow(r))}mapDocumentRow(e){return{id:e.id,userId:e.user_id,filename:e.filename,mimeType:e.mime_type,sizeBytes:e.size_bytes,chunkCount:e.chunk_count,contentHash:e.content_hash||void 0,createdAt:e.created_at}}mapChunkRow(e){return{id:e.id,documentId:e.document_id,chunkIndex:e.chunk_index,content:e.content,embeddingId:e.embedding_id||void 0,createdAt:e.created_at}}}});import{randomUUID as qh}from"node:crypto";var ms,td=T(()=>{"use strict";ms=class{static{p(this,"TodoRepository")}db;constructor(e){this.db=e}add(e,t,s){let r=new Date().toISOString(),n=qh(),o=s?.list??"default",i=s?.priority??"normal";return this.db.prepare("INSERT INTO todos (id, user_id, list, title, description, priority, due_date, completed, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)").run(n,e,o,t,s?.description??null,i,s?.dueDate??null,r,r),{id:n,userId:e,list:o,title:t,description:s?.description,priority:i,dueDate:s?.dueDate,completed:!1,createdAt:r,updatedAt:r}}list(e,t,s=!1){let r="SELECT * FROM todos WHERE user_id = ?",n=[e];return t&&(r+=" AND list = ?",n.push(t)),s||(r+=" AND completed = 0"),r+=" ORDER BY CASE priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'normal' THEN 2 WHEN 'low' THEN 3 END, created_at DESC",this.db.prepare(r).all(...n).map(i=>this.mapRow(i))}getById(e){let t=this.db.prepare("SELECT * FROM todos WHERE id = ?").get(e);return t?this.mapRow(t):void 0}complete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 1, updated_at = ? WHERE id = ? AND completed = 0").run(t,e).changes>0}uncomplete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 0, updated_at = ? WHERE id = ? AND completed = 1").run(t,e).changes>0}delete(e){return this.db.prepare("DELETE FROM todos WHERE id = ?").run(e).changes>0}clearCompleted(e,t){let s="DELETE FROM todos WHERE user_id = ? AND completed = 1",r=[e];return t&&(s+=" AND list = ?",r.push(t)),this.db.prepare(s).run(...r).changes}getLists(e){return this.db.prepare(`SELECT list,
516
+ `).run(t,s,e)}setEnabled(e,t){return this.db.prepare("UPDATE scheduled_actions SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM scheduled_actions WHERE id = ?").run(e).changes>0}calculateInitialNextRun(e,t){let s=new Date;switch(e){case"interval":{let r=parseInt(t,10);return isNaN(r)||r<=0?null:new Date(s.getTime()+r*6e4).toISOString()}case"once":return new Date(t).toISOString();case"cron":return po(t,s)?.toISOString()??null;default:return null}}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as Ql}from"node:crypto";var ps,ed=T(()=>{"use strict";ps=class{static{p(this,"DocumentRepository")}db;constructor(e){this.db=e}createDocument(e,t,s,r,n){let o=Ql(),i=new Date().toISOString();return this.db.prepare("INSERT INTO documents (id, user_id, filename, mime_type, size_bytes, chunk_count, content_hash, created_at) VALUES (?, ?, ?, ?, ?, 0, ?, ?)").run(o,e,t,s,r,n??null,i),{id:o,userId:e,filename:t,mimeType:s,sizeBytes:r,chunkCount:0,contentHash:n,createdAt:i}}findByContentHash(e,t){let s=this.db.prepare("SELECT * FROM documents WHERE user_id = ? AND content_hash = ? ORDER BY chunk_count DESC LIMIT 1").get(e,t);return s?this.mapDocumentRow(s):void 0}updateChunkCount(e,t){this.db.prepare("UPDATE documents SET chunk_count = ? WHERE id = ?").run(t,e)}addChunk(e,t,s,r){let n=Ql(),o=new Date().toISOString();return this.db.prepare("INSERT INTO document_chunks (id, document_id, chunk_index, content, embedding_id, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(n,e,t,s,r??null,o),{id:n,documentId:e,chunkIndex:t,content:s,embeddingId:r,createdAt:o}}getDocument(e){let t=this.db.prepare("SELECT * FROM documents WHERE id = ?").get(e);return t?this.mapDocumentRow(t):void 0}getChunks(e){return this.db.prepare("SELECT * FROM document_chunks WHERE document_id = ? ORDER BY chunk_index ASC").all(e).map(s=>this.mapChunkRow(s))}listByUser(e){return this.db.prepare("SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapDocumentRow(s))}deleteDocument(e){this.db.transaction(()=>{let s=this.db.prepare("SELECT embedding_id FROM document_chunks WHERE document_id = ? AND embedding_id IS NOT NULL").all(e);if(s.length>0){let r=s.map(o=>o.embedding_id),n=r.map(()=>"?").join(", ");this.db.prepare(`DELETE FROM embeddings WHERE id IN (${n})`).run(...r)}this.db.prepare("DELETE FROM document_chunks WHERE document_id = ?").run(e),this.db.prepare("DELETE FROM documents WHERE id = ?").run(e)})()}getChunksByEmbeddingIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(", ");return this.db.prepare(`SELECT * FROM document_chunks WHERE embedding_id IN (${t}) ORDER BY chunk_index ASC`).all(...e).map(r=>this.mapChunkRow(r))}mapDocumentRow(e){return{id:e.id,userId:e.user_id,filename:e.filename,mimeType:e.mime_type,sizeBytes:e.size_bytes,chunkCount:e.chunk_count,contentHash:e.content_hash||void 0,createdAt:e.created_at}}mapChunkRow(e){return{id:e.id,documentId:e.document_id,chunkIndex:e.chunk_index,content:e.content,embeddingId:e.embedding_id||void 0,createdAt:e.created_at}}}});import{randomUUID as qh}from"node:crypto";var ms,td=T(()=>{"use strict";ms=class{static{p(this,"TodoRepository")}db;constructor(e){this.db=e}add(e,t,s){let r=new Date().toISOString(),n=qh(),o=s?.list??"default",i=s?.priority??"normal";return this.db.prepare("INSERT INTO todos (id, user_id, list, title, description, priority, due_date, completed, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)").run(n,e,o,t,s?.description??null,i,s?.dueDate??null,r,r),{id:n,userId:e,list:o,title:t,description:s?.description,priority:i,dueDate:s?.dueDate,completed:!1,createdAt:r,updatedAt:r}}list(e,t,s=!1){let r="SELECT * FROM todos WHERE user_id = ?",n=[e];return t&&(r+=" AND list = ?",n.push(t)),s||(r+=" AND completed = 0"),r+=" ORDER BY CASE priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'normal' THEN 2 WHEN 'low' THEN 3 END, created_at DESC",this.db.prepare(r).all(...n).map(i=>this.mapRow(i))}getById(e){let t=this.db.prepare("SELECT * FROM todos WHERE id = ?").get(e);return t?this.mapRow(t):void 0}complete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 1, updated_at = ? WHERE id = ? AND completed = 0").run(t,e).changes>0}uncomplete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 0, updated_at = ? WHERE id = ? AND completed = 1").run(t,e).changes>0}delete(e){return this.db.prepare("DELETE FROM todos WHERE id = ?").run(e).changes>0}clearCompleted(e,t){let s="DELETE FROM todos WHERE user_id = ? AND completed = 1",r=[e];return t&&(s+=" AND list = ?",r.push(t)),this.db.prepare(s).run(...r).changes}getLists(e){return this.db.prepare(`SELECT list,
517
517
  SUM(CASE WHEN completed = 0 THEN 1 ELSE 0 END) as open,
518
518
  SUM(CASE WHEN completed = 1 THEN 1 ELSE 0 END) as completed,
519
519
  COUNT(*) as total
@@ -619,12 +619,12 @@ var hl=Object.defineProperty;var p=(l,e)=>hl(l,"name",{value:e,configurable:!0})
619
619
  `).run(s,e,t,r),{id:s,chainId:e,status:"running",stepsCompleted:0,totalSteps:t,startedAt:r}}updateExecution(e,t){let s=[],r=[];t.status!==void 0&&(s.push("status = ?"),r.push(t.status)),t.stepsCompleted!==void 0&&(s.push("steps_completed = ?"),r.push(t.stepsCompleted)),t.stepResults!==void 0&&(s.push("step_results = ?"),r.push(t.stepResults)),t.error!==void 0&&(s.push("error = ?"),r.push(t.error)),t.completedAt!==void 0&&(s.push("completed_at = ?"),r.push(t.completedAt)),s.length!==0&&(r.push(e),this.db.prepare(`UPDATE workflow_executions SET ${s.join(", ")} WHERE id = ?`).run(...r))}getExecution(e){let t=this.db.prepare("SELECT * FROM workflow_executions WHERE id = ?").get(e);return t?this.mapExecution(t):void 0}getRecentExecutions(e,t=10){return this.db.prepare("SELECT * FROM workflow_executions WHERE chain_id = ? ORDER BY started_at DESC LIMIT ?").all(e,t).map(r=>this.mapExecution(r))}mapChain(e){return{id:e.id,name:e.name,userId:e.user_id,chatId:e.chat_id,platform:e.platform,steps:JSON.parse(e.steps),triggerType:e.trigger_type,triggerConfig:e.trigger_config?JSON.parse(e.trigger_config):void 0,enabled:e.enabled===1,createdAt:e.created_at}}mapExecution(e){return{id:e.id,chainId:e.chain_id,status:e.status,stepsCompleted:e.steps_completed,totalSteps:e.total_steps,stepResults:e.step_results,error:e.error,startedAt:e.started_at,completedAt:e.completed_at}}}});import{randomUUID as Vh}from"node:crypto";var _s,ud=T(()=>{"use strict";_s=class{static{p(this,"FeedbackRepository")}db;constructor(e){this.db=e}recordEvent(e,t,s,r,n,o){let i=Vh(),a=new Date().toISOString();return this.db.prepare(`
620
620
  INSERT INTO feedback_events (id, user_id, feedback_type, source_id, context_key, description, raw_context, occurred_at)
621
621
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
622
- `).run(i,e,t,s??null,r,n,o?JSON.stringify(o):null,a),{id:i,userId:e,feedbackType:t,sourceId:s,contextKey:r,description:n,rawContext:o?JSON.stringify(o):void 0,occurredAt:a}}countEvents(e,t,s){return s?this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ? AND occurred_at >= ?").get(e,t,s).cnt:this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ?").get(e,t).cnt}getRecentEvents(e,t=20){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? ORDER BY occurred_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}getEventsForKey(e,t){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? AND context_key = ? ORDER BY occurred_at DESC").all(e,t).map(r=>this.mapRow(r))}pruneOldEvents(e=180){let t=new Date(Date.now()-e*24*60*6e4).toISOString();return this.db.prepare("DELETE FROM feedback_events WHERE occurred_at < ?").run(t).changes}mapRow(e){return{id:e.id,userId:e.user_id,feedbackType:e.feedback_type,sourceId:e.source_id,contextKey:e.context_key,description:e.description,rawContext:e.raw_context,occurredAt:e.occurred_at}}}});import{randomUUID as Yh}from"node:crypto";var po,pd=T(()=>{"use strict";po=class{static{p(this,"ProjectAgentSessionRepository")}db;constructor(e){this.db=e}create(e){let t=Yh(),s=new Date().toISOString();return this.db.prepare(`
622
+ `).run(i,e,t,s??null,r,n,o?JSON.stringify(o):null,a),{id:i,userId:e,feedbackType:t,sourceId:s,contextKey:r,description:n,rawContext:o?JSON.stringify(o):void 0,occurredAt:a}}countEvents(e,t,s){return s?this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ? AND occurred_at >= ?").get(e,t,s).cnt:this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ?").get(e,t).cnt}getRecentEvents(e,t=20){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? ORDER BY occurred_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}getEventsForKey(e,t){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? AND context_key = ? ORDER BY occurred_at DESC").all(e,t).map(r=>this.mapRow(r))}pruneOldEvents(e=180){let t=new Date(Date.now()-e*24*60*6e4).toISOString();return this.db.prepare("DELETE FROM feedback_events WHERE occurred_at < ?").run(t).changes}mapRow(e){return{id:e.id,userId:e.user_id,feedbackType:e.feedback_type,sourceId:e.source_id,contextKey:e.context_key,description:e.description,rawContext:e.raw_context,occurredAt:e.occurred_at}}}});import{randomUUID as Yh}from"node:crypto";var mo,pd=T(()=>{"use strict";mo=class{static{p(this,"ProjectAgentSessionRepository")}db;constructor(e){this.db=e}create(e){let t=Yh(),s=new Date().toISOString();return this.db.prepare(`
623
623
  INSERT INTO project_agent_sessions (id, task_id, goal, cwd, agent_name, created_at, updated_at)
624
624
  VALUES (?, ?, ?, ?, ?, ?, ?)
625
- `).run(t,e.taskId,e.goal,e.cwd,e.agentName,s,s),{id:t,taskId:e.taskId,goal:e.goal,cwd:e.cwd,agentName:e.agentName,currentPhase:"planning",currentIteration:0,totalFilesChanged:0,lastBuildPassed:!1,milestones:[],createdAt:s,updatedAt:s}}getByTaskId(e){let t=this.db.prepare("SELECT * FROM project_agent_sessions WHERE task_id = ?").get(e);return t?this.mapRow(t):void 0}updateProgress(e,t){let s=["updated_at = datetime('now')"],r=[];t.currentPhase!==void 0&&(s.push("current_phase = ?"),r.push(t.currentPhase)),t.currentIteration!==void 0&&(s.push("current_iteration = ?"),r.push(t.currentIteration)),t.totalFilesChanged!==void 0&&(s.push("total_files_changed = ?"),r.push(t.totalFilesChanged)),t.lastBuildPassed!==void 0&&(s.push("last_build_passed = ?"),r.push(t.lastBuildPassed?1:0)),t.lastCommitSha!==void 0&&(s.push("last_commit_sha = ?"),r.push(t.lastCommitSha)),s.push("last_progress_at = datetime('now')"),r.push(e),this.db.prepare(`UPDATE project_agent_sessions SET ${s.join(", ")} WHERE task_id = ?`).run(...r)}addMilestone(e,t){let s=this.getByTaskId(e);if(!s)return;let r=[...s.milestones,t];this.db.prepare("UPDATE project_agent_sessions SET milestones = ?, updated_at = datetime('now') WHERE task_id = ?").run(JSON.stringify(r),e)}mapRow(e){let t=[];try{t=JSON.parse(e.milestones)}catch{}return{id:e.id,taskId:e.task_id,goal:e.goal,cwd:e.cwd,agentName:e.agent_name,currentPhase:e.current_phase,currentIteration:e.current_iteration,totalFilesChanged:e.total_files_changed,lastBuildPassed:e.last_build_passed===1,lastCommitSha:e.last_commit_sha,lastProgressAt:e.last_progress_at,milestones:t,createdAt:e.created_at,updatedAt:e.updated_at}}}});var md={};me(md,{ActivityRepository:()=>yt,AuditRepository:()=>ft,BackgroundTaskRepository:()=>ls,CalendarNotificationRepository:()=>gt,ConfirmationRepository:()=>fs,ConversationRepository:()=>ss,Database:()=>ht,DocumentRepository:()=>ps,EmbeddingRepository:()=>as,FeedbackRepository:()=>_s,LinkTokenRepository:()=>cs,MIGRATIONS:()=>co,MemoryRepository:()=>ns,Migrator:()=>Ut,NoteRepository:()=>is,ProjectAgentSessionRepository:()=>po,ReminderRepository:()=>os,ScheduledActionRepository:()=>us,SkillHealthRepository:()=>ws,SummaryRepository:()=>gs,TodoRepository:()=>ms,UsageRepository:()=>ys,UserRepository:()=>rs,WatchRepository:()=>hs,WorkflowRepository:()=>Ts});var mo=T(()=>{"use strict";Nl();Dl();Ml();Ol();Pl();ao();sa();Ul();Fl();jl();Bl();Hl();Zl();ed();td();sd();rd();nd();od();id();ad();cd();dd();ud();pd()});function it(l){if(na[l])return na[l];let e=Object.entries(na).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var na,Jh,Ne,Ft=T(()=>{"use strict";na={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Jh={maxInputTokens:128e3,maxOutputTokens:8192};p(it,"lookupContextWindow");Ne=class{static{p(this,"LLMProvider")}config;contextWindow=Jh;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Zh from"@anthropic-ai/sdk";var xr,oa=T(()=>{"use strict";Ft();xr=class extends Ne{static{p(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Zh({apiKey:this.config.apiKey,maxRetries:5});let e=it(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s},n=await this.client.messages.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s});for await(let n of r)if(n.type==="content_block_delta")n.delta.type==="text_delta"?yield{type:"text_delta",text:n.delta.text}:n.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:n.delta.partial_json}});else if(n.type==="content_block_start")n.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:n.content_block.id,name:n.content_block.name}});else if(n.type==="message_stop"){let o=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(o)}}}isAvailable(){return!!this.config.apiKey}mapMessages(e){return e.map(t=>{if(typeof t.content=="string")return{role:t.role,content:t.content};let s=t.content.map(r=>{switch(r.type){case"text":return{type:"text",text:r.text};case"image":return{type:"image",source:{type:"base64",media_type:r.source.media_type,data:r.source.data}};case"tool_use":return{type:"tool_use",id:r.id,name:r.name,input:r.input};case"tool_result":return{type:"tool_result",tool_use_id:r.tool_use_id,content:r.content,is_error:r.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(r=>r!==void 0);return{role:t.role,content:s}})}mapTools(e){let t=e.map(s=>({name:s.name,description:s.description,input_schema:s.inputSchema}));return t.length>0&&(t[t.length-1].cache_control={type:"ephemeral"}),t}mapResponse(e){let t="",s=[];for(let r of e.content)r.type==="text"?t+=r.text:r.type==="tool_use"&&s.push({id:r.id,name:r.name,input:r.input});return{content:t,model:e.model??this.config.model,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens,cacheCreationTokens:e.usage.cache_creation_input_tokens??0,cacheReadTokens:e.usage.cache_read_input_tokens??0},stopReason:e.stop_reason}}}});import Qh from"openai";var He,ks=T(()=>{"use strict";Ft();He=class extends Ne{static{p(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Qh({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=it(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},n=await this.client.chat.completions.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.chat.completions.create({model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},stream:!0}),n,o,i="",a="",c=[],d=null,u=0,m=0;for await(let h of r){let f=h.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(a+=g.content,yield{type:"text_delta",text:g.content}),g?.tool_calls)for(let y of g.tool_calls)if(y.id){if(n){let _;try{_=JSON.parse(i||"{}")}catch{_={}}c.push({id:n,name:o,input:_})}n=y.id,o=y.function?.name,i=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:o}}}else y.function?.arguments&&(i+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),h.usage&&(u=h.usage.prompt_tokens,m=h.usage.completion_tokens)}if(n){let h;try{h=JSON.parse(i||"{}")}catch{h={}}c.push({id:n,name:o,input:h})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:m},stopReason:this.mapStopReason(d)}}}isAvailable(){return!!this.config.apiKey}async embed(e){try{let s=(await this.client.embeddings.create({model:"text-embedding-3-small",input:e})).data[0];return{embedding:s.embedding,model:"text-embedding-3-small",dimensions:s.embedding.length}}catch(t){let s=t instanceof Error?t.message:String(t);console.warn(`[OpenAIProvider] embed() failed: ${s}`);return}}supportsEmbeddings(){return!0}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let n=[],o=[],i=[];for(let a of r.content)switch(a.type){case"text":n.push({type:"text",text:a.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":o.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input)}});break;case"tool_result":i.push({tool_call_id:a.tool_use_id,content:a.content});break}if(r.role==="assistant"&&o.length>0){let a=n.map(c=>c.text).join("");s.push({role:"assistant",content:a||null,tool_calls:o})}else if(i.length>0)for(let a of i)s.push({role:"tool",tool_call_id:a.tool_call_id,content:a.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(a=>a.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,r=s?.content??"",n=s?.tool_calls?.map(o=>({id:o.id,name:o.function.name,input:(()=>{try{return JSON.parse(o.function.arguments)}catch{return{}}})()}));return{content:r,model:e.model??this.config.model,toolCalls:n&&n.length>0?n:void 0,usage:{inputTokens:e.usage?.prompt_tokens??0,outputTokens:e.usage?.completion_tokens??0},stopReason:this.mapStopReason(t?.finish_reason??null)}}mapStopReason(e){switch(e){case"stop":return"end_turn";case"tool_calls":return"tool_use";case"length":return"max_tokens";default:return"end_turn"}}}});var Cr,ia=T(()=>{"use strict";ks();Cr=class extends He{static{p(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Nr,aa=T(()=>{"use strict";Ft();Nr=class extends Ne{static{p(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=it(this.config.model);t?this.contextWindow=t:await this.fetchModelContextWindow()}async fetchModelContextWindow(){try{let e=await fetch(`${this.baseUrl}/api/show`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:this.config.model})});if(!e.ok)return;let s=(await e.json()).model_info??{},r=Object.keys(s).find(o=>o.includes("context_length")||o==="num_ctx"),n=r?Number(s[r]):0;n>0&&(this.contextWindow={maxInputTokens:n,maxOutputTokens:Math.min(n,4096)})}catch{}}getHeaders(){let e={"Content-Type":"application/json"};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}async complete(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text();throw new Error(`Ollama API error (${n.status}): ${i}`)}let o=await n.json();return this.mapResponse(o)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let h=await n.text();throw new Error(`Ollama API error (${n.status}): ${h}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let o=n.body.getReader(),i=new TextDecoder,a="",c="",d=0,u=0,m=[];try{for(;;){let{done:h,value:f}=await o.read();if(h)break;a+=i.decode(f,{stream:!0});let g=a.split(`
625
+ `).run(t,e.taskId,e.goal,e.cwd,e.agentName,s,s),{id:t,taskId:e.taskId,goal:e.goal,cwd:e.cwd,agentName:e.agentName,currentPhase:"planning",currentIteration:0,totalFilesChanged:0,lastBuildPassed:!1,milestones:[],createdAt:s,updatedAt:s}}getByTaskId(e){let t=this.db.prepare("SELECT * FROM project_agent_sessions WHERE task_id = ?").get(e);return t?this.mapRow(t):void 0}updateProgress(e,t){let s=["updated_at = datetime('now')"],r=[];t.currentPhase!==void 0&&(s.push("current_phase = ?"),r.push(t.currentPhase)),t.currentIteration!==void 0&&(s.push("current_iteration = ?"),r.push(t.currentIteration)),t.totalFilesChanged!==void 0&&(s.push("total_files_changed = ?"),r.push(t.totalFilesChanged)),t.lastBuildPassed!==void 0&&(s.push("last_build_passed = ?"),r.push(t.lastBuildPassed?1:0)),t.lastCommitSha!==void 0&&(s.push("last_commit_sha = ?"),r.push(t.lastCommitSha)),s.push("last_progress_at = datetime('now')"),r.push(e),this.db.prepare(`UPDATE project_agent_sessions SET ${s.join(", ")} WHERE task_id = ?`).run(...r)}addMilestone(e,t){let s=this.getByTaskId(e);if(!s)return;let r=[...s.milestones,t];this.db.prepare("UPDATE project_agent_sessions SET milestones = ?, updated_at = datetime('now') WHERE task_id = ?").run(JSON.stringify(r),e)}mapRow(e){let t=[];try{t=JSON.parse(e.milestones)}catch{}return{id:e.id,taskId:e.task_id,goal:e.goal,cwd:e.cwd,agentName:e.agent_name,currentPhase:e.current_phase,currentIteration:e.current_iteration,totalFilesChanged:e.total_files_changed,lastBuildPassed:e.last_build_passed===1,lastCommitSha:e.last_commit_sha,lastProgressAt:e.last_progress_at,milestones:t,createdAt:e.created_at,updatedAt:e.updated_at}}}});var md={};me(md,{ActivityRepository:()=>yt,AuditRepository:()=>ft,BackgroundTaskRepository:()=>ls,CalendarNotificationRepository:()=>gt,ConfirmationRepository:()=>fs,ConversationRepository:()=>ss,Database:()=>ht,DocumentRepository:()=>ps,EmbeddingRepository:()=>as,FeedbackRepository:()=>_s,LinkTokenRepository:()=>cs,MIGRATIONS:()=>lo,MemoryRepository:()=>ns,Migrator:()=>Ut,NoteRepository:()=>is,ProjectAgentSessionRepository:()=>mo,ReminderRepository:()=>os,ScheduledActionRepository:()=>us,SkillHealthRepository:()=>ws,SummaryRepository:()=>gs,TodoRepository:()=>ms,UsageRepository:()=>ys,UserRepository:()=>rs,WatchRepository:()=>hs,WorkflowRepository:()=>Ts});var ho=T(()=>{"use strict";Nl();Dl();Ml();Ol();Pl();co();sa();Ul();Fl();jl();Bl();Hl();Zl();ed();td();sd();rd();nd();od();id();ad();cd();dd();ud();pd()});function it(l){if(na[l])return na[l];let e=Object.entries(na).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var na,Jh,Ne,Ft=T(()=>{"use strict";na={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Jh={maxInputTokens:128e3,maxOutputTokens:8192};p(it,"lookupContextWindow");Ne=class{static{p(this,"LLMProvider")}config;contextWindow=Jh;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Zh from"@anthropic-ai/sdk";var xr,oa=T(()=>{"use strict";Ft();xr=class extends Ne{static{p(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Zh({apiKey:this.config.apiKey,maxRetries:5});let e=it(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s},n=await this.client.messages.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s});for await(let n of r)if(n.type==="content_block_delta")n.delta.type==="text_delta"?yield{type:"text_delta",text:n.delta.text}:n.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:n.delta.partial_json}});else if(n.type==="content_block_start")n.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:n.content_block.id,name:n.content_block.name}});else if(n.type==="message_stop"){let o=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(o)}}}isAvailable(){return!!this.config.apiKey}mapMessages(e){return e.map(t=>{if(typeof t.content=="string")return{role:t.role,content:t.content};let s=t.content.map(r=>{switch(r.type){case"text":return{type:"text",text:r.text};case"image":return{type:"image",source:{type:"base64",media_type:r.source.media_type,data:r.source.data}};case"tool_use":return{type:"tool_use",id:r.id,name:r.name,input:r.input};case"tool_result":return{type:"tool_result",tool_use_id:r.tool_use_id,content:r.content,is_error:r.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(r=>r!==void 0);return{role:t.role,content:s}})}mapTools(e){let t=e.map(s=>({name:s.name,description:s.description,input_schema:s.inputSchema}));return t.length>0&&(t[t.length-1].cache_control={type:"ephemeral"}),t}mapResponse(e){let t="",s=[];for(let r of e.content)r.type==="text"?t+=r.text:r.type==="tool_use"&&s.push({id:r.id,name:r.name,input:r.input});return{content:t,model:e.model??this.config.model,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens,cacheCreationTokens:e.usage.cache_creation_input_tokens??0,cacheReadTokens:e.usage.cache_read_input_tokens??0},stopReason:e.stop_reason}}}});import Qh from"openai";var He,ks=T(()=>{"use strict";Ft();He=class extends Ne{static{p(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Qh({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=it(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},n=await this.client.chat.completions.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.chat.completions.create({model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},stream:!0}),n,o,i="",a="",c=[],d=null,u=0,m=0;for await(let h of r){let f=h.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(a+=g.content,yield{type:"text_delta",text:g.content}),g?.tool_calls)for(let y of g.tool_calls)if(y.id){if(n){let _;try{_=JSON.parse(i||"{}")}catch{_={}}c.push({id:n,name:o,input:_})}n=y.id,o=y.function?.name,i=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:o}}}else y.function?.arguments&&(i+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),h.usage&&(u=h.usage.prompt_tokens,m=h.usage.completion_tokens)}if(n){let h;try{h=JSON.parse(i||"{}")}catch{h={}}c.push({id:n,name:o,input:h})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:m},stopReason:this.mapStopReason(d)}}}isAvailable(){return!!this.config.apiKey}async embed(e){try{let s=(await this.client.embeddings.create({model:"text-embedding-3-small",input:e})).data[0];return{embedding:s.embedding,model:"text-embedding-3-small",dimensions:s.embedding.length}}catch(t){let s=t instanceof Error?t.message:String(t);console.warn(`[OpenAIProvider] embed() failed: ${s}`);return}}supportsEmbeddings(){return!0}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let n=[],o=[],i=[];for(let a of r.content)switch(a.type){case"text":n.push({type:"text",text:a.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":o.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input)}});break;case"tool_result":i.push({tool_call_id:a.tool_use_id,content:a.content});break}if(r.role==="assistant"&&o.length>0){let a=n.map(c=>c.text).join("");s.push({role:"assistant",content:a||null,tool_calls:o})}else if(i.length>0)for(let a of i)s.push({role:"tool",tool_call_id:a.tool_call_id,content:a.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(a=>a.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,r=s?.content??"",n=s?.tool_calls?.map(o=>({id:o.id,name:o.function.name,input:(()=>{try{return JSON.parse(o.function.arguments)}catch{return{}}})()}));return{content:r,model:e.model??this.config.model,toolCalls:n&&n.length>0?n:void 0,usage:{inputTokens:e.usage?.prompt_tokens??0,outputTokens:e.usage?.completion_tokens??0},stopReason:this.mapStopReason(t?.finish_reason??null)}}mapStopReason(e){switch(e){case"stop":return"end_turn";case"tool_calls":return"tool_use";case"length":return"max_tokens";default:return"end_turn"}}}});var Cr,ia=T(()=>{"use strict";ks();Cr=class extends He{static{p(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Nr,aa=T(()=>{"use strict";Ft();Nr=class extends Ne{static{p(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=it(this.config.model);t?this.contextWindow=t:await this.fetchModelContextWindow()}async fetchModelContextWindow(){try{let e=await fetch(`${this.baseUrl}/api/show`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:this.config.model})});if(!e.ok)return;let s=(await e.json()).model_info??{},r=Object.keys(s).find(o=>o.includes("context_length")||o==="num_ctx"),n=r?Number(s[r]):0;n>0&&(this.contextWindow={maxInputTokens:n,maxOutputTokens:Math.min(n,4096)})}catch{}}getHeaders(){let e={"Content-Type":"application/json"};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}async complete(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text();throw new Error(`Ollama API error (${n.status}): ${i}`)}let o=await n.json();return this.mapResponse(o)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let h=await n.text();throw new Error(`Ollama API error (${n.status}): ${h}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let o=n.body.getReader(),i=new TextDecoder,a="",c="",d=0,u=0,m=[];try{for(;;){let{done:h,value:f}=await o.read();if(h)break;a+=i.decode(f,{stream:!0});let g=a.split(`
626
626
  `);a=g.pop()??"";for(let y of g){let _=y.trim();if(!_)continue;let S;try{S=JSON.parse(_)}catch{continue}if(S.message?.content&&(c+=S.message.content,yield{type:"text_delta",text:S.message.content}),S.message?.tool_calls)for(let E of S.message.tool_calls){let $={id:`ollama_tool_${m.length}`,name:E.function.name,input:E.function.arguments};m.push($),yield{type:"tool_use_start",toolCall:{id:$.id,name:$.name}},yield{type:"tool_use_delta",toolCall:{input:$.input}}}S.done&&(d=S.prompt_eval_count??0,u=S.eval_count??0,yield{type:"message_complete",response:{content:c,model:this.config.model,toolCalls:m.length>0?m:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:m.length>0?"tool_use":"end_turn"}})}}if(a.trim()){let h;try{h=JSON.parse(a.trim())}catch{return}if(h.message?.content&&(c+=h.message.content,yield{type:"text_delta",text:h.message.content}),h.message?.tool_calls)for(let f of h.message.tool_calls){let g={id:`ollama_tool_${m.length}`,name:f.function.name,input:f.function.arguments};m.push(g),yield{type:"tool_use_start",toolCall:{id:g.id,name:g.name}},yield{type:"tool_use_delta",toolCall:{input:g.input}}}h.done&&(d=h.prompt_eval_count??0,u=h.eval_count??0,yield{type:"message_complete",response:{content:c,toolCalls:m.length>0?m:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:m.length>0?"tool_use":"end_turn"}})}}finally{o.releaseLock()}}isAvailable(){try{return this.baseUrl.length>0}catch{return!1}}async embed(e){try{let t=await fetch(`${this.baseUrl}/api/embed`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({model:"nomic-embed-text",input:e})});if(!t.ok)return;let s=await t.json();if(!s.embeddings||s.embeddings.length===0)return;let r=s.embeddings[0];return{embedding:r,model:"nomic-embed-text",dimensions:r.length}}catch{return}}supportsEmbeddings(){return!0}buildOptions(e){let t={},s=e.temperature??this.config.temperature;s!==void 0&&(t.temperature=s);let r=e.maxTokens??this.config.maxTokens;return r!==void 0&&(t.num_predict=r),t}buildMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e)typeof r.content=="string"?s.push({role:r.role,content:r.content}):s.push(this.mapContentBlocks(r.role,r.content));return s}mapContentBlocks(e,t){let s=[],r=[];for(let o of t)switch(o.type){case"text":s.push(o.text);break;case"image":r.push(o.source.data);break;case"tool_use":s.push(`[Tool call: ${o.name}(${JSON.stringify(o.input)})]`);break;case"tool_result":s.push(`[Tool result for ${o.tool_use_id}]: ${o.content}`);break}let n={role:e,content:s.join(`
627
- `)};return r.length>0&&(n.images=r),n}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=[];if(e.message.tool_calls)for(let s of e.message.tool_calls)t.push({id:`ollama_tool_${t.length}`,name:s.function.name,input:s.function.arguments});return{content:e.message.content,model:this.config.model,toolCalls:t.length>0?t:void 0,usage:{inputTokens:e.prompt_eval_count??0,outputTokens:e.eval_count??0},stopReason:t.length>0?"tool_use":"end_turn"}}}});var Lr,ca=T(()=>{"use strict";ks();Lr=class extends He{static{p(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as ef}from"@google/genai";var Dr,la=T(()=>{"use strict";Ft();Dr=class extends Ne{static{p(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new ef({apiKey:this.config.apiKey});let e=it(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),n="",o=[],i=0,a=0,c;for await(let d of r){c=d;let u=d.text;if(u&&(n+=u,yield{type:"text_delta",text:u}),d.functionCalls)for(let m of d.functionCalls){let h={id:m.id??`google_tool_${o.length}`,name:m.name,input:m.args??{}};o.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:o.length>0?o:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:o.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(n=>n.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let n=this.rawContentCache.keys().next().value;n&&this.rawContentCache.delete(n)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let n of r.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let r of e){let n=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:n,parts:[{text:r.content}]});continue}let o=[],i=[],a=[];for(let c of r.content)switch(c.type){case"text":i.push({text:c.text});break;case"image":i.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":o.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let d=t.get(c.tool_use_id)??c.tool_use_id,u;try{let m=JSON.parse(c.content);u=typeof m=="object"&&m!==null?m:{result:m}}catch{u={result:c.content}}a.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&o.length>0){let c=this.buildCacheKeyFromBlocks(o),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...i];for(let m=0;m<o.length;m++){let h=o[m];u.push({functionCall:{id:h.id,name:h.name,args:h.input},...m===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else i.length>0&&s.push({role:n,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let c=a.functionCall.id??a.functionCall.name??"";c&&t.add(c)}s.push(i)}else{let a=(i.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let c=a.functionResponse.id??a.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&n.push({role:i.role,parts:a})}else n.push(i);if(n.length<=1)return n;let o=[n[0]];for(let i=1;i<n.length;i++){let a=o[o.length-1],c=n[i];a.role===c.role?a.parts=[...a.parts??[],...c.parts??[]]:o.push(c)}return o}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((n,o)=>({id:n.id??`google_tool_${o}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var Mr,da=T(()=>{"use strict";ks();Mr=class extends He{static{p(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function ua(l){switch(l.provider){case"anthropic":return new xr(l);case"openai":return new He(l);case"openrouter":return new Cr(l);case"ollama":return new Nr(l);case"openwebui":return new Lr(l);case"google":return new Dr(l);case"mistral":return new Mr(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var pa=T(()=>{"use strict";oa();ks();ia();aa();ca();la();da();p(ua,"createLLMProvider")});function hd(l){let e=l.toLowerCase();for(let[t,s]of tf)if(e.startsWith(t.toLowerCase()))return s}function ho(l,e){let t=hd(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=Math.max(0,e.inputTokens-n);return r+=i/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),o>0&&t.cacheWrite&&(r+=o/s*t.cacheWrite),r}var tf,Or,ma=T(()=>{"use strict";tf=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];p(hd,"getModelPricing");p(ho,"calculateCost");Or=class{static{p(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=ho(e,t),r=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=r,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let o=this.data.byModel[e];o||(o={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=o),o.calls++,o.inputTokens+=t.inputTokens,o.outputTokens+=t.outputTokens,o.cacheReadTokens+=r,o.cacheWriteTokens+=n,o.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,r,n,s)}catch{}return s}getSummary(){return{...this.data,totalCostUsd:Math.round(this.data.totalCostUsd*1e6)/1e6,byModel:Object.fromEntries(Object.entries(this.data.byModel).map(([e,t])=>[e,{...t,costUsd:Math.round(t.costUsd*1e6)/1e6}]))}}}});function ha(l,e){return new fo(l,e)}var fd,fo,gd=T(()=>{"use strict";Ft();pa();ma();fd=["default","strong","fast","embeddings","local"],fo=class extends Ne{static{p(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new Or;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of fd){let t=this.multiConfig[e];if(t){let s=ua(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}if(!this.providers.has("default"))throw new Error(`ModelRouter: no "default" tier configured. Available tiers: [${[...this.providers.keys()].join(", ")}]`)}resolve(e){if(e&&this.providers.has(e))return{provider:this.providers.get(e),resolvedTier:e};let t=this.providers.get("default");if(!t)throw new Error('ModelRouter: no "default" tier available. Was initialize() called?');return{provider:t,resolvedTier:"default"}}async complete(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=this.multiConfig[s];this.logger?.debug({requestedTier:e.tier??"default",resolvedTier:s,model:r?.model},"LLM routing request");try{return await this.executeComplete(t,s,e)}catch(n){if(!this.isRetryableError(n))throw n;return this.logger?.warn({err:n,tier:s},"Provider failed, attempting fallback"),this.completeWithFallback(e,s,n)}}async executeComplete(e,t,s){let r=this.multiConfig[t],n=await e.complete(s),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:t,model:o,costUsd:Math.round(i*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let r=["default","strong","fast"].filter(n=>n!==t);for(let n of r){let o=this.providers.get(n);if(o)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(o,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=!1;try{for await(let n of t.stream(e))r=!0,yield n}catch(n){if(r||!this.isRetryableError(n))throw n;this.logger?.warn({err:n,tier:s},"Stream provider failed before first chunk, attempting fallback");let o=["default","strong","fast"].filter(i=>i!==s);for(let i of o){let a=this.providers.get(i);if(a)try{this.logger?.info({tier:i},"Stream fallback to tier"),yield*a.stream(e);return}catch{continue}}throw n}}async embed(e){return(this.providers.get("embeddings")??this.resolve().provider).embed(e)}supportsEmbeddings(){return(this.providers.get("embeddings")??this.resolve().provider).supportsEmbeddings()}isAvailable(){return this.resolve().provider.isAvailable()}getContextWindow(){return this.resolve().provider.getContextWindow()}getProviderStatuses(){let e={};for(let t of fd){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};p(ha,"createModelRouter")});function We(l){return Math.ceil(l.length/3.5)}function jt(l){if(typeof l.content=="string")return We(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=We(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=We(t.name)+We(JSON.stringify(t.input));break;case"tool_result":e+=We(t.content);break}return e}function fa(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let a of l)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&n.set(c.id,c.name);let o=[];for(let a=0;a<l.length;a++){let c=l[a];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&o.push(a)}let i=new Set(o.slice(-t));return l.map((a,c)=>{if(i.has(c)||a.role!=="user"||!Array.isArray(a.content))return a;let d=!1,u=a.content.map(m=>{if(m.type!=="tool_result")return m;let h=m.content;if(typeof h!="string"||h.length<r)return m;d=!0;let f=n.get(m.tool_use_id)||"unknown",g=h.split(`
627
+ `)};return r.length>0&&(n.images=r),n}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=[];if(e.message.tool_calls)for(let s of e.message.tool_calls)t.push({id:`ollama_tool_${t.length}`,name:s.function.name,input:s.function.arguments});return{content:e.message.content,model:this.config.model,toolCalls:t.length>0?t:void 0,usage:{inputTokens:e.prompt_eval_count??0,outputTokens:e.eval_count??0},stopReason:t.length>0?"tool_use":"end_turn"}}}});var Lr,ca=T(()=>{"use strict";ks();Lr=class extends He{static{p(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as ef}from"@google/genai";var Dr,la=T(()=>{"use strict";Ft();Dr=class extends Ne{static{p(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new ef({apiKey:this.config.apiKey});let e=it(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),n="",o=[],i=0,a=0,c;for await(let d of r){c=d;let u=d.text;if(u&&(n+=u,yield{type:"text_delta",text:u}),d.functionCalls)for(let m of d.functionCalls){let h={id:m.id??`google_tool_${o.length}`,name:m.name,input:m.args??{}};o.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:o.length>0?o:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:o.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(n=>n.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let n=this.rawContentCache.keys().next().value;n&&this.rawContentCache.delete(n)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let n of r.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let r of e){let n=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:n,parts:[{text:r.content}]});continue}let o=[],i=[],a=[];for(let c of r.content)switch(c.type){case"text":i.push({text:c.text});break;case"image":i.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":o.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let d=t.get(c.tool_use_id)??c.tool_use_id,u;try{let m=JSON.parse(c.content);u=typeof m=="object"&&m!==null?m:{result:m}}catch{u={result:c.content}}a.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&o.length>0){let c=this.buildCacheKeyFromBlocks(o),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...i];for(let m=0;m<o.length;m++){let h=o[m];u.push({functionCall:{id:h.id,name:h.name,args:h.input},...m===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else i.length>0&&s.push({role:n,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let c=a.functionCall.id??a.functionCall.name??"";c&&t.add(c)}s.push(i)}else{let a=(i.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let c=a.functionResponse.id??a.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&n.push({role:i.role,parts:a})}else n.push(i);if(n.length<=1)return n;let o=[n[0]];for(let i=1;i<n.length;i++){let a=o[o.length-1],c=n[i];a.role===c.role?a.parts=[...a.parts??[],...c.parts??[]]:o.push(c)}return o}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((n,o)=>({id:n.id??`google_tool_${o}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var Mr,da=T(()=>{"use strict";ks();Mr=class extends He{static{p(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function ua(l){switch(l.provider){case"anthropic":return new xr(l);case"openai":return new He(l);case"openrouter":return new Cr(l);case"ollama":return new Nr(l);case"openwebui":return new Lr(l);case"google":return new Dr(l);case"mistral":return new Mr(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var pa=T(()=>{"use strict";oa();ks();ia();aa();ca();la();da();p(ua,"createLLMProvider")});function hd(l){let e=l.toLowerCase();for(let[t,s]of tf)if(e.startsWith(t.toLowerCase()))return s}function fo(l,e){let t=hd(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=Math.max(0,e.inputTokens-n);return r+=i/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),o>0&&t.cacheWrite&&(r+=o/s*t.cacheWrite),r}var tf,Or,ma=T(()=>{"use strict";tf=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];p(hd,"getModelPricing");p(fo,"calculateCost");Or=class{static{p(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=fo(e,t),r=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=r,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let o=this.data.byModel[e];o||(o={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=o),o.calls++,o.inputTokens+=t.inputTokens,o.outputTokens+=t.outputTokens,o.cacheReadTokens+=r,o.cacheWriteTokens+=n,o.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,r,n,s)}catch{}return s}getSummary(){return{...this.data,totalCostUsd:Math.round(this.data.totalCostUsd*1e6)/1e6,byModel:Object.fromEntries(Object.entries(this.data.byModel).map(([e,t])=>[e,{...t,costUsd:Math.round(t.costUsd*1e6)/1e6}]))}}}});function ha(l,e){return new go(l,e)}var fd,go,gd=T(()=>{"use strict";Ft();pa();ma();fd=["default","strong","fast","embeddings","local"],go=class extends Ne{static{p(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new Or;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of fd){let t=this.multiConfig[e];if(t){let s=ua(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}if(!this.providers.has("default"))throw new Error(`ModelRouter: no "default" tier configured. Available tiers: [${[...this.providers.keys()].join(", ")}]`)}resolve(e){if(e&&this.providers.has(e))return{provider:this.providers.get(e),resolvedTier:e};let t=this.providers.get("default");if(!t)throw new Error('ModelRouter: no "default" tier available. Was initialize() called?');return{provider:t,resolvedTier:"default"}}async complete(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=this.multiConfig[s];this.logger?.debug({requestedTier:e.tier??"default",resolvedTier:s,model:r?.model},"LLM routing request");try{return await this.executeComplete(t,s,e)}catch(n){if(!this.isRetryableError(n))throw n;return this.logger?.warn({err:n,tier:s},"Provider failed, attempting fallback"),this.completeWithFallback(e,s,n)}}async executeComplete(e,t,s){let r=this.multiConfig[t],n=await e.complete(s),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:t,model:o,costUsd:Math.round(i*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let r=["default","strong","fast"].filter(n=>n!==t);for(let n of r){let o=this.providers.get(n);if(o)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(o,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=!1;try{for await(let n of t.stream(e))r=!0,yield n}catch(n){if(r||!this.isRetryableError(n))throw n;this.logger?.warn({err:n,tier:s},"Stream provider failed before first chunk, attempting fallback");let o=["default","strong","fast"].filter(i=>i!==s);for(let i of o){let a=this.providers.get(i);if(a)try{this.logger?.info({tier:i},"Stream fallback to tier"),yield*a.stream(e);return}catch{continue}}throw n}}async embed(e){return(this.providers.get("embeddings")??this.resolve().provider).embed(e)}supportsEmbeddings(){return(this.providers.get("embeddings")??this.resolve().provider).supportsEmbeddings()}isAvailable(){return this.resolve().provider.isAvailable()}getContextWindow(){return this.resolve().provider.getContextWindow()}getProviderStatuses(){let e={};for(let t of fd){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};p(ha,"createModelRouter")});function We(l){return Math.ceil(l.length/3.5)}function jt(l){if(typeof l.content=="string")return We(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=We(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=We(t.name)+We(JSON.stringify(t.input));break;case"tool_result":e+=We(t.content);break}return e}function fa(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let a of l)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&n.set(c.id,c.name);let o=[];for(let a=0;a<l.length;a++){let c=l[a];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&o.push(a)}let i=new Set(o.slice(-t));return l.map((a,c)=>{if(i.has(c)||a.role!=="user"||!Array.isArray(a.content))return a;let d=!1,u=a.content.map(m=>{if(m.type!=="tool_result")return m;let h=m.content;if(typeof h!="string"||h.length<r)return m;d=!0;let f=n.get(m.tool_use_id)||"unknown",g=h.split(`
628
628
  `)[0].slice(0,s),y=m.is_error?"Fehler":"Ergebnis";return{...m,content:`[${y}: ${f} \u2014 ${g}]`}});return d?{...a,content:u}:a})}var Pr,yd=T(()=>{"use strict";p(We,"estimateTokens");p(jt,"estimateMessageTokens");p(fa,"trimOldToolResults");Pr=class{static{p(this,"PromptBuilder")}buildSystemPrompt(e={}){let{memories:t,skills:s,userProfile:r,todayEvents:n,conversationSummary:o}=e,i=process.platform==="darwin"?"macOS":process.platform==="win32"?"Windows":"Linux",a=process.env.HOME||process.env.USERPROFILE||"~",c=`You are Alfred, a personal AI assistant. You run on ${i} (home: ${a}).
629
629
 
630
630
  ## Core principles
@@ -698,7 +698,7 @@ This summarizes the earlier conversation. Use it to maintain continuity. The mos
698
698
  `;c+=`
699
699
  Use these memories to personalize your responses. When the user tells you new facts or preferences, use the memory tool to save them.`}else c+=`
700
700
 
701
- When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return c}buildMessages(e){let t=e.filter(s=>s.role==="user"||s.role==="assistant").map(s=>{if(s.toolCalls){let r;try{r=JSON.parse(s.toolCalls)}catch{r=[]}if(s.role==="assistant"){let i=r,a=[];s.content&&a.push({type:"text",text:s.content});for(let c of i)a.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let n=r,o=[];for(let i of n)i.type==="tool_result"&&o.push(i);return o.length>0?{role:"user",content:o}:{role:"user",content:s.content||""}}return{role:s.role,content:s.content}});return this.sanitizeToolMessages(t)}sanitizeToolMessages(e){let t=new Set,s=new Set;for(let a of e)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&t.add(c.id);else if(a.role==="user"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_result"&&t.has(c.tool_use_id)&&s.add(c.tool_use_id);let r=new Set,n=new Set,o=[];for(let a of e){if(!Array.isArray(a.content)){o.push(a);continue}let c=a.content.filter(d=>d.type==="tool_use"?!s.has(d.id)||r.has(d.id)?!1:(r.add(d.id),!0):d.type==="tool_result"?!s.has(d.tool_use_id)||n.has(d.tool_use_id)?!1:(n.add(d.tool_use_id),!0):!0);c.length!==0&&o.push({...a,content:c})}let i=[];for(let a of o){let c=i[i.length-1];if(c&&c.role===a.role){let d=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content,u=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...c,content:[...d,...u]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var ga=T(()=>{"use strict";Ft();oa();ks();ia();aa();ca();la();da();pa();gd();yd();ma()});var Ur,ya=T(()=>{"use strict";Ur=class{static{p(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let o=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:o,resetsAt:n.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);!n||s>n.windowStart+n.windowMs?this.buckets.set(e,{count:1,windowStart:s,windowMs:r}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+s.windowMs*2&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var Fr,wd=T(()=>{"use strict";ya();Fr=class{static{p(this,"RuleEngine")}rules=[];rateLimiter=new Ur;loadRules(e){this.rules=[...e].sort((t,s)=>t.priority-s.priority)}getRules(){return this.rules}evaluate(e){for(let t of this.rules)if(this.ruleMatches(t,e))return t.rateLimit&&t.effect==="allow"&&!this.checkRateLimit(t,e)?{allowed:!1,matchedRule:t,reason:`Rate limit exceeded for rule: ${t.id}`,timestamp:new Date}:{allowed:t.effect==="allow",matchedRule:t,reason:`Matched rule: ${t.id}`,timestamp:new Date};return{allowed:!1,matchedRule:void 0,reason:"No matching rule found \u2014 default deny",timestamp:new Date}}checkRateLimit(e,t){if(!e.rateLimit)return!0;let s=this.getScopeKey(e.scope,t),r=`${e.id}:${s}`;return this.rateLimiter.checkAndIncrement(r,e.rateLimit).allowed}resetRateLimits(){this.rateLimiter.reset()}getScopeKey(e,t){switch(e){case"global":return"global";case"user":return t.userId;case"conversation":return t.chatId??"unknown";case"platform":return t.platform}}ruleMatches(e,t){return!(!e.actions.includes("*")&&!e.actions.includes(t.action)||!e.riskLevels.includes(t.riskLevel)||e.conditions&&(e.conditions.users&&e.conditions.users.length>0&&!e.conditions.users.includes(t.userId)||e.conditions.platforms&&e.conditions.platforms.length>0&&!e.conditions.platforms.includes(t.platform)||e.conditions.chatType&&e.conditions.chatType!==t.chatType||e.conditions.timeWindow&&!this.matchesTimeWindow(e.conditions.timeWindow)))}matchesTimeWindow(e){if(!e)return!0;let t=new Date;if(e.daysOfWeek&&e.daysOfWeek.length>0&&!e.daysOfWeek.includes(t.getDay()))return!1;let s=t.getHours();if(e.startHour!==void 0&&e.endHour!==void 0){if(e.startHour<=e.endHour){if(s<e.startHour||s>=e.endHour)return!1}else if(s>=e.endHour&&s<e.startHour)return!1}else if(e.startHour!==void 0){if(s<e.startHour)return!1}else if(e.endHour!==void 0&&s>=e.endHour)return!1;return!0}}});var Td,_d,kd,at,bd=T(()=>{"use strict";Td=["allow","deny"],_d=["global","user","conversation","platform"],kd=["read","write","destructive","admin"],at=class{static{p(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!Td.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Td.join(", ")}`);if(typeof s.priority!="number"||!Number.isFinite(s.priority))throw new Error(`Rule "${s.id}" is missing a valid "priority" number`);if(typeof s.scope!="string"||!_d.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${_d.join(", ")}`);if(!Array.isArray(s.actions)||s.actions.length===0)throw new Error(`Rule "${s.id}" is missing a valid "actions" array`);for(let n of s.actions)if(typeof n!="string")throw new Error(`Rule "${s.id}" has a non-string entry in "actions"`);if(!Array.isArray(s.riskLevels)||s.riskLevels.length===0)throw new Error(`Rule "${s.id}" is missing a valid "riskLevels" array`);for(let n of s.riskLevels)if(!kd.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${kd.join(", ")}`);let r={id:s.id,effect:s.effect,priority:s.priority,scope:s.scope,actions:s.actions,riskLevels:s.riskLevels};if(s.conditions!==void 0){if(typeof s.conditions!="object"||s.conditions===null)throw new Error(`Rule "${s.id}" has invalid "conditions": expected an object`);let n=s.conditions;if(n.users!==void 0&&!Array.isArray(n.users))throw new Error(`Rule "${s.id}" has invalid "conditions.users": expected an array`);if(n.platforms!==void 0&&!Array.isArray(n.platforms))throw new Error(`Rule "${s.id}" has invalid "conditions.platforms": expected an array`);if(n.chatType!==void 0&&typeof n.chatType!="string")throw new Error(`Rule "${s.id}" has invalid "conditions.chatType": expected a string`);if(n.timeWindow!==void 0){let o=n.timeWindow;if(typeof o!="object"||o===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(o.startHour!==void 0&&(typeof o.startHour!="number"||o.startHour<0||o.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(o.endHour!==void 0&&(typeof o.endHour!="number"||o.endHour<0||o.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(o.daysOfWeek!==void 0&&(!Array.isArray(o.daysOfWeek)||!o.daysOfWeek.every(i=>typeof i=="number"&&i>=0&&i<=6)))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.daysOfWeek": expected array of 0-6`)}r.conditions=s.conditions}if(s.rateLimit!==void 0){if(typeof s.rateLimit!="object"||s.rateLimit===null)throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected an object`);let n=s.rateLimit;if(typeof n.maxInvocations!="number"||typeof n.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import sf from"node:crypto";var jr,Ed=T(()=>{"use strict";jr=class{static{p(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:sf.randomUUID(),timestamp:t.timestamp,userId:e.userId,action:e.action,riskLevel:e.riskLevel,ruleId:t.matchedRule?.id,effect:t.allowed?"allow":"deny",platform:e.platform,chatId:e.chatId,context:{chatType:e.chatType,reason:t.reason}};try{this.auditRepository.log(s)}catch(r){this.logger.error({err:r,auditEntry:s},"Failed to write audit log entry")}return this.logger.debug({userId:e.userId,action:e.action,allowed:t.allowed,ruleId:t.matchedRule?.id,reason:t.reason},"Security evaluation completed"),t}}});var go=T(()=>{"use strict";wd();ya();bd();Ed()});var x,B=T(()=>{"use strict";x=class{static{p(this,"Skill")}}});function de(l){return l.masterUserId??l.userId}function J(l){let e=new Set;if(e.add(de(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Oe=T(()=>{"use strict";p(de,"effectiveUserId");p(J,"allUserIds")});var bs,Sd=T(()=>{"use strict";bs=class{static{p(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var Es,$d=T(()=>{"use strict";Es=class{static{p(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:o}=e.metadata;return this.logger.info({skill:o,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,o,r,n):this.executeWithHardTimeout(e,t,s,o,r)}async executeWithTracker(e,t,s,r,n,o){return new Promise(i=>{let a=!1,c,d,u,m=p(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),h=p(f=>{a||(a=!0,m(),i(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),h(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),h({success:!1,error:g})}),u=setTimeout(()=>{if(a)return;let f=o.getIdleMs();if(f>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),h({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=o.getSnapshot();this.logger.info({skill:r,idleMs:f,state:g.state,iteration:g.iteration,totalMs:g.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){m();return}let y=o.getIdleMs(),_=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:_.state,iteration:_.iteration,totalMs:_.totalElapsedMs},"Agent went inactive \u2014 aborting"),h({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${_.state})`})):this.logger.debug({skill:r,idleMs:y,state:_.state,iteration:_.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let f=o.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),h({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,n){try{let o,i=await Promise.race([e.execute(t,s),new Promise((a,c)=>{o=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{o&&clearTimeout(o)});return this.logger.info({skill:r,success:i.success,...i.success?{}:{error:i.error}},"Skill execution completed"),i}catch(o){let i=o instanceof Error?o.message:String(o);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var Bt,wa=T(()=>{"use strict";Bt=class{static{p(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import rf from"node:fs";import Ta from"node:path";var yo,vd=T(()=>{"use strict";B();yo=class{static{p(this,"PluginLoader")}async loadFromDirectory(e){let t=Ta.resolve(e),s;try{s=await rf.promises.readdir(t)}catch(o){let i=o instanceof Error?o.message:String(o);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(o=>o.endsWith(".js")),n=[];for(let o of r){let i=Ta.join(t,o);try{let a=await this.loadFromFile(i);n.push(a)}catch(a){let c=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${c}`)}}return n}async loadFromFile(e){let t=Ta.resolve(e),n=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof n!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let o=new n;if(!(o instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(o,t),o}validateMetadata(e,t){let{metadata:s}=e;if(!s)throw new Error(`Plugin "${t}" is missing metadata`);if(!s.name||typeof s.name!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.name`);if(!s.description||typeof s.description!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.description`);if(!["read","write","destructive","admin"].includes(s.riskLevel))throw new Error(`Plugin "${t}" has invalid metadata.riskLevel: "${String(s.riskLevel)}"`);if(!s.version||typeof s.version!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.version`)}}});function nf(l){let e=[],t=0;for(;t<l.length;){if(l[t]===" "||l[t]===" "){t++;continue}if(/[\d.]/.test(l[t])){let s="";for(;t<l.length&&/[\d.]/.test(l[t]);)s+=l[t++];let r=Number(s);if(isNaN(r))throw new Error(`Invalid number: ${s}`);e.push({type:"num",value:r});continue}if(l.startsWith("Math.",t)){t+=5;let s="";for(;t<l.length&&/[a-zA-Z0-9]/.test(l[t]);)s+=l[t++];if(s in Ad)e.push({type:"const",value:Ad[s]});else if(s in Id)e.push({type:"fn",value:s});else throw new Error(`Unknown Math member: Math.${s}`);continue}if("+-*/%".includes(l[t])){e.push({type:"op",value:l[t++]});continue}if(l[t]==="("||l[t]===")"){e.push({type:"paren",value:l[t++]});continue}if(l[t]===","){e.push({type:"comma"}),t++;continue}throw new Error(`Unexpected character: ${l[t]}`)}return e}function of(l){let e=nf(l);if(e.length===0)throw new Error("Empty expression");return new _a(e).parse()}var Id,Ad,_a,Ss,Rd=T(()=>{"use strict";B();Id={sin:Math.sin,cos:Math.cos,tan:Math.tan,sqrt:Math.sqrt,pow:Math.pow,abs:Math.abs,floor:Math.floor,ceil:Math.ceil,round:Math.round,log:Math.log,log2:Math.log2,log10:Math.log10},Ad={PI:Math.PI,E:Math.E};p(nf,"tokenize");_a=class{static{p(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return Id[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};p(of,"safeEval");Ss=class extends x{static{p(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=of(r);return typeof n!="number"||!isFinite(n)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:n,display:`${r} = ${n}`}}catch(n){let o=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${o}`}}}}});var $s,xd=T(()=>{"use strict";B();$s=class extends x{static{p(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=p(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var vs,Cd=T(()=>{"use strict";B();vs=class extends x{static{p(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let o;switch(this.config.provider){case"brave":o=await this.searchBrave(s,r);break;case"searxng":o=await this.searchSearXNG(s,r);break;case"tavily":o=await this.searchTavily(s,r);break;case"duckduckgo":o=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(o.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=o.map((a,c)=>`${c+1}. **${a.title}**
701
+ When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return c}buildMessages(e){let t=e.filter(s=>s.role==="user"||s.role==="assistant").map(s=>{if(s.toolCalls){let r;try{r=JSON.parse(s.toolCalls)}catch{r=[]}if(s.role==="assistant"){let i=r,a=[];s.content&&a.push({type:"text",text:s.content});for(let c of i)a.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let n=r,o=[];for(let i of n)i.type==="tool_result"&&o.push(i);return o.length>0?{role:"user",content:o}:{role:"user",content:s.content||""}}return{role:s.role,content:s.content}});return this.sanitizeToolMessages(t)}sanitizeToolMessages(e){let t=new Set,s=new Set;for(let a of e)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&t.add(c.id);else if(a.role==="user"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_result"&&t.has(c.tool_use_id)&&s.add(c.tool_use_id);let r=new Set,n=new Set,o=[];for(let a of e){if(!Array.isArray(a.content)){o.push(a);continue}let c=a.content.filter(d=>d.type==="tool_use"?!s.has(d.id)||r.has(d.id)?!1:(r.add(d.id),!0):d.type==="tool_result"?!s.has(d.tool_use_id)||n.has(d.tool_use_id)?!1:(n.add(d.tool_use_id),!0):!0);c.length!==0&&o.push({...a,content:c})}let i=[];for(let a of o){let c=i[i.length-1];if(c&&c.role===a.role){let d=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content,u=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...c,content:[...d,...u]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var ga=T(()=>{"use strict";Ft();oa();ks();ia();aa();ca();la();da();pa();gd();yd();ma()});var Ur,ya=T(()=>{"use strict";Ur=class{static{p(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let o=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:o,resetsAt:n.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);!n||s>n.windowStart+n.windowMs?this.buckets.set(e,{count:1,windowStart:s,windowMs:r}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+s.windowMs*2&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var Fr,wd=T(()=>{"use strict";ya();Fr=class{static{p(this,"RuleEngine")}rules=[];rateLimiter=new Ur;loadRules(e){this.rules=[...e].sort((t,s)=>t.priority-s.priority)}getRules(){return this.rules}evaluate(e){for(let t of this.rules)if(this.ruleMatches(t,e))return t.rateLimit&&t.effect==="allow"&&!this.checkRateLimit(t,e)?{allowed:!1,matchedRule:t,reason:`Rate limit exceeded for rule: ${t.id}`,timestamp:new Date}:{allowed:t.effect==="allow",matchedRule:t,reason:`Matched rule: ${t.id}`,timestamp:new Date};return{allowed:!1,matchedRule:void 0,reason:"No matching rule found \u2014 default deny",timestamp:new Date}}checkRateLimit(e,t){if(!e.rateLimit)return!0;let s=this.getScopeKey(e.scope,t),r=`${e.id}:${s}`;return this.rateLimiter.checkAndIncrement(r,e.rateLimit).allowed}resetRateLimits(){this.rateLimiter.reset()}getScopeKey(e,t){switch(e){case"global":return"global";case"user":return t.userId;case"conversation":return t.chatId??"unknown";case"platform":return t.platform}}ruleMatches(e,t){return!(!e.actions.includes("*")&&!e.actions.includes(t.action)||!e.riskLevels.includes(t.riskLevel)||e.conditions&&(e.conditions.users&&e.conditions.users.length>0&&!e.conditions.users.includes(t.userId)||e.conditions.platforms&&e.conditions.platforms.length>0&&!e.conditions.platforms.includes(t.platform)||e.conditions.chatType&&e.conditions.chatType!==t.chatType||e.conditions.timeWindow&&!this.matchesTimeWindow(e.conditions.timeWindow)))}matchesTimeWindow(e){if(!e)return!0;let t=new Date;if(e.daysOfWeek&&e.daysOfWeek.length>0&&!e.daysOfWeek.includes(t.getDay()))return!1;let s=t.getHours();if(e.startHour!==void 0&&e.endHour!==void 0){if(e.startHour<=e.endHour){if(s<e.startHour||s>=e.endHour)return!1}else if(s>=e.endHour&&s<e.startHour)return!1}else if(e.startHour!==void 0){if(s<e.startHour)return!1}else if(e.endHour!==void 0&&s>=e.endHour)return!1;return!0}}});var Td,_d,kd,at,bd=T(()=>{"use strict";Td=["allow","deny"],_d=["global","user","conversation","platform"],kd=["read","write","destructive","admin"],at=class{static{p(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!Td.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Td.join(", ")}`);if(typeof s.priority!="number"||!Number.isFinite(s.priority))throw new Error(`Rule "${s.id}" is missing a valid "priority" number`);if(typeof s.scope!="string"||!_d.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${_d.join(", ")}`);if(!Array.isArray(s.actions)||s.actions.length===0)throw new Error(`Rule "${s.id}" is missing a valid "actions" array`);for(let n of s.actions)if(typeof n!="string")throw new Error(`Rule "${s.id}" has a non-string entry in "actions"`);if(!Array.isArray(s.riskLevels)||s.riskLevels.length===0)throw new Error(`Rule "${s.id}" is missing a valid "riskLevels" array`);for(let n of s.riskLevels)if(!kd.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${kd.join(", ")}`);let r={id:s.id,effect:s.effect,priority:s.priority,scope:s.scope,actions:s.actions,riskLevels:s.riskLevels};if(s.conditions!==void 0){if(typeof s.conditions!="object"||s.conditions===null)throw new Error(`Rule "${s.id}" has invalid "conditions": expected an object`);let n=s.conditions;if(n.users!==void 0&&!Array.isArray(n.users))throw new Error(`Rule "${s.id}" has invalid "conditions.users": expected an array`);if(n.platforms!==void 0&&!Array.isArray(n.platforms))throw new Error(`Rule "${s.id}" has invalid "conditions.platforms": expected an array`);if(n.chatType!==void 0&&typeof n.chatType!="string")throw new Error(`Rule "${s.id}" has invalid "conditions.chatType": expected a string`);if(n.timeWindow!==void 0){let o=n.timeWindow;if(typeof o!="object"||o===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(o.startHour!==void 0&&(typeof o.startHour!="number"||o.startHour<0||o.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(o.endHour!==void 0&&(typeof o.endHour!="number"||o.endHour<0||o.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(o.daysOfWeek!==void 0&&(!Array.isArray(o.daysOfWeek)||!o.daysOfWeek.every(i=>typeof i=="number"&&i>=0&&i<=6)))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.daysOfWeek": expected array of 0-6`)}r.conditions=s.conditions}if(s.rateLimit!==void 0){if(typeof s.rateLimit!="object"||s.rateLimit===null)throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected an object`);let n=s.rateLimit;if(typeof n.maxInvocations!="number"||typeof n.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import sf from"node:crypto";var jr,Ed=T(()=>{"use strict";jr=class{static{p(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:sf.randomUUID(),timestamp:t.timestamp,userId:e.userId,action:e.action,riskLevel:e.riskLevel,ruleId:t.matchedRule?.id,effect:t.allowed?"allow":"deny",platform:e.platform,chatId:e.chatId,context:{chatType:e.chatType,reason:t.reason}};try{this.auditRepository.log(s)}catch(r){this.logger.error({err:r,auditEntry:s},"Failed to write audit log entry")}return this.logger.debug({userId:e.userId,action:e.action,allowed:t.allowed,ruleId:t.matchedRule?.id,reason:t.reason},"Security evaluation completed"),t}}});var yo=T(()=>{"use strict";wd();ya();bd();Ed()});var x,B=T(()=>{"use strict";x=class{static{p(this,"Skill")}}});function de(l){return l.masterUserId??l.userId}function J(l){let e=new Set;if(e.add(de(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Oe=T(()=>{"use strict";p(de,"effectiveUserId");p(J,"allUserIds")});var bs,Sd=T(()=>{"use strict";bs=class{static{p(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var Es,$d=T(()=>{"use strict";Es=class{static{p(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:o}=e.metadata;return this.logger.info({skill:o,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,o,r,n):this.executeWithHardTimeout(e,t,s,o,r)}async executeWithTracker(e,t,s,r,n,o){return new Promise(i=>{let a=!1,c,d,u,m=p(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),h=p(f=>{a||(a=!0,m(),i(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),h(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),h({success:!1,error:g})}),u=setTimeout(()=>{if(a)return;let f=o.getIdleMs();if(f>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),h({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=o.getSnapshot();this.logger.info({skill:r,idleMs:f,state:g.state,iteration:g.iteration,totalMs:g.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){m();return}let y=o.getIdleMs(),_=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:_.state,iteration:_.iteration,totalMs:_.totalElapsedMs},"Agent went inactive \u2014 aborting"),h({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${_.state})`})):this.logger.debug({skill:r,idleMs:y,state:_.state,iteration:_.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let f=o.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),h({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,n){try{let o,i=await Promise.race([e.execute(t,s),new Promise((a,c)=>{o=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{o&&clearTimeout(o)});return this.logger.info({skill:r,success:i.success,...i.success?{}:{error:i.error}},"Skill execution completed"),i}catch(o){let i=o instanceof Error?o.message:String(o);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var Bt,wa=T(()=>{"use strict";Bt=class{static{p(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import rf from"node:fs";import Ta from"node:path";var wo,vd=T(()=>{"use strict";B();wo=class{static{p(this,"PluginLoader")}async loadFromDirectory(e){let t=Ta.resolve(e),s;try{s=await rf.promises.readdir(t)}catch(o){let i=o instanceof Error?o.message:String(o);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(o=>o.endsWith(".js")),n=[];for(let o of r){let i=Ta.join(t,o);try{let a=await this.loadFromFile(i);n.push(a)}catch(a){let c=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${c}`)}}return n}async loadFromFile(e){let t=Ta.resolve(e),n=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof n!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let o=new n;if(!(o instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(o,t),o}validateMetadata(e,t){let{metadata:s}=e;if(!s)throw new Error(`Plugin "${t}" is missing metadata`);if(!s.name||typeof s.name!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.name`);if(!s.description||typeof s.description!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.description`);if(!["read","write","destructive","admin"].includes(s.riskLevel))throw new Error(`Plugin "${t}" has invalid metadata.riskLevel: "${String(s.riskLevel)}"`);if(!s.version||typeof s.version!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.version`)}}});function nf(l){let e=[],t=0;for(;t<l.length;){if(l[t]===" "||l[t]===" "){t++;continue}if(/[\d.]/.test(l[t])){let s="";for(;t<l.length&&/[\d.]/.test(l[t]);)s+=l[t++];let r=Number(s);if(isNaN(r))throw new Error(`Invalid number: ${s}`);e.push({type:"num",value:r});continue}if(l.startsWith("Math.",t)){t+=5;let s="";for(;t<l.length&&/[a-zA-Z0-9]/.test(l[t]);)s+=l[t++];if(s in Ad)e.push({type:"const",value:Ad[s]});else if(s in Id)e.push({type:"fn",value:s});else throw new Error(`Unknown Math member: Math.${s}`);continue}if("+-*/%".includes(l[t])){e.push({type:"op",value:l[t++]});continue}if(l[t]==="("||l[t]===")"){e.push({type:"paren",value:l[t++]});continue}if(l[t]===","){e.push({type:"comma"}),t++;continue}throw new Error(`Unexpected character: ${l[t]}`)}return e}function of(l){let e=nf(l);if(e.length===0)throw new Error("Empty expression");return new _a(e).parse()}var Id,Ad,_a,Ss,Rd=T(()=>{"use strict";B();Id={sin:Math.sin,cos:Math.cos,tan:Math.tan,sqrt:Math.sqrt,pow:Math.pow,abs:Math.abs,floor:Math.floor,ceil:Math.ceil,round:Math.round,log:Math.log,log2:Math.log2,log10:Math.log10},Ad={PI:Math.PI,E:Math.E};p(nf,"tokenize");_a=class{static{p(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return Id[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};p(of,"safeEval");Ss=class extends x{static{p(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=of(r);return typeof n!="number"||!isFinite(n)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:n,display:`${r} = ${n}`}}catch(n){let o=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${o}`}}}}});var $s,xd=T(()=>{"use strict";B();$s=class extends x{static{p(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=p(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var vs,Cd=T(()=>{"use strict";B();vs=class extends x{static{p(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let o;switch(this.config.provider){case"brave":o=await this.searchBrave(s,r);break;case"searxng":o=await this.searchSearXNG(s,r);break;case"tavily":o=await this.searchTavily(s,r);break;case"duckduckgo":o=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(o.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=o.map((a,c)=>`${c+1}. **${a.title}**
702
702
  ${a.url}
703
703
  ${a.snippet}`).join(`
704
704
 
@@ -731,12 +731,12 @@ Available JS libraries in code_sandbox (no install needed): exceljs, pdfkit, pdf
731
731
 
732
732
  Additional context: ${r}`);let f,g;t.resumeState?.conversationHistory?.length?(f=t.resumeState.conversationHistory,g=t.resumeState.currentIteration):(f=[{role:"user",content:h}],g=0);try{let y=g,_=0,S=0;for(;;){if(t.abortSignal?.aborted)return t.onIteration?.({iteration:y,maxIterations:o,messages:[...f],dataStore:Object.fromEntries(d)}),a.ping("done",{iteration:y,maxIterations:o}),{success:!0,data:{response:"Task paused \u2014 can be resumed later.",iterations:y,paused:!0,usage:{inputTokens:_,outputTokens:S}},display:"Task paused \u2014 can be resumed later."};a.ping("llm_call",{iteration:y,maxIterations:o});let E=await this.llm.complete({messages:f,system:m,tools:c.length>0?c:void 0,maxTokens:8192,tier:"strong"});if(_+=E.usage.inputTokens,S+=E.usage.outputTokens,a.ping("processing",{iteration:y,maxIterations:o}),!E.toolCalls||E.toolCalls.length===0||y>=o)return a.ping("done",{iteration:y,maxIterations:o}),{success:!0,data:{response:E.content,iterations:y,usage:{inputTokens:_,outputTokens:S}},display:E.content};y++;let $=[];E.content&&$.push({type:"text",text:E.content});for(let M of E.toolCalls)$.push({type:"tool_use",id:M.id,name:M.name,input:M.input});f.push({role:"assistant",content:$});let R=[];for(let M of E.toolCalls){a.ping("tool_call",{iteration:y,maxIterations:o,tool:M.name});let q=M.input;if(M.name==="code_sandbox"&&M.input.data){let ee=String(M.input.data);d.has(ee)&&(q={...M.input,data:d.get(ee)},q.action==="run"&&(q.action="run_with_data"))}let G=await this.executeSubAgentTool({...M,input:q},t),F=G.content;if(!G.isError&&F.length>500){let ee=`result_${++u}`,ue=G.rawData!=null?JSON.stringify(G.rawData):F;d.set(ee,ue),F+=`
733
733
 
734
- [Data stored as "${ee}" \u2014 use code_sandbox action "run_with_data" with data="${ee}" to process this data. Do NOT copy data into code.]`}R.push({type:"tool_result",tool_use_id:M.id,content:F,is_error:G.isError})}f.push({role:"user",content:R}),t.onIteration?.({iteration:y,maxIterations:o,messages:[...f],dataStore:Object.fromEntries(d)})}}catch(y){return{success:!1,error:`Sub-agent failed: ${y instanceof Error?y.message:String(y)}`}}}buildSubAgentTools(){return this.skillRegistry?this.skillRegistry.getAll().filter(e=>e.metadata.name!=="delegate").map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema})):[]}async executeSubAgentTool(e,t){let s=this.skillRegistry?.get(e.name);if(!s)return{content:`Error: Unknown tool "${e.name}"`,isError:!0};if(this.securityManager){let r=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:s.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!r.allowed)return{content:`Access denied: ${r.reason}`,isError:!0}}if(this.skillSandbox){let r=await this.skillSandbox.execute(s,e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}try{let r=await s.execute(e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}catch(r){return{content:`Skill execution failed: ${r instanceof Error?r.message:String(r)}`,isError:!0}}}}});var ct,wo=T(()=>{"use strict";ct=class{static{p(this,"EmailProvider")}async extractFromSearch(e,t,s,r,n){throw new Error("Extract is not supported by this email provider.")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var jd={};me(jd,{MicrosoftGraphEmailProvider:()=>To});var To,ka=T(()=>{"use strict";wo();To=class extends ct{static{p(this,"MicrosoftGraphEmailProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){if(!this.config.refreshToken)throw new Error("Microsoft email: refreshToken is missing from config");let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${n.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let n=await s(this.accessToken);if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return this.parseJsonOrUndefined(n)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${n}`}}),"doFetch"),s=await t(this.accessToken);if(s.status===401&&(await this.refreshAccessToken(),s=await t(this.accessToken)),!s.ok)throw new Error(`Graph API error: ${s.status}`);let r=await s.arrayBuffer();return Buffer.from(r)}async fetchInbox(e){let t=new URLSearchParams({$top:String(Math.min(Math.max(1,e),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/inbox/messages?${t}`)).value??[]).map(r=>this.mapMessage(r))}async readMessage(e){let t=new URLSearchParams({$select:"id,from,toRecipients,ccRecipients,bccRecipients,subject,body,receivedDateTime,isRead,hasAttachments"}),s=await this.graphRequest(`/me/messages/${e}?${t}`),r=[];return s.hasAttachments&&(r=((await this.graphRequest(`/me/messages/${e}/attachments?$select=id,name,contentType,size`)).value??[]).map(o=>({id:o.id,name:o.name,contentType:o.contentType,size:o.size??0}))),{id:s.id,from:this.formatGraphAddress(s.from),to:(s.toRecipients??[]).map(n=>this.formatGraphAddress(n)),subject:s.subject??"(no subject)",date:new Date(s.receivedDateTime),read:s.isRead??!1,body:s.body?.contentType==="html"?this.stripHtml(s.body.content??""):s.body?.content??"",bodyHtml:s.body?.contentType==="html"?s.body.content:void 0,cc:s.ccRecipients?.map(n=>this.formatGraphAddress(n)),bcc:s.bccRecipients?.map(n=>this.formatGraphAddress(n)),hasAttachments:s.hasAttachments,attachments:r}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=new URLSearchParams({$search:`"${e}"`,$top:String(s),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"}),n=await this.graphRequest(`/me/messages?${r}`),o=(n.value??[]).map(i=>this.mapMessage(i));if(t>50){let i=n["@odata.nextLink"];for(;i&&o.length<t;){let a=await this.graphRequest(i.replace("https://graph.microsoft.com/v1.0","")),c=(a.value??[]).map(d=>this.mapMessage(d));o.push(...c),i=a["@odata.nextLink"]}}return o.slice(0,t)}async extractFromSearch(e,t,s,r,n){let o=await this.searchWithDateFilter(e,t,r,n),i=s.includes("amount"),a=[];if(i)for(let d=0;d<o.length;d+=5){let u=o.slice(d,d+5),m=await Promise.allSettled(u.map(async h=>{let f={id:h.id,from:h.from,subject:h.subject,date:h.date.toISOString().split("T")[0],preview:(h.preview??"").slice(0,200)};try{let g=await this.readMessage(h.id),y=this.extractAmount(g.body);y&&(f.amount=y.amount,f.currency=y.currency)}catch{}return f}));for(let h of m)h.status==="fulfilled"&&a.push(h.value)}else for(let c of o)a.push({id:c.id,from:c.from,subject:c.subject,date:c.date.toISOString().split("T")[0],preview:(c.preview??"").slice(0,200)});return a}async searchWithDateFilter(e,t,s,r){let n=Math.min(Math.max(1,t),50),o=[];if(s||r){let m=s?this.toKqlDate(s):"01/01/2000",h=r?this.toKqlDate(r):"12/31/2099";o.push(`received:${m}..${h}`)}e&&o.push(e.includes(" ")?`(${e})`:e);let i=o.join(" AND "),a=new URLSearchParams({$top:String(n),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});i?a.set("$search",`"${i}"`):a.set("$orderby","receivedDateTime desc");let c=await this.graphRequest(`/me/messages?${a}`),d=(c.value??[]).map(m=>this.mapMessage(m)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let m=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),h=(m.value??[]).map(f=>this.mapMessage(f));d.push(...h),u=m["@odata.nextLink"]}return d.slice(0,t)}toKqlDate(e){let[t,s,r]=e.split("-");return`${s}/${r}/${t}`}extractAmount(e){let t=[{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*€\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*€/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*EUR\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*EUR/i,currency:"EUR"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*\$\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*USD\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*([\d.,]+)\s*USD/i,currency:"USD"},{regex:/€\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\b([\d]+[.,]\d{2})\s*€/,currency:"EUR"},{regex:/EUR\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\$([\d]+[.,]\d{2})\b/,currency:"USD"},{regex:/USD\s*([\d]+[.,]\d{2})\b/,currency:"USD"}];for(let{regex:s,currency:r}of t){let n=e.match(s);if(n?.[1])return{amount:n[1].trim(),currency:r}}return null}async sendMessage(e){if(e.replyTo)return await this.graphRequest(`/me/messages/${e.replyTo}/reply`,{method:"POST",body:JSON.stringify({comment:e.body})}),{messageId:e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(s=>({emailAddress:{address:s.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(s=>({emailAddress:{address:s.trim()}}))),await this.graphRequest("/me/sendMail",{method:"POST",body:JSON.stringify({message:t})}),{messageId:`sent-${Date.now()}`}}async createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`/me/messages/${e.replyTo}/createReply`,{method:"POST",body:JSON.stringify({comment:e.body})}))?.id??e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(r=>({emailAddress:{address:r.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(r=>({emailAddress:{address:r.trim()}}))),{messageId:(await this.graphRequest("/me/messages",{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest("/me/mailFolders?$select=displayName&$top=100")).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest("/me/mailFolders?$select=id,displayName&$top=100")).value??[]).find(i=>i.displayName.toLowerCase()===e.toLowerCase());if(!r)throw new Error(`Folder "${e}" not found. Use the 'folders' action to list available folders.`);let n=new URLSearchParams({$top:String(Math.min(Math.max(1,t),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/${r.id}/messages?${n}`)).value??[]).map(i=>this.mapMessage(i))}async downloadAttachment(e,t){return this.graphRequestRaw(`/me/messages/${e}/attachments/${t}/$value`)}async forwardMessage(e,t,s){return await this.graphRequest(`/me/messages/${e}/forward`,{method:"POST",body:JSON.stringify({comment:s??"",toRecipients:t.split(",").map(r=>({emailAddress:{address:r.trim()}}))})}),{messageId:`fwd-${Date.now()}`}}mapMessage(e){return{id:e.id,from:this.formatGraphAddress(e.from),to:(e.toRecipients??[]).map(t=>this.formatGraphAddress(t)),subject:e.subject??"(no subject)",date:new Date(e.receivedDateTime),read:e.isRead??!1,preview:e.bodyPreview??void 0,hasAttachments:e.hasAttachments??!1}}formatGraphAddress(e){if(!e)return"unknown";let t=e.emailAddress??e;return t?.address?t.name?`${t.name} <${t.address}>`:t.address:"unknown"}stripHtml(e){return e.replace(/<br\s*\/?>/gi,`
734
+ [Data stored as "${ee}" \u2014 use code_sandbox action "run_with_data" with data="${ee}" to process this data. Do NOT copy data into code.]`}R.push({type:"tool_result",tool_use_id:M.id,content:F,is_error:G.isError})}f.push({role:"user",content:R}),t.onIteration?.({iteration:y,maxIterations:o,messages:[...f],dataStore:Object.fromEntries(d)})}}catch(y){return{success:!1,error:`Sub-agent failed: ${y instanceof Error?y.message:String(y)}`}}}buildSubAgentTools(){return this.skillRegistry?this.skillRegistry.getAll().filter(e=>e.metadata.name!=="delegate").map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema})):[]}async executeSubAgentTool(e,t){let s=this.skillRegistry?.get(e.name);if(!s)return{content:`Error: Unknown tool "${e.name}"`,isError:!0};if(this.securityManager){let r=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:s.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!r.allowed)return{content:`Access denied: ${r.reason}`,isError:!0}}if(this.skillSandbox){let r=await this.skillSandbox.execute(s,e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}try{let r=await s.execute(e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}catch(r){return{content:`Skill execution failed: ${r instanceof Error?r.message:String(r)}`,isError:!0}}}}});var ct,To=T(()=>{"use strict";ct=class{static{p(this,"EmailProvider")}async extractFromSearch(e,t,s,r,n){throw new Error("Extract is not supported by this email provider.")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var jd={};me(jd,{MicrosoftGraphEmailProvider:()=>_o});var _o,ka=T(()=>{"use strict";To();_o=class extends ct{static{p(this,"MicrosoftGraphEmailProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){if(!this.config.refreshToken)throw new Error("Microsoft email: refreshToken is missing from config");let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${n.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let n=await s(this.accessToken);if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return this.parseJsonOrUndefined(n)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${n}`}}),"doFetch"),s=await t(this.accessToken);if(s.status===401&&(await this.refreshAccessToken(),s=await t(this.accessToken)),!s.ok)throw new Error(`Graph API error: ${s.status}`);let r=await s.arrayBuffer();return Buffer.from(r)}async fetchInbox(e){let t=new URLSearchParams({$top:String(Math.min(Math.max(1,e),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/inbox/messages?${t}`)).value??[]).map(r=>this.mapMessage(r))}async readMessage(e){let t=new URLSearchParams({$select:"id,from,toRecipients,ccRecipients,bccRecipients,subject,body,receivedDateTime,isRead,hasAttachments"}),s=await this.graphRequest(`/me/messages/${e}?${t}`),r=[];return s.hasAttachments&&(r=((await this.graphRequest(`/me/messages/${e}/attachments?$select=id,name,contentType,size`)).value??[]).map(o=>({id:o.id,name:o.name,contentType:o.contentType,size:o.size??0}))),{id:s.id,from:this.formatGraphAddress(s.from),to:(s.toRecipients??[]).map(n=>this.formatGraphAddress(n)),subject:s.subject??"(no subject)",date:new Date(s.receivedDateTime),read:s.isRead??!1,body:s.body?.contentType==="html"?this.stripHtml(s.body.content??""):s.body?.content??"",bodyHtml:s.body?.contentType==="html"?s.body.content:void 0,cc:s.ccRecipients?.map(n=>this.formatGraphAddress(n)),bcc:s.bccRecipients?.map(n=>this.formatGraphAddress(n)),hasAttachments:s.hasAttachments,attachments:r}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=new URLSearchParams({$search:`"${e}"`,$top:String(s),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"}),n=await this.graphRequest(`/me/messages?${r}`),o=(n.value??[]).map(i=>this.mapMessage(i));if(t>50){let i=n["@odata.nextLink"];for(;i&&o.length<t;){let a=await this.graphRequest(i.replace("https://graph.microsoft.com/v1.0","")),c=(a.value??[]).map(d=>this.mapMessage(d));o.push(...c),i=a["@odata.nextLink"]}}return o.slice(0,t)}async extractFromSearch(e,t,s,r,n){let o=await this.searchWithDateFilter(e,t,r,n),i=s.includes("amount"),a=[];if(i)for(let d=0;d<o.length;d+=5){let u=o.slice(d,d+5),m=await Promise.allSettled(u.map(async h=>{let f={id:h.id,from:h.from,subject:h.subject,date:h.date.toISOString().split("T")[0],preview:(h.preview??"").slice(0,200)};try{let g=await this.readMessage(h.id),y=this.extractAmount(g.body);y&&(f.amount=y.amount,f.currency=y.currency)}catch{}return f}));for(let h of m)h.status==="fulfilled"&&a.push(h.value)}else for(let c of o)a.push({id:c.id,from:c.from,subject:c.subject,date:c.date.toISOString().split("T")[0],preview:(c.preview??"").slice(0,200)});return a}async searchWithDateFilter(e,t,s,r){let n=Math.min(Math.max(1,t),50),o=[];if(s||r){let m=s?this.toKqlDate(s):"01/01/2000",h=r?this.toKqlDate(r):"12/31/2099";o.push(`received:${m}..${h}`)}e&&o.push(e.includes(" ")?`(${e})`:e);let i=o.join(" AND "),a=new URLSearchParams({$top:String(n),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});i?a.set("$search",`"${i}"`):a.set("$orderby","receivedDateTime desc");let c=await this.graphRequest(`/me/messages?${a}`),d=(c.value??[]).map(m=>this.mapMessage(m)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let m=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),h=(m.value??[]).map(f=>this.mapMessage(f));d.push(...h),u=m["@odata.nextLink"]}return d.slice(0,t)}toKqlDate(e){let[t,s,r]=e.split("-");return`${s}/${r}/${t}`}extractAmount(e){let t=[{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*€\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*€/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*EUR\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*EUR/i,currency:"EUR"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*\$\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*USD\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*([\d.,]+)\s*USD/i,currency:"USD"},{regex:/€\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\b([\d]+[.,]\d{2})\s*€/,currency:"EUR"},{regex:/EUR\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\$([\d]+[.,]\d{2})\b/,currency:"USD"},{regex:/USD\s*([\d]+[.,]\d{2})\b/,currency:"USD"}];for(let{regex:s,currency:r}of t){let n=e.match(s);if(n?.[1])return{amount:n[1].trim(),currency:r}}return null}async sendMessage(e){if(e.replyTo)return await this.graphRequest(`/me/messages/${e.replyTo}/reply`,{method:"POST",body:JSON.stringify({comment:e.body})}),{messageId:e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(s=>({emailAddress:{address:s.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(s=>({emailAddress:{address:s.trim()}}))),await this.graphRequest("/me/sendMail",{method:"POST",body:JSON.stringify({message:t})}),{messageId:`sent-${Date.now()}`}}async createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`/me/messages/${e.replyTo}/createReply`,{method:"POST",body:JSON.stringify({comment:e.body})}))?.id??e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(r=>({emailAddress:{address:r.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(r=>({emailAddress:{address:r.trim()}}))),{messageId:(await this.graphRequest("/me/messages",{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest("/me/mailFolders?$select=displayName&$top=100")).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest("/me/mailFolders?$select=id,displayName&$top=100")).value??[]).find(i=>i.displayName.toLowerCase()===e.toLowerCase());if(!r)throw new Error(`Folder "${e}" not found. Use the 'folders' action to list available folders.`);let n=new URLSearchParams({$top:String(Math.min(Math.max(1,t),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/${r.id}/messages?${n}`)).value??[]).map(i=>this.mapMessage(i))}async downloadAttachment(e,t){return this.graphRequestRaw(`/me/messages/${e}/attachments/${t}/$value`)}async forwardMessage(e,t,s){return await this.graphRequest(`/me/messages/${e}/forward`,{method:"POST",body:JSON.stringify({comment:s??"",toRecipients:t.split(",").map(r=>({emailAddress:{address:r.trim()}}))})}),{messageId:`fwd-${Date.now()}`}}mapMessage(e){return{id:e.id,from:this.formatGraphAddress(e.from),to:(e.toRecipients??[]).map(t=>this.formatGraphAddress(t)),subject:e.subject??"(no subject)",date:new Date(e.receivedDateTime),read:e.isRead??!1,preview:e.bodyPreview??void 0,hasAttachments:e.hasAttachments??!1}}formatGraphAddress(e){if(!e)return"unknown";let t=e.emailAddress??e;return t?.address?t.name?`${t.name} <${t.address}>`:t.address:"unknown"}stripHtml(e){return e.replace(/<br\s*\/?>/gi,`
735
735
  `).replace(/<\/p>/gi,`
736
736
 
737
737
  `).replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\n{3,}/g,`
738
738
 
739
- `).trim()}}});var Bd={};me(Bd,{StandardEmailProvider:()=>_o});var _o,ba=T(()=>{"use strict";wo();_o=class extends ct{static{p(this,"StandardEmailProvider")}config;constructor(e){super(),this.config=e}async initialize(){}createImapClient(){return import("imapflow").then(({ImapFlow:e})=>new e({host:this.config.imap.host,port:this.config.imap.port,secure:this.config.imap.secure,auth:this.config.auth,logger:!1}))}formatAddress(e){return e?e.name?`${e.name} <${e.address}>`:e.address??"unknown":"unknown"}async fetchInbox(e){return this.fetchFolder("INBOX",e)}async readMessage(e){let t=parseInt(e,10);if(isNaN(t)||t<1)throw new Error("messageId must be a positive number (sequence number).");let s=await this.createImapClient();try{await s.connect();let r=await s.getMailboxLock("INBOX");try{let n=await s.fetchOne(String(t),{envelope:!0,source:!0,bodyStructure:!0});if(!n)throw new Error(`Message #${t} not found.`);let o=this.formatAddress(n.envelope?.from?.[0]),i=n.envelope?.to?.map(m=>m.name?`${m.name} <${m.address}>`:m.address??"")??[],a=n.envelope?.cc?.map(m=>m.name?`${m.name} <${m.address}>`:m.address??""),c=n.source?.toString()??"",d=this.extractTextBody(c),u=this.extractAttachmentInfo(n.bodyStructure);return{id:String(t),from:o,to:i,subject:n.envelope?.subject??"(no subject)",date:n.envelope?.date??new Date,read:n.flags?.has("\\Seen")??!1,body:d,cc:a,attachments:u}}finally{r.release()}}finally{await s.logout()}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock("INBOX");try{let o=await r.search({or:[{subject:e},{from:e},{body:e}]}),i=Array.isArray(o)?o:[];if(i.length===0)return[];let a=i.slice(-s),c=[];for await(let d of r.fetch(a,{envelope:!0,flags:!0}))c.push({id:String(d.seq),from:this.formatAddress(d.envelope?.from?.[0]),to:d.envelope?.to?.map(u=>u.name?`${u.name} <${u.address}>`:u.address??"")??[],subject:d.envelope?.subject??"(no subject)",date:d.envelope?.date??new Date,read:d.flags?.has("\\Seen")??!1});return c.reverse(),c}finally{n.release()}}finally{await r.logout()}}async sendMessage(e){let s=(await import("nodemailer")).createTransport({host:this.config.smtp.host,port:this.config.smtp.port,secure:this.config.smtp.secure,auth:this.config.auth}),r={from:this.config.auth.user,to:e.to,subject:e.subject};return e.cc&&(r.cc=e.cc),e.isHtml?r.html=e.body:r.text=e.body,e.replyTo&&(r.inReplyTo=e.replyTo,r.references=e.replyTo),{messageId:(await s.sendMail(r)).messageId}}async listFolders(){let e=await this.createImapClient();try{await e.connect();let t=await e.list(),s=[];for(let r of t)s.push(r.path);return s}finally{await e.logout()}}async fetchFolder(e,t){let s=Math.min(Math.max(1,t),50),r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock(e);try{let o=[],i=r.mailbox,a=i&&typeof i=="object"?i.exists??0:0;if(a===0)return[];let d=`${Math.max(1,a-s+1)}:*`;for await(let u of r.fetch(d,{envelope:!0,flags:!0})){let m=this.formatAddress(u.envelope?.from?.[0]);o.push({id:String(u.seq),from:m,to:u.envelope?.to?.map(h=>h.name?`${h.name} <${h.address}>`:h.address??"")??[],subject:u.envelope?.subject??"(no subject)",date:u.envelope?.date??new Date,read:u.flags?.has("\\Seen")??!1})}return o.reverse(),o}finally{n.release()}}finally{await r.logout()}}async downloadAttachment(e,t){let s=parseInt(e,10);if(isNaN(s)||s<1)throw new Error("messageId must be a positive number.");let r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock("INBOX");try{let i=(await r.fetchOne(String(s),{bodyParts:[t]}))?.bodyParts?.get(t);if(!i)throw new Error(`Attachment "${t}" not found in message #${s}.`);return Buffer.from(i)}finally{n.release()}}finally{await r.logout()}}extractAttachmentInfo(e){let t=[];if(!e)return t;let s=p((r,n)=>{if(r.childNodes){for(let i=0;i<r.childNodes.length;i++)s(r.childNodes[i],n?`${n}.${i+1}`:String(i+1));return}let o=r.disposition?.toLowerCase();if(o==="attachment"||r.type&&!r.type.startsWith("text/")&&o!=="inline"){let i=r.dispositionParameters?.filename??r.parameters?.name??`part-${n}`;t.push({id:r.part??n,name:i,contentType:r.type??"application/octet-stream",size:r.size??0})}},"walk");return s(e,""),t}extractTextBody(e){let t=e.split(/\r?\n\r?\n/);if(t.length<2)return e;let s=t[0].toLowerCase();if(!s.includes("multipart"))return this.decodeBody(t.slice(1).join(`
739
+ `).trim()}}});var Bd={};me(Bd,{StandardEmailProvider:()=>ko});var ko,ba=T(()=>{"use strict";To();ko=class extends ct{static{p(this,"StandardEmailProvider")}config;constructor(e){super(),this.config=e}async initialize(){}createImapClient(){return import("imapflow").then(({ImapFlow:e})=>new e({host:this.config.imap.host,port:this.config.imap.port,secure:this.config.imap.secure,auth:this.config.auth,logger:!1}))}formatAddress(e){return e?e.name?`${e.name} <${e.address}>`:e.address??"unknown":"unknown"}async fetchInbox(e){return this.fetchFolder("INBOX",e)}async readMessage(e){let t=parseInt(e,10);if(isNaN(t)||t<1)throw new Error("messageId must be a positive number (sequence number).");let s=await this.createImapClient();try{await s.connect();let r=await s.getMailboxLock("INBOX");try{let n=await s.fetchOne(String(t),{envelope:!0,source:!0,bodyStructure:!0});if(!n)throw new Error(`Message #${t} not found.`);let o=this.formatAddress(n.envelope?.from?.[0]),i=n.envelope?.to?.map(m=>m.name?`${m.name} <${m.address}>`:m.address??"")??[],a=n.envelope?.cc?.map(m=>m.name?`${m.name} <${m.address}>`:m.address??""),c=n.source?.toString()??"",d=this.extractTextBody(c),u=this.extractAttachmentInfo(n.bodyStructure);return{id:String(t),from:o,to:i,subject:n.envelope?.subject??"(no subject)",date:n.envelope?.date??new Date,read:n.flags?.has("\\Seen")??!1,body:d,cc:a,attachments:u}}finally{r.release()}}finally{await s.logout()}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock("INBOX");try{let o=await r.search({or:[{subject:e},{from:e},{body:e}]}),i=Array.isArray(o)?o:[];if(i.length===0)return[];let a=i.slice(-s),c=[];for await(let d of r.fetch(a,{envelope:!0,flags:!0}))c.push({id:String(d.seq),from:this.formatAddress(d.envelope?.from?.[0]),to:d.envelope?.to?.map(u=>u.name?`${u.name} <${u.address}>`:u.address??"")??[],subject:d.envelope?.subject??"(no subject)",date:d.envelope?.date??new Date,read:d.flags?.has("\\Seen")??!1});return c.reverse(),c}finally{n.release()}}finally{await r.logout()}}async sendMessage(e){let s=(await import("nodemailer")).createTransport({host:this.config.smtp.host,port:this.config.smtp.port,secure:this.config.smtp.secure,auth:this.config.auth}),r={from:this.config.auth.user,to:e.to,subject:e.subject};return e.cc&&(r.cc=e.cc),e.isHtml?r.html=e.body:r.text=e.body,e.replyTo&&(r.inReplyTo=e.replyTo,r.references=e.replyTo),{messageId:(await s.sendMail(r)).messageId}}async listFolders(){let e=await this.createImapClient();try{await e.connect();let t=await e.list(),s=[];for(let r of t)s.push(r.path);return s}finally{await e.logout()}}async fetchFolder(e,t){let s=Math.min(Math.max(1,t),50),r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock(e);try{let o=[],i=r.mailbox,a=i&&typeof i=="object"?i.exists??0:0;if(a===0)return[];let d=`${Math.max(1,a-s+1)}:*`;for await(let u of r.fetch(d,{envelope:!0,flags:!0})){let m=this.formatAddress(u.envelope?.from?.[0]);o.push({id:String(u.seq),from:m,to:u.envelope?.to?.map(h=>h.name?`${h.name} <${h.address}>`:h.address??"")??[],subject:u.envelope?.subject??"(no subject)",date:u.envelope?.date??new Date,read:u.flags?.has("\\Seen")??!1})}return o.reverse(),o}finally{n.release()}}finally{await r.logout()}}async downloadAttachment(e,t){let s=parseInt(e,10);if(isNaN(s)||s<1)throw new Error("messageId must be a positive number.");let r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock("INBOX");try{let i=(await r.fetchOne(String(s),{bodyParts:[t]}))?.bodyParts?.get(t);if(!i)throw new Error(`Attachment "${t}" not found in message #${s}.`);return Buffer.from(i)}finally{n.release()}}finally{await r.logout()}}extractAttachmentInfo(e){let t=[];if(!e)return t;let s=p((r,n)=>{if(r.childNodes){for(let i=0;i<r.childNodes.length;i++)s(r.childNodes[i],n?`${n}.${i+1}`:String(i+1));return}let o=r.disposition?.toLowerCase();if(o==="attachment"||r.type&&!r.type.startsWith("text/")&&o!=="inline"){let i=r.dispositionParameters?.filename??r.parameters?.name??`part-${n}`;t.push({id:r.part??n,name:i,contentType:r.type??"application/octet-stream",size:r.size??0})}},"walk");return s(e,""),t}extractTextBody(e){let t=e.split(/\r?\n\r?\n/);if(t.length<2)return e;let s=t[0].toLowerCase();if(!s.includes("multipart"))return this.decodeBody(t.slice(1).join(`
740
740
 
741
741
  `));let r=s.match(/boundary="?([^"\s;]+)"?/i)??e.match(/boundary="?([^"\s;]+)"?/i);if(!r)return t.slice(1).join(`
742
742
 
@@ -746,7 +746,7 @@ Additional context: ${r}`);let f,g;t.resumeState?.conversationHistory?.length?(f
746
746
  \r
747
747
  `);if(d>=0)return this.decodeBody(i.slice(d+4))}}return this.decodeBody(t.slice(1).join(`
748
748
 
749
- `).slice(0,5e3))}decodeBody(e){return e.replace(/=\r?\n/g,"").replace(/=([0-9A-Fa-f]{2})/g,(t,s)=>String.fromCharCode(parseInt(s,16))).trim()}}});async function Br(l){if(l.provider==="microsoft"){if(!l.microsoft)throw new Error("Microsoft email config missing");let{MicrosoftGraphEmailProvider:s}=await Promise.resolve().then(()=>(ka(),jd)),r=new s(l.microsoft);return await r.initialize(),r}if(!l.imap||!l.smtp||!l.auth)throw new Error("IMAP/SMTP email config missing (imap, smtp, auth required)");let{StandardEmailProvider:e}=await Promise.resolve().then(()=>(ba(),Bd)),t=new e(l);return await t.initialize(),t}var Hd=T(()=>{"use strict";p(Br,"createEmailProvider")});var wt,Wd=T(()=>{"use strict";wo();Hd();ba();ka();B();wt=class extends x{static{p(this,"EmailSkill")}metadata;providers;accountNames;defaultAccount;multiAccount;llm;constructor(e){super(),e instanceof Map?this.providers=e:e?this.providers=new Map([["default",e]]):this.providers=new Map,this.accountNames=[...this.providers.keys()],this.defaultAccount=this.accountNames[0]??"default",this.multiAccount=this.providers.size>1;let t=this.multiAccount?{account:{type:"string",enum:this.accountNames,description:`Email account to use (available: ${this.accountNames.join(", ")}). Required for multi-account setups.`}}:{},s=this.multiAccount?`Access the user's email accounts (${this.accountNames.join(", ")}): check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments.`:`Access the user's email: check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments. Use "draft" instead of "send" when the user asks to prepare/draft an email without sending it.`;this.metadata={name:"email",category:"productivity",description:s,riskLevel:"write",version:"3.1.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["inbox","read","search","send","draft","folders","folder","reply","forward","attachment","extract","summarize_inbox","categorize"],description:'The email action to perform. Use "extract" for bulk invoice/receipt extraction. Use "summarize_inbox" for an AI-generated summary of recent unread emails. Use "categorize" to classify unread emails by priority.'},...t,count:{type:"number",description:"Number of emails to fetch (for inbox/search/folder, default: 10)"},messageId:{type:"string",description:"Message ID to read or reply to"},query:{type:"string",description:"Search query (for search action)"},to:{type:"string",description:"Recipient email address (for send action)"},subject:{type:"string",description:"Email subject (for send action)"},body:{type:"string",description:"Email body text (for send/reply action)"},cc:{type:"string",description:"CC recipients, comma-separated (for send action)"},folder:{type:"string",description:"Folder name (for folder action)"},attachmentId:{type:"string",description:"Attachment ID or filename (for attachment action)"},save:{type:"string",description:"Directory path to save the attachment to disk instead of reading its content (for attachment action)"},isHtml:{type:"boolean",description:"Whether the body is HTML (for send action)"},maxResults:{type:"number",description:"Maximum number of results for extract action (default: 200, max: 1000)"},fields:{type:"array",items:{type:"string"},description:'Fields to extract (for extract action). Available: "from", "subject", "date", "amount". Include "amount" to read email bodies and extract monetary amounts.'},dateFrom:{type:"string",description:'Start date filter for extract action (YYYY-MM-DD format, e.g. "2026-01-01")'},dateTo:{type:"string",description:'End date filter for extract action (YYYY-MM-DD format, e.g. "2026-12-31")'}},required:["action"]}}}setLLM(e){this.llm=e}async execute(e,t){if(this.providers.size===0)return{success:!1,error:"Email is not configured. Run `alfred setup` to configure email access."};let s=e.action;try{switch(s){case"inbox":return await this.handleInbox(e);case"read":return await this.handleRead(e);case"search":return await this.handleSearch(e);case"send":return await this.handleSend(e);case"draft":return await this.handleDraft(e);case"folders":return await this.handleFolders(e);case"folder":return await this.handleFolder(e);case"reply":return await this.handleReply(e);case"forward":return await this.handleForward(e);case"attachment":return await this.handleAttachment(e);case"extract":return await this.handleExtract(e);case"summarize_inbox":return await this.handleSummarizeInbox(e);case"categorize":return await this.handleCategorize(e);default:return{success:!1,error:`Unknown action: ${s}. Use: inbox, read, search, send, draft, folders, folder, reply, forward, attachment, summarize_inbox, categorize`}}}catch(r){return{success:!1,error:`Email error: ${r instanceof Error?r.message:String(r)}`}}}resolveProvider(e){let t=e.account??this.defaultAccount,s=this.providers.get(t);return s?{provider:s,account:t}:{success:!1,error:`Unknown email account "${t}". Available: ${this.accountNames.join(", ")}`}}encodeId(e,t){return this.multiAccount?`${e}::${t}`:t}decodeId(e){if(this.multiAccount){let t=e.indexOf("::");if(t>=0)return{account:e.slice(0,t),rawId:e.slice(t+2)}}return{account:this.defaultAccount,rawId:e}}accountLabel(e,t){return this.multiAccount?`[${e}] ${t}`:t}async handleInbox(e){let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,n=Math.min(Math.max(1,e.count??10),50),o=await s.fetchInbox(n);if(o.length===0)return{success:!0,data:{messages:[]},display:this.accountLabel(r,"Inbox is empty.")};let i=o.filter(c=>!c.read).length,a=o.map((c,d)=>{let u=c.read?"":" [UNREAD]",m=c.hasAttachments?" [ATT]":"";return`${d+1}. [${this.encodeId(r,c.id)}]${u}${m} ${c.subject}
749
+ `).slice(0,5e3))}decodeBody(e){return e.replace(/=\r?\n/g,"").replace(/=([0-9A-Fa-f]{2})/g,(t,s)=>String.fromCharCode(parseInt(s,16))).trim()}}});async function Br(l){if(l.provider==="microsoft"){if(!l.microsoft)throw new Error("Microsoft email config missing");let{MicrosoftGraphEmailProvider:s}=await Promise.resolve().then(()=>(ka(),jd)),r=new s(l.microsoft);return await r.initialize(),r}if(!l.imap||!l.smtp||!l.auth)throw new Error("IMAP/SMTP email config missing (imap, smtp, auth required)");let{StandardEmailProvider:e}=await Promise.resolve().then(()=>(ba(),Bd)),t=new e(l);return await t.initialize(),t}var Hd=T(()=>{"use strict";p(Br,"createEmailProvider")});var wt,Wd=T(()=>{"use strict";To();Hd();ba();ka();B();wt=class extends x{static{p(this,"EmailSkill")}metadata;providers;accountNames;defaultAccount;multiAccount;llm;constructor(e){super(),e instanceof Map?this.providers=e:e?this.providers=new Map([["default",e]]):this.providers=new Map,this.accountNames=[...this.providers.keys()],this.defaultAccount=this.accountNames[0]??"default",this.multiAccount=this.providers.size>1;let t=this.multiAccount?{account:{type:"string",enum:this.accountNames,description:`Email account to use (available: ${this.accountNames.join(", ")}). Required for multi-account setups.`}}:{},s=this.multiAccount?`Access the user's email accounts (${this.accountNames.join(", ")}): check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments.`:`Access the user's email: check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments. Use "draft" instead of "send" when the user asks to prepare/draft an email without sending it.`;this.metadata={name:"email",category:"productivity",description:s,riskLevel:"write",version:"3.1.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["inbox","read","search","send","draft","folders","folder","reply","forward","attachment","extract","summarize_inbox","categorize"],description:'The email action to perform. Use "extract" for bulk invoice/receipt extraction. Use "summarize_inbox" for an AI-generated summary of recent unread emails. Use "categorize" to classify unread emails by priority.'},...t,count:{type:"number",description:"Number of emails to fetch (for inbox/search/folder, default: 10)"},messageId:{type:"string",description:"Message ID to read or reply to"},query:{type:"string",description:"Search query (for search action)"},to:{type:"string",description:"Recipient email address (for send action)"},subject:{type:"string",description:"Email subject (for send action)"},body:{type:"string",description:"Email body text (for send/reply action)"},cc:{type:"string",description:"CC recipients, comma-separated (for send action)"},folder:{type:"string",description:"Folder name (for folder action)"},attachmentId:{type:"string",description:"Attachment ID or filename (for attachment action)"},save:{type:"string",description:"Directory path to save the attachment to disk instead of reading its content (for attachment action)"},isHtml:{type:"boolean",description:"Whether the body is HTML (for send action)"},maxResults:{type:"number",description:"Maximum number of results for extract action (default: 200, max: 1000)"},fields:{type:"array",items:{type:"string"},description:'Fields to extract (for extract action). Available: "from", "subject", "date", "amount". Include "amount" to read email bodies and extract monetary amounts.'},dateFrom:{type:"string",description:'Start date filter for extract action (YYYY-MM-DD format, e.g. "2026-01-01")'},dateTo:{type:"string",description:'End date filter for extract action (YYYY-MM-DD format, e.g. "2026-12-31")'}},required:["action"]}}}setLLM(e){this.llm=e}async execute(e,t){if(this.providers.size===0)return{success:!1,error:"Email is not configured. Run `alfred setup` to configure email access."};let s=e.action;try{switch(s){case"inbox":return await this.handleInbox(e);case"read":return await this.handleRead(e);case"search":return await this.handleSearch(e);case"send":return await this.handleSend(e);case"draft":return await this.handleDraft(e);case"folders":return await this.handleFolders(e);case"folder":return await this.handleFolder(e);case"reply":return await this.handleReply(e);case"forward":return await this.handleForward(e);case"attachment":return await this.handleAttachment(e);case"extract":return await this.handleExtract(e);case"summarize_inbox":return await this.handleSummarizeInbox(e);case"categorize":return await this.handleCategorize(e);default:return{success:!1,error:`Unknown action: ${s}. Use: inbox, read, search, send, draft, folders, folder, reply, forward, attachment, summarize_inbox, categorize`}}}catch(r){return{success:!1,error:`Email error: ${r instanceof Error?r.message:String(r)}`}}}resolveProvider(e){let t=e.account??this.defaultAccount,s=this.providers.get(t);return s?{provider:s,account:t}:{success:!1,error:`Unknown email account "${t}". Available: ${this.accountNames.join(", ")}`}}encodeId(e,t){return this.multiAccount?`${e}::${t}`:t}decodeId(e){if(this.multiAccount){let t=e.indexOf("::");if(t>=0)return{account:e.slice(0,t),rawId:e.slice(t+2)}}return{account:this.defaultAccount,rawId:e}}accountLabel(e,t){return this.multiAccount?`[${e}] ${t}`:t}async handleInbox(e){let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,n=Math.min(Math.max(1,e.count??10),50),o=await s.fetchInbox(n);if(o.length===0)return{success:!0,data:{messages:[]},display:this.accountLabel(r,"Inbox is empty.")};let i=o.filter(c=>!c.read).length,a=o.map((c,d)=>{let u=c.read?"":" [UNREAD]",m=c.hasAttachments?" [ATT]":"";return`${d+1}. [${this.encodeId(r,c.id)}]${u}${m} ${c.subject}
750
750
  From: ${c.from}
751
751
  Date: ${c.date.toISOString()}`}).join(`
752
752
 
@@ -825,7 +825,7 @@ Or add it to Alfred: npm install puppeteer`};switch(s){case"open":return this.op
825
825
 
826
826
  ${c}`}}catch(n){return{success:!1,error:`Failed to open "${s}": ${n.message}`}}}async screenshotPage(e,t){try{let s=await this.ensurePage(e),r=t.url;r&&await s.goto(r,{waitUntil:"networkidle2",timeout:3e4});let n=s.url();if(n==="about:blank")return{success:!1,error:'No page is open. Use action "open" with a URL first, or provide a URL.'};let o=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),i=t.path||gf.join(yf.homedir(),"Desktop",`browser-${o}.png`);return await s.screenshot({path:i,fullPage:!1}),{success:!0,data:{path:i,url:n},display:`Screenshot saved to ${i}`}}catch(s){return{success:!1,error:`Screenshot failed: ${s.message}`}}}async clickElement(e){let t=e.selector;if(!t)return{success:!1,error:'Missing "selector" for click action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t);try{await this.page.waitForNavigation({timeout:3e3})}catch{}let s=await this.page.title();return{success:!0,data:{selector:t,url:this.page.url(),title:s},display:`Clicked "${t}" \u2014 now on: ${s} (${this.page.url()})`}}catch(s){return{success:!1,error:`Click failed on "${t}": ${s.message}`}}}async typeText(e){let t=e.selector,s=e.text;if(!t)return{success:!1,error:'Missing "selector" for type action'};if(!s)return{success:!1,error:'Missing "text" for type action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{return await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t),await this.page.type(t,s,{delay:50}),{success:!0,data:{selector:t,textLength:s.length},display:`Typed ${s.length} characters into "${t}"`}}catch(r){return{success:!1,error:`Type failed on "${t}": ${r.message}`}}}async evaluateScript(e){let t=e.script;if(!t)return{success:!1,error:'Missing "script" for evaluate action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{let s=await this.page.evaluate(t),r=typeof s=="string"?s:JSON.stringify(s,null,2);return{success:!0,data:{result:s},display:r?.slice(0,1e4)??"(no output)"}}catch(s){return{success:!1,error:`Evaluate failed: ${s.message}`}}}async validateUrl(e){let t;try{t=new URL(e)}catch{return`Invalid URL: "${e}"`}if(["file:","chrome:","about:","data:","javascript:"].includes(t.protocol))return`Blocked URL protocol "${t.protocol}". Only http: and https: are allowed.`;if(t.protocol!=="http:"&&t.protocol!=="https:")return`Unsupported URL protocol "${t.protocol}". Only http: and https: are allowed.`;let r=t.hostname;return await this.resolveAndCheckHost(r)?`Access to private/internal network address "${r}" is blocked.`:null}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await wf(e);if(this.isPrivateIp(t))return!0}catch{}return!1}async closeBrowser(){try{return this.page=null,this.browser&&(await this.browser.close(),this.browser=null),{success:!0,display:"Browser closed."}}catch(e){return this.browser=null,this.page=null,{success:!1,error:`Close failed: ${e.message}`}}}}});var Fs,Qd=T(()=>{"use strict";B();Oe();Fs=class extends x{static{p(this,"ProfileSkill")}userRepo;metadata={name:"profile",category:"core",description:"Manage user profile settings including timezone, language, and bio. Use this to personalize Alfred for each user.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get","set_timezone","set_language","set_bio","set_preference"],description:"The profile action to perform"},value:{type:"string",description:"The value to set (for set_* actions)"},preference_key:{type:"string",description:"The preference key (for set_preference)"},preference_value:{type:"string",description:"The preference value (for set_preference)"}},required:["action"]}};constructor(e){super(),this.userRepo=e}async execute(e,t){let s=e.action,r=de(t);switch(s){case"get":return this.getProfile(r);case"set_timezone":return this.setField(r,"timezone",e.value);case"set_language":return this.setField(r,"language",e.value);case"set_bio":return this.setField(r,"bio",e.value);case"set_preference":return this.setPreference(r,e.preference_key,e.preference_value);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}getProfile(e){let t=this.userRepo.getProfile(e);if(!t)return{success:!0,data:null,display:"No profile found. Set your timezone, language, or bio to create one."};let s=[];if(t.displayName&&s.push(`Name: ${t.displayName}`),t.timezone&&s.push(`Timezone: ${t.timezone}`),t.language&&s.push(`Language: ${t.language}`),t.bio&&s.push(`Bio: ${t.bio}`),t.preferences)for(let[r,n]of Object.entries(t.preferences))s.push(`${r}: ${String(n)}`);return{success:!0,data:t,display:s.length>0?`Profile:
827
827
  ${s.map(r=>`- ${r}`).join(`
828
- `)}`:"Profile is empty."}}setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let n=this.userRepo.getProfile(e)?.preferences??{};return n[t]=s,this.userRepo.updateProfile(e,{preferences:n}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var ze,Wr=T(()=>{"use strict";ze=class{static{p(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var eu={};me(eu,{CalDAVProvider:()=>ko});var ko,Sa=T(()=>{"use strict";Wr();ko=class extends ze{static{p(this,"CalDAVProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"caldav"})}catch(e){throw new Error(`CalDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){let s=await this.client.fetchCalendars();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchCalendarObjects({calendar:n,timeRange:{start:e.toISOString(),end:t.toISOString()}});for(let i of o){let a=this.parseICalEvent(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.start.getTime()-o.start.getTime())}async createEvent(e){let t=await this.client.fetchCalendars();if(!t||t.length===0)throw new Error("No calendars found");let s=`alfred-${Date.now()}@alfred`,r=this.buildICalEvent(s,e);return await this.client.createCalendarObject({calendar:t[0],filename:`${s}.ics`,iCalString:r}),{id:s,title:e.title,start:e.start,end:e.end,location:e.location,description:e.description,allDay:e.allDay}}async updateEvent(e,t){let s=await this.client.fetchCalendars();for(let r of s){let n=await this.client.fetchCalendarObjects({calendar:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseICalEvent(o.data,o.url);if(!i)continue;let a={title:t.title??i.title,start:t.start??i.start,end:t.end??i.end,location:t.location??i.location,description:t.description??i.description,allDay:t.allDay??i.allDay},c=this.buildICalEvent(e,a);return await this.client.updateCalendarObject({calendarObject:{...o,data:c}}),{id:e,...a}}}throw new Error(`Event ${e} not found`)}async deleteEvent(e){let t=await this.client.fetchCalendars();for(let s of t){let r=await this.client.fetchCalendarObjects({calendar:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteCalendarObject({calendarObject:n});return}}throw new Error(`Event ${e} not found`)}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}parseICalEvent(e,t){try{let s=e.split(`
828
+ `)}`:"Profile is empty."}}setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let n=this.userRepo.getProfile(e)?.preferences??{};return n[t]=s,this.userRepo.updateProfile(e,{preferences:n}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var ze,Wr=T(()=>{"use strict";ze=class{static{p(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var eu={};me(eu,{CalDAVProvider:()=>bo});var bo,Sa=T(()=>{"use strict";Wr();bo=class extends ze{static{p(this,"CalDAVProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"caldav"})}catch(e){throw new Error(`CalDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){let s=await this.client.fetchCalendars();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchCalendarObjects({calendar:n,timeRange:{start:e.toISOString(),end:t.toISOString()}});for(let i of o){let a=this.parseICalEvent(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.start.getTime()-o.start.getTime())}async createEvent(e){let t=await this.client.fetchCalendars();if(!t||t.length===0)throw new Error("No calendars found");let s=`alfred-${Date.now()}@alfred`,r=this.buildICalEvent(s,e);return await this.client.createCalendarObject({calendar:t[0],filename:`${s}.ics`,iCalString:r}),{id:s,title:e.title,start:e.start,end:e.end,location:e.location,description:e.description,allDay:e.allDay}}async updateEvent(e,t){let s=await this.client.fetchCalendars();for(let r of s){let n=await this.client.fetchCalendarObjects({calendar:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseICalEvent(o.data,o.url);if(!i)continue;let a={title:t.title??i.title,start:t.start??i.start,end:t.end??i.end,location:t.location??i.location,description:t.description??i.description,allDay:t.allDay??i.allDay},c=this.buildICalEvent(e,a);return await this.client.updateCalendarObject({calendarObject:{...o,data:c}}),{id:e,...a}}}throw new Error(`Event ${e} not found`)}async deleteEvent(e){let t=await this.client.fetchCalendars();for(let s of t){let r=await this.client.fetchCalendarObjects({calendar:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteCalendarObject({calendarObject:n});return}}throw new Error(`Event ${e} not found`)}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}parseICalEvent(e,t){try{let s=e.split(`
829
829
  `).map(m=>m.trim()),r=p(m=>s.find(h=>h.startsWith(m+":"))?.slice(m.length+1),"get"),n=r("SUMMARY"),o=r("DTSTART")??r("DTSTART;VALUE=DATE"),i=r("DTEND")??r("DTEND;VALUE=DATE"),a=r("LOCATION"),c=r("DESCRIPTION"),d=r("UID")??t;if(!n||!o)return;let u=o.length===8;return{id:d,title:n,start:this.parseICalDate(o),end:i?this.parseICalDate(i):this.parseICalDate(o),location:a||void 0,description:c||void 0,allDay:u}}catch(s){console.error("[caldav] Failed to parse iCal event",s);return}}parseICalDate(e){if(e.length===8)return new Date(`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`);let t=e.replace(/[^0-9TZ]/g,"");return t.length>=15?new Date(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T${t.slice(9,11)}:${t.slice(11,13)}:${t.slice(13,15)}Z`):new Date(e)}buildICalEvent(e,t){let s=p((n,o)=>o?n.toISOString().slice(0,10).replace(/-/g,""):n.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),"formatDate"),r=`BEGIN:VCALENDAR\r
830
830
  VERSION:2.0\r
831
831
  PRODID:-//Alfred//EN\r
@@ -841,7 +841,7 @@ BEGIN:VEVENT\r
841
841
  `),r+=`DTSTAMP:${s(new Date)}\r
842
842
  `,r+=`END:VEVENT\r
843
843
  END:VCALENDAR\r
844
- `,r}}});var tu={};me(tu,{GoogleCalendarProvider:()=>bo});var bo,$a=T(()=>{"use strict";Wr();bo=class extends ze{static{p(this,"GoogleCalendarProvider")}config;calendar;constructor(e){super(),this.config=e}async initialize(){try{let{google:e}=await import("googleapis"),t=new e.auth.OAuth2(this.config.clientId,this.config.clientSecret);t.setCredentials({refresh_token:this.config.refreshToken}),this.calendar=e.calendar({version:"v3",auth:t})}catch(e){throw new Error(`Google Calendar initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){return((await this.calendar.events.list({calendarId:"primary",timeMin:e.toISOString(),timeMax:t.toISOString(),singleEvents:!0,orderBy:"startTime"})).data.items??[]).map(r=>this.mapEvent(r))}async createEvent(e){let t={summary:e.title,location:e.location,description:e.description};e.allDay?(t.start={date:e.start.toISOString().slice(0,10)},t.end={date:e.end.toISOString().slice(0,10)}):(t.start={dateTime:e.start.toISOString()},t.end={dateTime:e.end.toISOString()});let s=await this.calendar.events.insert({calendarId:"primary",requestBody:t});return this.mapEvent(s.data)}async updateEvent(e,t){let s={};t.title&&(s.summary=t.title),t.location&&(s.location=t.location),t.description&&(s.description=t.description),t.start&&(s.start=t.allDay?{date:t.start.toISOString().slice(0,10)}:{dateTime:t.start.toISOString()}),t.end&&(s.end=t.allDay?{date:t.end.toISOString().slice(0,10)}:{dateTime:t.end.toISOString()});let r=await this.calendar.events.patch({calendarId:"primary",eventId:e,requestBody:s});return this.mapEvent(r.data)}async deleteEvent(e){await this.calendar.events.delete({calendarId:"primary",eventId:e})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}mapEvent(e){let t=!!e.start?.date;return{id:e.id,title:e.summary??"(No title)",start:new Date(e.start?.dateTime??e.start?.date),end:new Date(e.end?.dateTime??e.end?.date),location:e.location??void 0,description:e.description??void 0,allDay:t}}}});var su={};me(su,{MicrosoftCalendarProvider:()=>Eo});var Eo,va=T(()=>{"use strict";Wr();Eo=class extends ze{static{p(this,"MicrosoftCalendarProvider")}config;client;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Calendars.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s={Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",Prefer:'outlook.timezone="UTC"',...t.headers??{}},r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:s});if(r.status===401){await this.refreshAccessToken(),s.Authorization=`Bearer ${this.accessToken}`;let n=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:s});if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return n.json()}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async listEvents(e,t){let s=new URLSearchParams({startDateTime:e.toISOString(),endDateTime:t.toISOString(),$orderby:"start/dateTime",$top:"50"});return((await this.graphRequest(`/me/calendarView?${s}`)).value??[]).map(n=>this.mapEvent(n))}async createEvent(e){let t=this.timezone,s={subject:e.title,body:e.description?{contentType:"text",content:e.description}:void 0,location:e.location?{displayName:e.location}:void 0,isAllDay:e.allDay??!1};e.allDay?(s.start={dateTime:this.formatDateInTz(e.start,t).slice(0,10)+"T00:00:00",timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t).slice(0,10)+"T00:00:00",timeZone:t}):(s.start={dateTime:this.formatDateInTz(e.start,t),timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t),timeZone:t});let r=await this.graphRequest("/me/events",{method:"POST",body:JSON.stringify(s)});return this.mapEvent(r)}async updateEvent(e,t){let s={};t.title&&(s.subject=t.title),t.description&&(s.body={contentType:"text",content:t.description}),t.location&&(s.location={displayName:t.location}),t.start&&(s.start={dateTime:this.formatDateInTz(t.start,this.timezone),timeZone:this.timezone}),t.end&&(s.end={dateTime:this.formatDateInTz(t.end,this.timezone),timeZone:this.timezone});let r=await this.graphRequest(`/me/events/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapEvent(r)}async deleteEvent(e){await this.graphRequest(`/me/events/${e}`,{method:"DELETE"})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}formatDateInTz(e,t){let s=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),r=p(n=>s.find(o=>o.type===n)?.value??"00","g");return`${r("year")}-${r("month")}-${r("day")}T${r("hour")}:${r("minute")}:${r("second")}`}mapEvent(e){return{id:e.id,title:e.subject??"(No title)",start:this.parseGraphDateTime(e.start),end:this.parseGraphDateTime(e.end),location:e.location?.displayName??void 0,description:e.body?.content??void 0,allDay:e.isAllDay??!1}}parseGraphDateTime(e){if(!e?.dateTime)return new Date;let t=e.dateTime.replace(/(\.\d{3})\d*$/,"$1"),s=e.timeZone;return!s||s==="UTC"||s.includes("Utc")?new Date(t+"Z"):this.parseDateInTimezone(t,s)}parseDateInTimezone(e,t){let s=new Date(e+"Z"),r=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(s),n=p(a=>r.find(c=>c.type===a)?.value??"00","g"),i=new Date(`${n("year")}-${n("month")}-${n("day")}T${n("hour")}:${n("minute")}:${n("second")}Z`).getTime()-s.getTime();return new Date(s.getTime()-i)}}});async function zr(l){switch(l.provider){case"caldav":{if(!l.caldav)throw new Error("CalDAV config missing");let{CalDAVProvider:e}=await Promise.resolve().then(()=>(Sa(),eu)),t=new e(l.caldav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google Calendar config missing");let{GoogleCalendarProvider:e}=await Promise.resolve().then(()=>($a(),tu)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft Calendar config missing");let{MicrosoftCalendarProvider:e}=await Promise.resolve().then(()=>(va(),su)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown calendar provider: ${l.provider}`)}}var ru=T(()=>{"use strict";p(zr,"createCalendarProvider")});var Ht,nu=T(()=>{"use strict";B();Ht=class extends x{static{p(this,"CalendarSkill")}calendarProvider;timezone;metadata={name:"calendar",category:"productivity",description:"Manage calendar events. List upcoming events, create new events, update or delete existing ones, and check availability.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_events","create_event","update_event","delete_event","check_availability","find_free_slot","check_conflicts"],description:"The calendar action to perform. Use find_free_slot to find available time windows."},start:{type:"string",description:`Start date/time in ISO 8601 format WITHOUT timezone suffix (e.g. "2026-03-09T14:00:00", NOT "2026-03-09T14:00:00Z"). Times are interpreted in the user's local timezone.`},end:{type:"string",description:`End date/time in ISO 8601 format WITHOUT timezone suffix (e.g. "2026-03-09T14:30:00"). Times are interpreted in the user's local timezone.`},title:{type:"string",description:"Event title (for create/update)"},location:{type:"string",description:"Event location (for create/update)"},description:{type:"string",description:"Event description (for create/update)"},event_id:{type:"string",description:"Event ID (for update/delete)"},all_day:{type:"boolean",description:"Whether this is an all-day event"},duration_minutes:{type:"number",description:"Duration in minutes to find a free slot for (for find_free_slot)"},working_hours_only:{type:"boolean",description:"If true, only consider 08:00-18:00 for free slots (default: true)"}},required:["action"]}};constructor(e,t){super(),this.calendarProvider=e,this.timezone=t}async execute(e,t){t.timezone&&(this.calendarProvider.timezone=t.timezone);let s=e.action;switch(s){case"list_events":return this.listEvents(e);case"create_event":return this.createEvent(e);case"update_event":return this.updateEvent(e);case"delete_event":return this.deleteEvent(e);case"check_availability":return this.checkAvailability(e);case"find_free_slot":return this.findFreeSlot(e);case"check_conflicts":return this.checkConflicts(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async getTodayEvents(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate()),s=new Date(e.getFullYear(),e.getMonth(),e.getDate()+1);try{return await this.calendarProvider.listEvents(t,s)}catch(r){return console.error("[calendar] Failed to fetch today events",r),[]}}async listEvents(e){let t=e.start?new Date(e.start):new Date,s=e.end?new Date(e.end):new Date(t.getTime()+10080*60*1e3);try{let r=await this.calendarProvider.listEvents(t,s);if(r.length===0)return{success:!0,data:[],display:"No events found in this time range."};let n=r.map(o=>this.formatEvent(o)).join(`
844
+ `,r}}});var tu={};me(tu,{GoogleCalendarProvider:()=>Eo});var Eo,$a=T(()=>{"use strict";Wr();Eo=class extends ze{static{p(this,"GoogleCalendarProvider")}config;calendar;constructor(e){super(),this.config=e}async initialize(){try{let{google:e}=await import("googleapis"),t=new e.auth.OAuth2(this.config.clientId,this.config.clientSecret);t.setCredentials({refresh_token:this.config.refreshToken}),this.calendar=e.calendar({version:"v3",auth:t})}catch(e){throw new Error(`Google Calendar initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){return((await this.calendar.events.list({calendarId:"primary",timeMin:e.toISOString(),timeMax:t.toISOString(),singleEvents:!0,orderBy:"startTime"})).data.items??[]).map(r=>this.mapEvent(r))}async createEvent(e){let t={summary:e.title,location:e.location,description:e.description};e.allDay?(t.start={date:e.start.toISOString().slice(0,10)},t.end={date:e.end.toISOString().slice(0,10)}):(t.start={dateTime:e.start.toISOString()},t.end={dateTime:e.end.toISOString()});let s=await this.calendar.events.insert({calendarId:"primary",requestBody:t});return this.mapEvent(s.data)}async updateEvent(e,t){let s={};t.title&&(s.summary=t.title),t.location&&(s.location=t.location),t.description&&(s.description=t.description),t.start&&(s.start=t.allDay?{date:t.start.toISOString().slice(0,10)}:{dateTime:t.start.toISOString()}),t.end&&(s.end=t.allDay?{date:t.end.toISOString().slice(0,10)}:{dateTime:t.end.toISOString()});let r=await this.calendar.events.patch({calendarId:"primary",eventId:e,requestBody:s});return this.mapEvent(r.data)}async deleteEvent(e){await this.calendar.events.delete({calendarId:"primary",eventId:e})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}mapEvent(e){let t=!!e.start?.date;return{id:e.id,title:e.summary??"(No title)",start:new Date(e.start?.dateTime??e.start?.date),end:new Date(e.end?.dateTime??e.end?.date),location:e.location??void 0,description:e.description??void 0,allDay:t}}}});var su={};me(su,{MicrosoftCalendarProvider:()=>So});var So,va=T(()=>{"use strict";Wr();So=class extends ze{static{p(this,"MicrosoftCalendarProvider")}config;client;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Calendars.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s={Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",Prefer:'outlook.timezone="UTC"',...t.headers??{}},r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:s});if(r.status===401){await this.refreshAccessToken(),s.Authorization=`Bearer ${this.accessToken}`;let n=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:s});if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return n.json()}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async listEvents(e,t){let s=new URLSearchParams({startDateTime:e.toISOString(),endDateTime:t.toISOString(),$orderby:"start/dateTime",$top:"50"});return((await this.graphRequest(`/me/calendarView?${s}`)).value??[]).map(n=>this.mapEvent(n))}async createEvent(e){let t=this.timezone,s={subject:e.title,body:e.description?{contentType:"text",content:e.description}:void 0,location:e.location?{displayName:e.location}:void 0,isAllDay:e.allDay??!1};e.allDay?(s.start={dateTime:this.formatDateInTz(e.start,t).slice(0,10)+"T00:00:00",timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t).slice(0,10)+"T00:00:00",timeZone:t}):(s.start={dateTime:this.formatDateInTz(e.start,t),timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t),timeZone:t});let r=await this.graphRequest("/me/events",{method:"POST",body:JSON.stringify(s)});return this.mapEvent(r)}async updateEvent(e,t){let s={};t.title&&(s.subject=t.title),t.description&&(s.body={contentType:"text",content:t.description}),t.location&&(s.location={displayName:t.location}),t.start&&(s.start={dateTime:this.formatDateInTz(t.start,this.timezone),timeZone:this.timezone}),t.end&&(s.end={dateTime:this.formatDateInTz(t.end,this.timezone),timeZone:this.timezone});let r=await this.graphRequest(`/me/events/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapEvent(r)}async deleteEvent(e){await this.graphRequest(`/me/events/${e}`,{method:"DELETE"})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}formatDateInTz(e,t){let s=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),r=p(n=>s.find(o=>o.type===n)?.value??"00","g");return`${r("year")}-${r("month")}-${r("day")}T${r("hour")}:${r("minute")}:${r("second")}`}mapEvent(e){return{id:e.id,title:e.subject??"(No title)",start:this.parseGraphDateTime(e.start),end:this.parseGraphDateTime(e.end),location:e.location?.displayName??void 0,description:e.body?.content??void 0,allDay:e.isAllDay??!1}}parseGraphDateTime(e){if(!e?.dateTime)return new Date;let t=e.dateTime.replace(/(\.\d{3})\d*$/,"$1"),s=e.timeZone;return!s||s==="UTC"||s.includes("Utc")?new Date(t+"Z"):this.parseDateInTimezone(t,s)}parseDateInTimezone(e,t){let s=new Date(e+"Z"),r=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(s),n=p(a=>r.find(c=>c.type===a)?.value??"00","g"),i=new Date(`${n("year")}-${n("month")}-${n("day")}T${n("hour")}:${n("minute")}:${n("second")}Z`).getTime()-s.getTime();return new Date(s.getTime()-i)}}});async function zr(l){switch(l.provider){case"caldav":{if(!l.caldav)throw new Error("CalDAV config missing");let{CalDAVProvider:e}=await Promise.resolve().then(()=>(Sa(),eu)),t=new e(l.caldav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google Calendar config missing");let{GoogleCalendarProvider:e}=await Promise.resolve().then(()=>($a(),tu)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft Calendar config missing");let{MicrosoftCalendarProvider:e}=await Promise.resolve().then(()=>(va(),su)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown calendar provider: ${l.provider}`)}}var ru=T(()=>{"use strict";p(zr,"createCalendarProvider")});var Ht,nu=T(()=>{"use strict";B();Ht=class extends x{static{p(this,"CalendarSkill")}calendarProvider;timezone;metadata={name:"calendar",category:"productivity",description:"Manage calendar events. List upcoming events, create new events, update or delete existing ones, and check availability.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_events","create_event","update_event","delete_event","check_availability","find_free_slot","check_conflicts"],description:"The calendar action to perform. Use find_free_slot to find available time windows."},start:{type:"string",description:`Start date/time in ISO 8601 format WITHOUT timezone suffix (e.g. "2026-03-09T14:00:00", NOT "2026-03-09T14:00:00Z"). Times are interpreted in the user's local timezone.`},end:{type:"string",description:`End date/time in ISO 8601 format WITHOUT timezone suffix (e.g. "2026-03-09T14:30:00"). Times are interpreted in the user's local timezone.`},title:{type:"string",description:"Event title (for create/update)"},location:{type:"string",description:"Event location (for create/update)"},description:{type:"string",description:"Event description (for create/update)"},event_id:{type:"string",description:"Event ID (for update/delete)"},all_day:{type:"boolean",description:"Whether this is an all-day event"},duration_minutes:{type:"number",description:"Duration in minutes to find a free slot for (for find_free_slot)"},working_hours_only:{type:"boolean",description:"If true, only consider 08:00-18:00 for free slots (default: true)"}},required:["action"]}};constructor(e,t){super(),this.calendarProvider=e,this.timezone=t}async execute(e,t){t.timezone&&(this.calendarProvider.timezone=t.timezone);let s=e.action;switch(s){case"list_events":return this.listEvents(e);case"create_event":return this.createEvent(e);case"update_event":return this.updateEvent(e);case"delete_event":return this.deleteEvent(e);case"check_availability":return this.checkAvailability(e);case"find_free_slot":return this.findFreeSlot(e);case"check_conflicts":return this.checkConflicts(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async getTodayEvents(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate()),s=new Date(e.getFullYear(),e.getMonth(),e.getDate()+1);try{return await this.calendarProvider.listEvents(t,s)}catch(r){return console.error("[calendar] Failed to fetch today events",r),[]}}async listEvents(e){let t=e.start?new Date(e.start):new Date,s=e.end?new Date(e.end):new Date(t.getTime()+10080*60*1e3);try{let r=await this.calendarProvider.listEvents(t,s);if(r.length===0)return{success:!0,data:[],display:"No events found in this time range."};let n=r.map(o=>this.formatEvent(o)).join(`
845
845
  `);return{success:!0,data:r,display:`${r.length} event(s):
846
846
  ${n}`}}catch(r){return{success:!1,error:`Failed to list events: ${r instanceof Error?r.message:String(r)}`}}}parseLocalTime(e){return new Date(e.replace(/Z$/i,""))}async createEvent(e){let t=e.title,s=e.start,r=e.end;if(!t)return{success:!1,error:'Missing required field "title"'};if(!s)return{success:!1,error:'Missing required field "start"'};if(!r)return{success:!1,error:'Missing required field "end"'};try{let n=await this.calendarProvider.createEvent({title:t,start:this.parseLocalTime(s),end:this.parseLocalTime(r),location:e.location,description:e.description,allDay:e.all_day});return{success:!0,data:n,display:`Event created: ${this.formatEvent(n)}`}}catch(n){return{success:!1,error:`Failed to create event: ${n instanceof Error?n.message:String(n)}`}}}async updateEvent(e){let t=e.event_id;if(!t)return{success:!1,error:'Missing required field "event_id"'};try{let s=await this.calendarProvider.updateEvent(t,{title:e.title,start:e.start?this.parseLocalTime(e.start):void 0,end:e.end?this.parseLocalTime(e.end):void 0,location:e.location,description:e.description,allDay:e.all_day});return{success:!0,data:s,display:`Event updated: ${this.formatEvent(s)}`}}catch(s){return{success:!1,error:`Failed to update event: ${s instanceof Error?s.message:String(s)}`}}}async deleteEvent(e){let t=e.event_id;if(!t)return{success:!1,error:'Missing required field "event_id"'};try{return await this.calendarProvider.deleteEvent(t),{success:!0,data:{deleted:t},display:`Event "${t}" deleted.`}}catch(s){return{success:!1,error:`Failed to delete event: ${s instanceof Error?s.message:String(s)}`}}}async checkAvailability(e){let t=e.start,s=e.end;if(!t||!s)return{success:!1,error:'Missing required fields "start" and "end"'};try{let r=await this.calendarProvider.checkAvailability(this.parseLocalTime(t),this.parseLocalTime(s)),n=r.available?"Time slot is available.":`Time slot has ${r.conflicts.length} conflict(s):
847
847
  ${r.conflicts.map(o=>this.formatEvent(o)).join(`
@@ -862,7 +862,7 @@ ${r.join(`
862
862
  `)}`}}async cancelTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for cancel action'};let n=this.getAllTasks(t).find(o=>o.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):this.taskRepo.cancel(s)||this.taskRepo.cancelTask(s),{success:!0,data:{taskId:s},display:`Background task "${s}" cancelled.`}):{success:!1,error:`Task "${s}" not found or already completed`}}async pauseTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for pause action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="running"&&n.status!=="resuming"?{success:!1,error:`Task "${s}" is not running (status: ${n.status})`}:(await this.persistentRunner.pause(s),{success:!0,data:{taskId:s},display:`Persistent task "${s}" paused. Use resume to continue.`}):{success:!1,error:`Task "${s}" not found`}}async resumeTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for resume action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="checkpointed"?{success:!1,error:`Task "${s}" is not checkpointed (status: ${n.status})`}:(this.persistentRunner.resume(n).catch(()=>{}),{success:!0,data:{taskId:s},display:`Persistent task "${s}" resuming. You'll be notified when it completes.`}):{success:!1,error:`Task "${s}" not found`}}}});var Hs,cu=T(()=>{"use strict";B();Oe();Hs=class extends x{static{p(this,"ScheduledTaskSkill")}actionRepo;metadata={name:"scheduled_task",category:"automation",description:'Create, list, enable, disable, or delete scheduled actions that run automatically on a recurring basis. Supports cron expressions (e.g. "0 9 * * *" for daily at 9 AM), intervals (in minutes), and one-time schedules. Each scheduled action executes a skill or sends a prompt to the LLM at the configured time. Use this for time-based tasks (reports, periodic checks, reminders). For condition-based alerts ("notify me WHEN X happens"), use the watch tool instead.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The scheduled task action to perform"},name:{type:"string",description:"Name for the scheduled action (for create)"},description:{type:"string",description:"What the scheduled action does (for create)"},schedule_type:{type:"string",enum:["cron","interval","once"],description:"Type of schedule: cron expression, interval in minutes, or one-time ISO date (for create)"},schedule_value:{type:"string",description:"Schedule value: cron expression, minutes as string, or ISO date (for create)"},skill_name:{type:"string",description:"The skill to execute on schedule (for create)"},skill_input:{type:"object",description:"Input to pass to the skill (for create)"},prompt_template:{type:"string",description:"Optional LLM prompt to run instead of a skill (for create)"},action_id:{type:"string",description:"Scheduled action ID (for enable, disable, delete)"}},required:["action"]}};constructor(e){super(),this.actionRepo=e}getAllActions(e){let t=new Set,s=[];for(let r of J(e))for(let n of this.actionRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"create":return this.createAction(e,t);case"list":return this.listActions(t);case"enable":return this.toggleAction(e,!0,t);case"disable":return this.toggleAction(e,!1,t);case"delete":return this.deleteAction(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: create, list, enable, disable, delete`}}}createAction(e,t){let s=e.name,r=e.description,n=e.schedule_type,o=e.schedule_value,i=e.skill_name,a=e.skill_input,c=e.prompt_template;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "name" for create action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "description" for create action'};if(!n||!["cron","interval","once"].includes(n))return{success:!1,error:'Missing or invalid "schedule_type". Must be "cron", "interval", or "once"'};if(!o||typeof o!="string")return{success:!1,error:'Missing required field "schedule_value" for create action'};if((!i||typeof i!="string")&&!c)return{success:!1,error:'Missing required field "skill_name" (or "prompt_template") for create action'};if(n==="interval"){let m=parseInt(o,10);if(isNaN(m)||m<=0)return{success:!1,error:"For interval schedule, value must be a positive number of minutes"}}if(n==="cron"&&o.trim().split(/\s+/).length!==5)return{success:!1,error:"Cron expression must have 5 fields: minute hour dayOfMonth month dayOfWeek"};if(n==="once"){let m=new Date(o);if(isNaN(m.getTime()))return{success:!1,error:"For once schedule, value must be a valid ISO date string"};if(m.getTime()<=Date.now())return{success:!1,error:"The scheduled time is in the past. Please specify a future time."}}let d=this.actionRepo.create({userId:de(t),platform:t.platform,chatId:t.chatId,name:s,description:r,scheduleType:n,scheduleValue:o,skillName:i??"llm_prompt",skillInput:JSON.stringify(a??{}),promptTemplate:c}),u=n==="cron"?`cron: ${o}`:n==="interval"?`every ${o} minutes`:`once at ${o}`;return{success:!0,data:{actionId:d.id,name:s,scheduleType:n,scheduleValue:o,skillName:i},display:`Scheduled action created (${d.id}): "${s}" \u2014 ${u}, running "${i}"${d.nextRunAt?`. Next run: ${d.nextRunAt}`:""}`}}listActions(e){let t=this.getAllActions(e);if(t.length===0)return{success:!0,data:[],display:"No scheduled actions."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=r.scheduleType==="cron"?`cron: ${r.scheduleValue}`:r.scheduleType==="interval"?`every ${r.scheduleValue} min`:`once: ${r.scheduleValue}`,i=r.nextRunAt?` | next: ${r.nextRunAt}`:"";return`- ${n} ${r.id}: "${r.name}" [${o}] \u2192 ${r.skillName}${i}`});return{success:!0,data:t.map(r=>({actionId:r.id,name:r.name,scheduleType:r.scheduleType,scheduleValue:r.scheduleValue,skillName:r.skillName,enabled:r.enabled,nextRunAt:r.nextRunAt,lastRunAt:r.lastRunAt})),display:`Scheduled actions:
863
863
  ${s.join(`
864
864
  `)}`}}toggleAction(e,t,s){let r=e.action_id;if(!r||typeof r!="string")return{success:!1,error:`Missing required field "action_id" for ${t?"enable":"disable"} action`};let n=this.actionRepo.findById(r),o=J(s);return!n||!o.includes(n.userId)?{success:!1,error:`Scheduled action "${r}" not found`}:this.actionRepo.setEnabled(r,t)?{success:!0,data:{actionId:r,enabled:t},display:`Scheduled action "${r}" ${t?"enabled":"disabled"}.`}:{success:!1,error:`Scheduled action "${r}" not found`}}deleteAction(e,t){let s=e.action_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "action_id" for delete action'};let r=this.actionRepo.findById(s),n=J(t);return!r||!n.includes(r.userId)?{success:!1,error:`Scheduled action "${s}" not found`}:this.actionRepo.delete(s)?{success:!0,data:{actionId:s},display:`Scheduled action "${s}" deleted.`}:{success:!1,error:`Scheduled action "${s}" not found`}}}});var Wt,Aa=T(()=>{"use strict";Wt=class{static{p(this,"MCPClient")}serverName;config;logger;client;transport;connected=!1;constructor(e,t,s){this.serverName=e,this.config=t,this.logger=s}async connect(){try{let{Client:e}=await import("@modelcontextprotocol/sdk/client/index.js");if(this.client=new e({name:`alfred-${this.serverName}`,version:"1.0.0"},{capabilities:{}}),this.config.command){let{StdioClientTransport:t}=await import("@modelcontextprotocol/sdk/client/stdio.js"),s={PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:process.env.NODE_ENV??"",SYSTEMROOT:process.env.SYSTEMROOT??""};if(this.config.env)for(let[r,n]of Object.entries(this.config.env))s[r]=n.replace(/\$\{(\w+)\}/g,(o,i)=>process.env[i]??"");this.transport=new t({command:this.config.command,args:this.config.args??[],env:s})}else if(this.config.url){let{SSEClientTransport:t}=await import("@modelcontextprotocol/sdk/client/sse.js");this.transport=new t(new URL(this.config.url))}else throw new Error(`MCP server "${this.serverName}": must specify either command or url`);await this.client.connect(this.transport),this.connected=!0,this.logger.info({server:this.serverName},"MCP server connected")}catch(e){throw this.logger.error({server:this.serverName,err:e},"Failed to connect MCP server"),e}}async listTools(){if(!this.connected||!this.client)return[];try{return((await this.client.listTools()).tools??[]).map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema??{type:"object",properties:{}}}))}catch(e){return this.logger.error({server:this.serverName,err:e},"Failed to list MCP tools"),[]}}async callTool(e,t){if(!this.connected||!this.client)return{content:"MCP server not connected",isError:!0};try{let s=await this.client.callTool({name:e,arguments:t});return{content:(s.content??[]).map(n=>n.text??JSON.stringify(n)).join(`
865
- `),isError:s.isError}}catch(s){return{content:`MCP tool error: ${s instanceof Error?s.message:String(s)}`,isError:!0}}}async disconnect(){if(this.transport)try{await this.transport.close?.()}catch{}this.connected=!1,this.logger.info({server:this.serverName},"MCP server disconnected")}}});var Tf,zt,Ia=T(()=>{"use strict";B();Tf=["read","write","destructive","admin"],zt=class extends x{static{p(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,n,o){super(),this.client=e,this.serverName=t,this.toolName=s;let i=o&&Tf.includes(o)?o:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:i,version:"1.0.0",inputSchema:n}}async execute(e,t){let s=await this.client.callTool(this.toolName,e);return{success:s.isError!==!0,data:s.content,display:s.content,error:s.isError===!0?s.content:void 0}}}});var qr,lu=T(()=>{"use strict";Aa();Ia();qr=class{static{p(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new Wt(t.name,t,this.logger.child({mcp:t.name}));await s.connect(),this.clients.push(s);let r=await s.listTools();for(let n of r){let o=new zt(s,t.name,n.name,n.description??"",n.inputSchema);this.skills.push(o)}this.logger.info({server:t.name,tools:r.length},"MCP server initialized")}catch(s){this.logger.error({server:t.name,err:s},"Failed to initialize MCP server")}}getSkills(){return this.skills}async shutdown(){for(let e of this.clients)await e.disconnect();this.clients.length=0,this.skills.length=0}}});var du=T(()=>{"use strict";Aa();Ia();lu()});import{spawn as _f}from"node:child_process";import qe from"node:fs";import Ge from"node:path";import kf from"node:os";import bf from"node:crypto";var qt,Ra=T(()=>{"use strict";qt=class{static{p(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=io.resolve(`${s}/package.json`);e.add(Ge.dirname(Ge.dirname(r)))}catch{}try{let s=qe.realpathSync(process.argv[1]??""),r=Ge.dirname(s),n=Ge.join(r,"node_modules");qe.existsSync(n)&&e.add(n);let o=Ge.join(r,"..","node_modules");qe.existsSync(o)&&e.add(qe.realpathSync(o))}catch{}let t=Ge.join(process.cwd(),"node_modules");if(qe.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(Ge.delimiter))s&&e.add(s);return[...e].join(Ge.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=Ge.join(kf.tmpdir(),`alfred-sandbox-${bf.randomUUID()}`);qe.mkdirSync(n,{recursive:!0});try{let o=t==="javascript"?"js":"py",i=Ge.join(n,`script.${o}`);qe.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[i],d=Date.now();return await new Promise(u=>{let m=_f(a,c,{cwd:n,timeout:r,env:{...process.env,NODE_ENV:"sandbox",PYTHONDONTWRITEBYTECODE:"1",...s?.env,TMPDIR:n,TEMP:n,TMP:n,NODE_PATH:this.resolveNodePath()},stdio:["pipe","pipe","pipe"]}),h="",f="";m.stdout.on("data",g=>{h+=g.toString()}),m.stderr.on("data",g=>{f+=g.toString()}),m.on("close",g=>{let y=Date.now()-d,_=[];try{let S=qe.readdirSync(n).filter(E=>!E.startsWith("script."));for(let E of S){let $=Ge.join(n,E),R=qe.statSync($);if(R.isFile()&&R.size<1e7){let M=qe.readFileSync($),q=E.endsWith(".png")?"image/png":E.endsWith(".jpg")||E.endsWith(".jpeg")?"image/jpeg":E.endsWith(".svg")?"image/svg+xml":E.endsWith(".csv")?"text/csv":E.endsWith(".json")?"application/json":E.endsWith(".html")||E.endsWith(".htm")?"text/html":E.endsWith(".txt")?"text/plain":E.endsWith(".md")?"text/markdown":E.endsWith(".xml")?"application/xml":E.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":E.endsWith(".xls")?"application/vnd.ms-excel":E.endsWith(".pdf")?"application/pdf":"application/octet-stream";_.push({name:E,data:M,mimeType:q})}}}catch{}u({stdout:h.slice(0,5e4),stderr:f.slice(0,1e4),exitCode:g??1,files:_.length>0?_:void 0,durationMs:y})}),m.on("error",g=>{u({stdout:"",stderr:g.message,exitCode:1,durationMs:Date.now()-d})}),m.stdin.end()})}finally{try{qe.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var Gr,uu=T(()=>{"use strict";B();Ra();Gr=class extends x{static{p(this,"CodeExecutionSkill")}metadata={name:"code_sandbox",category:"automation",description:"Execute code in a sandboxed environment. Supports JavaScript (Node.js) and Python. Use for calculations, data processing, generating files (PDF, HTML, CSV, images, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. Any files written to the working directory are automatically collected and sent to the user as attachments \u2014 do NOT use the file skill to send them afterwards. For PDF generation use pdfkit (Node.js) or reportlab/fpdf (Python). IMPORTANT: When generating large files, write compact data-driven code \u2014 define data as arrays/objects, then build the output programmatically. Never embed large HTML/text as string literals.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","run_with_data"],description:"Action to perform"},code:{type:"string",description:"Code to execute"},language:{type:"string",enum:["javascript","python"],description:"Programming language"},data:{type:"string",description:"Input data (available as variable INPUT_DATA, already parsed if JSON). Do NOT use os.environ or process.env \u2014 use INPUT_DATA directly."},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new qt;allowedLanguages;maxTimeout;constructor(e){super(),this.allowedLanguages=new Set(e?.allowedLanguages??["javascript","python"]),this.maxTimeout=e?.maxTimeoutMs??12e4}async execute(e,t){let s=e.action,r=e.code,n=e.language,o=e.data,i=Math.min(e.timeout??3e4,this.maxTimeout);if(!r)return{success:!1,error:'Missing required field "code". IMPORTANT: Do NOT embed large HTML/text as string literals \u2014 write compact code that builds content programmatically from data arrays/objects, e.g. rows.map(r => `<tr><td>${r.time}</td><td>${r.price}</td></tr>`).join(""). Keep the code short and data-driven.'};if(!n)return{success:!1,error:'Missing required field "language"'};if(!this.allowedLanguages.has(n))return{success:!1,error:`Language "${n}" is not allowed. Allowed: ${[...this.allowedLanguages].join(", ")}`};if(s==="run"&&r.length>4e3)return{success:!1,error:`Code too large (${r.length} chars, limit 4000 for action "run"). This usually means data is hardcoded in the code. Use action "run_with_data" with the data parameter instead. The data will be available as INPUT_DATA (already parsed). If you received a data reference like "result_1", pass it as the data parameter.`};let a=r;if(s==="run_with_data"&&o){let m=!1;try{JSON.parse(o),m=!0}catch{}n==="javascript"?a=m?`const INPUT_DATA = ${o};
865
+ `),isError:s.isError}}catch(s){return{content:`MCP tool error: ${s instanceof Error?s.message:String(s)}`,isError:!0}}}async disconnect(){if(this.transport)try{await this.transport.close?.()}catch{}this.connected=!1,this.logger.info({server:this.serverName},"MCP server disconnected")}}});var Tf,zt,Ia=T(()=>{"use strict";B();Tf=["read","write","destructive","admin"],zt=class extends x{static{p(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,n,o){super(),this.client=e,this.serverName=t,this.toolName=s;let i=o&&Tf.includes(o)?o:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:i,version:"1.0.0",inputSchema:n}}async execute(e,t){let s=await this.client.callTool(this.toolName,e);return{success:s.isError!==!0,data:s.content,display:s.content,error:s.isError===!0?s.content:void 0}}}});var qr,lu=T(()=>{"use strict";Aa();Ia();qr=class{static{p(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new Wt(t.name,t,this.logger.child({mcp:t.name}));await s.connect(),this.clients.push(s);let r=await s.listTools();for(let n of r){let o=new zt(s,t.name,n.name,n.description??"",n.inputSchema);this.skills.push(o)}this.logger.info({server:t.name,tools:r.length},"MCP server initialized")}catch(s){this.logger.error({server:t.name,err:s},"Failed to initialize MCP server")}}getSkills(){return this.skills}async shutdown(){for(let e of this.clients)await e.disconnect();this.clients.length=0,this.skills.length=0}}});var du=T(()=>{"use strict";Aa();Ia();lu()});import{spawn as _f}from"node:child_process";import qe from"node:fs";import Ge from"node:path";import kf from"node:os";import bf from"node:crypto";var qt,Ra=T(()=>{"use strict";qt=class{static{p(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=ao.resolve(`${s}/package.json`);e.add(Ge.dirname(Ge.dirname(r)))}catch{}try{let s=qe.realpathSync(process.argv[1]??""),r=Ge.dirname(s),n=Ge.join(r,"node_modules");qe.existsSync(n)&&e.add(n);let o=Ge.join(r,"..","node_modules");qe.existsSync(o)&&e.add(qe.realpathSync(o))}catch{}let t=Ge.join(process.cwd(),"node_modules");if(qe.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(Ge.delimiter))s&&e.add(s);return[...e].join(Ge.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=Ge.join(kf.tmpdir(),`alfred-sandbox-${bf.randomUUID()}`);qe.mkdirSync(n,{recursive:!0});try{let o=t==="javascript"?"js":"py",i=Ge.join(n,`script.${o}`);qe.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[i],d=Date.now();return await new Promise(u=>{let m=_f(a,c,{cwd:n,timeout:r,env:{...process.env,NODE_ENV:"sandbox",PYTHONDONTWRITEBYTECODE:"1",...s?.env,TMPDIR:n,TEMP:n,TMP:n,NODE_PATH:this.resolveNodePath()},stdio:["pipe","pipe","pipe"]}),h="",f="";m.stdout.on("data",g=>{h+=g.toString()}),m.stderr.on("data",g=>{f+=g.toString()}),m.on("close",g=>{let y=Date.now()-d,_=[];try{let S=qe.readdirSync(n).filter(E=>!E.startsWith("script."));for(let E of S){let $=Ge.join(n,E),R=qe.statSync($);if(R.isFile()&&R.size<1e7){let M=qe.readFileSync($),q=E.endsWith(".png")?"image/png":E.endsWith(".jpg")||E.endsWith(".jpeg")?"image/jpeg":E.endsWith(".svg")?"image/svg+xml":E.endsWith(".csv")?"text/csv":E.endsWith(".json")?"application/json":E.endsWith(".html")||E.endsWith(".htm")?"text/html":E.endsWith(".txt")?"text/plain":E.endsWith(".md")?"text/markdown":E.endsWith(".xml")?"application/xml":E.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":E.endsWith(".xls")?"application/vnd.ms-excel":E.endsWith(".pdf")?"application/pdf":"application/octet-stream";_.push({name:E,data:M,mimeType:q})}}}catch{}u({stdout:h.slice(0,5e4),stderr:f.slice(0,1e4),exitCode:g??1,files:_.length>0?_:void 0,durationMs:y})}),m.on("error",g=>{u({stdout:"",stderr:g.message,exitCode:1,durationMs:Date.now()-d})}),m.stdin.end()})}finally{try{qe.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var Gr,uu=T(()=>{"use strict";B();Ra();Gr=class extends x{static{p(this,"CodeExecutionSkill")}metadata={name:"code_sandbox",category:"automation",description:"Execute code in a sandboxed environment. Supports JavaScript (Node.js) and Python. Use for calculations, data processing, generating files (PDF, HTML, CSV, images, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. Any files written to the working directory are automatically collected and sent to the user as attachments \u2014 do NOT use the file skill to send them afterwards. For PDF generation use pdfkit (Node.js) or reportlab/fpdf (Python). IMPORTANT: When generating large files, write compact data-driven code \u2014 define data as arrays/objects, then build the output programmatically. Never embed large HTML/text as string literals.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","run_with_data"],description:"Action to perform"},code:{type:"string",description:"Code to execute"},language:{type:"string",enum:["javascript","python"],description:"Programming language"},data:{type:"string",description:"Input data (available as variable INPUT_DATA, already parsed if JSON). Do NOT use os.environ or process.env \u2014 use INPUT_DATA directly."},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new qt;allowedLanguages;maxTimeout;constructor(e){super(),this.allowedLanguages=new Set(e?.allowedLanguages??["javascript","python"]),this.maxTimeout=e?.maxTimeoutMs??12e4}async execute(e,t){let s=e.action,r=e.code,n=e.language,o=e.data,i=Math.min(e.timeout??3e4,this.maxTimeout);if(!r)return{success:!1,error:'Missing required field "code". IMPORTANT: Do NOT embed large HTML/text as string literals \u2014 write compact code that builds content programmatically from data arrays/objects, e.g. rows.map(r => `<tr><td>${r.time}</td><td>${r.price}</td></tr>`).join(""). Keep the code short and data-driven.'};if(!n)return{success:!1,error:'Missing required field "language"'};if(!this.allowedLanguages.has(n))return{success:!1,error:`Language "${n}" is not allowed. Allowed: ${[...this.allowedLanguages].join(", ")}`};if(s==="run"&&r.length>4e3)return{success:!1,error:`Code too large (${r.length} chars, limit 4000 for action "run"). This usually means data is hardcoded in the code. Use action "run_with_data" with the data parameter instead. The data will be available as INPUT_DATA (already parsed). If you received a data reference like "result_1", pass it as the data parameter.`};let a=r;if(s==="run_with_data"&&o){let m=!1;try{JSON.parse(o),m=!0}catch{}n==="javascript"?a=m?`const INPUT_DATA = ${o};
866
866
  ${r}`:`const INPUT_DATA = ${JSON.stringify(o)};
867
867
  ${r}`:a=m?`import json as _json
868
868
  INPUT_DATA = _json.loads(${JSON.stringify(o)})
@@ -883,11 +883,11 @@ ${c}`}}summarize(e){let t=e.document_id;if(!t||typeof t!="string")return{success
883
883
 
884
884
  ${a}`}}list(e,t){let s=e.limit||50,r=J(t),n=new Set,o=[];for(let c of r)for(let d of this.docRepo.listByUser(c))n.has(d.id)||(n.add(d.id),o.push(d));let i=o.slice(0,s);if(i.length===0)return{success:!0,data:[],display:"No documents found."};let a=i.map(c=>`- **${c.filename}** [id=${c.id}] \u2014 ${c.mimeType}, ${c.chunkCount} chunks, ${c.sizeBytes} bytes`).join(`
885
885
  `);return{success:!0,data:i,display:`${i.length} document(s):
886
- ${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success:!1,error:'Missing required field "document_id" for delete action'};let s=this.docRepo.getDocument(t);return s?(this.docRepo.deleteDocument(t),{success:!0,data:{documentId:t},display:`Document "${s.filename}" deleted.`}):{success:!1,error:`Document "${t}" not found`}}}});var zs,hu=T(()=>{"use strict";B();zs=class extends x{static{p(this,"TTSSkill")}synthesizer;metadata={name:"text_to_speech",category:"media",description:"Send a voice/audio message to the user. You MUST use this tool whenever the user asks you to respond as a voice message, speak, or reply with audio. Pass the full response text \u2014 it will be converted to speech and delivered as a playable voice message.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{text:{type:"string",description:"The text to convert to speech"}},required:["text"]}};constructor(e){super(),this.synthesizer=e}async execute(e,t){let s=e.text;if(!s)return{success:!1,error:"No text provided for speech synthesis."};try{return{success:!0,display:"Voice message sent.",attachments:[{fileName:"voice.ogg",data:await this.synthesizer.synthesize(s),mimeType:"audio/ogg"}]}}catch(r){return{success:!1,error:`Speech synthesis failed: ${r instanceof Error?r.message:String(r)}`}}}}});var qs,fu=T(()=>{"use strict";B();qs=class extends x{static{p(this,"ImageGenerateSkill")}generator;metadata={name:"image_generate",category:"media",description:"Generate an image from a text description. Use this tool when the user asks you to create, generate, draw, or design an image or picture. Returns the generated image that will be sent to the user.",riskLevel:"read",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{prompt:{type:"string",description:"Detailed description of the image to generate. Be specific about style, composition, colors, and subject matter."},model:{type:"string",description:"Optional model to use (e.g. gpt-image-1, gpt-image-1-mini, gemini-2.0-flash-exp). Uses provider default if omitted."},size:{type:"string",enum:["1024x1024","1536x1024","1024x1536"],description:"Image dimensions. 1024x1024 (square, default), 1536x1024 (landscape), 1024x1536 (portrait)."},quality:{type:"string",enum:["low","medium","high"],description:"Image quality level. Higher quality takes longer and costs more."}},required:["prompt"]}};constructor(e){super(),this.generator=e}async execute(e,t){let s=e.prompt;if(!s)return{success:!1,error:"No prompt provided for image generation."};try{let r=await this.generator.generate(s,{model:e.model,size:e.size,quality:e.quality});return{success:!0,display:"Image generated.",attachments:[{fileName:"image.png",data:r.data,mimeType:r.mimeType}]}}catch(r){return{success:!1,error:`Image generation failed: ${r instanceof Error?r.message:String(r)}`}}}}});function ge(l){return l==null?"-":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function Kr(l){return l==null?"-":`${(l*100).toFixed(1)}%`}function So(l){if(!l)return"-";let e=Math.floor(l/86400),t=Math.floor(l%86400/3600),s=Math.floor(l%3600/60),r=[];return e&&r.push(`${e}d`),t&&r.push(`${t}h`),r.push(`${s}m`),r.join(" ")}var $o,gu=T(()=>{"use strict";B();p(ge,"bytes");p(Kr,"pct");p(So,"uptimeStr");$o=class l extends x{static{p(this,"ProxmoxSkill")}metadata={name:"proxmox",category:"infrastructure",description:'Manage Proxmox VE virtual machines, containers, and cluster. Use action "list_vms" to see VMs, "start_vm"/"shutdown_vm" to control them, "cluster_status" for health, "create_snapshot" for backups.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["cluster_status","list_nodes","node_stats","list_vms","vm_status","list_snapshots","list_storage","list_tasks","task_status","start_vm","shutdown_vm","reboot_vm","suspend_vm","resume_vm","create_snapshot","backup_vm","migrate_vm","stop_vm","delete_snapshot","rollback_snapshot"],description:"The Proxmox action to perform"},vmid:{type:"number",description:"Virtual machine / container ID"},node:{type:"string",description:"Proxmox node name (optional \u2014 resolved automatically when omitted)"},type:{type:"string",enum:["qemu","lxc"],description:"VM type filter for list_vms (default: both)"},name:{type:"string",description:"Snapshot name (for create/delete/rollback_snapshot)"},description:{type:"string",description:"Snapshot description (optional)"},target:{type:"string",description:"Target node for migration"},storage:{type:"string",description:"Storage target for backup_vm"},upid:{type:"string",description:"Task UPID for task_status"}},required:["action"]}};config;vmCache=null;static VM_CACHE_TTL=3e4;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"cluster_status":return await this.clusterStatus();case"list_nodes":return await this.listNodes();case"node_stats":return await this.nodeStats(e.node);case"list_vms":return await this.listVms(e.node,e.type);case"vm_status":return await this.vmStatus(e.vmid,e.node);case"list_snapshots":return await this.listSnapshots(e.vmid,e.node);case"list_storage":return await this.listStorage(e.node);case"list_tasks":return await this.listTasks(e.node);case"task_status":return await this.taskStatus(e.upid);case"start_vm":return await this.vmPowerAction("start",e);case"shutdown_vm":return await this.vmPowerAction("shutdown",e);case"reboot_vm":return await this.vmPowerAction("reboot",e);case"suspend_vm":return await this.vmPowerAction("suspend",e);case"resume_vm":return await this.vmPowerAction("resume",e);case"stop_vm":return await this.vmPowerAction("stop",e);case"create_snapshot":return await this.createSnapshot(e);case"backup_vm":return await this.backupVm(e);case"migrate_vm":return await this.migrateVm(e);case"delete_snapshot":return await this.deleteSnapshot(e);case"rollback_snapshot":return await this.rollbackSnapshot(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Proxmox API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl}/api2/json${t}`,n={Authorization:`PVEAPIToken=${this.config.tokenId}=${this.config.tokenSecret}`},o={method:e,headers:n};s&&e!=="GET"&&(n["Content-Type"]="application/json",o.body=JSON.stringify(s));let i=this.config.verifyTls===!1;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let a;try{a=await fetch(r,o)}finally{i&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}if(!a.ok){let d="";try{d=(await a.text()).slice(0,500)}catch{}throw new Error(`HTTP ${a.status} ${a.statusText} \u2014 ${d}`)}return(await a.json()).data}async get(e){return this.api("GET",e)}async post(e,t){return this.api("POST",e,t)}async del(e){return this.api("DELETE",e)}async resolveVm(e,t){if(t)try{return await this.get(`/nodes/${t}/qemu/${e}/status/current`),{node:t,type:"qemu"}}catch{try{return await this.get(`/nodes/${t}/lxc/${e}/status/current`),{node:t,type:"lxc"}}catch{throw new Error(`VM ${e} not found on node "${t}"`)}}let r=(await this.getAllVms()).find(n=>n.vmid===e);if(!r)throw new Error(`VM ${e} not found on any node. Use "list_vms" to see available VMs.`);return{node:r.node,type:r.type}}async getAllVms(){let e=Date.now();if(this.vmCache&&e-this.vmCache.ts<l.VM_CACHE_TTL)return this.vmCache.entries;let t=await this.get("/nodes"),s=[];for(let r of t){let[n,o]=await Promise.all([this.get(`/nodes/${r.node}/qemu`).catch(()=>[]),this.get(`/nodes/${r.node}/lxc`).catch(()=>[])]);for(let i of n)s.push({...i,node:r.node,type:"qemu"});for(let i of o)s.push({...i,node:r.node,type:"lxc"})}return this.vmCache={entries:s,ts:e},s}async clusterStatus(){let e=await this.get("/cluster/status"),t=["## Cluster Status",""],s=e.find(n=>n.type==="cluster");s&&(t.push(`**Cluster:** ${s.name}`),t.push(`**Quorum:** ${s.quorate?"Yes":"No"}`),t.push(`**Nodes:** ${s.nodes??"-"}`),t.push(`**Version:** ${s.version??"-"}`),t.push(""));let r=e.filter(n=>n.type==="node");if(r.length){t.push("| Node | Online | Level | ID |"),t.push("|------|--------|-------|----|");for(let n of r)t.push(`| ${n.name} | ${n.online?"Yes":"**No**"} | ${n.level??"-"} | ${n.nodeid??"-"} |`)}return{success:!0,data:e,display:t.join(`
887
- `)}}async listNodes(){let e=await this.get("/nodes"),t=["## Nodes","","| Node | Status | CPU | RAM Used / Total | Uptime |"];t.push("|------|--------|-----|------------------|--------|");for(let s of e){let r=typeof s.cpu=="number"?Kr(s.cpu):"-",n=ge(s.mem),o=ge(s.maxmem);t.push(`| ${s.node} | ${s.status} | ${r} | ${n} / ${o} | ${So(s.uptime)} |`)}return{success:!0,data:e,display:t.join(`
888
- `)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,n=s.memory,o=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${So(s.uptime)}`,`**Kernel:** ${s.kversion??"-"}`,`**PVE Version:** ${s.pveversion??"-"}`,""];return r&&(a.push(`**CPU:** ${r.model??"-"} (${r.cpus??"-"} cores)`),a.push(`**CPU Usage:** ${Kr(r.cpu)}`),a.push(`**Load:** ${Array.isArray(s.loadavg)?s.loadavg.join(", "):"-"}`)),n&&a.push(`**RAM:** ${ge(n.used)} / ${ge(n.total)} (${Kr(n.used/n.total)})`),i&&a.push(`**Swap:** ${ge(i.used)} / ${ge(i.total)}`),o&&a.push(`**Root FS:** ${ge(o.used)} / ${ge(o.total)}`),{success:!0,data:s,display:a.join(`
889
- `)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let n=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"qemu"})}if(!t||t==="lxc"){let n=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(n=>n.type===t));s.sort((n,o)=>n.vmid-o.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let n of s)r.push(`| ${n.vmid} | ${n.name??"-"} | ${n.type} | ${n.node} | ${n.status??"-"} | ${Kr(n.cpu)} | ${ge(n.mem)} / ${ge(n.maxmem)} | ${So(n.uptime)} |`);return s.length===0&&r.push("| - | No VMs found | - | - | - | - | - | - |"),{success:!0,data:s,display:r.join(`
890
- `)}}async vmStatus(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/status/current`),n=[`## VM ${e} (${s.type}) on ${s.node}`,"",`**Name:** ${r.name??"-"}`,`**Status:** ${r.status}`,`**CPU:** ${Kr(r.cpu)} (${r.cpus??"-"} cores)`,`**RAM:** ${ge(r.mem)} / ${ge(r.maxmem)}`,`**Disk:** ${ge(r.disk)} / ${ge(r.maxdisk)}`,`**Uptime:** ${So(r.uptime)}`,`**PID:** ${r.pid??"-"}`,`**Net In / Out:** ${ge(r.netin)} / ${ge(r.netout)}`];return r.lock&&n.push(`**Lock:** ${r.lock}`),{success:!0,data:r,display:n.join(`
886
+ ${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success:!1,error:'Missing required field "document_id" for delete action'};let s=this.docRepo.getDocument(t);return s?(this.docRepo.deleteDocument(t),{success:!0,data:{documentId:t},display:`Document "${s.filename}" deleted.`}):{success:!1,error:`Document "${t}" not found`}}}});var zs,hu=T(()=>{"use strict";B();zs=class extends x{static{p(this,"TTSSkill")}synthesizer;metadata={name:"text_to_speech",category:"media",description:"Send a voice/audio message to the user. You MUST use this tool whenever the user asks you to respond as a voice message, speak, or reply with audio. Pass the full response text \u2014 it will be converted to speech and delivered as a playable voice message.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{text:{type:"string",description:"The text to convert to speech"}},required:["text"]}};constructor(e){super(),this.synthesizer=e}async execute(e,t){let s=e.text;if(!s)return{success:!1,error:"No text provided for speech synthesis."};try{return{success:!0,display:"Voice message sent.",attachments:[{fileName:"voice.ogg",data:await this.synthesizer.synthesize(s),mimeType:"audio/ogg"}]}}catch(r){return{success:!1,error:`Speech synthesis failed: ${r instanceof Error?r.message:String(r)}`}}}}});var qs,fu=T(()=>{"use strict";B();qs=class extends x{static{p(this,"ImageGenerateSkill")}generator;metadata={name:"image_generate",category:"media",description:"Generate an image from a text description. Use this tool when the user asks you to create, generate, draw, or design an image or picture. Returns the generated image that will be sent to the user.",riskLevel:"read",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{prompt:{type:"string",description:"Detailed description of the image to generate. Be specific about style, composition, colors, and subject matter."},model:{type:"string",description:"Optional model to use (e.g. gpt-image-1, gpt-image-1-mini, gemini-2.0-flash-exp). Uses provider default if omitted."},size:{type:"string",enum:["1024x1024","1536x1024","1024x1536"],description:"Image dimensions. 1024x1024 (square, default), 1536x1024 (landscape), 1024x1536 (portrait)."},quality:{type:"string",enum:["low","medium","high"],description:"Image quality level. Higher quality takes longer and costs more."}},required:["prompt"]}};constructor(e){super(),this.generator=e}async execute(e,t){let s=e.prompt;if(!s)return{success:!1,error:"No prompt provided for image generation."};try{let r=await this.generator.generate(s,{model:e.model,size:e.size,quality:e.quality});return{success:!0,display:"Image generated.",attachments:[{fileName:"image.png",data:r.data,mimeType:r.mimeType}]}}catch(r){return{success:!1,error:`Image generation failed: ${r instanceof Error?r.message:String(r)}`}}}}});function ge(l){return l==null?"-":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function Kr(l){return l==null?"-":`${(l*100).toFixed(1)}%`}function $o(l){if(!l)return"-";let e=Math.floor(l/86400),t=Math.floor(l%86400/3600),s=Math.floor(l%3600/60),r=[];return e&&r.push(`${e}d`),t&&r.push(`${t}h`),r.push(`${s}m`),r.join(" ")}var vo,gu=T(()=>{"use strict";B();p(ge,"bytes");p(Kr,"pct");p($o,"uptimeStr");vo=class l extends x{static{p(this,"ProxmoxSkill")}metadata={name:"proxmox",category:"infrastructure",description:'Manage Proxmox VE virtual machines, containers, and cluster. Use action "list_vms" to see VMs, "start_vm"/"shutdown_vm" to control them, "cluster_status" for health, "create_snapshot" for backups.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["cluster_status","list_nodes","node_stats","list_vms","vm_status","list_snapshots","list_storage","list_tasks","task_status","start_vm","shutdown_vm","reboot_vm","suspend_vm","resume_vm","create_snapshot","backup_vm","migrate_vm","stop_vm","delete_snapshot","rollback_snapshot"],description:"The Proxmox action to perform"},vmid:{type:"number",description:"Virtual machine / container ID"},node:{type:"string",description:"Proxmox node name (optional \u2014 resolved automatically when omitted)"},type:{type:"string",enum:["qemu","lxc"],description:"VM type filter for list_vms (default: both)"},name:{type:"string",description:"Snapshot name (for create/delete/rollback_snapshot)"},description:{type:"string",description:"Snapshot description (optional)"},target:{type:"string",description:"Target node for migration"},storage:{type:"string",description:"Storage target for backup_vm"},upid:{type:"string",description:"Task UPID for task_status"}},required:["action"]}};config;vmCache=null;static VM_CACHE_TTL=3e4;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"cluster_status":return await this.clusterStatus();case"list_nodes":return await this.listNodes();case"node_stats":return await this.nodeStats(e.node);case"list_vms":return await this.listVms(e.node,e.type);case"vm_status":return await this.vmStatus(e.vmid,e.node);case"list_snapshots":return await this.listSnapshots(e.vmid,e.node);case"list_storage":return await this.listStorage(e.node);case"list_tasks":return await this.listTasks(e.node);case"task_status":return await this.taskStatus(e.upid);case"start_vm":return await this.vmPowerAction("start",e);case"shutdown_vm":return await this.vmPowerAction("shutdown",e);case"reboot_vm":return await this.vmPowerAction("reboot",e);case"suspend_vm":return await this.vmPowerAction("suspend",e);case"resume_vm":return await this.vmPowerAction("resume",e);case"stop_vm":return await this.vmPowerAction("stop",e);case"create_snapshot":return await this.createSnapshot(e);case"backup_vm":return await this.backupVm(e);case"migrate_vm":return await this.migrateVm(e);case"delete_snapshot":return await this.deleteSnapshot(e);case"rollback_snapshot":return await this.rollbackSnapshot(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Proxmox API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl}/api2/json${t}`,n={Authorization:`PVEAPIToken=${this.config.tokenId}=${this.config.tokenSecret}`},o={method:e,headers:n};s&&e!=="GET"&&(n["Content-Type"]="application/json",o.body=JSON.stringify(s));let i=this.config.verifyTls===!1;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let a;try{a=await fetch(r,o)}finally{i&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}if(!a.ok){let d="";try{d=(await a.text()).slice(0,500)}catch{}throw new Error(`HTTP ${a.status} ${a.statusText} \u2014 ${d}`)}return(await a.json()).data}async get(e){return this.api("GET",e)}async post(e,t){return this.api("POST",e,t)}async del(e){return this.api("DELETE",e)}async resolveVm(e,t){if(t)try{return await this.get(`/nodes/${t}/qemu/${e}/status/current`),{node:t,type:"qemu"}}catch{try{return await this.get(`/nodes/${t}/lxc/${e}/status/current`),{node:t,type:"lxc"}}catch{throw new Error(`VM ${e} not found on node "${t}"`)}}let r=(await this.getAllVms()).find(n=>n.vmid===e);if(!r)throw new Error(`VM ${e} not found on any node. Use "list_vms" to see available VMs.`);return{node:r.node,type:r.type}}async getAllVms(){let e=Date.now();if(this.vmCache&&e-this.vmCache.ts<l.VM_CACHE_TTL)return this.vmCache.entries;let t=await this.get("/nodes"),s=[];for(let r of t){let[n,o]=await Promise.all([this.get(`/nodes/${r.node}/qemu`).catch(()=>[]),this.get(`/nodes/${r.node}/lxc`).catch(()=>[])]);for(let i of n)s.push({...i,node:r.node,type:"qemu"});for(let i of o)s.push({...i,node:r.node,type:"lxc"})}return this.vmCache={entries:s,ts:e},s}async clusterStatus(){let e=await this.get("/cluster/status"),t=["## Cluster Status",""],s=e.find(n=>n.type==="cluster");s&&(t.push(`**Cluster:** ${s.name}`),t.push(`**Quorum:** ${s.quorate?"Yes":"No"}`),t.push(`**Nodes:** ${s.nodes??"-"}`),t.push(`**Version:** ${s.version??"-"}`),t.push(""));let r=e.filter(n=>n.type==="node");if(r.length){t.push("| Node | Online | Level | ID |"),t.push("|------|--------|-------|----|");for(let n of r)t.push(`| ${n.name} | ${n.online?"Yes":"**No**"} | ${n.level??"-"} | ${n.nodeid??"-"} |`)}return{success:!0,data:e,display:t.join(`
887
+ `)}}async listNodes(){let e=await this.get("/nodes"),t=["## Nodes","","| Node | Status | CPU | RAM Used / Total | Uptime |"];t.push("|------|--------|-----|------------------|--------|");for(let s of e){let r=typeof s.cpu=="number"?Kr(s.cpu):"-",n=ge(s.mem),o=ge(s.maxmem);t.push(`| ${s.node} | ${s.status} | ${r} | ${n} / ${o} | ${$o(s.uptime)} |`)}return{success:!0,data:e,display:t.join(`
888
+ `)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,n=s.memory,o=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${$o(s.uptime)}`,`**Kernel:** ${s.kversion??"-"}`,`**PVE Version:** ${s.pveversion??"-"}`,""];return r&&(a.push(`**CPU:** ${r.model??"-"} (${r.cpus??"-"} cores)`),a.push(`**CPU Usage:** ${Kr(r.cpu)}`),a.push(`**Load:** ${Array.isArray(s.loadavg)?s.loadavg.join(", "):"-"}`)),n&&a.push(`**RAM:** ${ge(n.used)} / ${ge(n.total)} (${Kr(n.used/n.total)})`),i&&a.push(`**Swap:** ${ge(i.used)} / ${ge(i.total)}`),o&&a.push(`**Root FS:** ${ge(o.used)} / ${ge(o.total)}`),{success:!0,data:s,display:a.join(`
889
+ `)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let n=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"qemu"})}if(!t||t==="lxc"){let n=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(n=>n.type===t));s.sort((n,o)=>n.vmid-o.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let n of s)r.push(`| ${n.vmid} | ${n.name??"-"} | ${n.type} | ${n.node} | ${n.status??"-"} | ${Kr(n.cpu)} | ${ge(n.mem)} / ${ge(n.maxmem)} | ${$o(n.uptime)} |`);return s.length===0&&r.push("| - | No VMs found | - | - | - | - | - | - |"),{success:!0,data:s,display:r.join(`
890
+ `)}}async vmStatus(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/status/current`),n=[`## VM ${e} (${s.type}) on ${s.node}`,"",`**Name:** ${r.name??"-"}`,`**Status:** ${r.status}`,`**CPU:** ${Kr(r.cpu)} (${r.cpus??"-"} cores)`,`**RAM:** ${ge(r.mem)} / ${ge(r.maxmem)}`,`**Disk:** ${ge(r.disk)} / ${ge(r.maxdisk)}`,`**Uptime:** ${$o(r.uptime)}`,`**PID:** ${r.pid??"-"}`,`**Net In / Out:** ${ge(r.netin)} / ${ge(r.netout)}`];return r.lock&&n.push(`**Lock:** ${r.lock}`),{success:!0,data:r,display:n.join(`
891
891
  `)}}async listSnapshots(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/snapshot`),n=[`## Snapshots for VM ${e}`,"","| Name | Description | Date | Parent |","|------|-------------|------|--------|"];for(let o of r){let i=o.snaptime?new Date(o.snaptime*1e3).toISOString():"-";n.push(`| ${o.name} | ${o.description??"-"} | ${i} | ${o.parent??"-"} |`)}return{success:!0,data:r,display:n.join(`
892
892
  `)}}async listStorage(e){let t=e??this.config.defaultNode,s=t?`/nodes/${t}/storage`:"/storage",r=await this.get(s),n=[`## Storage${t?` (Node: ${t})`:""}`,"","| Storage | Type | Content | Used / Total | Status |","|---------|------|---------|--------------|--------|"];for(let o of r){let i=ge(o.used),a=ge(o.total);n.push(`| ${o.storage} | ${o.type} | ${o.content??"-"} | ${i} / ${a} | ${o.active?"active":o.enabled?"enabled":"disabled"} |`)}return{success:!0,data:r,display:n.join(`
893
893
  `)}}async listTasks(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/tasks?limit=20`),r=[`## Recent Tasks (Node: ${t})`,"","| UPID | Type | Status | Start | User |","|------|------|--------|-------|------|"];for(let n of s){let o=n.starttime?new Date(n.starttime*1e3).toISOString():"-";r.push(`| \`${n.upid?.slice(-16)??"-"}\` | ${n.type??"-"} | ${n.status??"running"} | ${o} | ${n.user??"-"} |`)}return{success:!0,data:s,display:r.join(`
@@ -898,7 +898,7 @@ ${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success
898
898
  `)}}async migrateVm(e){let t=e.vmid,s=e.target;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "target" parameter (target node)'};let r=await this.resolveVm(t,e.node),n=await this.post(`/nodes/${r.node}/${r.type}/${t}/migrate`,{target:s,online:1});return{success:!0,data:{vmid:t,from:r.node,target:s,type:r.type,upid:n},display:[`Live migration of VM ${t} from **${r.node}** to **${s}** started.`,"",`UPID: \`${n}\``].join(`
899
899
  `)}}async deleteSnapshot(e){let t=e.vmid,s=e.name;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "name" parameter (snapshot name)'};let r=await this.resolveVm(t,e.node),n=await this.del(`/nodes/${r.node}/${r.type}/${t}/snapshot/${encodeURIComponent(s)}`);return{success:!0,data:{vmid:t,node:r.node,type:r.type,snapname:s,upid:n},display:[`Snapshot **"${s}"** deletion started for VM ${t} on **${r.node}**.`,"",`UPID: \`${n}\``].join(`
900
900
  `)}}async rollbackSnapshot(e){let t=e.vmid,s=e.name;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "name" parameter (snapshot name)'};let r=await this.resolveVm(t,e.node),n=await this.post(`/nodes/${r.node}/${r.type}/${t}/snapshot/${encodeURIComponent(s)}/rollback`);return{success:!0,data:{vmid:t,node:r.node,type:r.type,snapname:s,upid:n},display:[`Rollback to snapshot **"${s}"** started for VM ${t} on **${r.node}**.`,"",`UPID: \`${n}\``,"","**Warning:** The VM will be stopped during rollback."].join(`
901
- `)}}}});var vo,yu=T(()=>{"use strict";B();vo=class extends x{static{p(this,"UniFiSkill")}metadata={name:"unifi",category:"infrastructure",description:'Manage UniFi network devices, clients, and WLANs. Use "list_devices" to see APs/switches, "list_clients" for connected clients, "restart_device" to reboot a device, "block_client"/"unblock_client" for access control.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_devices","device_info","list_clients","client_info","list_networks","list_wlans","site_stats","dpi_stats","list_alerts","list_events","list_vouchers","restart_device","locate_device","reconnect_client","create_voucher","enable_wlan","disable_wlan","archive_alerts","block_client","unblock_client","forget_client","adopt_device"],description:"The UniFi action to perform"},mac:{type:"string",description:"MAC address of device or client (for device_info, client_info, restart_device, locate_device, reconnect_client, block_client, unblock_client, forget_client, adopt_device)"},active:{type:"boolean",description:"If true list only active clients, if false list all known clients (for list_clients, default: true)"},enabled:{type:"boolean",description:"Enable or disable device locate LED (for locate_device, default: true)"},id:{type:"string",description:"WLAN config ID (for enable_wlan, disable_wlan)"},limit:{type:"number",description:"Maximum number of items to return (for list_alerts, list_events)"},count:{type:"number",description:"Number of vouchers to create (for create_voucher, default: 1)"},duration:{type:"number",description:"Voucher validity in minutes (for create_voucher)"},bandwidth_down:{type:"number",description:"Download bandwidth limit in Kbps (for create_voucher, optional)"},bandwidth_up:{type:"number",description:"Upload bandwidth limit in Kbps (for create_voucher, optional)"},quota:{type:"number",description:"Number of uses per voucher (for create_voucher, 0 = unlimited, default: 1)"}},required:["action"]}};config;site;controllerMode;cookies=[];csrfToken;constructor(e){if(super(),!e.apiKey&&!(e.username&&e.password))throw new Error('UniFi config requires either "apiKey" or both "username" and "password".');this.config=e,this.site=e.site??"default",e.apiKey&&(this.controllerMode="unifi-os")}async execute(e,t){let s=e.action;try{switch(s){case"list_devices":return await this.listDevices();case"device_info":return await this.deviceInfo(e.mac);case"list_clients":return await this.listClients(e.active);case"client_info":return await this.clientInfo(e.mac);case"list_networks":return await this.listNetworks();case"list_wlans":return await this.listWlans();case"site_stats":return await this.siteStats();case"dpi_stats":return await this.dpiStats(e.mac);case"list_alerts":return await this.listAlerts(e.limit);case"list_events":return await this.listEvents(e.limit);case"list_vouchers":return await this.listVouchers();case"restart_device":return await this.restartDevice(e.mac);case"locate_device":return await this.locateDevice(e.mac,e.enabled);case"reconnect_client":return await this.reconnectClient(e.mac);case"create_voucher":return await this.createVoucher(e.count,e.duration,e.bandwidth_down,e.bandwidth_up,e.quota);case"enable_wlan":return await this.enableWlan(e.id);case"disable_wlan":return await this.disableWlan(e.id);case"archive_alerts":return await this.archiveAlerts();case"block_client":return await this.blockClient(e.mac);case"unblock_client":return await this.unblockClient(e.mac);case"forget_client":return await this.forgetClient(e.mac);case"adopt_device":return await this.adoptDevice(e.mac);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:`UniFi error: ${r instanceof Error?r.message:String(r)}`}}}apiUrl(e){let t=this.config.baseUrl.replace(/\/+$/,"");return this.controllerMode==="unifi-os"?`${t}/proxy/network/api/s/${this.site}/${e}`:`${t}/api/s/${this.site}/${e}`}async ensureAuth(){this.config.apiKey||this.cookies.length>0||await this.login()}async login(){let e=this.config.baseUrl.replace(/\/+$/,""),t=JSON.stringify({username:this.config.username,password:this.config.password}),s=await this.rawFetch(`${e}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(s.status===200){this.controllerMode="unifi-os",this.storeCookies(s);return}if(s.status===404){let r=await this.rawFetch(`${e}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(r.ok){this.controllerMode="classic",this.storeCookies(r);return}throw new Error(`UniFi Classic login failed (HTTP ${r.status}): ${await r.text()}`)}throw new Error(`UniFi OS login failed (HTTP ${s.status}): ${await s.text()}`)}storeCookies(e){let t=e.headers.getSetCookie?.()??[];t.length>0&&(this.cookies=t.map(r=>r.split(";")[0]));let s=e.headers.get("x-csrf-token");s&&(this.csrfToken=s)}clearSession(){this.cookies=[],this.csrfToken=void 0}async rawFetch(e,t){let s=this.config.verifyTls===!1;s&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{s&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}}async request(e,t,s){await this.ensureAuth();let r=await this.doFetch(e,t,s);if(r.status===401&&!this.config.apiKey){this.clearSession(),await this.login();let n=await this.doFetch(e,t,s);if(!n.ok)throw new Error(`UniFi API error after relogin: HTTP ${n.status} ${await n.text()}`);return this.parseResponse(n)}if(!r.ok)throw new Error(`UniFi API error: HTTP ${r.status} ${await r.text()}`);return this.parseResponse(r)}async doFetch(e,t,s){let r=this.apiUrl(t),n={"Content-Type":"application/json"};return this.config.apiKey?n["X-API-Key"]=this.config.apiKey:(this.cookies.length>0&&(n.Cookie=this.cookies.join("; ")),this.csrfToken&&(n["X-CSRF-Token"]=this.csrfToken)),this.rawFetch(r,{method:e,headers:n,body:s!==void 0?JSON.stringify(s):void 0,signal:AbortSignal.timeout(3e4)})}async parseResponse(e){let t=await e.json(),s=e.headers.get("x-csrf-token");if(s&&(this.csrfToken=s),t.meta?.rc==="error")throw new Error(`UniFi: ${t.meta.msg??"unknown error"}`);return t.data}async listDevices(){let e=await this.request("GET","stat/device"),t=(e??[]).map(r=>({name:r.name??r.hostname??r.mac,model:r.model??"unknown",ip:r.ip??"-",mac:r.mac,status:r.state===1?"online":"offline",clients:r.num_sta??0,load:r["system-stats"]?.cpu!=null?`${r["system-stats"].cpu}%`:"-"})),s=t.length===0?"No devices found.":["| Name | Model | IP | MAC | Status | Clients | CPU |","|------|-------|----|-----|--------|---------|-----|",...t.map(r=>`| ${r.name} | ${r.model} | ${r.ip} | ${r.mac} | ${r.status} | ${r.clients} | ${r.load} |`)].join(`
901
+ `)}}}});var Ao,yu=T(()=>{"use strict";B();Ao=class extends x{static{p(this,"UniFiSkill")}metadata={name:"unifi",category:"infrastructure",description:'Manage UniFi network devices, clients, and WLANs. Use "list_devices" to see APs/switches, "list_clients" for connected clients, "restart_device" to reboot a device, "block_client"/"unblock_client" for access control.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_devices","device_info","list_clients","client_info","list_networks","list_wlans","site_stats","dpi_stats","list_alerts","list_events","list_vouchers","restart_device","locate_device","reconnect_client","create_voucher","enable_wlan","disable_wlan","archive_alerts","block_client","unblock_client","forget_client","adopt_device"],description:"The UniFi action to perform"},mac:{type:"string",description:"MAC address of device or client (for device_info, client_info, restart_device, locate_device, reconnect_client, block_client, unblock_client, forget_client, adopt_device)"},active:{type:"boolean",description:"If true list only active clients, if false list all known clients (for list_clients, default: true)"},enabled:{type:"boolean",description:"Enable or disable device locate LED (for locate_device, default: true)"},id:{type:"string",description:"WLAN config ID (for enable_wlan, disable_wlan)"},limit:{type:"number",description:"Maximum number of items to return (for list_alerts, list_events)"},count:{type:"number",description:"Number of vouchers to create (for create_voucher, default: 1)"},duration:{type:"number",description:"Voucher validity in minutes (for create_voucher)"},bandwidth_down:{type:"number",description:"Download bandwidth limit in Kbps (for create_voucher, optional)"},bandwidth_up:{type:"number",description:"Upload bandwidth limit in Kbps (for create_voucher, optional)"},quota:{type:"number",description:"Number of uses per voucher (for create_voucher, 0 = unlimited, default: 1)"}},required:["action"]}};config;site;controllerMode;cookies=[];csrfToken;constructor(e){if(super(),!e.apiKey&&!(e.username&&e.password))throw new Error('UniFi config requires either "apiKey" or both "username" and "password".');this.config=e,this.site=e.site??"default",e.apiKey&&(this.controllerMode="unifi-os")}async execute(e,t){let s=e.action;try{switch(s){case"list_devices":return await this.listDevices();case"device_info":return await this.deviceInfo(e.mac);case"list_clients":return await this.listClients(e.active);case"client_info":return await this.clientInfo(e.mac);case"list_networks":return await this.listNetworks();case"list_wlans":return await this.listWlans();case"site_stats":return await this.siteStats();case"dpi_stats":return await this.dpiStats(e.mac);case"list_alerts":return await this.listAlerts(e.limit);case"list_events":return await this.listEvents(e.limit);case"list_vouchers":return await this.listVouchers();case"restart_device":return await this.restartDevice(e.mac);case"locate_device":return await this.locateDevice(e.mac,e.enabled);case"reconnect_client":return await this.reconnectClient(e.mac);case"create_voucher":return await this.createVoucher(e.count,e.duration,e.bandwidth_down,e.bandwidth_up,e.quota);case"enable_wlan":return await this.enableWlan(e.id);case"disable_wlan":return await this.disableWlan(e.id);case"archive_alerts":return await this.archiveAlerts();case"block_client":return await this.blockClient(e.mac);case"unblock_client":return await this.unblockClient(e.mac);case"forget_client":return await this.forgetClient(e.mac);case"adopt_device":return await this.adoptDevice(e.mac);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:`UniFi error: ${r instanceof Error?r.message:String(r)}`}}}apiUrl(e){let t=this.config.baseUrl.replace(/\/+$/,"");return this.controllerMode==="unifi-os"?`${t}/proxy/network/api/s/${this.site}/${e}`:`${t}/api/s/${this.site}/${e}`}async ensureAuth(){this.config.apiKey||this.cookies.length>0||await this.login()}async login(){let e=this.config.baseUrl.replace(/\/+$/,""),t=JSON.stringify({username:this.config.username,password:this.config.password}),s=await this.rawFetch(`${e}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(s.status===200){this.controllerMode="unifi-os",this.storeCookies(s);return}if(s.status===404){let r=await this.rawFetch(`${e}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(r.ok){this.controllerMode="classic",this.storeCookies(r);return}throw new Error(`UniFi Classic login failed (HTTP ${r.status}): ${await r.text()}`)}throw new Error(`UniFi OS login failed (HTTP ${s.status}): ${await s.text()}`)}storeCookies(e){let t=e.headers.getSetCookie?.()??[];t.length>0&&(this.cookies=t.map(r=>r.split(";")[0]));let s=e.headers.get("x-csrf-token");s&&(this.csrfToken=s)}clearSession(){this.cookies=[],this.csrfToken=void 0}async rawFetch(e,t){let s=this.config.verifyTls===!1;s&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{s&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}}async request(e,t,s){await this.ensureAuth();let r=await this.doFetch(e,t,s);if(r.status===401&&!this.config.apiKey){this.clearSession(),await this.login();let n=await this.doFetch(e,t,s);if(!n.ok)throw new Error(`UniFi API error after relogin: HTTP ${n.status} ${await n.text()}`);return this.parseResponse(n)}if(!r.ok)throw new Error(`UniFi API error: HTTP ${r.status} ${await r.text()}`);return this.parseResponse(r)}async doFetch(e,t,s){let r=this.apiUrl(t),n={"Content-Type":"application/json"};return this.config.apiKey?n["X-API-Key"]=this.config.apiKey:(this.cookies.length>0&&(n.Cookie=this.cookies.join("; ")),this.csrfToken&&(n["X-CSRF-Token"]=this.csrfToken)),this.rawFetch(r,{method:e,headers:n,body:s!==void 0?JSON.stringify(s):void 0,signal:AbortSignal.timeout(3e4)})}async parseResponse(e){let t=await e.json(),s=e.headers.get("x-csrf-token");if(s&&(this.csrfToken=s),t.meta?.rc==="error")throw new Error(`UniFi: ${t.meta.msg??"unknown error"}`);return t.data}async listDevices(){let e=await this.request("GET","stat/device"),t=(e??[]).map(r=>({name:r.name??r.hostname??r.mac,model:r.model??"unknown",ip:r.ip??"-",mac:r.mac,status:r.state===1?"online":"offline",clients:r.num_sta??0,load:r["system-stats"]?.cpu!=null?`${r["system-stats"].cpu}%`:"-"})),s=t.length===0?"No devices found.":["| Name | Model | IP | MAC | Status | Clients | CPU |","|------|-------|----|-----|--------|---------|-----|",...t.map(r=>`| ${r.name} | ${r.model} | ${r.ip} | ${r.mac} | ${r.status} | ${r.clients} | ${r.load} |`)].join(`
902
902
  `);return{success:!0,data:e,display:s}}async deviceInfo(e){if(!e)return{success:!1,error:"mac is required for device_info."};let s=(await this.request("GET",`stat/device/${e}`))?.[0];if(!s)return{success:!1,error:`Device ${e} not found.`};let r=[`**${s.name??s.hostname??e}**`,`- Model: ${s.model??"unknown"} (${s.model_in_lts?"LTS":s.model_in_eol?"EOL":"supported"})`,`- IP: ${s.ip??"-"}`,`- MAC: ${s.mac}`,`- Status: ${s.state===1?"online":"offline"}`,`- Version: ${s.version??"-"}`,`- Uptime: ${s.uptime?this.formatUptime(s.uptime):"-"}`,`- Clients: ${s.num_sta??0}`,`- CPU: ${s["system-stats"]?.cpu??"-"}%`,`- Memory: ${s["system-stats"]?.mem??"-"}%`,`- TX bytes: ${this.formatBytes(s.tx_bytes??0)}`,`- RX bytes: ${this.formatBytes(s.rx_bytes??0)}`];return{success:!0,data:s,display:r.join(`
903
903
  `)}}async listClients(e){let t=e!==!1,s=t?"stat/sta":"rest/user",r=await this.request("GET",s),n=(r??[]).map(i=>({name:i.name??i.hostname??i.mac,ip:i.ip??i.fixed_ip??"-",mac:i.mac,network:i.essid??i.network??"-",signal:i.signal!=null?`${i.signal} dBm`:"-",tx:this.formatBytes(i.tx_bytes??0),rx:this.formatBytes(i.rx_bytes??0)})),o=n.length===0?"No clients found.":["| Name | IP | MAC | Network | Signal | TX | RX |","|------|----|-----|---------|--------|----|----|",...n.map(i=>`| ${i.name} | ${i.ip} | ${i.mac} | ${i.network} | ${i.signal} | ${i.tx} | ${i.rx} |`)].join(`
904
904
  `);return{success:!0,data:r,display:`${t?"Active":"All known"} clients (${n.length}):
@@ -914,7 +914,7 @@ ${o}`}}async clientInfo(e){if(!e)return{success:!1,error:"mac is required for cl
914
914
  `);return{success:!0,data:s,display:n}}async listEvents(e){let t=Math.min(Math.max(1,e??20),200),s=await this.request("GET",`stat/event?_limit=${t}`),r=(s??[]).slice(0,t).map(o=>({time:o.datetime??o.time??"-",type:o.key??"-",message:o.msg??"-"})),n=r.length===0?"No events.":["| Time | Type | Message |","|------|------|---------|",...r.map(o=>`| ${o.time} | ${o.type} | ${o.message} |`)].join(`
915
915
  `);return{success:!0,data:s,display:n}}async listVouchers(){let e=await this.request("GET","stat/voucher"),t=(e??[]).map(r=>({code:r.code??"-",duration:r.duration!=null?`${r.duration} min`:"-",quota:r.quota??0,used:r.used??0,created:r.create_time?new Date(r.create_time*1e3).toISOString():"-",note:r.note??"-"})),s=t.length===0?"No vouchers.":["| Code | Duration | Quota | Used | Created | Note |","|------|----------|-------|------|---------|------|",...t.map(r=>`| ${r.code} | ${r.duration} | ${r.quota} | ${r.used} | ${r.created} | ${r.note} |`)].join(`
916
916
  `);return{success:!0,data:e,display:s}}async restartDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"restart",mac:e}),{success:!0,data:{mac:e},display:`Restart command sent to device ${e}.`}):{success:!1,error:"mac is required for restart_device."}}async locateDevice(e,t){if(!e)return{success:!1,error:"mac is required for locate_device."};let s=t!==!1,r=s?"set-locate":"unset-locate";return await this.request("POST","cmd/devmgr",{cmd:r,mac:e}),{success:!0,data:{mac:e,enabled:s},display:`Device ${e} locate LED ${s?"enabled":"disabled"}.`}}async reconnectClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"kick-sta",mac:e}),{success:!0,data:{mac:e},display:`Reconnect (kick) command sent to client ${e}.`}):{success:!1,error:"mac is required for reconnect_client."}}async createVoucher(e,t,s,r,n){if(!t)return{success:!1,error:"duration (minutes) is required for create_voucher."};let o={cmd:"create-voucher",n:e??1,expire:t,quota:n??1};s!=null&&(o.down=s),r!=null&&(o.up=r);let i=await this.request("POST","cmd/hotspot",o),a=i?.[0]?.create_time;return{success:!0,data:i,display:`Created ${e??1} voucher(s), duration ${t} min.${a?` Batch: ${a}`:""}
917
- Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!0}),{success:!0,data:{id:e,enabled:!0},display:`WLAN ${e} enabled.`}):{success:!1,error:"id is required for enable_wlan."}}async disableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!1}),{success:!0,data:{id:e,enabled:!1},display:`WLAN ${e} disabled.`}):{success:!1,error:"id is required for disable_wlan."}}async archiveAlerts(){return await this.request("POST","cmd/evtmgr",{cmd:"archive-all-alarms"}),{success:!0,data:{},display:"All alerts archived."}}async blockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"block-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} blocked.`}):{success:!1,error:"mac is required for block_client."}}async unblockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"unblock-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} unblocked.`}):{success:!1,error:"mac is required for unblock_client."}}async forgetClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"forget-sta",macs:[e]}),{success:!0,data:{mac:e},display:`Client ${e} forgotten (removed from known clients).`}):{success:!1,error:"mac is required for forget_client."}}async adoptDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"adopt",mac:e}),{success:!0,data:{mac:e},display:`Adopt command sent to device ${e}.`}):{success:!1,error:"mac is required for adopt_device."}}formatBytes(e){if(e===0)return"0 B";let t=["B","KB","MB","GB","TB"],s=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/Math.pow(1024,s)).toFixed(s===0?0:1)} ${t[s]}`}formatUptime(e){let t=Math.floor(e/86400),s=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=[];return t>0&&n.push(`${t}d`),s>0&&n.push(`${s}h`),n.push(`${r}m`),n.join(" ")}}});function xa(l){let e=l.match(/^(\d+)\s*(h|d|m|w)$/i);if(!e)return new Date(Date.now()-36e5).toISOString();let t=parseInt(e[1],10),s=e[2].toLowerCase(),r={m:6e4,h:36e5,d:864e5,w:6048e5}[s]??36e5;return new Date(Date.now()-t*r).toISOString()}function Ef(l){let e=l.indexOf(".");if(e<1)throw new Error(`Invalid entity_id "${l}" \u2014 expected format "domain.name"`);return l.slice(0,e)}var Ao,wu=T(()=>{"use strict";B();p(xa,"parsePeriod");p(Ef,"extractDomain");Ao=class extends x{static{p(this,"HomeAssistantSkill")}metadata={name:"homeassistant",category:"infrastructure",description:'Control Home Assistant smart home devices. Use "states" to list entities, "turn_on"/"turn_off"/"toggle" to control devices, "call_service" for advanced service calls, "history" for entity state history. Also: "areas" for rooms/zones, "presence" for who is home, "activate_scene"/"trigger_automation"/"run_script" for automations, "notify" for notifications, "calendar_events" for calendars, "template" for Jinja2 queries, "error_log" for HA logs. Config API: "create_automation"/"delete_automation", "create_script"/"delete_script", "create_scene"/"delete_scene" \u2014 create persistent automations, scripts, and scenes in HA. Use configData (JSON) with the HA automation/script/scene schema. "briefing_summary" for a compact smart home overview (open contacts, lights on, battery/SoC, energy, climate, presence). Optionally pass entities[] or domains[] to filter. "energy_stats" for energy consumption statistics over a period (today, yesterday, last_week, etc.) \u2014 auto-discovers all energy sensors and calculates kWh consumed.',riskLevel:"write",version:"2.1.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["states","state","turn_on","turn_off","toggle","call_service","services","history","logbook","config","areas","template","presence","notify","activate_scene","trigger_automation","run_script","calendar_events","error_log","create_automation","delete_automation","create_script","delete_script","create_scene","delete_scene","briefing_summary","energy_stats"],description:"The Home Assistant action to perform"},entityId:{type:"string",description:"Entity ID, e.g. light.wohnzimmer, switch.garage, sensor.temperature"},domain:{type:"string",description:'Domain filter for "states" (e.g. light, sensor, switch) or domain for "call_service"'},service:{type:"string",description:'Service name for "call_service", e.g. set_temperature, set_hvac_mode'},serviceData:{type:"string",description:'JSON string with service parameters, e.g. {"brightness": 200, "color_name": "red"}'},period:{type:"string",description:'Time period for history/logbook/energy_stats. Formats: "1h", "24h", "7d" or friendly names "today", "yesterday", "this_week", "last_week", "this_month", "last_month" (default for energy_stats: "today")'},area:{type:"string",description:"Area name or ID (for areas action)"},template:{type:"string",description:"Jinja2 template string (for template action)"},target:{type:"string",description:"Notification target (for notify action, e.g. mobile_app_pixel)"},message:{type:"string",description:"Notification message (for notify action)"},title:{type:"string",description:"Optional title (for notify action)"},startTime:{type:"string",description:"ISO datetime start (for calendar_events, default: now)"},endTime:{type:"string",description:"ISO datetime end (for calendar_events, default: +24h)"},subAction:{type:"string",enum:["trigger","enable","disable"],description:"Sub-action for trigger_automation"},variables:{type:"string",description:"JSON string with script variables (for run_script)"},configId:{type:"string",description:'Unique ID for create/delete automation, script, or scene (e.g. "notify_garage_light"). Used as the HA config entry ID.'},configData:{type:"string",description:"JSON string with the HA config object for create actions. For automations: {alias, description, trigger[], condition[], action[], mode}. For scripts: {alias, sequence[], mode}. For scenes: {name, entities: {entity_id: state}}."},entities:{type:"array",items:{type:"string"},description:'Specific entity IDs for briefing_summary (e.g. ["sensor.victron_soc", "sensor.power_consumption"])'},domains:{type:"array",items:{type:"string"},description:'Domain filters for briefing_summary (e.g. ["binary_sensor", "light", "climate"])'}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"states":return await this.getStates(e.domain);case"state":return await this.getState(e.entityId);case"turn_on":return await this.switchAction("turn_on",e.entityId,e.serviceData);case"turn_off":return await this.switchAction("turn_off",e.entityId,e.serviceData);case"toggle":return await this.switchAction("toggle",e.entityId,e.serviceData);case"call_service":return await this.callService(e.domain,e.service,e.entityId,e.serviceData);case"services":return await this.getServices();case"history":return await this.getHistory(e.entityId,e.period);case"logbook":return await this.getLogbook(e.entityId,e.period);case"config":return await this.getConfig();case"areas":return await this.getAreas(e.area);case"template":return await this.renderTemplate(e.template);case"presence":return await this.getPresence();case"notify":return await this.sendNotification(e.message,e.title,e.target);case"activate_scene":return await this.activateScene(e.entityId);case"trigger_automation":return await this.triggerAutomation(e.entityId,e.subAction);case"run_script":return await this.runScript(e.entityId,e.variables);case"calendar_events":return await this.getCalendarEvents(e.entityId,e.startTime,e.endTime);case"error_log":return await this.getErrorLog();case"create_automation":return await this.createConfig("automation",e.configId,e.configData);case"delete_automation":return await this.deleteConfig("automation",e.configId);case"create_script":return await this.createConfig("script",e.configId,e.configData);case"delete_script":return await this.deleteConfig("script",e.configId);case"create_scene":return await this.createConfig("scene",e.configId,e.configData);case"delete_scene":return await this.deleteConfig("scene",e.configId);case"briefing_summary":return await this.getBriefingSummary(e.entities,e.domains);case"energy_stats":return await this.getEnergyStats(e.period,e.entityId);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Home Assistant API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.json()}async apiText(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.text()}async getStates(e){let t=await this.api("GET","/api/states");e&&(t=t.filter(r=>r.entity_id.startsWith(`${e}.`)));let s=[`## Entities${e?` (${e})`:""}`,"","| Entity ID | State | Name | Unit |","|-----------|-------|------|------|"];for(let r of t){let n=r.attributes?.friendly_name??"-",o=r.attributes?.unit_of_measurement??"-";s.push(`| ${r.entity_id} | ${r.state} | ${n} | ${o} |`)}return t.length===0&&s.push(`| - | No entities found${e?` for domain "${e}"`:""} | - | - |`),{success:!0,data:t,display:s.join(`
917
+ Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!0}),{success:!0,data:{id:e,enabled:!0},display:`WLAN ${e} enabled.`}):{success:!1,error:"id is required for enable_wlan."}}async disableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!1}),{success:!0,data:{id:e,enabled:!1},display:`WLAN ${e} disabled.`}):{success:!1,error:"id is required for disable_wlan."}}async archiveAlerts(){return await this.request("POST","cmd/evtmgr",{cmd:"archive-all-alarms"}),{success:!0,data:{},display:"All alerts archived."}}async blockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"block-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} blocked.`}):{success:!1,error:"mac is required for block_client."}}async unblockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"unblock-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} unblocked.`}):{success:!1,error:"mac is required for unblock_client."}}async forgetClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"forget-sta",macs:[e]}),{success:!0,data:{mac:e},display:`Client ${e} forgotten (removed from known clients).`}):{success:!1,error:"mac is required for forget_client."}}async adoptDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"adopt",mac:e}),{success:!0,data:{mac:e},display:`Adopt command sent to device ${e}.`}):{success:!1,error:"mac is required for adopt_device."}}formatBytes(e){if(e===0)return"0 B";let t=["B","KB","MB","GB","TB"],s=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/Math.pow(1024,s)).toFixed(s===0?0:1)} ${t[s]}`}formatUptime(e){let t=Math.floor(e/86400),s=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=[];return t>0&&n.push(`${t}d`),s>0&&n.push(`${s}h`),n.push(`${r}m`),n.join(" ")}}});function xa(l){let e=l.match(/^(\d+)\s*(h|d|m|w)$/i);if(!e)return new Date(Date.now()-36e5).toISOString();let t=parseInt(e[1],10),s=e[2].toLowerCase(),r={m:6e4,h:36e5,d:864e5,w:6048e5}[s]??36e5;return new Date(Date.now()-t*r).toISOString()}function Ef(l){let e=l.indexOf(".");if(e<1)throw new Error(`Invalid entity_id "${l}" \u2014 expected format "domain.name"`);return l.slice(0,e)}var Io,wu=T(()=>{"use strict";B();p(xa,"parsePeriod");p(Ef,"extractDomain");Io=class extends x{static{p(this,"HomeAssistantSkill")}metadata={name:"homeassistant",category:"infrastructure",description:'Control Home Assistant smart home devices. Use "states" to list entities, "turn_on"/"turn_off"/"toggle" to control devices, "call_service" for advanced service calls, "history" for entity state history. Also: "areas" for rooms/zones, "presence" for who is home, "activate_scene"/"trigger_automation"/"run_script" for automations, "notify" for notifications, "calendar_events" for calendars, "template" for Jinja2 queries, "error_log" for HA logs. Config API: "create_automation"/"delete_automation", "create_script"/"delete_script", "create_scene"/"delete_scene" \u2014 create persistent automations, scripts, and scenes in HA. Use configData (JSON) with the HA automation/script/scene schema. "briefing_summary" for a compact smart home overview (open contacts, lights on, battery/SoC, energy, climate, presence). Optionally pass entities[] or domains[] to filter. "energy_stats" for energy consumption statistics over a period (today, yesterday, last_week, etc.) \u2014 auto-discovers all energy sensors and calculates kWh consumed.',riskLevel:"write",version:"2.1.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["states","state","turn_on","turn_off","toggle","call_service","services","history","logbook","config","areas","template","presence","notify","activate_scene","trigger_automation","run_script","calendar_events","error_log","create_automation","delete_automation","create_script","delete_script","create_scene","delete_scene","briefing_summary","energy_stats"],description:"The Home Assistant action to perform"},entityId:{type:"string",description:"Entity ID, e.g. light.wohnzimmer, switch.garage, sensor.temperature"},domain:{type:"string",description:'Domain filter for "states" (e.g. light, sensor, switch) or domain for "call_service"'},service:{type:"string",description:'Service name for "call_service", e.g. set_temperature, set_hvac_mode'},serviceData:{type:"string",description:'JSON string with service parameters, e.g. {"brightness": 200, "color_name": "red"}'},period:{type:"string",description:'Time period for history/logbook/energy_stats. Formats: "1h", "24h", "7d" or friendly names "today", "yesterday", "this_week", "last_week", "this_month", "last_month" (default for energy_stats: "today")'},area:{type:"string",description:"Area name or ID (for areas action)"},template:{type:"string",description:"Jinja2 template string (for template action)"},target:{type:"string",description:"Notification target (for notify action, e.g. mobile_app_pixel)"},message:{type:"string",description:"Notification message (for notify action)"},title:{type:"string",description:"Optional title (for notify action)"},startTime:{type:"string",description:"ISO datetime start (for calendar_events, default: now)"},endTime:{type:"string",description:"ISO datetime end (for calendar_events, default: +24h)"},subAction:{type:"string",enum:["trigger","enable","disable"],description:"Sub-action for trigger_automation"},variables:{type:"string",description:"JSON string with script variables (for run_script)"},configId:{type:"string",description:'Unique ID for create/delete automation, script, or scene (e.g. "notify_garage_light"). Used as the HA config entry ID.'},configData:{type:"string",description:"JSON string with the HA config object for create actions. For automations: {alias, description, trigger[], condition[], action[], mode}. For scripts: {alias, sequence[], mode}. For scenes: {name, entities: {entity_id: state}}."},entities:{type:"array",items:{type:"string"},description:'Specific entity IDs for briefing_summary (e.g. ["sensor.victron_soc", "sensor.power_consumption"])'},domains:{type:"array",items:{type:"string"},description:'Domain filters for briefing_summary (e.g. ["binary_sensor", "light", "climate"])'}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"states":return await this.getStates(e.domain);case"state":return await this.getState(e.entityId);case"turn_on":return await this.switchAction("turn_on",e.entityId,e.serviceData);case"turn_off":return await this.switchAction("turn_off",e.entityId,e.serviceData);case"toggle":return await this.switchAction("toggle",e.entityId,e.serviceData);case"call_service":return await this.callService(e.domain,e.service,e.entityId,e.serviceData);case"services":return await this.getServices();case"history":return await this.getHistory(e.entityId,e.period);case"logbook":return await this.getLogbook(e.entityId,e.period);case"config":return await this.getConfig();case"areas":return await this.getAreas(e.area);case"template":return await this.renderTemplate(e.template);case"presence":return await this.getPresence();case"notify":return await this.sendNotification(e.message,e.title,e.target);case"activate_scene":return await this.activateScene(e.entityId);case"trigger_automation":return await this.triggerAutomation(e.entityId,e.subAction);case"run_script":return await this.runScript(e.entityId,e.variables);case"calendar_events":return await this.getCalendarEvents(e.entityId,e.startTime,e.endTime);case"error_log":return await this.getErrorLog();case"create_automation":return await this.createConfig("automation",e.configId,e.configData);case"delete_automation":return await this.deleteConfig("automation",e.configId);case"create_script":return await this.createConfig("script",e.configId,e.configData);case"delete_script":return await this.deleteConfig("script",e.configId);case"create_scene":return await this.createConfig("scene",e.configId,e.configData);case"delete_scene":return await this.deleteConfig("scene",e.configId);case"briefing_summary":return await this.getBriefingSummary(e.entities,e.domains);case"energy_stats":return await this.getEnergyStats(e.period,e.entityId);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Home Assistant API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.json()}async apiText(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.text()}async getStates(e){let t=await this.api("GET","/api/states");e&&(t=t.filter(r=>r.entity_id.startsWith(`${e}.`)));let s=[`## Entities${e?` (${e})`:""}`,"","| Entity ID | State | Name | Unit |","|-----------|-------|------|------|"];for(let r of t){let n=r.attributes?.friendly_name??"-",o=r.attributes?.unit_of_measurement??"-";s.push(`| ${r.entity_id} | ${r.state} | ${n} | ${o} |`)}return t.length===0&&s.push(`| - | No entities found${e?` for domain "${e}"`:""} | - | - |`),{success:!0,data:t,display:s.join(`
918
918
  `)}}async getState(e){if(!e)return{success:!1,error:'Missing required "entityId" parameter'};let t=await this.api("GET",`/api/states/${e}`),s=t.attributes??{},r=[`## ${s.friendly_name??e}`,"",`**Entity ID:** ${t.entity_id}`,`**State:** ${t.state}`,`**Last Changed:** ${t.last_changed??"-"}`,`**Last Updated:** ${t.last_updated??"-"}`,"","### Attributes"];for(let[n,o]of Object.entries(s)){let i=typeof o=="object"?JSON.stringify(o):String(o);r.push(`- **${n}:** ${i}`)}return{success:!0,data:t,display:r.join(`
919
919
  `)}}async getServices(){let e=await this.api("GET","/api/services"),t=["## Available Services",""];for(let s of e){let r=s.domain??"unknown",n=Object.keys(s.services??{});if(n.length!==0){t.push(`### ${r}`);for(let o of n){let i=s.services[o]?.description??"";t.push(`- **${o}**${i?`: ${i}`:""}`)}t.push("")}}return{success:!0,data:e,display:t.join(`
920
920
  `)}}async getHistory(e,t){let s=xa(t??"1h"),r=new Date().toISOString(),n=e?`?filter_entity_id=${e}&end_time=${r}`:`?end_time=${r}`,o=await this.api("GET",`/api/history/period/${s}${n}`),i=["## History",""];if(!o||o.length===0||o.every(a=>a.length===0))return i.push("No history entries found for the given period."),{success:!0,data:[],display:i.join(`
@@ -944,7 +944,7 @@ Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this
944
944
  `)}}async getEnergyStatsViaTemplate(e,t,s,r){let n=[`## Energie-Sensoren: ${r}`,"","*Hinweis: F\xFCr diesen Zeitraum sind keine History-Daten verf\xFCgbar. Zeige aktuelle Z\xE4hlerst\xE4nde.*","","| Sensor | Aktueller Stand | Einheit |","|--------|----------------|---------|"];for(let o of e)try{let i=await this.api("GET",`/api/states/${o}`),a=i.attributes?.friendly_name??o,c=i.attributes?.unit_of_measurement??"",d=i.state;n.push(`| ${a} | ${d} | ${c} |`)}catch{n.push(`| ${o} | Fehler | - |`)}return{success:!0,data:[],display:n.join(`
945
945
  `)}}parseEnergyPeriod(e){let t=new Date;switch(e.toLowerCase().replace(/\s+/g,"_")){case"today":case"heute":return{start:new Date(t.getFullYear(),t.getMonth(),t.getDate()).toISOString(),end:t.toISOString(),label:"Heute"};case"yesterday":case"gestern":{let s=new Date(t.getFullYear(),t.getMonth(),t.getDate()-1),r=new Date(t.getFullYear(),t.getMonth(),t.getDate());return{start:s.toISOString(),end:r.toISOString(),label:"Gestern"}}case"this_week":case"diese_woche":{let s=t.getDay(),r=s===0?-6:1-s;return{start:new Date(t.getFullYear(),t.getMonth(),t.getDate()+r).toISOString(),end:t.toISOString(),label:"Diese Woche"}}case"last_week":case"letzte_woche":{let s=t.getDay(),r=s===0?-6:1-s,n=new Date(t.getFullYear(),t.getMonth(),t.getDate()+r);return{start:new Date(n.getTime()-7*864e5).toISOString(),end:n.toISOString(),label:"Letzte Woche"}}case"this_month":case"dieser_monat":return{start:new Date(t.getFullYear(),t.getMonth(),1).toISOString(),end:t.toISOString(),label:"Dieser Monat"};case"last_month":case"letzter_monat":{let s=new Date(t.getFullYear(),t.getMonth()-1,1),r=new Date(t.getFullYear(),t.getMonth(),1);return{start:s.toISOString(),end:r.toISOString(),label:"Letzter Monat"}}default:return{start:xa(e),end:t.toISOString(),label:e}}}async createConfig(e,t,s){if(!t)return{success:!1,error:`Missing required "configId" for create_${e}`};if(!s)return{success:!1,error:`Missing required "configData" for create_${e}`};let r;try{r=JSON.parse(s)}catch{return{success:!1,error:'Invalid "configData" \u2014 must be valid JSON'}}return{success:!0,data:await this.apiPost(`/api/config/${e}/config/${t}`,r),display:`**${e} created:** \`${t}\`
946
946
 
947
- ${r.alias??r.name??t}`}}async deleteConfig(e,t){return t?(await this.apiDelete(`/api/config/${e}/config/${t}`),{success:!0,data:{deleted:t},display:`**${e} deleted:** \`${t}\``}):{success:!1,error:`Missing required "configId" for delete_${e}`}}async apiPost(e,t){let s=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,r={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},n=this.config.verifyTls===!1,o=process.env.NODE_TLS_REJECT_UNAUTHORIZED;n&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let i;try{i=await fetch(s,{method:"POST",headers:r,body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)})}finally{n&&(o===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}if(!i.ok){let a="";try{a=(await i.text()).slice(0,500)}catch{}throw new Error(`HTTP ${i.status} ${i.statusText} \u2014 ${a}`)}return await i.json()}async apiDelete(e){let t=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,s={Authorization:`Bearer ${this.config.accessToken}`},r=this.config.verifyTls===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let o;try{o=await fetch(t,{method:"DELETE",headers:s,signal:AbortSignal.timeout(15e3)})}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}if(!o.ok){let i="";try{i=(await o.text()).slice(0,500)}catch{}throw new Error(`HTTP ${o.status} ${o.statusText} \u2014 ${i}`)}}}});var Ke,Xr=T(()=>{"use strict";Ke=class{static{p(this,"ContactsProvider")}}});var Tu={};me(Tu,{CardDAVContactsProvider:()=>Io});var Io,Ca=T(()=>{"use strict";Xr();Io=class extends Ke{static{p(this,"CardDAVContactsProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"carddav"})}catch(e){throw new Error(`CardDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async list(e,t){let s=await this.client.fetchAddressBooks();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchVCards({addressBook:n});for(let i of o){let a=this.parseVCard(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.displayName.localeCompare(o.displayName)),e?r.slice(0,e):r}async search(e){let t=await this.list(),s=e.toLowerCase();return t.filter(r=>r.displayName.toLowerCase().includes(s)||r.emails.some(n=>n.address.toLowerCase().includes(s))||r.phones.some(n=>n.number.includes(s)))}async get(e){return(await this.list()).find(s=>s.id===e)}async create(e){let t=await this.client.fetchAddressBooks();if(!t||t.length===0)throw new Error("No address books found");let s=`alfred-${Date.now()}@alfred`,r=this.buildVCard(s,e);await this.client.createVCard({addressBook:t[0],filename:`${s}.vcf`,vCardString:r});let n=e.displayName??([e.firstName,e.lastName].filter(Boolean).join(" ")||"Unknown");return{id:s,displayName:n,firstName:e.firstName,lastName:e.lastName,emails:e.emails??[],phones:e.phones??[],addresses:e.addresses??[],organization:e.organization,birthday:e.birthday,notes:e.notes}}async update(e,t){let s=await this.client.fetchAddressBooks();for(let r of s){let n=await this.client.fetchVCards({addressBook:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseVCard(o.data,o.url);if(!i)continue;let a={firstName:t.firstName??i.firstName,lastName:t.lastName??i.lastName,displayName:t.displayName??i.displayName,emails:t.emails??i.emails,phones:t.phones??i.phones,addresses:t.addresses??i.addresses,organization:t.organization??i.organization,birthday:t.birthday??i.birthday,notes:t.notes??i.notes},c=this.buildVCard(e,a);await this.client.updateVCard({vCard:{...o,data:c}});let d=a.displayName??([a.firstName,a.lastName].filter(Boolean).join(" ")||"Unknown");return{id:e,displayName:d,firstName:a.firstName,lastName:a.lastName,emails:a.emails??[],phones:a.phones??[],addresses:a.addresses??[],organization:a.organization,birthday:a.birthday,notes:a.notes}}}throw new Error(`Contact ${e} not found`)}async delete(e){let t=await this.client.fetchAddressBooks();for(let s of t){let r=await this.client.fetchVCards({addressBook:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteVCard({vCard:n});return}}throw new Error(`Contact ${e} not found`)}parseVCard(e,t){let s=p(g=>e.match(new RegExp(`^${g}[;:](.*)$`,"mi"))?.[1]?.trim(),"get"),r=s("FN");if(!r)return;let n=s("N"),[o,i]=n?n.split(";"):[void 0,void 0],a=[];for(let g of e.matchAll(/^EMAIL[^:]*:(.+)$/gmi)){let y=g[0],_=g[1].trim(),S=y.match(/TYPE=([^;:,]+)/i)?.[1],E=/TYPE=pref/i.test(y);a.push({address:_,label:S,primary:E})}let c=[];for(let g of e.matchAll(/^TEL[^:]*:(.+)$/gmi)){let y=g[0],_=g[1].trim(),S=y.match(/TYPE=([^;:,]+)/i)?.[1],E=/TYPE=pref/i.test(y);c.push({number:_,label:S,primary:E})}let d=[];for(let g of e.matchAll(/^ADR[^:]*:(.+)$/gmi)){let y=g[1].split(";");d.push({street:y[2]?.trim()||void 0,city:y[3]?.trim()||void 0,region:y[4]?.trim()||void 0,postalCode:y[5]?.trim()||void 0,country:y[6]?.trim()||void 0})}let u=s("ORG")?.replace(/;.*$/,""),m=s("BDAY"),h=s("NOTE");return{id:s("UID")??t,displayName:r,firstName:i,lastName:o,emails:a,phones:c,addresses:d,organization:u,birthday:m,notes:h}}buildVCard(e,t){let s=t.displayName??([t.firstName,t.lastName].filter(Boolean).join(" ")||"Unknown"),r=`BEGIN:VCARD\r
947
+ ${r.alias??r.name??t}`}}async deleteConfig(e,t){return t?(await this.apiDelete(`/api/config/${e}/config/${t}`),{success:!0,data:{deleted:t},display:`**${e} deleted:** \`${t}\``}):{success:!1,error:`Missing required "configId" for delete_${e}`}}async apiPost(e,t){let s=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,r={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},n=this.config.verifyTls===!1,o=process.env.NODE_TLS_REJECT_UNAUTHORIZED;n&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let i;try{i=await fetch(s,{method:"POST",headers:r,body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)})}finally{n&&(o===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}if(!i.ok){let a="";try{a=(await i.text()).slice(0,500)}catch{}throw new Error(`HTTP ${i.status} ${i.statusText} \u2014 ${a}`)}return await i.json()}async apiDelete(e){let t=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,s={Authorization:`Bearer ${this.config.accessToken}`},r=this.config.verifyTls===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let o;try{o=await fetch(t,{method:"DELETE",headers:s,signal:AbortSignal.timeout(15e3)})}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}if(!o.ok){let i="";try{i=(await o.text()).slice(0,500)}catch{}throw new Error(`HTTP ${o.status} ${o.statusText} \u2014 ${i}`)}}}});var Ke,Xr=T(()=>{"use strict";Ke=class{static{p(this,"ContactsProvider")}}});var Tu={};me(Tu,{CardDAVContactsProvider:()=>Ro});var Ro,Ca=T(()=>{"use strict";Xr();Ro=class extends Ke{static{p(this,"CardDAVContactsProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"carddav"})}catch(e){throw new Error(`CardDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async list(e,t){let s=await this.client.fetchAddressBooks();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchVCards({addressBook:n});for(let i of o){let a=this.parseVCard(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.displayName.localeCompare(o.displayName)),e?r.slice(0,e):r}async search(e){let t=await this.list(),s=e.toLowerCase();return t.filter(r=>r.displayName.toLowerCase().includes(s)||r.emails.some(n=>n.address.toLowerCase().includes(s))||r.phones.some(n=>n.number.includes(s)))}async get(e){return(await this.list()).find(s=>s.id===e)}async create(e){let t=await this.client.fetchAddressBooks();if(!t||t.length===0)throw new Error("No address books found");let s=`alfred-${Date.now()}@alfred`,r=this.buildVCard(s,e);await this.client.createVCard({addressBook:t[0],filename:`${s}.vcf`,vCardString:r});let n=e.displayName??([e.firstName,e.lastName].filter(Boolean).join(" ")||"Unknown");return{id:s,displayName:n,firstName:e.firstName,lastName:e.lastName,emails:e.emails??[],phones:e.phones??[],addresses:e.addresses??[],organization:e.organization,birthday:e.birthday,notes:e.notes}}async update(e,t){let s=await this.client.fetchAddressBooks();for(let r of s){let n=await this.client.fetchVCards({addressBook:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseVCard(o.data,o.url);if(!i)continue;let a={firstName:t.firstName??i.firstName,lastName:t.lastName??i.lastName,displayName:t.displayName??i.displayName,emails:t.emails??i.emails,phones:t.phones??i.phones,addresses:t.addresses??i.addresses,organization:t.organization??i.organization,birthday:t.birthday??i.birthday,notes:t.notes??i.notes},c=this.buildVCard(e,a);await this.client.updateVCard({vCard:{...o,data:c}});let d=a.displayName??([a.firstName,a.lastName].filter(Boolean).join(" ")||"Unknown");return{id:e,displayName:d,firstName:a.firstName,lastName:a.lastName,emails:a.emails??[],phones:a.phones??[],addresses:a.addresses??[],organization:a.organization,birthday:a.birthday,notes:a.notes}}}throw new Error(`Contact ${e} not found`)}async delete(e){let t=await this.client.fetchAddressBooks();for(let s of t){let r=await this.client.fetchVCards({addressBook:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteVCard({vCard:n});return}}throw new Error(`Contact ${e} not found`)}parseVCard(e,t){let s=p(g=>e.match(new RegExp(`^${g}[;:](.*)$`,"mi"))?.[1]?.trim(),"get"),r=s("FN");if(!r)return;let n=s("N"),[o,i]=n?n.split(";"):[void 0,void 0],a=[];for(let g of e.matchAll(/^EMAIL[^:]*:(.+)$/gmi)){let y=g[0],_=g[1].trim(),S=y.match(/TYPE=([^;:,]+)/i)?.[1],E=/TYPE=pref/i.test(y);a.push({address:_,label:S,primary:E})}let c=[];for(let g of e.matchAll(/^TEL[^:]*:(.+)$/gmi)){let y=g[0],_=g[1].trim(),S=y.match(/TYPE=([^;:,]+)/i)?.[1],E=/TYPE=pref/i.test(y);c.push({number:_,label:S,primary:E})}let d=[];for(let g of e.matchAll(/^ADR[^:]*:(.+)$/gmi)){let y=g[1].split(";");d.push({street:y[2]?.trim()||void 0,city:y[3]?.trim()||void 0,region:y[4]?.trim()||void 0,postalCode:y[5]?.trim()||void 0,country:y[6]?.trim()||void 0})}let u=s("ORG")?.replace(/;.*$/,""),m=s("BDAY"),h=s("NOTE");return{id:s("UID")??t,displayName:r,firstName:i,lastName:o,emails:a,phones:c,addresses:d,organization:u,birthday:m,notes:h}}buildVCard(e,t){let s=t.displayName??([t.firstName,t.lastName].filter(Boolean).join(" ")||"Unknown"),r=`BEGIN:VCARD\r
948
948
  VERSION:3.0\r
949
949
  `;r+=`UID:${e}\r
950
950
  `,r+=`FN:${s}\r
@@ -956,7 +956,7 @@ VERSION:3.0\r
956
956
  `),t.birthday&&(r+=`BDAY:${t.birthday}\r
957
957
  `),t.notes&&(r+=`NOTE:${t.notes}\r
958
958
  `),r+=`END:VCARD\r
959
- `,r}}});var _u={};me(_u,{GoogleContactsProvider:()=>xo});var Ro,Gt,xo,Na=T(()=>{"use strict";Xr();Ro="names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies",Gt="https://people.googleapis.com/v1",xo=class extends Ke{static{p(this,"GoogleContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),t=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!t.ok)throw new Error(`Google token refresh failed: ${t.status}`);let s=await t.json();this.accessToken=s.access_token}async apiRequest(e,t,s){let r={method:e,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}};s&&(r.body=JSON.stringify(s));let n=await fetch(t,r);if(n.status===401){await this.refreshAccessToken();let o=await fetch(t,{...r,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}});if(!o.ok)throw new Error(`People API error: ${o.status}`);return o.status===204?void 0:o.json()}if(!n.ok)throw new Error(`People API error: ${n.status}`);if(n.status!==204)return n.json()}async list(e=50){let t=`${Gt}/people/me/connections?personFields=${Ro}&pageSize=${e}`;return((await this.apiRequest("GET",t)).connections??[]).map(r=>this.mapPerson(r))}async search(e){let t=`${Gt}/people:searchContacts?query=${encodeURIComponent(e)}&readMask=${Ro}&pageSize=30`;return((await this.apiRequest("GET",t)).results??[]).map(r=>this.mapPerson(r.person))}async get(e){try{let t=`${Gt}/${e}?personFields=${Ro}`,s=await this.apiRequest("GET",t);return this.mapPerson(s)}catch{return}}async create(e){let t=this.buildPersonBody(e),s=await this.apiRequest("POST",`${Gt}/people:createContact`,t);return this.mapPerson(s)}async update(e,t){let s=await this.apiRequest("GET",`${Gt}/${e}?personFields=${Ro}`),r=this.buildPersonBody(t);r.etag=s.etag;let o=`${Gt}/${e}:updateContact?updatePersonFields=names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies`,i=await this.apiRequest("PATCH",o,r);return this.mapPerson(i)}async delete(e){await this.apiRequest("DELETE",`${Gt}/${e}:deleteContact`)}mapPerson(e){let t=e.names?.[0],s=(e.emailAddresses??[]).map(c=>({address:c.value,label:c.type,primary:c.metadata?.primary??!1})),r=(e.phoneNumbers??[]).map(c=>({number:c.value,label:c.type,primary:c.metadata?.primary??!1})),n=(e.addresses??[]).map(c=>({street:c.streetAddress??void 0,city:c.city??void 0,region:c.region??void 0,postalCode:c.postalCode??void 0,country:c.country??void 0,label:c.type??void 0})),o=e.organizations?.[0]?.name,i=e.birthdays?.[0]?.date?`${e.birthdays[0].date.year??"????"}-${String(e.birthdays[0].date.month).padStart(2,"0")}-${String(e.birthdays[0].date.day).padStart(2,"0")}`:void 0,a=e.biographies?.[0]?.value;return{id:e.resourceName??e.etag??"",displayName:t?.displayName??"(No name)",firstName:t?.givenName,lastName:t?.familyName,emails:s,phones:r,addresses:n,organization:o,birthday:i,notes:a}}buildPersonBody(e){let t={};if((e.firstName!==void 0||e.lastName!==void 0||e.displayName!==void 0)&&(t.names=[{givenName:e.firstName,familyName:e.lastName,displayName:e.displayName}]),e.emails&&(t.emailAddresses=e.emails.map(s=>({value:s.address,type:s.label??"home"}))),e.phones&&(t.phoneNumbers=e.phones.map(s=>({value:s.number,type:s.label??"mobile"}))),e.addresses&&(t.addresses=e.addresses.map(s=>({streetAddress:s.street,city:s.city,region:s.region,postalCode:s.postalCode,country:s.country,type:s.label??"home"}))),e.organization&&(t.organizations=[{name:e.organization}]),e.birthday){let s=e.birthday.split("-");t.birthdays=[{date:{year:s[0]!=="????"?parseInt(s[0],10):void 0,month:parseInt(s[1],10),day:parseInt(s[2],10)}}]}return e.notes&&(t.biographies=[{value:e.notes,contentType:"TEXT_PLAIN"}]),t}}});var ku={};me(ku,{MicrosoftContactsProvider:()=>Co});var Co,La=T(()=>{"use strict";Xr();Co=class extends Ke{static{p(this,"MicrosoftContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Contacts.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.status===204?void 0:r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async list(e=50){return((await this.graphRequest(`/me/contacts?$top=${e}&$orderby=displayName`)).value??[]).map(s=>this.mapContact(s))}async search(e){try{return((await this.graphRequest(`/me/contacts?$search="${encodeURIComponent(e)}"`,{headers:{ConsistencyLevel:"eventual"}})).value??[]).map(s=>this.mapContact(s))}catch{return((await this.graphRequest(`/me/contacts?$filter=contains(displayName, '${encodeURIComponent(e)}')`)).value??[]).map(s=>this.mapContact(s))}}async get(e){try{let t=await this.graphRequest(`/me/contacts/${e}`);return this.mapContact(t)}catch{return}}async create(e){let t=this.buildContactBody(e),s=await this.graphRequest("/me/contacts",{method:"POST",body:JSON.stringify(t)});return this.mapContact(s)}async update(e,t){let s=this.buildContactBody(t),r=await this.graphRequest(`/me/contacts/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapContact(r)}async delete(e){await this.graphRequest(`/me/contacts/${e}`,{method:"DELETE"})}mapContact(e){let t=(e.emailAddresses??[]).map(o=>({address:o.address,label:o.name??void 0,primary:!1})),s=[];if(e.mobilePhone&&s.push({number:e.mobilePhone,label:"mobile"}),e.businessPhones)for(let o of e.businessPhones)s.push({number:o,label:"work"});if(e.homePhones)for(let o of e.homePhones)s.push({number:o,label:"home"});let r=[];e.homeAddress&&Object.values(e.homeAddress).some(Boolean)&&r.push({street:e.homeAddress.street??void 0,city:e.homeAddress.city??void 0,region:e.homeAddress.state??void 0,postalCode:e.homeAddress.postalCode??void 0,country:e.homeAddress.countryOrRegion??void 0,label:"home"}),e.businessAddress&&Object.values(e.businessAddress).some(Boolean)&&r.push({street:e.businessAddress.street??void 0,city:e.businessAddress.city??void 0,region:e.businessAddress.state??void 0,postalCode:e.businessAddress.postalCode??void 0,country:e.businessAddress.countryOrRegion??void 0,label:"work"});let n=e.birthday?e.birthday.slice(0,10):void 0;return{id:e.id,displayName:e.displayName??"(No name)",firstName:e.givenName??void 0,lastName:e.surname??void 0,emails:t,phones:s,addresses:r,organization:e.companyName??void 0,birthday:n,notes:e.personalNotes??void 0}}buildContactBody(e){let t={};if(e.firstName!==void 0&&(t.givenName=e.firstName),e.lastName!==void 0&&(t.surname=e.lastName),e.displayName!==void 0&&(t.displayName=e.displayName),e.emails&&(t.emailAddresses=e.emails.map(s=>({address:s.address,name:s.label??s.address}))),e.phones){let s=e.phones.find(i=>i.label==="mobile"),r=e.phones.filter(i=>i.label==="work"),n=e.phones.filter(i=>i.label==="home"),o=e.phones.filter(i=>!["mobile","work","home"].includes(i.label??""));s&&(t.mobilePhone=s.number),r.length>0&&(t.businessPhones=r.map(i=>i.number)),n.length>0&&(t.homePhones=n.map(i=>i.number)),o.length>0&&!r.length&&(t.businessPhones=o.map(i=>i.number))}if(e.addresses)for(let s of e.addresses){let r={street:s.street,city:s.city,state:s.region,postalCode:s.postalCode,countryOrRegion:s.country};s.label==="work"?t.businessAddress=r:t.homeAddress=r}return e.organization!==void 0&&(t.companyName=e.organization),e.birthday!==void 0&&(t.birthday=e.birthday),e.notes!==void 0&&(t.personalNotes=e.notes),t}}});async function Da(l){switch(l.provider){case"carddav":{if(!l.carddav)throw new Error("CardDAV contacts config missing");let{CardDAVContactsProvider:e}=await Promise.resolve().then(()=>(Ca(),Tu)),t=new e(l.carddav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google contacts config missing");let{GoogleContactsProvider:e}=await Promise.resolve().then(()=>(Na(),_u)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft contacts config missing");let{MicrosoftContactsProvider:e}=await Promise.resolve().then(()=>(La(),ku)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown contacts provider: ${l.provider}`)}}var bu=T(()=>{"use strict";p(Da,"createContactsProvider")});var Vr,Eu=T(()=>{"use strict";B();Vr=class extends x{static{p(this,"ContactsSkill")}contactsProvider;metadata={name:"contacts",category:"productivity",description:"Manage contacts. Search, view, create, update, or delete contacts.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","get","list","create","update","delete"],description:"The contacts action to perform"},query:{type:"string",description:"Search query (for search action)"},contactId:{type:"string",description:"Contact ID (for get/update/delete)"},firstName:{type:"string",description:"First name (for create/update)"},lastName:{type:"string",description:"Last name (for create/update)"},displayName:{type:"string",description:"Display name (for create/update)"},email:{type:"string",description:"Single email address (for create/update, shorthand)"},phone:{type:"string",description:"Single phone number (for create/update, shorthand)"},organization:{type:"string",description:"Organization / company (for create/update)"},birthday:{type:"string",description:"Birthday in YYYY-MM-DD format (for create/update)"},notes:{type:"string",description:"Notes (for create/update)"},emailAddresses:{type:"string",description:"JSON array of {address, label?, primary?} for multiple emails"},phoneNumbers:{type:"string",description:"JSON array of {number, label?, primary?} for multiple phones"},addresses:{type:"string",description:"JSON array of {street?, city?, region?, postalCode?, country?, label?}"},limit:{type:"number",description:"Maximum number of contacts to return (for list, default 50)"}},required:["action"]}};constructor(e){super(),this.contactsProvider=e}async execute(e,t){let s=e.action;switch(s){case"search":return this.searchContacts(e);case"get":return this.getContact(e);case"list":return this.listContacts(e);case"create":return this.createContact(e);case"update":return this.updateContact(e);case"delete":return this.deleteContact(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async searchContacts(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query"'};try{let s=await this.contactsProvider.search(t);if(s.length===0)return{success:!0,data:[],display:`No contacts found for "${t}".`};let r=this.formatTable(s);return{success:!0,data:s,display:`${s.length} contact(s) found:
959
+ `,r}}});var _u={};me(_u,{GoogleContactsProvider:()=>Co});var xo,Gt,Co,Na=T(()=>{"use strict";Xr();xo="names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies",Gt="https://people.googleapis.com/v1",Co=class extends Ke{static{p(this,"GoogleContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),t=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!t.ok)throw new Error(`Google token refresh failed: ${t.status}`);let s=await t.json();this.accessToken=s.access_token}async apiRequest(e,t,s){let r={method:e,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}};s&&(r.body=JSON.stringify(s));let n=await fetch(t,r);if(n.status===401){await this.refreshAccessToken();let o=await fetch(t,{...r,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}});if(!o.ok)throw new Error(`People API error: ${o.status}`);return o.status===204?void 0:o.json()}if(!n.ok)throw new Error(`People API error: ${n.status}`);if(n.status!==204)return n.json()}async list(e=50){let t=`${Gt}/people/me/connections?personFields=${xo}&pageSize=${e}`;return((await this.apiRequest("GET",t)).connections??[]).map(r=>this.mapPerson(r))}async search(e){let t=`${Gt}/people:searchContacts?query=${encodeURIComponent(e)}&readMask=${xo}&pageSize=30`;return((await this.apiRequest("GET",t)).results??[]).map(r=>this.mapPerson(r.person))}async get(e){try{let t=`${Gt}/${e}?personFields=${xo}`,s=await this.apiRequest("GET",t);return this.mapPerson(s)}catch{return}}async create(e){let t=this.buildPersonBody(e),s=await this.apiRequest("POST",`${Gt}/people:createContact`,t);return this.mapPerson(s)}async update(e,t){let s=await this.apiRequest("GET",`${Gt}/${e}?personFields=${xo}`),r=this.buildPersonBody(t);r.etag=s.etag;let o=`${Gt}/${e}:updateContact?updatePersonFields=names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies`,i=await this.apiRequest("PATCH",o,r);return this.mapPerson(i)}async delete(e){await this.apiRequest("DELETE",`${Gt}/${e}:deleteContact`)}mapPerson(e){let t=e.names?.[0],s=(e.emailAddresses??[]).map(c=>({address:c.value,label:c.type,primary:c.metadata?.primary??!1})),r=(e.phoneNumbers??[]).map(c=>({number:c.value,label:c.type,primary:c.metadata?.primary??!1})),n=(e.addresses??[]).map(c=>({street:c.streetAddress??void 0,city:c.city??void 0,region:c.region??void 0,postalCode:c.postalCode??void 0,country:c.country??void 0,label:c.type??void 0})),o=e.organizations?.[0]?.name,i=e.birthdays?.[0]?.date?`${e.birthdays[0].date.year??"????"}-${String(e.birthdays[0].date.month).padStart(2,"0")}-${String(e.birthdays[0].date.day).padStart(2,"0")}`:void 0,a=e.biographies?.[0]?.value;return{id:e.resourceName??e.etag??"",displayName:t?.displayName??"(No name)",firstName:t?.givenName,lastName:t?.familyName,emails:s,phones:r,addresses:n,organization:o,birthday:i,notes:a}}buildPersonBody(e){let t={};if((e.firstName!==void 0||e.lastName!==void 0||e.displayName!==void 0)&&(t.names=[{givenName:e.firstName,familyName:e.lastName,displayName:e.displayName}]),e.emails&&(t.emailAddresses=e.emails.map(s=>({value:s.address,type:s.label??"home"}))),e.phones&&(t.phoneNumbers=e.phones.map(s=>({value:s.number,type:s.label??"mobile"}))),e.addresses&&(t.addresses=e.addresses.map(s=>({streetAddress:s.street,city:s.city,region:s.region,postalCode:s.postalCode,country:s.country,type:s.label??"home"}))),e.organization&&(t.organizations=[{name:e.organization}]),e.birthday){let s=e.birthday.split("-");t.birthdays=[{date:{year:s[0]!=="????"?parseInt(s[0],10):void 0,month:parseInt(s[1],10),day:parseInt(s[2],10)}}]}return e.notes&&(t.biographies=[{value:e.notes,contentType:"TEXT_PLAIN"}]),t}}});var ku={};me(ku,{MicrosoftContactsProvider:()=>No});var No,La=T(()=>{"use strict";Xr();No=class extends Ke{static{p(this,"MicrosoftContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Contacts.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.status===204?void 0:r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async list(e=50){return((await this.graphRequest(`/me/contacts?$top=${e}&$orderby=displayName`)).value??[]).map(s=>this.mapContact(s))}async search(e){try{return((await this.graphRequest(`/me/contacts?$search="${encodeURIComponent(e)}"`,{headers:{ConsistencyLevel:"eventual"}})).value??[]).map(s=>this.mapContact(s))}catch{return((await this.graphRequest(`/me/contacts?$filter=contains(displayName, '${encodeURIComponent(e)}')`)).value??[]).map(s=>this.mapContact(s))}}async get(e){try{let t=await this.graphRequest(`/me/contacts/${e}`);return this.mapContact(t)}catch{return}}async create(e){let t=this.buildContactBody(e),s=await this.graphRequest("/me/contacts",{method:"POST",body:JSON.stringify(t)});return this.mapContact(s)}async update(e,t){let s=this.buildContactBody(t),r=await this.graphRequest(`/me/contacts/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapContact(r)}async delete(e){await this.graphRequest(`/me/contacts/${e}`,{method:"DELETE"})}mapContact(e){let t=(e.emailAddresses??[]).map(o=>({address:o.address,label:o.name??void 0,primary:!1})),s=[];if(e.mobilePhone&&s.push({number:e.mobilePhone,label:"mobile"}),e.businessPhones)for(let o of e.businessPhones)s.push({number:o,label:"work"});if(e.homePhones)for(let o of e.homePhones)s.push({number:o,label:"home"});let r=[];e.homeAddress&&Object.values(e.homeAddress).some(Boolean)&&r.push({street:e.homeAddress.street??void 0,city:e.homeAddress.city??void 0,region:e.homeAddress.state??void 0,postalCode:e.homeAddress.postalCode??void 0,country:e.homeAddress.countryOrRegion??void 0,label:"home"}),e.businessAddress&&Object.values(e.businessAddress).some(Boolean)&&r.push({street:e.businessAddress.street??void 0,city:e.businessAddress.city??void 0,region:e.businessAddress.state??void 0,postalCode:e.businessAddress.postalCode??void 0,country:e.businessAddress.countryOrRegion??void 0,label:"work"});let n=e.birthday?e.birthday.slice(0,10):void 0;return{id:e.id,displayName:e.displayName??"(No name)",firstName:e.givenName??void 0,lastName:e.surname??void 0,emails:t,phones:s,addresses:r,organization:e.companyName??void 0,birthday:n,notes:e.personalNotes??void 0}}buildContactBody(e){let t={};if(e.firstName!==void 0&&(t.givenName=e.firstName),e.lastName!==void 0&&(t.surname=e.lastName),e.displayName!==void 0&&(t.displayName=e.displayName),e.emails&&(t.emailAddresses=e.emails.map(s=>({address:s.address,name:s.label??s.address}))),e.phones){let s=e.phones.find(i=>i.label==="mobile"),r=e.phones.filter(i=>i.label==="work"),n=e.phones.filter(i=>i.label==="home"),o=e.phones.filter(i=>!["mobile","work","home"].includes(i.label??""));s&&(t.mobilePhone=s.number),r.length>0&&(t.businessPhones=r.map(i=>i.number)),n.length>0&&(t.homePhones=n.map(i=>i.number)),o.length>0&&!r.length&&(t.businessPhones=o.map(i=>i.number))}if(e.addresses)for(let s of e.addresses){let r={street:s.street,city:s.city,state:s.region,postalCode:s.postalCode,countryOrRegion:s.country};s.label==="work"?t.businessAddress=r:t.homeAddress=r}return e.organization!==void 0&&(t.companyName=e.organization),e.birthday!==void 0&&(t.birthday=e.birthday),e.notes!==void 0&&(t.personalNotes=e.notes),t}}});async function Da(l){switch(l.provider){case"carddav":{if(!l.carddav)throw new Error("CardDAV contacts config missing");let{CardDAVContactsProvider:e}=await Promise.resolve().then(()=>(Ca(),Tu)),t=new e(l.carddav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google contacts config missing");let{GoogleContactsProvider:e}=await Promise.resolve().then(()=>(Na(),_u)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft contacts config missing");let{MicrosoftContactsProvider:e}=await Promise.resolve().then(()=>(La(),ku)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown contacts provider: ${l.provider}`)}}var bu=T(()=>{"use strict";p(Da,"createContactsProvider")});var Vr,Eu=T(()=>{"use strict";B();Vr=class extends x{static{p(this,"ContactsSkill")}contactsProvider;metadata={name:"contacts",category:"productivity",description:"Manage contacts. Search, view, create, update, or delete contacts.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","get","list","create","update","delete"],description:"The contacts action to perform"},query:{type:"string",description:"Search query (for search action)"},contactId:{type:"string",description:"Contact ID (for get/update/delete)"},firstName:{type:"string",description:"First name (for create/update)"},lastName:{type:"string",description:"Last name (for create/update)"},displayName:{type:"string",description:"Display name (for create/update)"},email:{type:"string",description:"Single email address (for create/update, shorthand)"},phone:{type:"string",description:"Single phone number (for create/update, shorthand)"},organization:{type:"string",description:"Organization / company (for create/update)"},birthday:{type:"string",description:"Birthday in YYYY-MM-DD format (for create/update)"},notes:{type:"string",description:"Notes (for create/update)"},emailAddresses:{type:"string",description:"JSON array of {address, label?, primary?} for multiple emails"},phoneNumbers:{type:"string",description:"JSON array of {number, label?, primary?} for multiple phones"},addresses:{type:"string",description:"JSON array of {street?, city?, region?, postalCode?, country?, label?}"},limit:{type:"number",description:"Maximum number of contacts to return (for list, default 50)"}},required:["action"]}};constructor(e){super(),this.contactsProvider=e}async execute(e,t){let s=e.action;switch(s){case"search":return this.searchContacts(e);case"get":return this.getContact(e);case"list":return this.listContacts(e);case"create":return this.createContact(e);case"update":return this.updateContact(e);case"delete":return this.deleteContact(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async searchContacts(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query"'};try{let s=await this.contactsProvider.search(t);if(s.length===0)return{success:!0,data:[],display:`No contacts found for "${t}".`};let r=this.formatTable(s);return{success:!0,data:s,display:`${s.length} contact(s) found:
960
960
  ${r}`}}catch(s){return{success:!1,error:`Failed to search contacts: ${s instanceof Error?s.message:String(s)}`}}}async getContact(e){let t=e.contactId;if(!t)return{success:!1,error:'Missing required field "contactId"'};try{let s=await this.contactsProvider.get(t);if(!s)return{success:!1,error:`Contact "${t}" not found.`};let r=this.formatDetail(s);return{success:!0,data:s,display:r}}catch(s){return{success:!1,error:`Failed to get contact: ${s instanceof Error?s.message:String(s)}`}}}async listContacts(e){let t=e.limit??50;try{let s=await this.contactsProvider.list(t);if(s.length===0)return{success:!0,data:[],display:"No contacts found."};let r=this.formatTable(s);return{success:!0,data:s,display:`${s.length} contact(s):
961
961
  ${r}`}}catch(s){return{success:!1,error:`Failed to list contacts: ${s instanceof Error?s.message:String(s)}`}}}async createContact(e){try{let t=this.buildContactInput(e),s=await this.contactsProvider.create(t);return{success:!0,data:s,display:`Contact created: ${s.displayName}`}}catch(t){return{success:!1,error:`Failed to create contact: ${t instanceof Error?t.message:String(t)}`}}}async updateContact(e){let t=e.contactId;if(!t)return{success:!1,error:'Missing required field "contactId"'};try{let s=this.buildContactInput(e),r=await this.contactsProvider.update(t,s);return{success:!0,data:r,display:`Contact updated: ${r.displayName}`}}catch(s){return{success:!1,error:`Failed to update contact: ${s instanceof Error?s.message:String(s)}`}}}async deleteContact(e){let t=e.contactId;if(!t)return{success:!1,error:'Missing required field "contactId"'};try{return await this.contactsProvider.delete(t),{success:!0,data:{deleted:t},display:`Contact "${t}" deleted.`}}catch(s){return{success:!1,error:`Failed to delete contact: ${s instanceof Error?s.message:String(s)}`}}}buildContactInput(e){let t={};if(e.firstName&&(t.firstName=e.firstName),e.lastName&&(t.lastName=e.lastName),e.displayName&&(t.displayName=e.displayName),e.organization&&(t.organization=e.organization),e.birthday&&(t.birthday=e.birthday),e.notes&&(t.notes=e.notes),e.emailAddresses)try{t.emails=JSON.parse(e.emailAddresses)}catch{t.emails=[{address:e.emailAddresses}]}else e.email&&(t.emails=[{address:e.email,primary:!0}]);if(e.phoneNumbers)try{t.phones=JSON.parse(e.phoneNumbers)}catch{t.phones=[{number:e.phoneNumbers}]}else e.phone&&(t.phones=[{number:e.phone,primary:!0}]);if(e.addresses)try{t.addresses=JSON.parse(e.addresses)}catch{}return t}formatTable(e){let t=`| Name | Email | Phone |
962
962
  |------|-------|-------|`,s=e.map(r=>{let n=r.emails[0]?.address??"-",o=r.phones[0]?.number??"-";return`| ${r.displayName} | ${n} | ${o} |`});return`${t}
@@ -970,7 +970,7 @@ ${a}`}}completeTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success
970
970
  |---|---|---|---|`,n=s.map(o=>`| ${o.list} | ${o.open} | ${o.completed} | ${o.total} |`).join(`
971
971
  `);return{success:!0,data:s,display:`${s.length} list(s):
972
972
  ${r}
973
- ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(de(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import vu from"node:http";import Au from"node:https";import{execFile as Sf}from"node:child_process";import{promisify as $f}from"node:util";function Ma(l){return l==null||l<0?"-":l===0?"0 B":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function Ru(l){return!l||l.length===0?"-":l.filter(e=>e.PublicPort||e.PrivatePort).map(e=>e.PublicPort?`${e.IP??"0.0.0.0"}:${e.PublicPort}->${e.PrivatePort}/${e.Type??"tcp"}`:`${e.PrivatePort}/${e.Type??"tcp"}`).join(", ")}function Oa(l){return!l||l.length===0?"-":l.map(e=>e.replace(/^\//,"")).join(", ")}function vf(l){let e=Buffer.from(l,"binary"),t=[],s=0;for(;s<e.length;)if(s+8<=e.length){let r=e.readUInt32BE(s+4),n=e.subarray(s+8,s+8+r).toString("utf8");t.push(n),s+=8+r}else{t.push(e.subarray(s).toString("utf8"));break}return t.join("")}function Af(l){return l?new Date(l*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var Iu,No,xu=T(()=>{"use strict";B();Iu=$f(Sf);p(Ma,"formatBytes");p(Ru,"formatPorts");p(Oa,"containerName");p(vf,"stripDockerStreamHeaders");p(Af,"relativeTime");No=class extends x{static{p(this,"DockerSkill")}metadata={name:"docker",category:"infrastructure",description:"Manage Docker containers, images, volumes, networks. Actions: containers, container, logs, start, stop, restart, images, pull_image, remove_image, networks, volumes, system_info, prune, compose_ps, compose_up, compose_down.",riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["containers","container","logs","start","stop","restart","images","pull_image","remove_image","networks","volumes","system_info","prune","compose_ps","compose_up","compose_down"],description:"The Docker action to perform"},containerId:{type:"string",description:"Container ID or name (for container, logs, start, stop, restart)"},imageName:{type:"string",description:"Image name (for pull_image, remove_image), e.g. nginx, ghcr.io/org/app"},imageTag:{type:"string",description:"Image tag (for pull_image), default: latest"},networkId:{type:"string",description:"Network ID or name"},project:{type:"string",description:"Docker Compose project name (for compose_ps, compose_up, compose_down)"},tail:{type:"number",description:"Number of log lines to retrieve (default: 100)"}},required:["action"]}};config;defaultSocket;constructor(e){super(),this.config=e,this.defaultSocket=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock"}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"containers":return await this.listContainers();case"container":return await this.inspectContainer(e.containerId);case"logs":return await this.getLogs(e.containerId,e.tail);case"start":return await this.startContainer(e.containerId);case"stop":return await this.stopContainer(e.containerId);case"restart":return await this.restartContainer(e.containerId);case"images":return await this.listImages();case"pull_image":return await this.pullImage(e.imageName,e.imageTag);case"remove_image":return await this.removeImage(e.imageName);case"networks":return await this.listNetworks();case"volumes":return await this.listVolumes();case"system_info":return await this.getSystemInfo();case"prune":return await this.pruneAll();case"compose_ps":return await this.composePs(e.project);case"compose_up":return await this.composeUp(e.project);case"compose_down":return await this.composeDown(e.project);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Docker API error: ${r instanceof Error?r.message:String(r)}`}}}api(e,t,s){return new Promise((r,n)=>{let o={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let c=new URL(this.config.host);o.hostname=c.hostname,o.port=c.port}else o.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?Au:vu).request(o,c=>{let d="";c.on("data",u=>{d+=u}),c.on("end",()=>{if(c.statusCode&&c.statusCode>=400){n(new Error(`Docker API ${c.statusCode}: ${d.slice(0,500)}`));return}try{r(d?JSON.parse(d):void 0)}catch{n(new Error(`Invalid JSON from Docker API: ${d.slice(0,200)}`))}})});a.on("error",n),a.setTimeout(3e4,()=>{a.destroy(),n(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}apiRaw(e,t,s){return new Promise((r,n)=>{let o={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let c=new URL(this.config.host);o.hostname=c.hostname,o.port=c.port}else o.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?Au:vu).request(o,c=>{let d=[];c.on("data",u=>{d.push(u)}),c.on("end",()=>{if(c.statusCode&&c.statusCode>=400){let u=Buffer.concat(d).toString("utf8");n(new Error(`Docker API ${c.statusCode}: ${u.slice(0,500)}`));return}r(Buffer.concat(d).toString("binary"))})});a.on("error",n),a.setTimeout(3e4,()=>{a.destroy(),n(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}async listContainers(){let e=await this.api("GET","/containers/json?all=true"),t=["## Docker Containers","","| Name | Image | Status | Ports |","|------|-------|--------|-------|"];for(let s of e)t.push(`| ${Oa(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${Ru(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
973
+ ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(de(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import vu from"node:http";import Au from"node:https";import{execFile as Sf}from"node:child_process";import{promisify as $f}from"node:util";function Ma(l){return l==null||l<0?"-":l===0?"0 B":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function Ru(l){return!l||l.length===0?"-":l.filter(e=>e.PublicPort||e.PrivatePort).map(e=>e.PublicPort?`${e.IP??"0.0.0.0"}:${e.PublicPort}->${e.PrivatePort}/${e.Type??"tcp"}`:`${e.PrivatePort}/${e.Type??"tcp"}`).join(", ")}function Oa(l){return!l||l.length===0?"-":l.map(e=>e.replace(/^\//,"")).join(", ")}function vf(l){let e=Buffer.from(l,"binary"),t=[],s=0;for(;s<e.length;)if(s+8<=e.length){let r=e.readUInt32BE(s+4),n=e.subarray(s+8,s+8+r).toString("utf8");t.push(n),s+=8+r}else{t.push(e.subarray(s).toString("utf8"));break}return t.join("")}function Af(l){return l?new Date(l*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var Iu,Lo,xu=T(()=>{"use strict";B();Iu=$f(Sf);p(Ma,"formatBytes");p(Ru,"formatPorts");p(Oa,"containerName");p(vf,"stripDockerStreamHeaders");p(Af,"relativeTime");Lo=class extends x{static{p(this,"DockerSkill")}metadata={name:"docker",category:"infrastructure",description:"Manage Docker containers, images, volumes, networks. Actions: containers, container, logs, start, stop, restart, images, pull_image, remove_image, networks, volumes, system_info, prune, compose_ps, compose_up, compose_down.",riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["containers","container","logs","start","stop","restart","images","pull_image","remove_image","networks","volumes","system_info","prune","compose_ps","compose_up","compose_down"],description:"The Docker action to perform"},containerId:{type:"string",description:"Container ID or name (for container, logs, start, stop, restart)"},imageName:{type:"string",description:"Image name (for pull_image, remove_image), e.g. nginx, ghcr.io/org/app"},imageTag:{type:"string",description:"Image tag (for pull_image), default: latest"},networkId:{type:"string",description:"Network ID or name"},project:{type:"string",description:"Docker Compose project name (for compose_ps, compose_up, compose_down)"},tail:{type:"number",description:"Number of log lines to retrieve (default: 100)"}},required:["action"]}};config;defaultSocket;constructor(e){super(),this.config=e,this.defaultSocket=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock"}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"containers":return await this.listContainers();case"container":return await this.inspectContainer(e.containerId);case"logs":return await this.getLogs(e.containerId,e.tail);case"start":return await this.startContainer(e.containerId);case"stop":return await this.stopContainer(e.containerId);case"restart":return await this.restartContainer(e.containerId);case"images":return await this.listImages();case"pull_image":return await this.pullImage(e.imageName,e.imageTag);case"remove_image":return await this.removeImage(e.imageName);case"networks":return await this.listNetworks();case"volumes":return await this.listVolumes();case"system_info":return await this.getSystemInfo();case"prune":return await this.pruneAll();case"compose_ps":return await this.composePs(e.project);case"compose_up":return await this.composeUp(e.project);case"compose_down":return await this.composeDown(e.project);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Docker API error: ${r instanceof Error?r.message:String(r)}`}}}api(e,t,s){return new Promise((r,n)=>{let o={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let c=new URL(this.config.host);o.hostname=c.hostname,o.port=c.port}else o.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?Au:vu).request(o,c=>{let d="";c.on("data",u=>{d+=u}),c.on("end",()=>{if(c.statusCode&&c.statusCode>=400){n(new Error(`Docker API ${c.statusCode}: ${d.slice(0,500)}`));return}try{r(d?JSON.parse(d):void 0)}catch{n(new Error(`Invalid JSON from Docker API: ${d.slice(0,200)}`))}})});a.on("error",n),a.setTimeout(3e4,()=>{a.destroy(),n(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}apiRaw(e,t,s){return new Promise((r,n)=>{let o={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let c=new URL(this.config.host);o.hostname=c.hostname,o.port=c.port}else o.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?Au:vu).request(o,c=>{let d=[];c.on("data",u=>{d.push(u)}),c.on("end",()=>{if(c.statusCode&&c.statusCode>=400){let u=Buffer.concat(d).toString("utf8");n(new Error(`Docker API ${c.statusCode}: ${u.slice(0,500)}`));return}r(Buffer.concat(d).toString("binary"))})});a.on("error",n),a.setTimeout(3e4,()=>{a.destroy(),n(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}async listContainers(){let e=await this.api("GET","/containers/json?all=true"),t=["## Docker Containers","","| Name | Image | Status | Ports |","|------|-------|--------|-------|"];for(let s of e)t.push(`| ${Oa(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${Ru(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
974
974
  `)}}async inspectContainer(e){if(!e)return{success:!1,error:'Missing required "containerId" parameter'};let t=await this.api("GET",`/containers/${encodeURIComponent(e)}/json`),s=t.State??{},r=t.Config??{},n=t.NetworkSettings??{},o=t.Mounts??[],a=Object.entries(n.Ports??{}).filter(([,m])=>m&&m.length>0).map(([m,h])=>`${h.map(g=>`${g.HostIp??"0.0.0.0"}:${g.HostPort}`).join(", ")} -> ${m}`),c=o.map(m=>`- ${m.Source??"-"} -> ${m.Destination??"-"} (${m.Type??"-"}, ${m.RW?"rw":"ro"})`),d=n.IPAddress||Object.values(n.Networks??{}).map(m=>m.IPAddress).filter(Boolean).join(", ")||"-",u=[`## Container: ${Oa(t.Name?[t.Name]:void 0)}`,"",`**ID:** ${t.Id?.slice(0,12)??"-"}`,`**Image:** ${r.Image??"-"}`,`**Status:** ${s.Status??"-"}`,`**Started:** ${s.StartedAt??"-"}`,`**IP Address:** ${d}`,"","### Ports",a.length>0?a.map(m=>`- ${m}`).join(`
975
975
  `):"- No port bindings","","### Mounts",c.length>0?c.join(`
976
976
  `):"- No mounts"];return{success:!0,data:t,display:u.join(`
@@ -987,16 +987,16 @@ ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(de(t),s);
987
987
  `+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose up:** \`${e}\``,"","```",r,"```"].join(`
988
988
  `)}}async composeDown(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await Iu("docker",["compose","-p",e,"down"],{timeout:12e4}),r=(t+`
989
989
  `+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose down:** \`${e}\``,"","```",r,"```"].join(`
990
- `)}}}});import{readFile as Cu,writeFile as Nu,mkdir as Lu,chmod as If}from"node:fs/promises";import{homedir as Pa}from"node:os";import{join as Ua}from"node:path";import Ou from"node:crypto";function Lf(){let l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Ou.randomBytes(86);return Array.from(e).map(t=>l[t%l.length]).join("")}function Df(l){return Ou.createHash("sha256").update(l).digest("base64url")}function Te(l,e){return l[e]?.value??"?"}var Rf,Du,Lo,xf,Cf,Nf,Mu,Yr,Mf,Do,Pu=T(()=>{"use strict";B();Rf="https://customer.bmwgroup.com/gcdm/oauth/device/code",Du="https://customer.bmwgroup.com/gcdm/oauth/token",Lo="https://api-cardata.bmwgroup.com",xf="v1",Cf="authenticate_user openid cardata:api:read cardata:streaming:read",Nf=5*6e4,Mu="Alfred",Yr=Ua(Pa(),".alfred","bmw-tokens.json");p(Lf,"generateCodeVerifier");p(Df,"generateCodeChallenge");Mf=["vehicle.drivetrain.batteryManagement.header","vehicle.drivetrain.batteryManagement.maxEnergy","vehicle.drivetrain.batteryManagement.batterySizeMax","vehicle.powertrain.electric.battery.stateOfHealth.displayed","vehicle.powertrain.electric.battery.stateOfCharge.target","vehicle.drivetrain.electricEngine.remainingElectricRange","vehicle.drivetrain.electricEngine.charging.status","vehicle.drivetrain.electricEngine.charging.level","vehicle.drivetrain.electricEngine.charging.timeRemaining","vehicle.drivetrain.electricEngine.charging.timeToFullyCharged","vehicle.drivetrain.electricEngine.charging.hvStatus","vehicle.drivetrain.electricEngine.charging.method","vehicle.drivetrain.electricEngine.charging.phaseNumber","vehicle.drivetrain.electricEngine.charging.lastChargingReason","vehicle.drivetrain.electricEngine.charging.lastChargingResult","vehicle.drivetrain.electricEngine.charging.reasonChargingEnd","vehicle.powertrain.electric.battery.charging.power","vehicle.drivetrain.electricEngine.charging.acVoltage","vehicle.drivetrain.electricEngine.charging.acAmpere","vehicle.powertrain.electric.battery.charging.acLimit.selected","vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged","vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen","vehicle.body.chargingPort.lockedStatus","vehicle.body.chargingPort.plugEventId","vehicle.powertrain.electric.battery.preconditioning.automaticMode.statusFeedback","vehicle.powertrain.electric.battery.preconditioning.manualMode.statusFeedback","vehicle.vehicle.avgAuxPower","vehicle.trip.segment.end.drivetrain.batteryManagement.hvSoc","vehicle.trip.segment.accumulated.drivetrain.electricEngine.recuperationTotal","vehicle.vehicleIdentification.basicVehicleData"];p(Te,"tv");Do=class extends x{static{p(this,"BMWSkill")}metadata={name:"bmw",category:"infrastructure",description:'BMW CarData \u2014 Fahrzeugdaten abrufen. "authorize" startet den Device-Auth-Flow (einmalig). WICHTIG: authorize ist ein 2-Schritt-Prozess. Schritt 1 (ohne device_code) liefert einen User-Code + URL. Schritt 2: Nachdem der User im Browser best\xE4tigt hat, rufe authorize ERNEUT auf \u2014 entweder mit dem device_code aus Schritt 1, oder einfach ohne Parameter (auto-resume). NIEMALS Schritt 1 wiederholen wenn bereits ein Code ausgegeben wurde! "status" zeigt SoC, Reichweite, Modell, Batterie-Gesundheit. "charging" zeigt Ladestatus, Leistung, Restzeit, Ziel-SoC, Stecker. "charging_sessions" listet Lade-Sessions (from/to Zeitraum). "consumption" berechnet Durchschnittsverbrauch (kWh/100km) aus Lade-Sessions \u2014 optional mit period: "last" (letzte Fahrt), "week", "month", "year", "all" (default: month).',riskLevel:"read",version:"2.2.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["authorize","status","charging","charging_sessions","consumption"],description:"BMW CarData action"},vin:{type:"string",description:"Vehicle Identification Number (optional \u2014 uses stored VIN if omitted)"},device_code:{type:"string",description:"Device code from authorize step 1 (optional \u2014 if omitted, auto-resumes pending authorization)"},from:{type:"string",description:"ISO date-time start for charging_sessions (required for that action)"},to:{type:"string",description:"ISO date-time end for charging_sessions (required for that action)"},period:{type:"string",enum:["last","week","month","year","all"],description:"Zeitraum f\xFCr consumption: last (letzte Fahrt), week, month, year, all (default: month)"}},required:["action"]}};config;tokens=null;cache=new Map;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"authorize":return await this.authorize(e.device_code);case"status":return await this.getStatus(e.vin);case"charging":return await this.getCharging(e.vin);case"charging_sessions":return await this.getChargingSessions(e.vin,e.from,e.to);case"consumption":return await this.getConsumption(e.vin,e.period);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`BMW API error: ${r instanceof Error?r.message:String(r)}`}}}async authorize(e){if(e)return await this.pollToken(e);let t=await this.loadTokensFromDisk();if(t?.deviceCode&&t?.codeVerifier)try{return await this.pollToken(t.deviceCode)}catch{}let s=Lf(),r=Df(s),n=await fetch(Rf,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,response_type:"device_code",code_challenge:r,code_challenge_method:"S256",scope:Cf}),signal:AbortSignal.timeout(15e3)});if(!n.ok){let a=await n.text().catch(()=>"");throw new Error(`Device code request failed: HTTP ${n.status} \u2014 ${a.slice(0,300)}`)}let o=await n.json(),i={codeVerifier:s,deviceCode:o.device_code};return await this.savePartialTokens(i),this.tokens=null,{success:!0,data:o,display:["## BMW Autorisierung","",`1. \xD6ffne: **${o.verification_uri_complete??o.verification_uri}**`,`2. Gib diesen Code ein: **${o.user_code}**`,"","Danach rufe einfach `authorize` erneut auf (ohne Parameter) \u2014 der Token wird automatisch abgeholt."].join(`
990
+ `)}}}});import{readFile as Cu,writeFile as Nu,mkdir as Lu,chmod as If}from"node:fs/promises";import{homedir as Pa}from"node:os";import{join as Ua}from"node:path";import Ou from"node:crypto";function Lf(){let l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Ou.randomBytes(86);return Array.from(e).map(t=>l[t%l.length]).join("")}function Df(l){return Ou.createHash("sha256").update(l).digest("base64url")}function Te(l,e){return l[e]?.value??"?"}var Rf,Du,Do,xf,Cf,Nf,Mu,Yr,Mf,Mo,Pu=T(()=>{"use strict";B();Rf="https://customer.bmwgroup.com/gcdm/oauth/device/code",Du="https://customer.bmwgroup.com/gcdm/oauth/token",Do="https://api-cardata.bmwgroup.com",xf="v1",Cf="authenticate_user openid cardata:api:read cardata:streaming:read",Nf=5*6e4,Mu="Alfred",Yr=Ua(Pa(),".alfred","bmw-tokens.json");p(Lf,"generateCodeVerifier");p(Df,"generateCodeChallenge");Mf=["vehicle.drivetrain.batteryManagement.header","vehicle.drivetrain.batteryManagement.maxEnergy","vehicle.drivetrain.batteryManagement.batterySizeMax","vehicle.powertrain.electric.battery.stateOfHealth.displayed","vehicle.powertrain.electric.battery.stateOfCharge.target","vehicle.drivetrain.electricEngine.remainingElectricRange","vehicle.drivetrain.electricEngine.charging.status","vehicle.drivetrain.electricEngine.charging.level","vehicle.drivetrain.electricEngine.charging.timeRemaining","vehicle.drivetrain.electricEngine.charging.timeToFullyCharged","vehicle.drivetrain.electricEngine.charging.hvStatus","vehicle.drivetrain.electricEngine.charging.method","vehicle.drivetrain.electricEngine.charging.phaseNumber","vehicle.drivetrain.electricEngine.charging.lastChargingReason","vehicle.drivetrain.electricEngine.charging.lastChargingResult","vehicle.drivetrain.electricEngine.charging.reasonChargingEnd","vehicle.powertrain.electric.battery.charging.power","vehicle.drivetrain.electricEngine.charging.acVoltage","vehicle.drivetrain.electricEngine.charging.acAmpere","vehicle.powertrain.electric.battery.charging.acLimit.selected","vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged","vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen","vehicle.body.chargingPort.lockedStatus","vehicle.body.chargingPort.plugEventId","vehicle.powertrain.electric.battery.preconditioning.automaticMode.statusFeedback","vehicle.powertrain.electric.battery.preconditioning.manualMode.statusFeedback","vehicle.vehicle.avgAuxPower","vehicle.trip.segment.end.drivetrain.batteryManagement.hvSoc","vehicle.trip.segment.accumulated.drivetrain.electricEngine.recuperationTotal","vehicle.vehicleIdentification.basicVehicleData"];p(Te,"tv");Mo=class extends x{static{p(this,"BMWSkill")}metadata={name:"bmw",category:"infrastructure",description:'BMW CarData \u2014 Fahrzeugdaten abrufen. "authorize" startet den Device-Auth-Flow (einmalig). WICHTIG: authorize ist ein 2-Schritt-Prozess. Schritt 1 (ohne device_code) liefert einen User-Code + URL. Schritt 2: Nachdem der User im Browser best\xE4tigt hat, rufe authorize ERNEUT auf \u2014 entweder mit dem device_code aus Schritt 1, oder einfach ohne Parameter (auto-resume). NIEMALS Schritt 1 wiederholen wenn bereits ein Code ausgegeben wurde! "status" zeigt SoC, Reichweite, Modell, Batterie-Gesundheit. "charging" zeigt Ladestatus, Leistung, Restzeit, Ziel-SoC, Stecker. "charging_sessions" listet Lade-Sessions (from/to Zeitraum). "consumption" berechnet Durchschnittsverbrauch (kWh/100km) aus Lade-Sessions \u2014 optional mit period: "last" (letzte Fahrt), "week", "month", "year", "all" (default: month).',riskLevel:"read",version:"2.2.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["authorize","status","charging","charging_sessions","consumption"],description:"BMW CarData action"},vin:{type:"string",description:"Vehicle Identification Number (optional \u2014 uses stored VIN if omitted)"},device_code:{type:"string",description:"Device code from authorize step 1 (optional \u2014 if omitted, auto-resumes pending authorization)"},from:{type:"string",description:"ISO date-time start for charging_sessions (required for that action)"},to:{type:"string",description:"ISO date-time end for charging_sessions (required for that action)"},period:{type:"string",enum:["last","week","month","year","all"],description:"Zeitraum f\xFCr consumption: last (letzte Fahrt), week, month, year, all (default: month)"}},required:["action"]}};config;tokens=null;cache=new Map;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"authorize":return await this.authorize(e.device_code);case"status":return await this.getStatus(e.vin);case"charging":return await this.getCharging(e.vin);case"charging_sessions":return await this.getChargingSessions(e.vin,e.from,e.to);case"consumption":return await this.getConsumption(e.vin,e.period);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`BMW API error: ${r instanceof Error?r.message:String(r)}`}}}async authorize(e){if(e)return await this.pollToken(e);let t=await this.loadTokensFromDisk();if(t?.deviceCode&&t?.codeVerifier)try{return await this.pollToken(t.deviceCode)}catch{}let s=Lf(),r=Df(s),n=await fetch(Rf,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,response_type:"device_code",code_challenge:r,code_challenge_method:"S256",scope:Cf}),signal:AbortSignal.timeout(15e3)});if(!n.ok){let a=await n.text().catch(()=>"");throw new Error(`Device code request failed: HTTP ${n.status} \u2014 ${a.slice(0,300)}`)}let o=await n.json(),i={codeVerifier:s,deviceCode:o.device_code};return await this.savePartialTokens(i),this.tokens=null,{success:!0,data:o,display:["## BMW Autorisierung","",`1. \xD6ffne: **${o.verification_uri_complete??o.verification_uri}**`,`2. Gib diesen Code ein: **${o.user_code}**`,"","Danach rufe einfach `authorize` erneut auf (ohne Parameter) \u2014 der Token wird automatisch abgeholt."].join(`
991
991
  `)}}async pollToken(e){let s=(await this.loadTokens())?.codeVerifier;if(!s)throw new Error('Kein code_verifier gefunden. Bitte zuerst "authorize" ohne device_code aufrufen.');let r=await fetch(Du,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,device_code:e,grant_type:"urn:ietf:params:oauth:grant-type:device_code",code_verifier:s}),signal:AbortSignal.timeout(15e3)});if(!r.ok){let m=await r.text().catch(()=>"");if(m.includes("authorization_pending"))return{success:!0,data:{status:"pending"},display:"Autorisierung noch ausstehend \u2014 bitte zuerst im Browser best\xE4tigen, dann erneut versuchen."};throw new Error(`Token poll failed: HTTP ${r.status} \u2014 ${m.slice(0,300)}`)}let n=await r.json(),o=n.access_token,i={accessToken:o,refreshToken:n.refresh_token,idToken:n.id_token,expiresAt:Date.now()+(n.expires_in??3600)*1e3,vin:"",containerId:""},a=await this.fetchVin(o);i.vin=a,await this.saveTokens(i);let c="",d="";try{c=await this.ensureContainer(o),i.containerId=c,await this.saveTokens(i)}catch(m){d=m instanceof Error?m.message:String(m)}this.tokens=i;let u=["## BMW Autorisierung erfolgreich","",`**VIN:** ${a}`];return c?(u.push(`**Container:** ${c}`),u.push("Tokens gespeichert. Du kannst jetzt Fahrzeugdaten abrufen.")):(u.push(`**Container-Fehler:** ${d}`),u.push("Tokens + VIN gespeichert, aber Container konnte nicht erstellt werden."),u.push("Erstelle den Container manuell im BMW CarData Portal oder versuche es erneut.")),{success:c!=="",data:{vin:a,containerId:c,containerError:d||void 0},display:u.join(`
992
- `)}}async fetchVin(e){let t=await fetch(`${Lo}/customers/vehicles/mappings`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(!t.ok)throw new Error(`Failed to fetch vehicles: HTTP ${t.status}`);let s=await t.json();if(typeof s.vin=="string")return s.vin;if(Array.isArray(s)){let r=s;return r.find(o=>o.mappingType==="PRIMARY")?.vin??r[0]?.vin??(()=>{throw new Error("No vehicles found")})()}throw new Error(`No vehicles found in account (response: ${JSON.stringify(s).slice(0,200)})`)}async ensureContainer(e){let t=await fetch(`${Lo}/customers/containers`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(t.ok){let n=await t.json(),i=(Array.isArray(n)?n:Array.isArray(n.containers)?n.containers:[]).find(a=>a.name===Mu);if(i)return i.containerId}let s=await fetch(`${Lo}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:Mu,purpose:"Alfred AI Assistant",technicalDescriptors:Mf}),signal:AbortSignal.timeout(15e3)});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Container creation failed: HTTP ${s.status} \u2014 ${n.slice(0,300)}`)}return(await s.json()).containerId}apiHeaders(e){return{Authorization:`Bearer ${e}`,"x-version":xf,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<Nf)return s.data;let r=await this.ensureToken(),n=`${Lo}${e}`,o=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)});if(o.status===401){let a=await this.loadTokens();a&&(r=await this.refreshAccessToken(a),o=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)}))}if(!o.ok){let a=await o.text().catch(()=>"");throw new Error(`HTTP ${o.status} \u2014 ${a.slice(0,300)}`)}let i=await o.json();return this.cache.set(t,{data:i,ts:Date.now()}),i}async loadTokens(){return this.tokens?this.tokens:await this.loadTokensFromDisk()}async loadTokensFromDisk(){try{let e=await Cu(Yr,"utf-8"),t=JSON.parse(e);return this.tokens=t,t}catch{return null}}async saveTokens(e){await Lu(Ua(Pa(),".alfred"),{recursive:!0}),await Nu(Yr,JSON.stringify(e,null,2),"utf-8");try{await If(Yr,384)}catch{}}async savePartialTokens(e){await Lu(Ua(Pa(),".alfred"),{recursive:!0});let t={};try{let s=await Cu(Yr,"utf-8");t=JSON.parse(s)}catch{}await Nu(Yr,JSON.stringify({...t,...e},null,2),"utf-8")}async ensureToken(){let e=await this.loadTokens();if(!e?.accessToken)throw new Error('Nicht autorisiert. Bitte zuerst die "authorize"-Action aufrufen, um den BMW-Account zu verbinden.');return Date.now()>e.expiresAt-6e4?await this.refreshAccessToken(e):e.accessToken}async refreshAccessToken(e){let t=await fetch(Du,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,grant_type:"refresh_token",refresh_token:e.refreshToken}),signal:AbortSignal.timeout(15e3)});if(!t.ok)throw this.tokens=null,new Error('Token-Refresh fehlgeschlagen. Bitte erneut "authorize" aufrufen.');let s=await t.json(),r={...e,accessToken:s.access_token,refreshToken:s.refresh_token??e.refreshToken,idToken:s.id_token??e.idToken,expiresAt:Date.now()+(s.expires_in??3600)*1e3};return delete r.codeVerifier,delete r.deviceCode,await this.saveTokens(r),this.tokens=r,r.accessToken}async resolveVin(e){if(e)return e;let t=await this.loadTokens();if(t?.vin)return t.vin;throw new Error('Keine VIN angegeben und keine gespeicherte VIN gefunden. Bitte zuerst "authorize" aufrufen.')}async resolveContainerId(){let e=await this.loadTokens();if(e?.containerId)return e.containerId;throw new Error('Kein Container gefunden. Bitte zuerst "authorize" aufrufen.')}async getStatus(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),[r,n]=await Promise.all([this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`),this.apiGet(`/customers/vehicles/${t}/basicData`)]),o=r.telematicData??{},i=Te(o,"vehicle.drivetrain.batteryManagement.header"),a=Te(o,"vehicle.drivetrain.electricEngine.remainingElectricRange"),c=Te(o,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=Te(o,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),m=["## BMW Fahrzeugstatus","",`**Modell:** ${n.modelName??n.model??"?"}`,`**VIN:** ${t}`,`**Ladestand (SoC):** ${i} %`,`**Elektrische Reichweite:** ${a} km`,`**Batteriekapazit\xE4t:** ${c} kWh`,`**Batterie-Gesundheit (SoH):** ${d} %`];return{success:!0,data:{telematic:o,basic:n},display:m.join(`
992
+ `)}}async fetchVin(e){let t=await fetch(`${Do}/customers/vehicles/mappings`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(!t.ok)throw new Error(`Failed to fetch vehicles: HTTP ${t.status}`);let s=await t.json();if(typeof s.vin=="string")return s.vin;if(Array.isArray(s)){let r=s;return r.find(o=>o.mappingType==="PRIMARY")?.vin??r[0]?.vin??(()=>{throw new Error("No vehicles found")})()}throw new Error(`No vehicles found in account (response: ${JSON.stringify(s).slice(0,200)})`)}async ensureContainer(e){let t=await fetch(`${Do}/customers/containers`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(t.ok){let n=await t.json(),i=(Array.isArray(n)?n:Array.isArray(n.containers)?n.containers:[]).find(a=>a.name===Mu);if(i)return i.containerId}let s=await fetch(`${Do}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:Mu,purpose:"Alfred AI Assistant",technicalDescriptors:Mf}),signal:AbortSignal.timeout(15e3)});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Container creation failed: HTTP ${s.status} \u2014 ${n.slice(0,300)}`)}return(await s.json()).containerId}apiHeaders(e){return{Authorization:`Bearer ${e}`,"x-version":xf,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<Nf)return s.data;let r=await this.ensureToken(),n=`${Do}${e}`,o=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)});if(o.status===401){let a=await this.loadTokens();a&&(r=await this.refreshAccessToken(a),o=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)}))}if(!o.ok){let a=await o.text().catch(()=>"");throw new Error(`HTTP ${o.status} \u2014 ${a.slice(0,300)}`)}let i=await o.json();return this.cache.set(t,{data:i,ts:Date.now()}),i}async loadTokens(){return this.tokens?this.tokens:await this.loadTokensFromDisk()}async loadTokensFromDisk(){try{let e=await Cu(Yr,"utf-8"),t=JSON.parse(e);return this.tokens=t,t}catch{return null}}async saveTokens(e){await Lu(Ua(Pa(),".alfred"),{recursive:!0}),await Nu(Yr,JSON.stringify(e,null,2),"utf-8");try{await If(Yr,384)}catch{}}async savePartialTokens(e){await Lu(Ua(Pa(),".alfred"),{recursive:!0});let t={};try{let s=await Cu(Yr,"utf-8");t=JSON.parse(s)}catch{}await Nu(Yr,JSON.stringify({...t,...e},null,2),"utf-8")}async ensureToken(){let e=await this.loadTokens();if(!e?.accessToken)throw new Error('Nicht autorisiert. Bitte zuerst die "authorize"-Action aufrufen, um den BMW-Account zu verbinden.');return Date.now()>e.expiresAt-6e4?await this.refreshAccessToken(e):e.accessToken}async refreshAccessToken(e){let t=await fetch(Du,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,grant_type:"refresh_token",refresh_token:e.refreshToken}),signal:AbortSignal.timeout(15e3)});if(!t.ok)throw this.tokens=null,new Error('Token-Refresh fehlgeschlagen. Bitte erneut "authorize" aufrufen.');let s=await t.json(),r={...e,accessToken:s.access_token,refreshToken:s.refresh_token??e.refreshToken,idToken:s.id_token??e.idToken,expiresAt:Date.now()+(s.expires_in??3600)*1e3};return delete r.codeVerifier,delete r.deviceCode,await this.saveTokens(r),this.tokens=r,r.accessToken}async resolveVin(e){if(e)return e;let t=await this.loadTokens();if(t?.vin)return t.vin;throw new Error('Keine VIN angegeben und keine gespeicherte VIN gefunden. Bitte zuerst "authorize" aufrufen.')}async resolveContainerId(){let e=await this.loadTokens();if(e?.containerId)return e.containerId;throw new Error('Kein Container gefunden. Bitte zuerst "authorize" aufrufen.')}async getStatus(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),[r,n]=await Promise.all([this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`),this.apiGet(`/customers/vehicles/${t}/basicData`)]),o=r.telematicData??{},i=Te(o,"vehicle.drivetrain.batteryManagement.header"),a=Te(o,"vehicle.drivetrain.electricEngine.remainingElectricRange"),c=Te(o,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=Te(o,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),m=["## BMW Fahrzeugstatus","",`**Modell:** ${n.modelName??n.model??"?"}`,`**VIN:** ${t}`,`**Ladestand (SoC):** ${i} %`,`**Elektrische Reichweite:** ${a} km`,`**Batteriekapazit\xE4t:** ${c} kWh`,`**Batterie-Gesundheit (SoH):** ${d} %`];return{success:!0,data:{telematic:o,basic:n},display:m.join(`
993
993
  `)}}async getCharging(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),n=(await this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`)).telematicData??{},o=Te(n,"vehicle.drivetrain.electricEngine.charging.status"),i=Te(n,"vehicle.drivetrain.batteryManagement.header"),a=Te(n,"vehicle.drivetrain.electricEngine.charging.level"),c=Te(n,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=Te(n,"vehicle.powertrain.electric.battery.charging.power"),u=Te(n,"vehicle.drivetrain.electricEngine.charging.hvStatus"),m=Te(n,"vehicle.powertrain.electric.battery.stateOfCharge.target"),h=Te(n,"vehicle.drivetrain.electricEngine.charging.acVoltage"),f=Te(n,"vehicle.drivetrain.electricEngine.charging.acAmpere"),g=Te(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"),y=Te(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen"),_=Te(n,"vehicle.body.chargingPort.lockedStatus"),S=["## BMW Ladestatus","",`**Status:** ${o}`,`**Ladestand:** ${i} %`,`**Ladelevel:** ${a}`,`**Ladeleistung:** ${d} kW`,`**Restzeit:** ${c} min`,`**Ziel-SoC:** ${m} %`,`**HV-Batterie:** ${u}`,`**AC Spannung:** ${h} V`,`**AC Strom:** ${f} A`,`**Stecker eingesteckt:** ${g}`,`**Ladeklappe offen:** ${y}`,`**Ladeport-Schloss:** ${_}`];return{success:!0,data:n,display:S.join(`
994
994
  `)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),n=new Date,o=s??n.toISOString(),i=t??new Date(n.getTime()-720*60*6e4).toISOString(),a=await this.apiGet(`/customers/vehicles/${r}/chargingHistory?from=${encodeURIComponent(i)}&to=${encodeURIComponent(o)}`),c=a.data??a.chargingSessions??[],d=[`## BMW Lade-Sessions (${i.slice(0,10)} \u2013 ${o.slice(0,10)})`,"","| Start | Ende | Dauer | Energie | Start-SoC | End-SoC | km-Stand | Ort |","|-------|------|-------|---------|-----------|---------|----------|-----|"];for(let u of c.slice(0,20)){let m=u.startTime,h=u.endTime,f=p(F=>new Date(F*1e3).toLocaleString("de-AT",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"}),"fmtDateTime"),g=m?f(m):"-",y=h?f(h):"-",_=u.totalChargingDurationSec,S=_!=null?Math.round(_/60):"-",E=u.energyConsumedFromPowerGridKwh??"-",$=u.displayedStartSoc??"-",R=u.displayedSoc??"-",M=u.mileage!=null?`${u.mileage}`:"-",q=u.chargingLocation,G=q?.formattedAddress??q?.streetAddress??"-";d.push(`| ${g} | ${y} | ${S} min | ${E} kWh | ${$}% | ${R}% | ${M} | ${G} |`)}return c.length===0&&d.push("| - | - | Keine Sessions gefunden | - | - | - | - | - |"),{success:!0,data:a,display:d.join(`
995
995
  `)}}async getConsumption(e,t){let s=await this.resolveVin(e),r=await this.resolveContainerId(),n=new Date,i={last:7,week:7,month:30,year:365,all:730}[t??"month"]??30,a=new Date(n.getTime()-i*864e5).toISOString(),c=n.toISOString(),[d,u]=await Promise.all([this.apiGet(`/customers/vehicles/${s}/chargingHistory?from=${encodeURIComponent(a)}&to=${encodeURIComponent(c)}`),this.apiGet(`/customers/vehicles/${s}/telematicData?containerId=${r}`)]),m=d.data??d.chargingSessions??[],h=parseFloat(Te(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(m.length<2)return{success:!0,data:{sessions:m.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let f=m.filter(F=>typeof F.mileage=="number"&&typeof F.displayedStartSoc=="number"&&typeof F.displayedSoc=="number").sort((F,ee)=>F.mileage-ee.mileage);if(f.length<2)return{success:!0,data:{sessions:f.length},display:"Nicht gen\xFCgend Lade-Sessions mit vollst\xE4ndigen Daten."};let g=[];for(let F=1;F<f.length;F++){let ee=f[F-1],ue=f[F],L=ee.mileage,ne=ue.mileage,ae=ne-L;if(ae<=0)continue;let Q=ee.displayedSoc,W=ue.displayedStartSoc,he=Q-W;if(he<=0)continue;let Ve=he/100*h,le=Ve/ae*100,Se=ue.startTime,pe=Se?new Date(Se*1e3).toLocaleDateString("de-AT"):"-";g.push({fromKm:L,toKm:ne,distance:ae,socUsed:he,kWhUsed:Ve,consumption:le,date:pe})}if(g.length===0)return{success:!0,data:{},display:"Keine auswertbaren Fahrtabschnitte gefunden."};if(t==="last"){let F=g[g.length-1];return{success:!0,data:F,display:["## Letzte Fahrt (gesch\xE4tzt)","",`**Datum:** ${F.date}`,`**Strecke:** ${F.distance} km`,`**Verbrauch:** ${F.consumption.toFixed(1)} kWh/100km`,`**Energie:** ${F.kWhUsed.toFixed(1)} kWh (${F.socUsed}% SoC)`,`**km-Stand:** ${F.fromKm} \u2192 ${F.toKm}`].join(`
996
996
  `)}}let y=g.reduce((F,ee)=>F+ee.distance,0),_=g.reduce((F,ee)=>F+ee.kWhUsed,0),S=_/y*100,E=g.map(F=>F.consumption).sort((F,ee)=>F-ee),$=E[0],R=E[E.length-1],M=E[Math.floor(E.length/2)],G=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${h} kWh`,`**Ausgewertete Fahrten:** ${g.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${_.toFixed(1)} kWh`,"",`**Durchschnitt:** ${S.toFixed(1)} kWh/100km`,`**Min:** ${$.toFixed(1)} kWh/100km`,`**Max:** ${R.toFixed(1)} kWh/100km`,`**Median:** ${M.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let F of g)G.push(`| ${F.date} | ${F.distance} km | ${F.consumption.toFixed(1)} kWh/100km | ${F.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:S,totalDistance:y,totalKwh:_,segments:g},display:G.join(`
997
- `)}}}});var Of,Mo,Uu=T(()=>{"use strict";B();Of="https://routes.googleapis.com/directions/v2:computeRoutes",Mo=class extends x{static{p(this,"RoutingSkill")}metadata={name:"routing",category:"information",description:'Routenberechnung mit Live-Traffic via Google Routes API. "route" berechnet Route mit Distanz, Dauer und Dauer im aktuellen Verkehr. "departure_time" empfiehlt wann man losfahren soll, um zu einer bestimmten Zeit anzukommen. WICHTIG: Aliase wie "zuhause", "daheim", "home", "bei mir", "im B\xFCro", "work" VOR dem Tool-Call in konkrete Adressen aufl\xF6sen \u2014 daf\xFCr bekannte Adressen aus Memory/Kontext verwenden. Nie rohe Alias-Werte wie "home" oder "work" als origin/destination senden. Wenn keine Adresse im Kontext vorhanden ist, den User nach der Adresse fragen.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["route","departure_time"],description:"Routing action"},origin:{type:"string",description:'Start-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},departure_time:{type:"string",description:"ISO-Zeitpunkt f\xFCr Abfahrt (optional, f\xFCr Traffic-Berechnung)"},arrival_time:{type:"string",description:"ISO-Zeitpunkt gew\xFCnschte Ankunft (f\xFCr departure_time-Action)"},travel_mode:{type:"string",enum:["DRIVE","BICYCLE","WALK","TRANSIT"],description:"Fortbewegungsart (Standard: DRIVE)"}},required:["action","origin","destination"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};let r=e.origin,n=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!n)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,n,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,n,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(o){return{success:!1,error:`Google Routes API error: ${o instanceof Error?o.message:String(o)}`}}}async computeRoute(e,t,s,r){let n=this.buildRequestBody(e,t,r,s),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=(i.distanceMeters/1e3).toFixed(1),c=this.parseDuration(i.duration),d=this.parseDuration(i.staticDuration),u=c-d,m=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(c)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(u>1&&m.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(u)}`),s){let h=new Date(new Date(s).getTime()+c*6e4);m.push(`**Gesch\xE4tzte Ankunft:** ${h.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:c,staticDurationMinutes:d},display:m.join(`
997
+ `)}}}});var Of,Oo,Uu=T(()=>{"use strict";B();Of="https://routes.googleapis.com/directions/v2:computeRoutes",Oo=class extends x{static{p(this,"RoutingSkill")}metadata={name:"routing",category:"information",description:'Routenberechnung mit Live-Traffic via Google Routes API. "route" berechnet Route mit Distanz, Dauer und Dauer im aktuellen Verkehr. "departure_time" empfiehlt wann man losfahren soll, um zu einer bestimmten Zeit anzukommen. WICHTIG: Aliase wie "zuhause", "daheim", "home", "bei mir", "im B\xFCro", "work" VOR dem Tool-Call in konkrete Adressen aufl\xF6sen \u2014 daf\xFCr bekannte Adressen aus Memory/Kontext verwenden. Nie rohe Alias-Werte wie "home" oder "work" als origin/destination senden. Wenn keine Adresse im Kontext vorhanden ist, den User nach der Adresse fragen.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["route","departure_time"],description:"Routing action"},origin:{type:"string",description:'Start-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},departure_time:{type:"string",description:"ISO-Zeitpunkt f\xFCr Abfahrt (optional, f\xFCr Traffic-Berechnung)"},arrival_time:{type:"string",description:"ISO-Zeitpunkt gew\xFCnschte Ankunft (f\xFCr departure_time-Action)"},travel_mode:{type:"string",enum:["DRIVE","BICYCLE","WALK","TRANSIT"],description:"Fortbewegungsart (Standard: DRIVE)"}},required:["action","origin","destination"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};let r=e.origin,n=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!n)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,n,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,n,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(o){return{success:!1,error:`Google Routes API error: ${o instanceof Error?o.message:String(o)}`}}}async computeRoute(e,t,s,r){let n=this.buildRequestBody(e,t,r,s),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=(i.distanceMeters/1e3).toFixed(1),c=this.parseDuration(i.duration),d=this.parseDuration(i.staticDuration),u=c-d,m=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(c)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(u>1&&m.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(u)}`),s){let h=new Date(new Date(s).getTime()+c*6e4);m.push(`**Gesch\xE4tzte Ankunft:** ${h.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:c,staticDurationMinutes:d},display:m.join(`
998
998
  `)}}async computeDepartureTime(e,t,s,r){if(!s)return{success:!1,error:'Missing required field "arrival_time" for departure_time action'};let n=this.buildRequestBody(e,t,r),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=this.parseDuration(i.duration),c=Math.max(5,Math.round(a*.15)),d=new Date(s),u=new Date(d.getTime()-(a+c)*6e4),m=["## Abfahrtszeit-Empfehlung","",`**Route:** ${e} \u2192 ${t}`,`**Gew\xFCnschte Ankunft:** ${d.toLocaleString("de-AT")}`,`**Gesch\xE4tzte Fahrzeit:** ${this.formatMinutes(a)} (inkl. Verkehr)`,`**Puffer:** ${c} min`,"",`**Empfohlene Abfahrt:** ${u.toLocaleString("de-AT")}`];return{success:!0,data:{departureTime:u.toISOString(),durationMinutes:a,bufferMinutes:c},display:m.join(`
999
- `)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",n=Math.abs(s),o=String(Math.floor(n/60)).padStart(2,"0"),i=String(n%60).padStart(2,"0"),a=p(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())}T${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}${r}${o}:${i}`}buildRequestBody(e,t,s,r,n){let o={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let i=this.normalizeTimestamp(r);new Date(i).getTime()>Date.now()+6e4&&(o.departureTime=i)}if(n){let i=this.normalizeTimestamp(n);new Date(i).getTime()>Date.now()+6e4&&(o.arrivalTime=i)}return o}async callRoutesApi(e){let t=await fetch(Of,{method:"POST",headers:{"Content-Type":"application/json","X-Goog-Api-Key":this.config.apiKey,"X-Goog-FieldMask":"routes.duration,routes.staticDuration,routes.distanceMeters,routes.legs"},body:JSON.stringify(e),signal:AbortSignal.timeout(15e3)});if(!t.ok){let s=await t.text().catch(()=>"");throw new Error(`HTTP ${t.status} \u2014 ${s.slice(0,300)}`)}return await t.json()}parseDuration(e){let t=e?.match(/(\d+)s/);return t?Math.round(parseInt(t[1],10)/60):0}formatMinutes(e){if(e<60)return`${e} min`;let t=Math.floor(e/60),s=e%60;return s>0?`${t} h ${s} min`:`${t} h`}}});var Fu,ju,Pf,Uf,Ff,Ks,Bu,Hu,Wu,Fa,ja,zu,Oo,qu=T(()=>{"use strict";B();Fu=1.5,ju=4.79,Pf=5.75,Uf=1.03,Ff=new Date("2026-04-01T00:00:00+02:00"),Ks=1.2,Bu=.1,Hu=.58,Wu=.04,Fa=.32,ja=1.62,zu="https://api.awattar.at/v1/marketdata",Oo=class extends x{static{p(this,"EnergyPriceSkill")}metadata={name:"energy_price",category:"information",description:'Strompreise (aWATTar HOURLY Tarif, EPEX Spot AT). "current" zeigt den aktuellen Strompreis mit Aufschl\xFCsselung (Marktpreis, Netzentgelte, Abgaben, Brutto). "today" zeigt alle Stundenpreise f\xFCr heute. "tomorrow" zeigt Stundenpreise f\xFCr morgen (verf\xFCgbar ab ~14:00). "cheapest" findet die g\xFCnstigsten Stunden (Standard: 3 Stunden in den n\xE4chsten 24h). "average" zeigt den Durchschnittspreis f\xFCr heute oder ein bestimmtes Datum.',riskLevel:"read",version:"1.0.0",timeoutMs:15e3,inputSchema:{type:"object",properties:{action:{type:"string",enum:["current","today","tomorrow","cheapest","average","briefing"],description:"Aktion (briefing = kompakte Tages\xFCbersicht f\xFCr Morgenbriefing)"},hours:{type:"number",description:"F\xFCr cheapest: Anzahl g\xFCnstigster Stunden (Standard: 3)"},date:{type:"string",description:"ISO-Datum f\xFCr average (Standard: heute)"}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"current":return await this.current();case"today":return await this.dayPrices("today");case"tomorrow":return await this.dayPrices("tomorrow");case"cheapest":return await this.cheapest(e.hours);case"average":return await this.average(e.date);case"briefing":return await this.briefingSummary();default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`aWATTar API error: ${r instanceof Error?r.message:String(r)}`}}}async current(){let e=Date.now(),s=(await this.fetchMarketData()).find(i=>i.start_timestamp<=e&&i.end_timestamp>e);if(!s)return{success:!1,error:"Kein Marktpreis f\xFCr die aktuelle Stunde verf\xFCgbar."};let r=this.calculatePrice(s.marketprice),o=[`## Aktueller Strompreis (${this.formatHourRange(s.start_timestamp,s.end_timestamp)})`,""];return o.push(this.formatBreakdown(r)),{success:!0,data:r,display:o.join(`
999
+ `)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",n=Math.abs(s),o=String(Math.floor(n/60)).padStart(2,"0"),i=String(n%60).padStart(2,"0"),a=p(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())}T${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}${r}${o}:${i}`}buildRequestBody(e,t,s,r,n){let o={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let i=this.normalizeTimestamp(r);new Date(i).getTime()>Date.now()+6e4&&(o.departureTime=i)}if(n){let i=this.normalizeTimestamp(n);new Date(i).getTime()>Date.now()+6e4&&(o.arrivalTime=i)}return o}async callRoutesApi(e){let t=await fetch(Of,{method:"POST",headers:{"Content-Type":"application/json","X-Goog-Api-Key":this.config.apiKey,"X-Goog-FieldMask":"routes.duration,routes.staticDuration,routes.distanceMeters,routes.legs"},body:JSON.stringify(e),signal:AbortSignal.timeout(15e3)});if(!t.ok){let s=await t.text().catch(()=>"");throw new Error(`HTTP ${t.status} \u2014 ${s.slice(0,300)}`)}return await t.json()}parseDuration(e){let t=e?.match(/(\d+)s/);return t?Math.round(parseInt(t[1],10)/60):0}formatMinutes(e){if(e<60)return`${e} min`;let t=Math.floor(e/60),s=e%60;return s>0?`${t} h ${s} min`:`${t} h`}}});var Fu,ju,Pf,Uf,Ff,Ks,Bu,Hu,Wu,Fa,ja,zu,Po,qu=T(()=>{"use strict";B();Fu=1.5,ju=4.79,Pf=5.75,Uf=1.03,Ff=new Date("2026-04-01T00:00:00+02:00"),Ks=1.2,Bu=.1,Hu=.58,Wu=.04,Fa=.32,ja=1.62,zu="https://api.awattar.at/v1/marketdata",Po=class extends x{static{p(this,"EnergyPriceSkill")}metadata={name:"energy_price",category:"information",description:'Strompreise (aWATTar HOURLY Tarif, EPEX Spot AT). "current" zeigt den aktuellen Strompreis mit Aufschl\xFCsselung (Marktpreis, Netzentgelte, Abgaben, Brutto). "today" zeigt alle Stundenpreise f\xFCr heute. "tomorrow" zeigt Stundenpreise f\xFCr morgen (verf\xFCgbar ab ~14:00). "cheapest" findet die g\xFCnstigsten Stunden (Standard: 3 Stunden in den n\xE4chsten 24h). "average" zeigt den Durchschnittspreis f\xFCr heute oder ein bestimmtes Datum.',riskLevel:"read",version:"1.0.0",timeoutMs:15e3,inputSchema:{type:"object",properties:{action:{type:"string",enum:["current","today","tomorrow","cheapest","average","briefing"],description:"Aktion (briefing = kompakte Tages\xFCbersicht f\xFCr Morgenbriefing)"},hours:{type:"number",description:"F\xFCr cheapest: Anzahl g\xFCnstigster Stunden (Standard: 3)"},date:{type:"string",description:"ISO-Datum f\xFCr average (Standard: heute)"}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"current":return await this.current();case"today":return await this.dayPrices("today");case"tomorrow":return await this.dayPrices("tomorrow");case"cheapest":return await this.cheapest(e.hours);case"average":return await this.average(e.date);case"briefing":return await this.briefingSummary();default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`aWATTar API error: ${r instanceof Error?r.message:String(r)}`}}}async current(){let e=Date.now(),s=(await this.fetchMarketData()).find(i=>i.start_timestamp<=e&&i.end_timestamp>e);if(!s)return{success:!1,error:"Kein Marktpreis f\xFCr die aktuelle Stunde verf\xFCgbar."};let r=this.calculatePrice(s.marketprice),o=[`## Aktueller Strompreis (${this.formatHourRange(s.start_timestamp,s.end_timestamp)})`,""];return o.push(this.formatBreakdown(r)),{success:!0,data:r,display:o.join(`
1000
1000
  `)}}async dayPrices(e){let t=new Date,s=new Date(t);e==="tomorrow"&&s.setDate(s.getDate()+1);let r=new Date(s);r.setHours(0,0,0,0);let n=new Date(r);n.setDate(n.getDate()+1);let o=await this.fetchMarketData(r.getTime(),n.getTime());if(o.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${e==="today"?"heute":"morgen"} verf\xFCgbar.${e==="tomorrow"?" Preise f\xFCr morgen sind ab ca. 14:00 verf\xFCgbar.":""}`};let i=e==="today"?"Heute":"Morgen",a=r.toLocaleDateString("de-AT"),c=[`## Strompreise ${i} (${a})`,""];c.push("| Uhrzeit | Markt ct/kWh | Brutto ct/kWh |"),c.push("|---|---|---|");let d=1/0,u=-1/0,m=0;for(let f of o){let g=this.calculatePrice(f.marketprice),y=this.formatHourRange(f.start_timestamp,f.end_timestamp),_=this.spotCtKwh(f.marketprice);c.push(`| ${y} | ${_.toFixed(2)} | ${g.bruttoCt.toFixed(2)} |`),d=Math.min(d,g.bruttoCt),u=Math.max(u,g.bruttoCt),m+=g.bruttoCt}let h=m/o.length;return c.push(""),c.push(`**Min:** ${d.toFixed(2)} ct/kWh | **Max:** ${u.toFixed(2)} ct/kWh | **\xD8:** ${h.toFixed(2)} ct/kWh`),{success:!0,data:{entries:o.length,min:d,max:u,avg:h},display:c.join(`
1001
1001
  `)}}async cheapest(e){let t=e??3,s=Date.now(),r=s+1440*60*1e3,n=await this.fetchMarketData(s,r);if(n.length===0)return{success:!1,error:"Keine Preisdaten f\xFCr die n\xE4chsten 24 Stunden verf\xFCgbar."};let o=n.map(c=>({entry:c,breakdown:this.calculatePrice(c.marketprice)}));o.sort((c,d)=>c.breakdown.bruttoCt-d.breakdown.bruttoCt);let i=o.slice(0,Math.min(t,o.length));i.sort((c,d)=>c.entry.start_timestamp-d.entry.start_timestamp);let a=[`## ${t} g\xFCnstigste Stunden (n\xE4chste 24h)`,""];for(let{entry:c,breakdown:d}of i){let u=this.formatHourRange(c.start_timestamp,c.end_timestamp),m=new Date(c.start_timestamp).toLocaleDateString("de-AT",{weekday:"short"});a.push(`- **${m} ${u}**: ${d.bruttoCt.toFixed(2)} ct/kWh brutto (Markt: ${this.spotCtKwh(c.marketprice).toFixed(2)} ct/kWh)`)}return{success:!0,data:i.map(c=>({time:this.formatHourRange(c.entry.start_timestamp,c.entry.end_timestamp),bruttoCt:c.breakdown.bruttoCt})),display:a.join(`
1002
1002
  `)}}async average(e){let t;e?(t=new Date(e),t.setHours(0,0,0,0)):(t=new Date,t.setHours(0,0,0,0));let s=new Date(t);s.setDate(s.getDate()+1);let r=await this.fetchMarketData(t.getTime(),s.getTime());if(r.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${t.toLocaleDateString("de-AT")} verf\xFCgbar.`};let n=0,o=0;for(let u of r)n+=this.spotCtKwh(u.marketprice),o+=this.calculatePrice(u.marketprice).bruttoCt;let i=n/r.length,a=o/r.length,c=t.toLocaleDateString("de-AT"),d=[`## Durchschnittspreis ${c}`,"",`**\xD8 Marktpreis:** ${i.toFixed(2)} ct/kWh`,`**\xD8 Brutto-Gesamtpreis:** ${a.toFixed(2)} ct/kWh`,"",`Basierend auf ${r.length} Stundenwerten.`];return{success:!0,data:{date:c,avgSpotCt:i,avgBruttoCt:a,hours:r.length},display:d.join(`
@@ -1020,26 +1020,26 @@ ${d}=${m}
1020
1020
  **${s.label} wurde aktiviert.** Du kannst es jetzt sofort nutzen.`):c.push(`
1021
1021
  **${s.label} is fully configured.** Hot-Reload fehlgeschlagen: ${d.error??"unbekannter Fehler"}. Restart Alfred: \`alfred start\``)}else c.push(`
1022
1022
  **${s.label} is fully configured.** Restart Alfred to activate: \`alfred start\``);return{success:!0,data:{envPath:n,written:i},display:c.join(`
1023
- `)}}};p(Xu,"maskValue");p(jf,"findEnvFile")});var Po,Yu=T(()=>{"use strict";B();Po=class extends x{static{p(this,"MonitorSkill")}metadata={name:"monitor",category:"infrastructure",description:"Deterministic infrastructure health checks without LLM. Checks Proxmox cluster, UniFi network, and Home Assistant for issues. Returns alerts only when problems are detected \u2014 empty display means all OK.",riskLevel:"read",version:"1.0.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{checks:{type:"array",items:{type:"string",enum:["proxmox","unifi","homeassistant","proxmox_backup"]},description:"Which checks to run (default: all configured)"}}}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.checks,r=[],n=p(c=>!s||s.length===0||s.includes(c),"shouldRun");if(this.config.proxmox&&n("proxmox")&&r.push({name:"proxmox",promise:this.checkProxmox()}),this.config.unifi&&n("unifi")&&r.push({name:"unifi",promise:this.checkUnifi()}),this.config.homeassistant&&n("homeassistant")&&r.push({name:"homeassistant",promise:this.checkHomeAssistant()}),this.config.proxmoxBackup&&n("proxmox_backup")&&r.push({name:"proxmox_backup",promise:this.checkProxmoxBackup()}),r.length===0)return{success:!0,display:""};let o=await Promise.allSettled(r.map(c=>c.promise)),i=[];for(let c=0;c<o.length;c++){let d=o[c];if(d.status==="fulfilled")i.push(...d.value);else{let u=d.reason instanceof Error?d.reason.message:String(d.reason);i.push({source:r[c].name,message:`Health check failed: ${u}`})}}if(i.length===0)return{success:!0,display:""};let a=["\u26A0 Infrastructure Alerts:",""];for(let c of i)a.push(`- [${c.source}] ${c.message}`);return{success:!0,display:a.join(`
1024
- `)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let n of s)n.type==="node"&&!n.online&&t.push({source:"proxmox",message:`Node "${n.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let n of r){let o=n.name??`VMID ${n.vmid}`,i=n.status,a=n.maxdisk,c=n.disk;if(a&&a>0&&c!=null){let d=c/a*100;d>90&&t.push({source:"proxmox",message:`${o} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=n.maxmem,u=n.mem;if(d&&d>0&&u!=null){let m=u/d*100;m>95&&t.push({source:"proxmox",message:`${o} RAM usage ${m.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`Proxmox HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return(await n.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,n=[],o;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let c=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),u=await this.apiFetch(`${c}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),m;if(u.status===200)m="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(h=>h.split(";")[0]),o=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let h=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!h.ok)throw new Error(`UniFi login failed: HTTP ${h.status}`);m="classic",n=(h.headers.getSetCookie?.()??[]).map(f=>f.split(";")[0])}else throw new Error(`UniFi login failed: HTTP ${u.status}`);r={"Content-Type":"application/json"},n.length>0&&(r.Cookie=n.join("; ")),o&&(r["X-CSRF-Token"]=o)}let i=p(c=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${c}`,"apiUrl"),a=p(async c=>{let d=await this.apiFetch(i(c),{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!d.ok)throw new Error(`UniFi HTTP ${d.status}`);return(await d.json()).data},"unifiGet");try{let c=await a("stat/health");for(let d of c??[])d.status&&d.status!=="ok"&&t.push({source:"unifi",message:`Subsystem "${d.subsystem}" status: ${d.status}`})}catch{}try{let c=await a("stat/device");for(let d of c??[])if(d.state!==1){let u=d.name??d.hostname??d.mac??"unknown";t.push({source:"unifi",message:`Device "${u}" is not connected (state: ${d.state})`})}}catch{}try{let c=await a("rest/alarm?archived=false");c&&c.length>0&&t.push({source:"unifi",message:`${c.length} open alert(s): ${c.slice(0,3).map(d=>d.key??d.msg??"unknown").join(", ")}`})}catch{}return t}async checkHomeAssistant(){let e=this.config.homeassistant,t=[],s=await this.haGet(e,"/api/states"),r=0,n=[];for(let o of s){let i=o.entity_id;if(i.startsWith("update."))continue;if(o.state==="unavailable"&&(r++,n.length<5)){let d=o.attributes?.friendly_name??i;n.push(d)}let a=o.attributes?.device_class??"",c=o.attributes?.unit_of_measurement??"";if(i.startsWith("sensor.")&&a==="battery"&&c==="%"){let d=parseFloat(o.state);if(!isNaN(d)&&d>=0&&d<20){let u=o.attributes?.friendly_name??i;t.push({source:"homeassistant",message:`Low battery: ${u} at ${d}%`})}}}if(r>0){let o=n.join(", "),i=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${o}${i}`})}return t}async haGet(e,t){let s=`${e.baseUrl.replace(/\/+$/,"")}${t}`,r={Authorization:`Bearer ${e.accessToken}`,"Content-Type":"application/json"},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`HA HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return await n.json()}async checkProxmoxBackup(){let e=this.config.proxmoxBackup,t=[],s=e.maxAgeHours??24,r=`${e.baseUrl.replace(/\/+$/,"")}/api2/json/nodes/localhost/tasks`,n={Authorization:`PBSAPIToken=${e.tokenId}:${e.tokenSecret}`},o=await this.apiFetch(r,{method:"GET",headers:n,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)return t.push({source:"proxmox_backup",message:`PBS unreachable: HTTP ${o.status}`}),t;let c=((await o.json()).data??[]).filter(h=>h.worker_type==="backup"),d=Date.now()/1e3,u=c.filter(h=>h.status==="OK").sort((h,f)=>(f.endtime??f.starttime)-(h.endtime??h.starttime));if(u.length===0)t.push({source:"proxmox_backup",message:"No successful backups found"});else{let h=u[0].endtime??u[0].starttime,f=(d-h)/3600;f>s&&t.push({source:"proxmox_backup",message:`Last successful backup is ${f.toFixed(1)}h old (threshold: ${s}h)`})}let m=c.filter(h=>h.status!=="OK"&&d-(h.endtime??h.starttime)<s*3600);return m.length>0&&t.push({source:"proxmox_backup",message:`${m.length} failed backup(s) in the last ${s}h`}),t}async apiFetch(e,t,s){let r=s===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}}}});var Uo,Ju=T(()=>{"use strict";B();Uo=class extends x{static{p(this,"MicrosoftTodoSkill")}config;accessToken="";metadata={name:"microsoft_todo",description:"Manage Microsoft To Do lists and tasks \u2014 list, create, complete, update and delete tasks across all lists.",version:"1.0.0",riskLevel:"write",category:"productivity",inputSchema:{type:"object",required:["action"],properties:{action:{type:"string",enum:["list_lists","list_tasks","add_task","complete_task","uncomplete_task","delete_task","update_task","create_list"],description:"Action to perform."},listId:{type:"string",description:"To Do list ID. Either listId or list (display name) is required for task actions."},list:{type:"string",description:'To Do list display name (resolved to listId automatically). E.g. "Einkaufsliste".'},taskId:{type:"string",description:"Task ID (required for complete/uncomplete/delete/update)."},title:{type:"string",description:"Task or list title (required for add_task, create_list; optional for update_task)."},body:{type:"string",description:"Task body/notes."},dueDate:{type:"string",description:"Due date in YYYY-MM-DD format."},importance:{type:"string",enum:["low","normal","high"],description:"Task importance."},includeCompleted:{type:"boolean",description:"Include completed tasks in list_tasks (default: false)."}}}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;try{switch(s){case"list_lists":return await this.listLists();case"list_tasks":return await this.listTasks(e);case"add_task":return await this.addTask(e);case"complete_task":return await this.completeTask(e);case"uncomplete_task":return await this.uncompleteTask(e);case"delete_task":return await this.deleteTask(e);case"update_task":return await this.updateTask(e);case"create_list":return await this.createList(e);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Tasks.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(()=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s();if(r.status===401){if(await this.refreshAccessToken(),r=await s(),!r.ok)throw new Error(`Graph API error: ${r.status}`)}else if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async resolveListId(e){if(e.listId)return e.listId;let s=(await this.graphRequest("/me/todo/lists")).value??[];if(e.list){let n=e.list.toLowerCase(),o=s.find(i=>i.displayName.toLowerCase()===n);if(!o){let i=s.map(a=>a.displayName).join(", ");throw new Error(`List "${e.list}" not found. Available lists: ${i}`)}return o.id}let r=s.find(n=>n.wellknownListName==="defaultList");if(r)return r.id;if(s.length>0)return s[0].id;throw new Error("No To Do lists found.")}async listLists(){let t=(await this.graphRequest("/me/todo/lists")).value??[],s=t.map(r=>`\u2022 **${r.displayName}**${r.wellknownListName==="defaultList"?" (Standard)":""} [listId=${r.id}]`).join(`
1023
+ `)}}};p(Xu,"maskValue");p(jf,"findEnvFile")});var Uo,Yu=T(()=>{"use strict";B();Uo=class extends x{static{p(this,"MonitorSkill")}metadata={name:"monitor",category:"infrastructure",description:"Deterministic infrastructure health checks without LLM. Checks Proxmox cluster, UniFi network, and Home Assistant for issues. Returns alerts only when problems are detected \u2014 empty display means all OK.",riskLevel:"read",version:"1.0.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{checks:{type:"array",items:{type:"string",enum:["proxmox","unifi","homeassistant","proxmox_backup"]},description:"Which checks to run (default: all configured)"}}}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.checks,r=[],n=p(c=>!s||s.length===0||s.includes(c),"shouldRun");if(this.config.proxmox&&n("proxmox")&&r.push({name:"proxmox",promise:this.checkProxmox()}),this.config.unifi&&n("unifi")&&r.push({name:"unifi",promise:this.checkUnifi()}),this.config.homeassistant&&n("homeassistant")&&r.push({name:"homeassistant",promise:this.checkHomeAssistant()}),this.config.proxmoxBackup&&n("proxmox_backup")&&r.push({name:"proxmox_backup",promise:this.checkProxmoxBackup()}),r.length===0)return{success:!0,display:""};let o=await Promise.allSettled(r.map(c=>c.promise)),i=[];for(let c=0;c<o.length;c++){let d=o[c];if(d.status==="fulfilled")i.push(...d.value);else{let u=d.reason instanceof Error?d.reason.message:String(d.reason);i.push({source:r[c].name,message:`Health check failed: ${u}`})}}if(i.length===0)return{success:!0,display:""};let a=["\u26A0 Infrastructure Alerts:",""];for(let c of i)a.push(`- [${c.source}] ${c.message}`);return{success:!0,display:a.join(`
1024
+ `)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let n of s)n.type==="node"&&!n.online&&t.push({source:"proxmox",message:`Node "${n.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let n of r){let o=n.name??`VMID ${n.vmid}`,i=n.status,a=n.maxdisk,c=n.disk;if(a&&a>0&&c!=null){let d=c/a*100;d>90&&t.push({source:"proxmox",message:`${o} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=n.maxmem,u=n.mem;if(d&&d>0&&u!=null){let m=u/d*100;m>95&&t.push({source:"proxmox",message:`${o} RAM usage ${m.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`Proxmox HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return(await n.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,n=[],o;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let c=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),u=await this.apiFetch(`${c}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),m;if(u.status===200)m="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(h=>h.split(";")[0]),o=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let h=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!h.ok)throw new Error(`UniFi login failed: HTTP ${h.status}`);m="classic",n=(h.headers.getSetCookie?.()??[]).map(f=>f.split(";")[0])}else throw new Error(`UniFi login failed: HTTP ${u.status}`);r={"Content-Type":"application/json"},n.length>0&&(r.Cookie=n.join("; ")),o&&(r["X-CSRF-Token"]=o)}let i=p(c=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${c}`,"apiUrl"),a=p(async c=>{let d=await this.apiFetch(i(c),{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!d.ok)throw new Error(`UniFi HTTP ${d.status}`);return(await d.json()).data},"unifiGet");try{let c=await a("stat/health");for(let d of c??[])d.status&&d.status!=="ok"&&t.push({source:"unifi",message:`Subsystem "${d.subsystem}" status: ${d.status}`})}catch{}try{let c=await a("stat/device");for(let d of c??[])if(d.state!==1){let u=d.name??d.hostname??d.mac??"unknown";t.push({source:"unifi",message:`Device "${u}" is not connected (state: ${d.state})`})}}catch{}try{let c=await a("rest/alarm?archived=false");c&&c.length>0&&t.push({source:"unifi",message:`${c.length} open alert(s): ${c.slice(0,3).map(d=>d.key??d.msg??"unknown").join(", ")}`})}catch{}return t}async checkHomeAssistant(){let e=this.config.homeassistant,t=[],s=await this.haGet(e,"/api/states"),r=0,n=[];for(let o of s){let i=o.entity_id;if(i.startsWith("update."))continue;if(o.state==="unavailable"&&(r++,n.length<5)){let d=o.attributes?.friendly_name??i;n.push(d)}let a=o.attributes?.device_class??"",c=o.attributes?.unit_of_measurement??"";if(i.startsWith("sensor.")&&a==="battery"&&c==="%"){let d=parseFloat(o.state);if(!isNaN(d)&&d>=0&&d<20){let u=o.attributes?.friendly_name??i;t.push({source:"homeassistant",message:`Low battery: ${u} at ${d}%`})}}}if(r>0){let o=n.join(", "),i=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${o}${i}`})}return t}async haGet(e,t){let s=`${e.baseUrl.replace(/\/+$/,"")}${t}`,r={Authorization:`Bearer ${e.accessToken}`,"Content-Type":"application/json"},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`HA HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return await n.json()}async checkProxmoxBackup(){let e=this.config.proxmoxBackup,t=[],s=e.maxAgeHours??24,r=`${e.baseUrl.replace(/\/+$/,"")}/api2/json/nodes/localhost/tasks`,n={Authorization:`PBSAPIToken=${e.tokenId}:${e.tokenSecret}`},o=await this.apiFetch(r,{method:"GET",headers:n,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)return t.push({source:"proxmox_backup",message:`PBS unreachable: HTTP ${o.status}`}),t;let c=((await o.json()).data??[]).filter(h=>h.worker_type==="backup"),d=Date.now()/1e3,u=c.filter(h=>h.status==="OK").sort((h,f)=>(f.endtime??f.starttime)-(h.endtime??h.starttime));if(u.length===0)t.push({source:"proxmox_backup",message:"No successful backups found"});else{let h=u[0].endtime??u[0].starttime,f=(d-h)/3600;f>s&&t.push({source:"proxmox_backup",message:`Last successful backup is ${f.toFixed(1)}h old (threshold: ${s}h)`})}let m=c.filter(h=>h.status!=="OK"&&d-(h.endtime??h.starttime)<s*3600);return m.length>0&&t.push({source:"proxmox_backup",message:`${m.length} failed backup(s) in the last ${s}h`}),t}async apiFetch(e,t,s){let r=s===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}}}});var Fo,Ju=T(()=>{"use strict";B();Fo=class extends x{static{p(this,"MicrosoftTodoSkill")}config;accessToken="";metadata={name:"microsoft_todo",description:"Manage Microsoft To Do lists and tasks \u2014 list, create, complete, update and delete tasks across all lists.",version:"1.0.0",riskLevel:"write",category:"productivity",inputSchema:{type:"object",required:["action"],properties:{action:{type:"string",enum:["list_lists","list_tasks","add_task","complete_task","uncomplete_task","delete_task","update_task","create_list"],description:"Action to perform."},listId:{type:"string",description:"To Do list ID. Either listId or list (display name) is required for task actions."},list:{type:"string",description:'To Do list display name (resolved to listId automatically). E.g. "Einkaufsliste".'},taskId:{type:"string",description:"Task ID (required for complete/uncomplete/delete/update)."},title:{type:"string",description:"Task or list title (required for add_task, create_list; optional for update_task)."},body:{type:"string",description:"Task body/notes."},dueDate:{type:"string",description:"Due date in YYYY-MM-DD format."},importance:{type:"string",enum:["low","normal","high"],description:"Task importance."},includeCompleted:{type:"boolean",description:"Include completed tasks in list_tasks (default: false)."}}}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;try{switch(s){case"list_lists":return await this.listLists();case"list_tasks":return await this.listTasks(e);case"add_task":return await this.addTask(e);case"complete_task":return await this.completeTask(e);case"uncomplete_task":return await this.uncompleteTask(e);case"delete_task":return await this.deleteTask(e);case"update_task":return await this.updateTask(e);case"create_list":return await this.createList(e);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Tasks.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(()=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s();if(r.status===401){if(await this.refreshAccessToken(),r=await s(),!r.ok)throw new Error(`Graph API error: ${r.status}`)}else if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async resolveListId(e){if(e.listId)return e.listId;let s=(await this.graphRequest("/me/todo/lists")).value??[];if(e.list){let n=e.list.toLowerCase(),o=s.find(i=>i.displayName.toLowerCase()===n);if(!o){let i=s.map(a=>a.displayName).join(", ");throw new Error(`List "${e.list}" not found. Available lists: ${i}`)}return o.id}let r=s.find(n=>n.wellknownListName==="defaultList");if(r)return r.id;if(s.length>0)return s[0].id;throw new Error("No To Do lists found.")}async listLists(){let t=(await this.graphRequest("/me/todo/lists")).value??[],s=t.map(r=>`\u2022 **${r.displayName}**${r.wellknownListName==="defaultList"?" (Standard)":""} [listId=${r.id}]`).join(`
1025
1025
  `);return{success:!0,data:t,display:s||"Keine Listen gefunden."}}async listTasks(e){let t=await this.resolveListId(e),s=e.includeCompleted===!0,r=`/me/todo/lists/${t}/tasks`;s||(r+="?$filter=status ne 'completed'");let o=(await this.graphRequest(r)).value??[],i=o.map(a=>{let c=a.status==="completed"?"\u2611":"\u2610",d=a.importance==="high"?" \u2757":"",u=a.dueDateTime?` (f\xE4llig: ${a.dueDateTime.dateTime.slice(0,10)})`:"";return`${c} ${a.title}${d}${u} [taskId=${a.id}]`});return{success:!0,data:o,display:i.length>0?`listId=${t}
1026
1026
  ${i.join(`
1027
- `)}`:"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});var Fo,Js,Zu=T(()=>{"use strict";B();Fo=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Js=class extends x{static{p(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,!0);case"disable":return this.toggleWatch(e,!1);case"delete":return this.deleteWatch(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},o=e.condition_field,i=e.condition_operator,a=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,m=e.action_skill_name,h=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,_=e.conditions,S=e.conditions_logic??"and";if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};let E=Array.isArray(_)&&_.length>0,$=!!o&&!!i;if(!E&&!$)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let R;if(E){for(let L of _){if(!L.field||!L.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!Fo.includes(L.operator))return{success:!1,error:`Invalid operator "${L.operator}" in conditions. Must be one of: ${Fo.join(", ")}`}}R={logic:S,conditions:_.map(L=>({field:L.field,operator:L.operator,value:L.value}))}}if($&&!Fo.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${Fo.join(", ")}`};if(c<1)return{success:!1,error:"interval_minutes must be >= 1"};if(d<0)return{success:!1,error:"cooldown_minutes must be >= 0"};if(f==="trigger_watch"&&!y)return{success:!1,error:'Missing "trigger_watch_id" \u2014 required when action_on_trigger is "trigger_watch"'};if(y&&!this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let L=this.skillRegistry.get(r);if(!L)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let ne=L.metadata.inputSchema;if(ne&&Array.isArray(ne.required)){let ae=ne.required.filter(Q=>!(Q in n));if(ae.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${ae.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(ne.required)}`}}}let M=o??(R?R.conditions[0].field:""),q=i??(R?R.conditions[0].operator:"changed"),G=a??(R?R.conditions[0].value:void 0),F=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:M,operator:q,value:G},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:R,actionSkillName:m,actionSkillParams:h,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),ee=R?`${R.logic.toUpperCase()}(${R.conditions.map(L=>`${L.field} ${L.operator}${L.value!=null?" "+L.value:""}`).join(", ")})`:`${M} ${q}${G!=null?" "+G:""}`,ue=y?` \u2192 Chain \u2192 Watch ${y}`:m?` \u2192 Aktion: ${m} (${f})`:"";return{success:!0,data:{watchId:F.id,name:s,skillName:r,conditionField:M,conditionOperator:q,conditionValue:G,intervalMinutes:c,compositeCondition:R,triggerWatchId:y},display:`Watch erstellt (${F.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${ee}${ue}`}}listWatches(e){let t=this.watchRepo.findByChatId(e.chatId,e.platform);if(t.length===0)return{success:!0,data:[],display:"Keine Watches vorhanden."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,i=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",a=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${a}${i}`});return{success:!0,data:t.map(r=>({watchId:r.id,name:r.name,skillName:r.skillName,condition:r.condition,intervalMinutes:r.intervalMinutes,enabled:r.enabled,lastCheckedAt:r.lastCheckedAt,lastTriggeredAt:r.lastTriggeredAt})),display:`Watches:
1027
+ `)}`:"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});var jo,Js,Zu=T(()=>{"use strict";B();jo=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Js=class extends x{static{p(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,!0);case"disable":return this.toggleWatch(e,!1);case"delete":return this.deleteWatch(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},o=e.condition_field,i=e.condition_operator,a=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,m=e.action_skill_name,h=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,_=e.conditions,S=e.conditions_logic??"and";if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};let E=Array.isArray(_)&&_.length>0,$=!!o&&!!i;if(!E&&!$)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let R;if(E){for(let L of _){if(!L.field||!L.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!jo.includes(L.operator))return{success:!1,error:`Invalid operator "${L.operator}" in conditions. Must be one of: ${jo.join(", ")}`}}R={logic:S,conditions:_.map(L=>({field:L.field,operator:L.operator,value:L.value}))}}if($&&!jo.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${jo.join(", ")}`};if(c<1)return{success:!1,error:"interval_minutes must be >= 1"};if(d<0)return{success:!1,error:"cooldown_minutes must be >= 0"};if(f==="trigger_watch"&&!y)return{success:!1,error:'Missing "trigger_watch_id" \u2014 required when action_on_trigger is "trigger_watch"'};if(y&&!this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let L=this.skillRegistry.get(r);if(!L)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let ne=L.metadata.inputSchema;if(ne&&Array.isArray(ne.required)){let ae=ne.required.filter(Q=>!(Q in n));if(ae.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${ae.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(ne.required)}`}}}let M=o??(R?R.conditions[0].field:""),q=i??(R?R.conditions[0].operator:"changed"),G=a??(R?R.conditions[0].value:void 0),F=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:M,operator:q,value:G},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:R,actionSkillName:m,actionSkillParams:h,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),ee=R?`${R.logic.toUpperCase()}(${R.conditions.map(L=>`${L.field} ${L.operator}${L.value!=null?" "+L.value:""}`).join(", ")})`:`${M} ${q}${G!=null?" "+G:""}`,ue=y?` \u2192 Chain \u2192 Watch ${y}`:m?` \u2192 Aktion: ${m} (${f})`:"";return{success:!0,data:{watchId:F.id,name:s,skillName:r,conditionField:M,conditionOperator:q,conditionValue:G,intervalMinutes:c,compositeCondition:R,triggerWatchId:y},display:`Watch erstellt (${F.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${ee}${ue}`}}listWatches(e){let t=this.watchRepo.findByChatId(e.chatId,e.platform);if(t.length===0)return{success:!0,data:[],display:"Keine Watches vorhanden."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,i=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",a=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${a}${i}`});return{success:!0,data:t.map(r=>({watchId:r.id,name:r.name,skillName:r.skillName,condition:r.condition,intervalMinutes:r.intervalMinutes,enabled:r.enabled,lastCheckedAt:r.lastCheckedAt,lastTriggeredAt:r.lastTriggeredAt})),display:`Watches:
1028
1028
  ${s.join(`
1029
1029
  `)}`}}toggleWatch(e,t){let s=e.watch_id;return s?this.watchRepo.toggle(s,t)?{success:!0,data:{watchId:s,enabled:t},display:`Watch "${s}" ${t?"aktiviert":"deaktiviert"}.`}:{success:!1,error:`Watch "${s}" not found`}:{success:!1,error:`Missing "watch_id" for ${t?"enable":"disable"}`}}deleteWatch(e){let t=e.watch_id;return t?this.watchRepo.delete(t)?{success:!0,data:{watchId:t},display:`Watch "${t}" gel\xF6scht.`}:{success:!1,error:`Watch "${t}" not found`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var Zs,Qu=T(()=>{"use strict";B();Oe();Zs=class extends x{static{p(this,"WorkflowSkill")}workflowRepo;metadata={name:"workflow",category:"automation",description:'Create and manage multi-step workflows (skill chains). Use "create" to define a workflow with sequential steps. Each step runs a skill and can pass data to the next via {{prev.field}} or {{steps.0.field}} templates. Use "run" to execute a workflow, "list" to see all workflows, "delete" to remove, "history" to see recent executions.',riskLevel:"write",version:"1.0.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","run","delete","history"],description:"Workflow action"},name:{type:"string",description:"Workflow name (for create)"},steps:{type:"array",description:'Workflow steps (for create). Action step: { skillName, inputMapping: { paramName: "{{prev.field}}" }, onError: "stop"|"skip"|"retry", jumpTo?: stepIndex|"end" }. Condition step: { type: "condition", condition: { field: "prev.rain", operator: "eq", value: "true" }, then: stepIndex|"end"|null, else: stepIndex|"end"|null, label?: "Regen?" }. Jump targets are 0-based step indices, "end" finishes the workflow, null proceeds to next step.',items:{type:"object"}},workflow_id:{type:"string",description:"Workflow ID (for run/delete/history)"}},required:["action"]}};runner;constructor(e){super(),this.workflowRepo=e}setRunner(e){this.runner=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWorkflow(e,t);case"list":return this.listWorkflows(t);case"run":return this.runWorkflow(e,t);case"delete":return this.deleteWorkflow(e,t);case"history":return this.getHistory(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}createWorkflow(e,t){let s=e.name,r=e.steps;if(!s)return{success:!1,error:'Missing required field "name"'};if(!r||!Array.isArray(r)||r.length===0)return{success:!1,error:'Missing or empty "steps" array'};let n=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"];for(let i=0;i<r.length;i++){let a=r[i];if(a.type==="condition"){if(!a.condition||typeof a.condition!="object")return{success:!1,error:`Step ${i}: condition step missing "condition" object`};if(!a.condition.field||typeof a.condition.field!="string")return{success:!1,error:`Step ${i}: condition.field must be a non-empty string`};if(!n.includes(a.condition.operator))return{success:!1,error:`Step ${i}: condition.operator must be one of: ${n.join(", ")}`};for(let c of["then","else"]){let d=a[c];if(d!==null&&d!=="end"&&(typeof d!="number"||d<0||d>=r.length))return{success:!1,error:`Step ${i}: "${c}" must be null, "end", or a step index (0-${r.length-1})`}}}else{if(!a.skillName)return{success:!1,error:`Step ${i}: missing skillName`};if(!a.inputMapping||typeof a.inputMapping!="object")return{success:!1,error:`Step ${i}: missing inputMapping`};if(!["stop","skip","retry"].includes(a.onError))return{success:!1,error:`Step ${i}: onError must be stop|skip|retry`};if(a.jumpTo!==void 0&&a.jumpTo!=="end"&&(typeof a.jumpTo!="number"||a.jumpTo<0||a.jumpTo>=r.length))return{success:!1,error:`Step ${i}: jumpTo must be "end" or a step index (0-${r.length-1})`}}}let o=this.workflowRepo.create({name:s,userId:de(t),chatId:t.chatId,platform:t.platform,steps:r,triggerType:"manual",enabled:!0});return{success:!0,data:{workflowId:o.id,name:s,stepCount:r.length},display:`Workflow "${s}" erstellt (${o.id}) mit ${r.length} Schritten.`}}listWorkflows(e){let t=[],s=new Set;for(let n of J(e))for(let o of this.workflowRepo.findByUser(n))s.has(o.id)||(s.add(o.id),t.push(o));if(t.length===0)return{success:!0,data:[],display:"Keine Workflows vorhanden."};let r=t.map(n=>`- ${n.enabled?"\u2705":"\u23F8\uFE0F"} ${n.name} (${n.id.slice(0,8)}) \u2014 ${n.steps.length} Schritte, Trigger: ${n.triggerType}`);return{success:!0,data:t.map(n=>({id:n.id,name:n.name,steps:n.steps.length,triggerType:n.triggerType,enabled:n.enabled})),display:`Workflows:
1030
1030
  ${r.join(`
1031
1031
  `)}`}}async runWorkflow(e,t){if(!this.runner)return{success:!1,error:"WorkflowRunner not available"};let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);if(!r)return{success:!1,error:`Workflow "${s}" not found`};if(!r.enabled)return{success:!1,error:`Workflow "${r.name}" is disabled`};let n=await this.runner.run(r,t),i=[`${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} Workflow "${r.name}": ${n.status}`];i.push(`Schritte: ${n.stepsCompleted}/${n.totalSteps}`),n.error&&i.push(`Fehler: ${n.error}`);for(let a=0;a<n.stepResults.length;a++){let c=n.stepResults[a];i.push(` ${a+1}. ${c.skillName}: ${c.success?"\u2705":"\u274C "+(c.error??"")}`)}return{success:n.status==="completed",data:n,display:i.join(`
1032
1032
  `)}}deleteWorkflow(e,t){let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);return r?J(t).includes(r.userId)?(this.workflowRepo.delete(s),{success:!0,data:{workflowId:s},display:`Workflow "${r.name}" gel\xF6scht.`}):{success:!1,error:"Not authorized to delete this workflow"}:{success:!1,error:`Workflow "${s}" not found`}}getHistory(e){let t=e.workflow_id;if(!t)return{success:!1,error:'Missing "workflow_id"'};let s=this.workflowRepo.getRecentExecutions(t);if(s.length===0)return{success:!0,data:[],display:"Keine Ausf\xFChrungen vorhanden."};let r=s.map(n=>`- ${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} ${n.startedAt} \u2014 ${n.stepsCompleted}/${n.totalSteps} Schritte (${n.status})`);return{success:!0,data:s,display:`Letzte Ausf\xFChrungen:
1033
1033
  ${r.join(`
1034
- `)}`}}}});var Kt,jo=T(()=>{"use strict";Kt=class{static{p(this,"MarketplaceProvider")}async getDetail(e){throw new Error("Detail not supported")}}});var ep,Jr,Ha=T(()=>{"use strict";jo();ep="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",Jr=class extends Kt{static{p(this,"WillhabenProvider")}platform="willhaben";async search(e){let t=Math.min(e.rows??100,100),s=new URL("https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz");if(s.searchParams.set("keyword",e.query),s.searchParams.set("rows",String(t)),e.priceMin!=null&&s.searchParams.set("PRICE_FROM",String(e.priceMin)),e.priceMax!=null&&s.searchParams.set("PRICE_TO",String(e.priceMax)),e.sort){let d={date_desc:"1",price_asc:"2",price_desc:"3"};s.searchParams.set("sfId",d[e.sort])}e.postcode&&s.searchParams.set("postcode",e.postcode);let r=await fetch(s.toString(),{headers:{"User-Agent":ep,Accept:"text/html"}});if(!r.ok)throw new Error(`willhaben HTTP ${r.status}`);let n=await r.text(),i=this.parseNextData(n).map(d=>this.mapAdvert(d)),a=e.query.toLowerCase().split(/\s+/).filter(d=>d.length>=2);return{listings:a.length>0?i.filter(d=>a.every(u=>d.title.toLowerCase().includes(u))):i,totalCount:this.extractTotalCount(n)??i.length,query:e.query,platform:"willhaben"}}async getDetail(e){let t=`https://www.willhaben.at/iad/object?adId=${e}`,s=await fetch(t,{headers:{"User-Agent":ep,Accept:"text/html"},redirect:"follow"});if(!s.ok)throw new Error(`willhaben detail HTTP ${s.status}`);let n=(await s.text()).match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!n)throw new Error("willhaben detail: __NEXT_DATA__ not found");let o;try{o=JSON.parse(n[1])}catch{throw new Error("willhaben detail: __NEXT_DATA__ contains invalid JSON")}let i=o?.props?.pageProps?.advertDetails;if(!i)throw new Error("willhaben detail: advertDetails not found in page data");let a=i.attributes?.attribute??[],c=p($=>a.find(M=>M.name===$)?.values?.[0]??void 0,"attr"),d={};for(let $ of a)$.name&&$.values?.[0]&&(d[$.name]=$.values[0]);let u=i.attributeInformation??[];for(let $ of u){let R=$.treeAttributeElement?.label,M=$.values?.[0]?.label;R&&M&&(d[R]=M)}let m=(i.advertImageList?.advertImage??[]).map($=>$.mainImageUrl??$.referenceImageUrl).filter(Boolean),h=i.advertAddressDetails,f=h?[h.postalName,h.postCode,h.district,h.province].filter(Boolean).join(", "):[c("LOCATION/ADDRESS_2"),c("LOCATION/ADDRESS_3")].filter(Boolean).join(", "),g=i.sellerProfileUserData,_=(c("DESCRIPTION")??i.description??"").replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim(),S=c("PRICE"),E=u.find($=>$.treeAttributeElement?.code==="Zustand")?.values?.[0]?.label;return{id:e,title:i.description??"Kein Titel",price:S?parseFloat(S):null,currency:"EUR",condition:E,location:f,url:s.url||t,imageUrls:m,seller:g?.name??void 0,sellerSince:g?.registerDate??void 0,publishedAt:i.publishedDate??void 0,description:_,attributes:d,platform:"willhaben"}}parseNextData(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)throw new Error("willhaben: __NEXT_DATA__ not found \u2014 page structure may have changed");let s;try{s=JSON.parse(t[1])}catch{throw new Error("willhaben: __NEXT_DATA__ contains invalid JSON")}return s?.props?.pageProps?.searchResult?.advertSummaryList?.advertSummary??[]}extractTotalCount(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)return;let s;try{s=JSON.parse(t[1])}catch{return}return s?.props?.pageProps?.searchResult?.rowsFound}mapAdvert(e){let t=e.attributes?.attribute??[],s=p(o=>t.find(a=>a.name===o)?.values?.[0]??void 0,"attr"),r=s("PRICE"),n=r?parseFloat(r):null;return{id:String(e.id),title:s("HEADING")??e.description??"Kein Titel",price:n,currency:"EUR",condition:s("CONDITION"),location:[s("LOCATION"),s("POSTCODE")].filter(Boolean).join(" "),url:`https://www.willhaben.at/iad/object?adId=${e.id}`,imageUrl:e.advertImageList?.advertImage?.[0]?.mainImageUrl??void 0,seller:s("ORGANIZER")??void 0,publishedAt:s("PUBLISHED_String")??void 0,platform:"willhaben"}}}});var Zr,Wa=T(()=>{"use strict";jo();Zr=class extends Kt{static{p(this,"EbayProvider")}appId;certId;platform="ebay";tokenCache=null;constructor(e,t){super(),this.appId=e,this.certId=t}async getToken(){if(this.tokenCache&&Date.now()<this.tokenCache.expiresAt)return this.tokenCache.token;let e=Buffer.from(`${this.appId}:${this.certId}`).toString("base64"),t=await fetch("https://api.ebay.com/identity/v1/oauth2/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:`Basic ${e}`},body:"grant_type=client_credentials&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope"});if(!t.ok)throw new Error(`eBay OAuth failed: HTTP ${t.status}`);let s=await t.json();return this.tokenCache={token:s.access_token,expiresAt:Date.now()+(s.expires_in-300)*1e3},this.tokenCache.token}async search(e){let t=await this.getToken(),s=Math.min(e.rows??50,200),r=new URL("https://api.ebay.com/buy/browse/v1/item_summary/search");if(r.searchParams.set("q",e.query),r.searchParams.set("limit",String(s)),e.sort){let d={price_asc:"price",price_desc:"-price",date_desc:"newlyListed"};r.searchParams.set("sort",d[e.sort])}let n=[];if(e.priceMin!=null||e.priceMax!=null){let d=e.priceMin!=null?String(e.priceMin):"",u=e.priceMax!=null?String(e.priceMax):"";n.push(`price:[${d}..${u}]`)}e.condition==="new"&&n.push("conditionIds:{1000}"),e.condition==="used"&&n.push("conditionIds:{3000}"),n.length>0&&r.searchParams.set("filter",n.join(","));let o=await fetch(r.toString(),{headers:{Authorization:`Bearer ${t}`,"X-EBAY-C-MARKETPLACE-ID":"EBAY_AT"}});if(!o.ok)throw new Error(`eBay API error: HTTP ${o.status}`);let i=await o.json(),c=(i.itemSummaries??[]).map(d=>({id:d.itemId??d.legacyItemId??"",title:d.title??"",price:d.price?.value?parseFloat(d.price.value):null,currency:d.price?.currency??"EUR",condition:d.condition??d.conditionId??void 0,location:d.itemLocation?.postalCode?`${d.itemLocation.city??""} ${d.itemLocation.postalCode}`.trim():d.itemLocation?.country??void 0,url:d.itemWebUrl??d.itemHref??"",imageUrl:d.image?.imageUrl??d.thumbnailImages?.[0]?.imageUrl??void 0,seller:d.seller?.username??void 0,publishedAt:void 0,platform:"ebay"}));return{listings:c,totalCount:i.total??c.length,query:e.query,platform:"ebay"}}}});function Bo(l){let e=[...l].sort((s,r)=>s-r),t=Math.floor(e.length/2);return e.length%2?e[t]:(e[t-1]+e[t])/2}function za(l,e){return l==null?"k.A.":`${l.toFixed(2)} ${e}`}var Qr,tp=T(()=>{"use strict";B();Ha();Wa();p(Bo,"median");p(za,"formatPrice");Qr=class extends x{static{p(this,"MarketplaceSkill")}metadata={name:"marketplace",category:"information",description:'Marktplatz-Suche auf willhaben.at und eBay. "search" liefert Inseratliste mit Preisstatistik. "compare" liefert Preisvergleich + g\xFCnstigste 5. "detail" zeigt Einzelinserat mit Beschreibung, Fotos, Verk\xE4ufer-Info \u2014 bewerte bei detail immer Seriosit\xE4t (Preis vs. Markt, Account-Alter, Foto-Anzahl, Beschreibungsqualit\xE4t, Zahlungsmethode). Filter: priceMin/priceMax, sort, condition (new/used), postcode. Watch-kompatibel: search\u2192"count"/"minPrice", compare\u2192"minPrice"/"avgPrice".',riskLevel:"read",version:"2.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","compare","detail"],description:"Aktion: search = Inserate auflisten, compare = Preisstatistik, detail = Einzelinserat"},query:{type:"string",description:"Suchbegriff (f\xFCr search/compare)"},platform:{type:"string",enum:["willhaben","ebay","all"],description:"Plattform (default: willhaben)"},priceMin:{type:"number",description:"Mindestpreis EUR"},priceMax:{type:"number",description:"H\xF6chstpreis EUR"},rows:{type:"number",description:"Max Ergebnisse (default 50, max 200)"},sort:{type:"string",enum:["price_asc","price_desc","date_desc"],description:"Sortierung"},condition:{type:"string",enum:["new","used"],description:"Zustand"},postcode:{type:"string",description:'PLZ-Filter (z.B. "1010")'},listing_id:{type:"string",description:"Inserat-ID f\xFCr detail-Aktion"}},required:["action"]}};providers=[];constructor(e){super(),this.providers.push(new Jr),e?.ebay?.appId&&e?.ebay?.certId&&this.providers.push(new Zr(e.ebay.appId,e.ebay.certId))}async execute(e,t){let s=e.action,r=e.platform??"willhaben",n=e.query,o=e.priceMin,i=e.priceMax,a=Math.min(e.rows??50,200),c=e.sort,d=e.condition,u=e.postcode;if(s==="detail"){let f=e.listing_id;return f?this.handleDetail(r,f):{success:!1,error:"listing_id ist erforderlich f\xFCr detail-Aktion"}}if(!n)return{success:!1,error:"query ist erforderlich f\xFCr search/compare"};let m=this.getProviders(r);if(m.length===0)return{success:!1,error:"Keine Marketplace-Provider verf\xFCgbar f\xFCr diese Plattform"};let h={query:n,priceMin:o,priceMax:i,rows:a,sort:c,condition:d,postcode:u};switch(s){case"search":return this.handleSearch(m,h);case"compare":return this.handleCompare(m,{...h,rows:Math.min(a,200)});default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getProviders(e){return e==="all"?this.providers:this.providers.filter(t=>t.platform===e)}async handleSearch(e,t){let s=await this.searchAll(e,t),r=s.flatMap(i=>i.listings);if(r.length===0)return{success:!0,data:{query:t.query,count:0,totalCount:0,minPrice:null,maxPrice:null,medianPrice:null,listings:[]},display:`Keine Inserate gefunden f\xFCr "${t.query}".`};let n=r.map(i=>i.price).filter(i=>i!=null),o=[];o.push(`**${r.length} Inserate** f\xFCr "${t.query}"${s.length>1?` (${s.map(i=>`${i.platform}: ${i.listings.length}`).join(", ")})`:""}
1035
- `),o.push("| # | Titel | Preis | Standort | Plattform | Link |"),o.push("|---|-------|-------|----------|-----------|------|");for(let i=0;i<r.length;i++){let a=r[i],c=a.title.length>60?a.title.slice(0,57)+"...":a.title;o.push(`| ${i+1} | ${c} | ${za(a.price,a.currency)} | ${a.location??"\u2014"} | ${a.platform} | [Link](${a.url}) |`)}return n.length>0&&(o.push(""),o.push(`**Min:** ${Math.min(...n).toFixed(2)} EUR | **Max:** ${Math.max(...n).toFixed(2)} EUR | **Median:** ${Bo(n).toFixed(2)} EUR`)),{success:!0,data:{query:t.query,count:r.length,totalCount:s.reduce((i,a)=>i+a.totalCount,0),minPrice:n.length?Math.min(...n):null,maxPrice:n.length?Math.max(...n):null,medianPrice:n.length?Bo(n):null,listings:r.map(i=>({id:i.id,title:i.title,price:i.price,location:i.location,url:i.url,platform:i.platform}))},display:o.join(`
1034
+ `)}`}}}});var Kt,Bo=T(()=>{"use strict";Kt=class{static{p(this,"MarketplaceProvider")}async getDetail(e){throw new Error("Detail not supported")}}});var ep,Jr,Ha=T(()=>{"use strict";Bo();ep="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",Jr=class extends Kt{static{p(this,"WillhabenProvider")}platform="willhaben";async search(e){let t=Math.min(e.rows??100,100),s=new URL("https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz");if(s.searchParams.set("keyword",e.query),s.searchParams.set("rows",String(t)),e.priceMin!=null&&s.searchParams.set("PRICE_FROM",String(e.priceMin)),e.priceMax!=null&&s.searchParams.set("PRICE_TO",String(e.priceMax)),e.sort){let d={date_desc:"1",price_asc:"2",price_desc:"3"};s.searchParams.set("sfId",d[e.sort])}e.postcode&&s.searchParams.set("postcode",e.postcode);let r=await fetch(s.toString(),{headers:{"User-Agent":ep,Accept:"text/html"}});if(!r.ok)throw new Error(`willhaben HTTP ${r.status}`);let n=await r.text(),i=this.parseNextData(n).map(d=>this.mapAdvert(d)),a=e.query.toLowerCase().split(/\s+/).filter(d=>d.length>=2);return{listings:a.length>0?i.filter(d=>a.every(u=>d.title.toLowerCase().includes(u))):i,totalCount:this.extractTotalCount(n)??i.length,query:e.query,platform:"willhaben"}}async getDetail(e){let t=`https://www.willhaben.at/iad/object?adId=${e}`,s=await fetch(t,{headers:{"User-Agent":ep,Accept:"text/html"},redirect:"follow"});if(!s.ok)throw new Error(`willhaben detail HTTP ${s.status}`);let n=(await s.text()).match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!n)throw new Error("willhaben detail: __NEXT_DATA__ not found");let o;try{o=JSON.parse(n[1])}catch{throw new Error("willhaben detail: __NEXT_DATA__ contains invalid JSON")}let i=o?.props?.pageProps?.advertDetails;if(!i)throw new Error("willhaben detail: advertDetails not found in page data");let a=i.attributes?.attribute??[],c=p($=>a.find(M=>M.name===$)?.values?.[0]??void 0,"attr"),d={};for(let $ of a)$.name&&$.values?.[0]&&(d[$.name]=$.values[0]);let u=i.attributeInformation??[];for(let $ of u){let R=$.treeAttributeElement?.label,M=$.values?.[0]?.label;R&&M&&(d[R]=M)}let m=(i.advertImageList?.advertImage??[]).map($=>$.mainImageUrl??$.referenceImageUrl).filter(Boolean),h=i.advertAddressDetails,f=h?[h.postalName,h.postCode,h.district,h.province].filter(Boolean).join(", "):[c("LOCATION/ADDRESS_2"),c("LOCATION/ADDRESS_3")].filter(Boolean).join(", "),g=i.sellerProfileUserData,_=(c("DESCRIPTION")??i.description??"").replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim(),S=c("PRICE"),E=u.find($=>$.treeAttributeElement?.code==="Zustand")?.values?.[0]?.label;return{id:e,title:i.description??"Kein Titel",price:S?parseFloat(S):null,currency:"EUR",condition:E,location:f,url:s.url||t,imageUrls:m,seller:g?.name??void 0,sellerSince:g?.registerDate??void 0,publishedAt:i.publishedDate??void 0,description:_,attributes:d,platform:"willhaben"}}parseNextData(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)throw new Error("willhaben: __NEXT_DATA__ not found \u2014 page structure may have changed");let s;try{s=JSON.parse(t[1])}catch{throw new Error("willhaben: __NEXT_DATA__ contains invalid JSON")}return s?.props?.pageProps?.searchResult?.advertSummaryList?.advertSummary??[]}extractTotalCount(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)return;let s;try{s=JSON.parse(t[1])}catch{return}return s?.props?.pageProps?.searchResult?.rowsFound}mapAdvert(e){let t=e.attributes?.attribute??[],s=p(o=>t.find(a=>a.name===o)?.values?.[0]??void 0,"attr"),r=s("PRICE"),n=r?parseFloat(r):null;return{id:String(e.id),title:s("HEADING")??e.description??"Kein Titel",price:n,currency:"EUR",condition:s("CONDITION"),location:[s("LOCATION"),s("POSTCODE")].filter(Boolean).join(" "),url:`https://www.willhaben.at/iad/object?adId=${e.id}`,imageUrl:e.advertImageList?.advertImage?.[0]?.mainImageUrl??void 0,seller:s("ORGANIZER")??void 0,publishedAt:s("PUBLISHED_String")??void 0,platform:"willhaben"}}}});var Zr,Wa=T(()=>{"use strict";Bo();Zr=class extends Kt{static{p(this,"EbayProvider")}appId;certId;platform="ebay";tokenCache=null;constructor(e,t){super(),this.appId=e,this.certId=t}async getToken(){if(this.tokenCache&&Date.now()<this.tokenCache.expiresAt)return this.tokenCache.token;let e=Buffer.from(`${this.appId}:${this.certId}`).toString("base64"),t=await fetch("https://api.ebay.com/identity/v1/oauth2/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:`Basic ${e}`},body:"grant_type=client_credentials&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope"});if(!t.ok)throw new Error(`eBay OAuth failed: HTTP ${t.status}`);let s=await t.json();return this.tokenCache={token:s.access_token,expiresAt:Date.now()+(s.expires_in-300)*1e3},this.tokenCache.token}async search(e){let t=await this.getToken(),s=Math.min(e.rows??50,200),r=new URL("https://api.ebay.com/buy/browse/v1/item_summary/search");if(r.searchParams.set("q",e.query),r.searchParams.set("limit",String(s)),e.sort){let d={price_asc:"price",price_desc:"-price",date_desc:"newlyListed"};r.searchParams.set("sort",d[e.sort])}let n=[];if(e.priceMin!=null||e.priceMax!=null){let d=e.priceMin!=null?String(e.priceMin):"",u=e.priceMax!=null?String(e.priceMax):"";n.push(`price:[${d}..${u}]`)}e.condition==="new"&&n.push("conditionIds:{1000}"),e.condition==="used"&&n.push("conditionIds:{3000}"),n.length>0&&r.searchParams.set("filter",n.join(","));let o=await fetch(r.toString(),{headers:{Authorization:`Bearer ${t}`,"X-EBAY-C-MARKETPLACE-ID":"EBAY_AT"}});if(!o.ok)throw new Error(`eBay API error: HTTP ${o.status}`);let i=await o.json(),c=(i.itemSummaries??[]).map(d=>({id:d.itemId??d.legacyItemId??"",title:d.title??"",price:d.price?.value?parseFloat(d.price.value):null,currency:d.price?.currency??"EUR",condition:d.condition??d.conditionId??void 0,location:d.itemLocation?.postalCode?`${d.itemLocation.city??""} ${d.itemLocation.postalCode}`.trim():d.itemLocation?.country??void 0,url:d.itemWebUrl??d.itemHref??"",imageUrl:d.image?.imageUrl??d.thumbnailImages?.[0]?.imageUrl??void 0,seller:d.seller?.username??void 0,publishedAt:void 0,platform:"ebay"}));return{listings:c,totalCount:i.total??c.length,query:e.query,platform:"ebay"}}}});function Ho(l){let e=[...l].sort((s,r)=>s-r),t=Math.floor(e.length/2);return e.length%2?e[t]:(e[t-1]+e[t])/2}function za(l,e){return l==null?"k.A.":`${l.toFixed(2)} ${e}`}var Qr,tp=T(()=>{"use strict";B();Ha();Wa();p(Ho,"median");p(za,"formatPrice");Qr=class extends x{static{p(this,"MarketplaceSkill")}metadata={name:"marketplace",category:"information",description:'Marktplatz-Suche auf willhaben.at und eBay. "search" liefert Inseratliste mit Preisstatistik. "compare" liefert Preisvergleich + g\xFCnstigste 5. "detail" zeigt Einzelinserat mit Beschreibung, Fotos, Verk\xE4ufer-Info \u2014 bewerte bei detail immer Seriosit\xE4t (Preis vs. Markt, Account-Alter, Foto-Anzahl, Beschreibungsqualit\xE4t, Zahlungsmethode). Filter: priceMin/priceMax, sort, condition (new/used), postcode. Watch-kompatibel: search\u2192"count"/"minPrice", compare\u2192"minPrice"/"avgPrice".',riskLevel:"read",version:"2.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","compare","detail"],description:"Aktion: search = Inserate auflisten, compare = Preisstatistik, detail = Einzelinserat"},query:{type:"string",description:"Suchbegriff (f\xFCr search/compare)"},platform:{type:"string",enum:["willhaben","ebay","all"],description:"Plattform (default: willhaben)"},priceMin:{type:"number",description:"Mindestpreis EUR"},priceMax:{type:"number",description:"H\xF6chstpreis EUR"},rows:{type:"number",description:"Max Ergebnisse (default 50, max 200)"},sort:{type:"string",enum:["price_asc","price_desc","date_desc"],description:"Sortierung"},condition:{type:"string",enum:["new","used"],description:"Zustand"},postcode:{type:"string",description:'PLZ-Filter (z.B. "1010")'},listing_id:{type:"string",description:"Inserat-ID f\xFCr detail-Aktion"}},required:["action"]}};providers=[];constructor(e){super(),this.providers.push(new Jr),e?.ebay?.appId&&e?.ebay?.certId&&this.providers.push(new Zr(e.ebay.appId,e.ebay.certId))}async execute(e,t){let s=e.action,r=e.platform??"willhaben",n=e.query,o=e.priceMin,i=e.priceMax,a=Math.min(e.rows??50,200),c=e.sort,d=e.condition,u=e.postcode;if(s==="detail"){let f=e.listing_id;return f?this.handleDetail(r,f):{success:!1,error:"listing_id ist erforderlich f\xFCr detail-Aktion"}}if(!n)return{success:!1,error:"query ist erforderlich f\xFCr search/compare"};let m=this.getProviders(r);if(m.length===0)return{success:!1,error:"Keine Marketplace-Provider verf\xFCgbar f\xFCr diese Plattform"};let h={query:n,priceMin:o,priceMax:i,rows:a,sort:c,condition:d,postcode:u};switch(s){case"search":return this.handleSearch(m,h);case"compare":return this.handleCompare(m,{...h,rows:Math.min(a,200)});default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getProviders(e){return e==="all"?this.providers:this.providers.filter(t=>t.platform===e)}async handleSearch(e,t){let s=await this.searchAll(e,t),r=s.flatMap(i=>i.listings);if(r.length===0)return{success:!0,data:{query:t.query,count:0,totalCount:0,minPrice:null,maxPrice:null,medianPrice:null,listings:[]},display:`Keine Inserate gefunden f\xFCr "${t.query}".`};let n=r.map(i=>i.price).filter(i=>i!=null),o=[];o.push(`**${r.length} Inserate** f\xFCr "${t.query}"${s.length>1?` (${s.map(i=>`${i.platform}: ${i.listings.length}`).join(", ")})`:""}
1035
+ `),o.push("| # | Titel | Preis | Standort | Plattform | Link |"),o.push("|---|-------|-------|----------|-----------|------|");for(let i=0;i<r.length;i++){let a=r[i],c=a.title.length>60?a.title.slice(0,57)+"...":a.title;o.push(`| ${i+1} | ${c} | ${za(a.price,a.currency)} | ${a.location??"\u2014"} | ${a.platform} | [Link](${a.url}) |`)}return n.length>0&&(o.push(""),o.push(`**Min:** ${Math.min(...n).toFixed(2)} EUR | **Max:** ${Math.max(...n).toFixed(2)} EUR | **Median:** ${Ho(n).toFixed(2)} EUR`)),{success:!0,data:{query:t.query,count:r.length,totalCount:s.reduce((i,a)=>i+a.totalCount,0),minPrice:n.length?Math.min(...n):null,maxPrice:n.length?Math.max(...n):null,medianPrice:n.length?Ho(n):null,listings:r.map(i=>({id:i.id,title:i.title,price:i.price,location:i.location,url:i.url,platform:i.platform}))},display:o.join(`
1036
1036
  `)}}async handleCompare(e,t){let r=(await this.searchAll(e,t)).flatMap(d=>d.listings),n=r.map(d=>d.price).filter(d=>d!=null);if(n.length===0)return{success:!0,data:{query:t.query,count:0,minPrice:null,maxPrice:null,medianPrice:null,avgPrice:null,cheapest:[]},display:`Keine Inserate mit Preisangabe gefunden f\xFCr "${t.query}".`};let i=r.filter(d=>d.price!=null).sort((d,u)=>d.price-u.price).slice(0,5),a=n.reduce((d,u)=>d+u,0)/n.length,c=[];c.push(`**Preisvergleich** "${t.query}" \u2014 ${r.length} Inserate (${n.length} mit Preis)
1037
- `),c.push("| Statistik | Wert |"),c.push("|-----------|------|"),c.push(`| Anzahl | ${n.length} |`),c.push(`| Minimum | ${Math.min(...n).toFixed(2)} EUR |`),c.push(`| Maximum | ${Math.max(...n).toFixed(2)} EUR |`),c.push(`| Median | ${Bo(n).toFixed(2)} EUR |`),c.push(`| Durchschnitt | ${a.toFixed(2)} EUR |`),c.push(""),c.push(`**G\xFCnstigste 5:**
1038
- `),c.push("| # | Titel | Preis | Standort | Plattform | Link |"),c.push("|---|-------|-------|----------|-----------|------|");for(let d=0;d<i.length;d++){let u=i[d],m=u.title.length>60?u.title.slice(0,57)+"...":u.title;c.push(`| ${d+1} | ${m} | ${za(u.price,u.currency)} | ${u.location??"\u2014"} | ${u.platform} | [Link](${u.url}) |`)}return{success:!0,data:{query:t.query,count:n.length,minPrice:Math.min(...n),maxPrice:Math.max(...n),medianPrice:Bo(n),avgPrice:a,cheapest:i.map(d=>({id:d.id,title:d.title,price:d.price,location:d.location,url:d.url,platform:d.platform}))},display:c.join(`
1037
+ `),c.push("| Statistik | Wert |"),c.push("|-----------|------|"),c.push(`| Anzahl | ${n.length} |`),c.push(`| Minimum | ${Math.min(...n).toFixed(2)} EUR |`),c.push(`| Maximum | ${Math.max(...n).toFixed(2)} EUR |`),c.push(`| Median | ${Ho(n).toFixed(2)} EUR |`),c.push(`| Durchschnitt | ${a.toFixed(2)} EUR |`),c.push(""),c.push(`**G\xFCnstigste 5:**
1038
+ `),c.push("| # | Titel | Preis | Standort | Plattform | Link |"),c.push("|---|-------|-------|----------|-----------|------|");for(let d=0;d<i.length;d++){let u=i[d],m=u.title.length>60?u.title.slice(0,57)+"...":u.title;c.push(`| ${d+1} | ${m} | ${za(u.price,u.currency)} | ${u.location??"\u2014"} | ${u.platform} | [Link](${u.url}) |`)}return{success:!0,data:{query:t.query,count:n.length,minPrice:Math.min(...n),maxPrice:Math.max(...n),medianPrice:Ho(n),avgPrice:a,cheapest:i.map(d=>({id:d.id,title:d.title,price:d.price,location:d.location,url:d.url,platform:d.platform}))},display:c.join(`
1039
1039
  `)}}async handleDetail(e,t){let r=(e==="all"?this.providers:this.providers.filter(c=>c.platform===e))[0];if(!r)return{success:!1,error:"Kein Provider verf\xFCgbar f\xFCr diese Plattform"};let n=await r.getDetail(t),o=[];o.push(`**${n.title}** \u2014 ${za(n.price,n.currency)}`),o.push(`\u{1F4CD} ${n.location??"k.A."}`),n.condition&&o.push(`Zustand: ${n.condition}`),o.push(`Verk\xE4ufer: ${n.seller??"k.A."}${n.sellerSince?` (registriert seit ${n.sellerSince.split("T")[0]})`:""}`),o.push(`Fotos: ${n.imageUrls.length}`),n.publishedAt&&o.push(`Ver\xF6ffentlicht: ${n.publishedAt.split("T")[0]}`);let i=new Set(["DESCRIPTION","PRICE","PRICE/AMOUNT","PRICE_FOR_DISPLAY","AREA_ID","REGION_AREA_ID","SHOW_MAP","SHOW_SHADOWMAP","ISPRIVATE","DEALER","ORG_TYPE","LOCATION/ADDRESS_2","LOCATION/ADDRESS_3","LOCATION/ADDRESS_4"]),a=Object.entries(n.attributes).filter(([c])=>!i.has(c));return a.length>0&&o.push(`Attribute: ${a.map(([c,d])=>`${c}=${d}`).join(", ")}`),o.push(`
1040
1040
  ${n.description.slice(0,500)}`),o.push(`
1041
1041
  Link: ${n.url}`),{success:!0,data:{id:n.id,title:n.title,price:n.price,currency:n.currency,condition:n.condition,location:n.location,url:n.url,description:n.description.slice(0,1e3),imageCount:n.imageUrls.length,imageUrls:n.imageUrls.slice(0,3),seller:n.seller,sellerSince:n.sellerSince,publishedAt:n.publishedAt,attributes:n.attributes,platform:n.platform},display:o.join(`
1042
- `)}}async searchAll(e,t){return await Promise.all(e.map(r=>r.search(t).catch(n=>({listings:[],totalCount:0,query:t.query,platform:r.platform,error:String(n)}))))}}});var sp=T(()=>{"use strict";tp();jo();Ha();Wa()});function Bf(){let l=new Date,e=new Date(l.getFullYear(),l.getMonth(),l.getDate()),t=new Date(e.getTime()+1440*60*1e3);return{start:e.toISOString(),end:t.toISOString()}}function Hf(l){let e=l.split(",").map(s=>s.trim());for(let s of e){let r=s.match(/^\d{4,5}\s+(.+)/);if(r)return r[1].trim()}return e.length>=3?e[e.length-2]:e[e.length-1]}function Wf(){let l=new Date().getDay();return l>=1&&l<=5}var qa,Ho,rp=T(()=>{"use strict";B();Oe();p(Bf,"todayRange");qa=[{name:"calendar",skill:"calendar",input:{action:"list_events"},label:"Kalender"},{name:"weather",skill:"weather",input:{},label:"Wetter"},{name:"todo",skill:"todo",input:{action:"list"},label:"Lokale Todos"},{name:"mstodo",skill:"microsoft_todo",input:{action:"list_tasks"},label:"Microsoft To Do"},{name:"email",skill:"email",input:{action:"inbox"},label:"E-Mail"},{name:"energy",skill:"energy_price",input:{action:"briefing"},label:"Strompreise"},{name:"bmw",skill:"bmw",input:{action:"status"},label:"BMW Status"},{name:"home",skill:"homeassistant",input:{action:"briefing_summary"},label:"Smart Home"},{name:"infra",skill:"monitor",input:{},label:"Infrastruktur"}];p(Hf,"extractCity");p(Wf,"isWeekday");Ho=class extends x{static{p(this,"BriefingSkill")}skillRegistry;alfredConfig;memoryRepo;metadata={name:"briefing",category:"productivity",description:'T\xE4gliches Morgenbriefing \u2014 sammelt Daten aus mehreren Skills parallel und liefert ein strukturiertes Ergebnis: Kalender, Wetter, Todos, E-Mails, Strompreise, Auto-Status, Smart Home, Infrastruktur. Mo\u2013Fr automatisch: Pendelzeit Heim\u2192B\xFCro + BMW-Akkucheck (wenn kein ausw\xE4rtiger Termin). "run" f\xFChrt das Briefing aus (optional mit location f\xFCr Wetter). "modules" zeigt verf\xFCgbare und aktive Module.',riskLevel:"read",version:"1.1.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","modules"],description:"run = Briefing ausf\xFChren, modules = verf\xFCgbare Module anzeigen"},location:{type:"string",description:'Ort f\xFCr Wetterabfrage (default: aus Config oder "Vienna")'},modules:{type:"array",items:{type:"string"},description:"Optionale Liste aktiver Module (default: alle verf\xFCgbaren)"}},required:["action"]}};constructor(e,t,s){super(),this.skillRegistry=e,this.alfredConfig=t,this.memoryRepo=s}async execute(e,t){let s=e.action??"run";switch(s){case"run":return this.runBriefing(e,t);case"modules":return this.showModules();default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getAvailableModules(){return qa.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=qa.map(n=>`${e.some(i=>i.name===n.name)?"\u2705":"\u274C"} ${n.name} (${n.label}) \u2192 ${n.skill}`),s=this.skillRegistry.has("routing"),r=!!(this.alfredConfig.briefing?.homeAddress&&this.alfredConfig.briefing?.officeAddress);return{success:!0,data:{available:e.map(n=>n.name),all:qa.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
1042
+ `)}}async searchAll(e,t){return await Promise.all(e.map(r=>r.search(t).catch(n=>({listings:[],totalCount:0,query:t.query,platform:r.platform,error:String(n)}))))}}});var sp=T(()=>{"use strict";tp();Bo();Ha();Wa()});function Bf(){let l=new Date,e=new Date(l.getFullYear(),l.getMonth(),l.getDate()),t=new Date(e.getTime()+1440*60*1e3);return{start:e.toISOString(),end:t.toISOString()}}function Hf(l){let e=l.split(",").map(s=>s.trim());for(let s of e){let r=s.match(/^\d{4,5}\s+(.+)/);if(r)return r[1].trim()}return e.length>=3?e[e.length-2]:e[e.length-1]}function Wf(){let l=new Date().getDay();return l>=1&&l<=5}var qa,Wo,rp=T(()=>{"use strict";B();Oe();p(Bf,"todayRange");qa=[{name:"calendar",skill:"calendar",input:{action:"list_events"},label:"Kalender"},{name:"weather",skill:"weather",input:{},label:"Wetter"},{name:"todo",skill:"todo",input:{action:"list"},label:"Lokale Todos"},{name:"mstodo",skill:"microsoft_todo",input:{action:"list_tasks"},label:"Microsoft To Do"},{name:"email",skill:"email",input:{action:"inbox"},label:"E-Mail"},{name:"energy",skill:"energy_price",input:{action:"briefing"},label:"Strompreise"},{name:"bmw",skill:"bmw",input:{action:"status"},label:"BMW Status"},{name:"home",skill:"homeassistant",input:{action:"briefing_summary"},label:"Smart Home"},{name:"infra",skill:"monitor",input:{},label:"Infrastruktur"}];p(Hf,"extractCity");p(Wf,"isWeekday");Wo=class extends x{static{p(this,"BriefingSkill")}skillRegistry;alfredConfig;memoryRepo;metadata={name:"briefing",category:"productivity",description:'T\xE4gliches Morgenbriefing \u2014 sammelt Daten aus mehreren Skills parallel und liefert ein strukturiertes Ergebnis: Kalender, Wetter, Todos, E-Mails, Strompreise, Auto-Status, Smart Home, Infrastruktur. Mo\u2013Fr automatisch: Pendelzeit Heim\u2192B\xFCro + BMW-Akkucheck (wenn kein ausw\xE4rtiger Termin). "run" f\xFChrt das Briefing aus (optional mit location f\xFCr Wetter). "modules" zeigt verf\xFCgbare und aktive Module.',riskLevel:"read",version:"1.1.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","modules"],description:"run = Briefing ausf\xFChren, modules = verf\xFCgbare Module anzeigen"},location:{type:"string",description:'Ort f\xFCr Wetterabfrage (default: aus Config oder "Vienna")'},modules:{type:"array",items:{type:"string"},description:"Optionale Liste aktiver Module (default: alle verf\xFCgbaren)"}},required:["action"]}};constructor(e,t,s){super(),this.skillRegistry=e,this.alfredConfig=t,this.memoryRepo=s}async execute(e,t){let s=e.action??"run";switch(s){case"run":return this.runBriefing(e,t);case"modules":return this.showModules();default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getAvailableModules(){return qa.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=qa.map(n=>`${e.some(i=>i.name===n.name)?"\u2705":"\u274C"} ${n.name} (${n.label}) \u2192 ${n.skill}`),s=this.skillRegistry.has("routing"),r=!!(this.alfredConfig.briefing?.homeAddress&&this.alfredConfig.briefing?.officeAddress);return{success:!0,data:{available:e.map(n=>n.name),all:qa.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
1043
1043
  ${t.join(`
1044
1044
  `)}
1045
1045
 
@@ -1068,19 +1068,19 @@ ${d.join(`
1068
1068
  `)}`:"No new entries in any feed."}}let s=this.memoryRepo.listByCategory(e,"feed").find(i=>i.key===`feed:${t}`);if(!s)return{success:!1,error:`Not subscribed to ${t}. Use subscribe first.`};let r=JSON.parse(s.value),n=await this.checkSingleFeed(e,r),o=n.items.map(i=>`\u2022 ${i.title}${i.link?` \u2014 ${i.link}`:""}${i.snippet?`
1069
1069
  ${i.snippet}`:""}`);return{success:!0,data:{newCount:n.newCount,items:n.items},display:n.newCount>0?`${n.newCount} new in ${n.label}:
1070
1070
  ${o.join(`
1071
- `)}`:`No new entries in ${n.label}.`}}async checkSingleFeed(e,t){let s=(await import("rss-parser")).default,o=(await new s({timeout:15e3}).parseURL(t.url)).items??[],i;if(t.lastEntryId){let d=o.findIndex(u=>(u.guid??u.link??u.title)===t.lastEntryId);i=d>0?o.slice(0,d):d===0?[]:o.slice(0,10)}else i=o.slice(0,5);let a=o[0]?o[0].guid??o[0].link??o[0].title??null:null,c={...t,lastCheckedAt:new Date().toISOString(),lastEntryId:a};return this.memoryRepo.save(e,`feed:${t.url}`,JSON.stringify(c),"feed"),{label:t.label,newCount:i.length,items:i.map(d=>{let u=d.contentSnippet??d.summary??"";return!u&&typeof d.content=="string"&&(u=d.content.replace(/<[^>]*>/g,"").slice(0,200)),{title:d.title??"(untitled)",link:d.link,pubDate:d.pubDate,snippet:u?u.slice(0,200).trim():void 0}})}}}});var Wo,zo,qo,op=T(()=>{"use strict";B();Wo="https://www.googleapis.com/youtube/v3",zo=15e3,qo=class extends x{static{p(this,"YouTubeSkill")}config;metadata={name:"youtube",category:"information",description:`YouTube video search, info, transcripts, and summaries.
1071
+ `)}`:`No new entries in ${n.label}.`}}async checkSingleFeed(e,t){let s=(await import("rss-parser")).default,o=(await new s({timeout:15e3}).parseURL(t.url)).items??[],i;if(t.lastEntryId){let d=o.findIndex(u=>(u.guid??u.link??u.title)===t.lastEntryId);i=d>0?o.slice(0,d):d===0?[]:o.slice(0,10)}else i=o.slice(0,5);let a=o[0]?o[0].guid??o[0].link??o[0].title??null:null,c={...t,lastCheckedAt:new Date().toISOString(),lastEntryId:a};return this.memoryRepo.save(e,`feed:${t.url}`,JSON.stringify(c),"feed"),{label:t.label,newCount:i.length,items:i.map(d=>{let u=d.contentSnippet??d.summary??"";return!u&&typeof d.content=="string"&&(u=d.content.replace(/<[^>]*>/g,"").slice(0,200)),{title:d.title??"(untitled)",link:d.link,pubDate:d.pubDate,snippet:u?u.slice(0,200).trim():void 0}})}}}});var en,zo,qo,op=T(()=>{"use strict";B();en="https://www.googleapis.com/youtube/v3",zo=15e3,qo=class extends x{static{p(this,"YouTubeSkill")}config;metadata={name:"youtube",category:"information",description:`YouTube video search, info, transcripts, and summaries.
1072
1072
  Actions:
1073
1073
  - search: Search YouTube videos. Params: query, maxResults (default 5)
1074
1074
  - info: Get video details. Params: videoId or url
1075
1075
  - transcript: Get video transcript with timestamps. Params: videoId or url, lang (optional, default "de")
1076
1076
  - channel: Get latest videos from a channel. Params: channelId or channelName, maxResults (default 5)
1077
- Watch-compatible: channel action returns "newCount" for new video alerts.`,riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","info","transcript","channel"],description:"YouTube action"},query:{type:"string",description:"Search query (for search)"},videoId:{type:"string",description:"YouTube video ID or URL (for info/transcript)"},url:{type:"string",description:"YouTube video URL (alternative to videoId)"},channelId:{type:"string",description:"Channel ID (for channel)"},channelName:{type:"string",description:"Channel name to search for (for channel)"},maxResults:{type:"number",description:"Max results (default 5)"},lang:{type:"string",description:'Transcript language (default "de", fallback "en")'}},required:["action"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;switch(s){case"search":return this.search(e);case"info":return this.videoInfo(e);case"transcript":return this.transcript(e);case"channel":return this.channelVideos(e);default:return{success:!1,error:`Unknown action "${s}". Use search, info, transcript, or channel.`}}}extractVideoId(e){let t=e.videoId,s=e.url;if(t&&!t.includes("/"))return t;let r=t??s;if(!r)return null;let n=[/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/)([a-zA-Z0-9_-]{11})/,/^([a-zA-Z0-9_-]{11})$/];for(let o of n){let i=o.exec(r);if(i)return i[1]}return null}async search(e){let t=e.query;if(!t)return{success:!1,error:'Missing "query"'};let s=Math.min(e.maxResults??5,20),r=new URLSearchParams({part:"snippet",q:t,type:"video",maxResults:String(s),key:this.config.apiKey}),n=await fetch(`${Wo}/search?${r}`);if(!n.ok)return{success:!1,error:`YouTube API: ${n.status} ${n.statusText}`};let i=((await n.json()).items??[]).map(c=>({videoId:c.id.videoId,title:c.snippet.title,channel:c.snippet.channelTitle,publishedAt:c.snippet.publishedAt?.slice(0,10),url:`https://youtube.com/watch?v=${c.id.videoId}`,thumbnail:c.snippet.thumbnails?.medium?.url})),a=i.map((c,d)=>`${d+1}. **${c.title}**
1077
+ Watch-compatible: channel action returns "newCount" for new video alerts.`,riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","info","transcript","channel"],description:"YouTube action"},query:{type:"string",description:"Search query (for search)"},videoId:{type:"string",description:"YouTube video ID or URL (for info/transcript)"},url:{type:"string",description:"YouTube video URL (alternative to videoId)"},channelId:{type:"string",description:"Channel ID (for channel)"},channelName:{type:"string",description:"Channel name to search for (for channel)"},maxResults:{type:"number",description:"Max results (default 5)"},lang:{type:"string",description:'Transcript language (default "de", fallback "en")'}},required:["action"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if((s==="info"||s==="transcript")&&!this.extractVideoId(e)){let r=e.url??e.videoId??"";if(r.includes("@")||r.includes("/channel/")||r.includes("/c/")||r.includes("/user/"))return this.channelVideos({...e,action:"channel",channelName:r})}switch(s){case"search":return this.search(e);case"info":return this.videoInfo(e);case"transcript":return this.transcript(e);case"channel":return this.channelVideos(e);default:return{success:!1,error:`Unknown action "${s}". Use search, info, transcript, or channel.`}}}extractVideoId(e){let t=e.videoId,s=e.url;if(t&&!t.includes("/"))return t;let r=t??s;if(!r)return null;let n=[/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/)([a-zA-Z0-9_-]{11})/,/^([a-zA-Z0-9_-]{11})$/];for(let o of n){let i=o.exec(r);if(i)return i[1]}return null}async search(e){let t=e.query;if(!t)return{success:!1,error:'Missing "query"'};let s=Math.min(e.maxResults??5,20),r=new URLSearchParams({part:"snippet",q:t,type:"video",maxResults:String(s),key:this.config.apiKey}),n=await fetch(`${en}/search?${r}`);if(!n.ok)return{success:!1,error:`YouTube API: ${n.status} ${n.statusText}`};let i=((await n.json()).items??[]).map(c=>({videoId:c.id.videoId,title:c.snippet.title,channel:c.snippet.channelTitle,publishedAt:c.snippet.publishedAt?.slice(0,10),url:`https://youtube.com/watch?v=${c.id.videoId}`,thumbnail:c.snippet.thumbnails?.medium?.url})),a=i.map((c,d)=>`${d+1}. **${c.title}**
1078
1078
  ${c.channel} \u2022 ${c.publishedAt}
1079
1079
  ${c.url}`).join(`
1080
1080
 
1081
1081
  `);return{success:!0,data:{count:i.length,videos:i},display:`**YouTube Suche: "${t}"** (${i.length} Ergebnisse)
1082
1082
 
1083
- ${a}`}}async videoInfo(e){let t=this.extractVideoId(e);if(!t)return{success:!1,error:'Missing "videoId" or "url"'};let s=new URLSearchParams({part:"snippet,statistics,contentDetails",id:t,key:this.config.apiKey}),r=await fetch(`${Wo}/videos?${s}`);if(!r.ok)return{success:!1,error:`YouTube API: ${r.status}`};let o=(await r.json()).items?.[0];if(!o)return{success:!1,error:`Video ${t} not found`};let i=this.parseDuration(o.contentDetails.duration),a={videoId:t,title:o.snippet.title,channel:o.snippet.channelTitle,publishedAt:o.snippet.publishedAt?.slice(0,10),description:o.snippet.description?.slice(0,500),duration:i,views:parseInt(o.statistics.viewCount??"0",10),likes:parseInt(o.statistics.likeCount??"0",10),comments:parseInt(o.statistics.commentCount??"0",10),url:`https://youtube.com/watch?v=${t}`};return{success:!0,data:a,display:`**${a.title}**
1083
+ ${a}`}}async videoInfo(e){let t=this.extractVideoId(e);if(!t)return{success:!1,error:'Missing "videoId" or "url"'};let s=new URLSearchParams({part:"snippet,statistics,contentDetails",id:t,key:this.config.apiKey}),r=await fetch(`${en}/videos?${s}`);if(!r.ok)return{success:!1,error:`YouTube API: ${r.status}`};let o=(await r.json()).items?.[0];if(!o)return{success:!1,error:`Video ${t} not found`};let i=this.parseDuration(o.contentDetails.duration),a={videoId:t,title:o.snippet.title,channel:o.snippet.channelTitle,publishedAt:o.snippet.publishedAt?.slice(0,10),description:o.snippet.description?.slice(0,500),duration:i,views:parseInt(o.statistics.viewCount??"0",10),likes:parseInt(o.statistics.likeCount??"0",10),comments:parseInt(o.statistics.commentCount??"0",10),url:`https://youtube.com/watch?v=${t}`};return{success:!0,data:a,display:`**${a.title}**
1084
1084
  ${a.channel} \u2022 ${a.publishedAt} \u2022 ${a.duration}
1085
1085
  ${a.views.toLocaleString("de-DE")} Views \u2022 ${a.likes.toLocaleString("de-DE")} Likes
1086
1086
  ${a.url}
@@ -1089,16 +1089,16 @@ ${a.description}`}}async transcript(e){let t=this.extractVideoId(e);if(!t)return
1089
1089
 
1090
1090
  ${o}`}}}catch{}if(this.config.supadata?.enabled&&this.config.supadata.apiKey)try{let r=await this.fetchTranscriptSupadata(t,s);if(r){let n=r.length>zo?r.slice(0,zo)+"...":r;return{success:!0,data:{videoId:t,lang:s,charCount:r.length,source:"supadata",transcript:n},display:`**Transkript** (${t}, via Supadata)
1091
1091
 
1092
- ${n}`}}}catch{}return{success:!1,error:`No transcript available for video ${t} (lang: ${s})`}}async fetchTranscriptSelfHosted(e,t){try{let{YoutubeTranscript:s}=await Function('return import("youtube-transcript")')(),r=await s.fetchTranscript(e,{lang:t});if(r&&r.length>0)return r.map(n=>({text:n.text,offset:n.offset,duration:n.duration}))}catch{if(t!=="en")try{let{YoutubeTranscript:s}=await Function('return import("youtube-transcript")')(),r=await s.fetchTranscript(e,{lang:"en"});if(r&&r.length>0)return r.map(n=>({text:n.text,offset:n.offset,duration:n.duration}))}catch{}}return null}async fetchTranscriptSupadata(e,t){let s=await fetch(`https://api.supadata.ai/v1/youtube/transcript?videoId=${e}&lang=${t}`,{headers:{"x-api-key":this.config.supadata.apiKey}});if(!s.ok)return null;let r=await s.json();return r.transcript?r.transcript:r.content?r.content.map(n=>n.text).join(" "):null}async channelVideos(e){let t=e.channelId,s=e.channelName,r=Math.min(e.maxResults??5,20);if(!t&&s){let u=new URLSearchParams({part:"snippet",q:s,type:"channel",maxResults:"1",key:this.config.apiKey}),m=await fetch(`${Wo}/search?${u}`);m.ok&&(t=(await m.json()).items?.[0]?.id?.channelId)}if(!t)return{success:!1,error:'Missing "channelId" or "channelName"'};let n=new URLSearchParams({part:"snippet",channelId:t,type:"video",order:"date",maxResults:String(r),key:this.config.apiKey}),o=await fetch(`${Wo}/search?${n}`);if(!o.ok)return{success:!1,error:`YouTube API: ${o.status}`};let i=await o.json(),a=(i.items??[]).map(u=>({videoId:u.id.videoId,title:u.snippet.title,publishedAt:u.snippet.publishedAt?.slice(0,10),url:`https://youtube.com/watch?v=${u.id.videoId}`})),c=i.items?.[0]?.snippet?.channelTitle??s??t,d=a.map((u,m)=>`${m+1}. **${u.title}** (${u.publishedAt})
1093
- ${u.url}`).join(`
1092
+ ${n}`}}}catch{}return{success:!1,error:`No transcript available for video ${t} (lang: ${s})`}}async fetchTranscriptSelfHosted(e,t){try{let r=await(await Function('return import("youtube-transcript/dist/youtube-transcript.esm.js")')()).fetchTranscript(e,{lang:t});if(r&&r.length>0)return r.map(n=>({text:n.text,offset:n.offset,duration:n.duration}))}catch{if(t!=="en")try{let r=await(await Function('return import("youtube-transcript/dist/youtube-transcript.esm.js")')()).fetchTranscript(e,{lang:"en"});if(r&&r.length>0)return r.map(n=>({text:n.text,offset:n.offset,duration:n.duration}))}catch{}}return null}async fetchTranscriptSupadata(e,t){let s=await fetch(`https://api.supadata.ai/v1/youtube/transcript?videoId=${e}&lang=${t}`,{headers:{"x-api-key":this.config.supadata.apiKey}});if(!s.ok)return null;let r=await s.json();return r.transcript?r.transcript:r.content?r.content.map(n=>n.text).join(" "):null}async channelVideos(e){let t=e.channelId,s=e.channelName,r=Math.min(e.maxResults??5,20),n=s??t??"",o=/@([\w.-]+)/.exec(n),i=/(?:channel\/)(UC[\w-]{22})/.exec(n);if(i&&(t=i[1]),!t&&o){let f=new URLSearchParams({part:"snippet",forHandle:o[1],key:this.config.apiKey}),g=await fetch(`${en}/channels?${f}`);g.ok&&(t=(await g.json()).items?.[0]?.id)}if(!t&&s){let f=s.replace(/^@/,"").replace(/https?:\/\/.*youtube\.com\//,""),g=new URLSearchParams({part:"snippet",q:f,type:"channel",maxResults:"1",key:this.config.apiKey}),y=await fetch(`${en}/search?${g}`);y.ok&&(t=(await y.json()).items?.[0]?.id?.channelId)}if(!t)return{success:!1,error:`Could not resolve channel "${s??t}". Try a channel ID (starts with UC) or handle (@name).`};let a=new URLSearchParams({part:"snippet",channelId:t,type:"video",order:"date",maxResults:String(r),key:this.config.apiKey}),c=await fetch(`${en}/search?${a}`);if(!c.ok)return{success:!1,error:`YouTube API: ${c.status}`};let d=await c.json(),u=(d.items??[]).map(f=>({videoId:f.id.videoId,title:f.snippet.title,publishedAt:f.snippet.publishedAt?.slice(0,10),url:`https://youtube.com/watch?v=${f.id.videoId}`})),m=d.items?.[0]?.snippet?.channelTitle??s??t,h=u.map((f,g)=>`${g+1}. **${f.title}** (${f.publishedAt})
1093
+ ${f.url}`).join(`
1094
1094
 
1095
- `);return{success:!0,data:{channelId:t,channelName:c,count:a.length,newCount:a.length,videos:a},display:`**${c}** \u2014 letzte ${a.length} Videos
1095
+ `);return{success:!0,data:{channelId:t,channelName:m,count:u.length,newCount:u.length,videos:u},display:`**${m}** \u2014 letzte ${u.length} Videos
1096
1096
 
1097
- ${d}`}}parseDuration(e){let t=/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/.exec(e??"");if(!t)return e??"";let s=t[1]?`${t[1]}:`:"",r=(t[2]??"0").padStart(s?2:1,"0"),n=(t[3]??"0").padStart(2,"0");return`${s}${r}:${n}`}}});import{spawn as zf}from"node:child_process";import ip from"node:fs";import lp from"node:path";function Xf(l){let e={};for(let[t,s]of Object.entries(l))e[t]=s.replace(/\$\{(\w+)\}/g,(r,n)=>process.env[n]??"");return e}function Vf(l,e){return l.map(t=>t.replace(/\{\{prompt\}\}/g,e))}function Go(l){return l.length<=ap?l:`[...truncated...]
1097
+ ${h}`}}parseDuration(e){let t=/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/.exec(e??"");if(!t)return e??"";let s=t[1]?`${t[1]}:`:"",r=(t[2]??"0").padStart(s?2:1,"0"),n=(t[3]??"0").padStart(2,"0");return`${s}${r}:${n}`}}});import{spawn as zf}from"node:child_process";import ip from"node:fs";import lp from"node:path";function Xf(l){let e={};for(let[t,s]of Object.entries(l))e[t]=s.replace(/\$\{(\w+)\}/g,(r,n)=>process.env[n]??"");return e}function Vf(l,e){return l.map(t=>t.replace(/\{\{prompt\}\}/g,e))}function Go(l){return l.length<=ap?l:`[...truncated...]
1098
1098
  `+l.slice(-ap)}function cp(l){let e=new Map;function t(s){let r;try{r=ip.readdirSync(s,{withFileTypes:!0})}catch{return}for(let n of r){if(Kf.has(n.name))continue;let o=lp.join(s,n.name);if(n.isDirectory())t(o);else if(n.isFile())try{let i=ip.statSync(o);e.set(o,i.mtimeMs)}catch{}}}return p(t,"walk"),t(l),e}function Yf(l,e,t){let s=[];for(let[r,n]of e){let o=l.get(r);(o===void 0||n>o)&&s.push(lp.relative(t,r))}return s.sort()}async function Ze(l,e,t={}){let s=t.cwd??l.cwd??process.cwd(),r=t.timeoutMs??l.timeoutMs??qf,n=Math.min(r,Gf),o=Vf(l.argsTemplate,e),i={...process.env,...l.env?Xf(l.env):{}},a=process.platform==="win32",c=cp(s),d=Date.now();return new Promise(u=>{let m=zf(l.command,o,{cwd:s,env:i,shell:a,stdio:l.promptVia==="stdin"?["pipe","pipe","pipe"]:["ignore","pipe","pipe"]}),h="",f="",g=!1,y=setTimeout(()=>{g=!0,m.kill("SIGTERM"),setTimeout(()=>m.kill("SIGKILL"),5e3)},n);m.stdout?.on("data",_=>{h+=_.toString()}),m.stderr?.on("data",_=>{let S=_.toString();if(f+=S,t.onProgress){let E=S.trim().split(`
1099
1099
  `).pop();E&&t.onProgress(`[${l.name}] ${E}`)}}),l.promptVia==="stdin"&&m.stdin&&(m.stdin.write(e),m.stdin.end()),m.on("close",_=>{clearTimeout(y);let S=Date.now()-d,E=cp(s),$=Yf(c,E,s);u({stdout:Go(h),stderr:Go(f),exitCode:g?124:_??1,durationMs:S,modifiedFiles:$})}),m.on("error",_=>{clearTimeout(y);let S=Date.now()-d;u({stdout:Go(h),stderr:Go(f+`
1100
1100
  `+_.message),exitCode:127,durationMs:S,modifiedFiles:[]})})})}var qf,Gf,ap,Kf,Ko=T(()=>{"use strict";qf=3e5,Gf=9e5,ap=1e5,Kf=new Set([".git","node_modules",".next","dist",".cache"]);p(Xf,"resolveEnv");p(Vf,"buildArgs");p(Go,"truncateOutput");p(cp,"snapshotMtimes");p(Yf,"detectModifiedFiles");p(Ze,"executeAgent")});import{execFile as Jf}from"node:child_process";function Xe(l,e){return new Promise((t,s)=>{Jf("git",l,{cwd:e.cwd,maxBuffer:10*1024*1024},(r,n,o)=>{if(r){let i=o?.trim()||r.message;s(new Error(`git ${l[0]} failed: ${i}`));return}t(n.trim())})})}async function Xo(l){try{let e=await Xe(["rev-parse","--abbrev-ref","HEAD"],l),t=await Xe(["status","--porcelain"],l);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function Ga(l,e){await Xe(["checkout","-b",l],e)}async function Ka(l){await Xe(["add","-A"],l)}async function Xa(l,e){await Xe(["commit","-m",l],e);let t=await Xe(["rev-parse","--short","HEAD"],e),r=(await Xe(["diff","--stat","HEAD~1","HEAD"],e)).split(`
1101
- `).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function Va(l,e,t){await Xe(["push","-u",l,e],t)}function Ya(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function er(l,e){try{return await Xe(["remote","get-url",l],e)}catch{return null}}function tr(l){let e=l.match(/^git@([^:]+):(.+?)(?:\.git)?$/);if(e){let s=e[1],n=e[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}let t=l.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);if(t){let s=t[1],n=t[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}return null}async function en(l){await Xe(["init"],l)}async function tn(l,e,t){await Xe(["remote","add",l,e],t)}var Ja=T(()=>{"use strict";p(Xe,"git");p(Xo,"gitStatus");p(Ga,"gitCreateBranch");p(Ka,"gitStageAll");p(Xa,"gitCommit");p(Va,"gitPush");p(Ya,"slugifyBranch");p(er,"gitGetRemoteUrl");p(tr,"parseRemoteUrl");p(en,"gitInitRepo");p(tn,"gitAddRemote")});function sr(l){switch(l.provider){case"github":{if(!l.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Za(l.github)}case"gitlab":{if(!l.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new Qa(l.gitlab)}default:throw new Error(`Unknown forge provider: ${l.provider}`)}}var Xt,Za,Qa,ec=T(()=>{"use strict";Xt=class{static{p(this,"ForgeClient")}},Za=class extends Xt{static{p(this,"GitHubForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://api.github.com"}async createPullRequest(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/pulls`,r=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({title:t.title,body:t.body,head:t.head,base:t.base})});if(!r.ok){let o=await r.text();throw new Error(`GitHub PR creation failed (${r.status}): ${o}`)}let n=await r.json();return{id:n.id,url:n.html_url,number:n.number,state:n.state}}async getPipelineStatus(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/commits/${t}/status`,r=await fetch(s,{headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json"}});if(!r.ok)return{state:"unknown"};let o=(await r.json()).state;return{state:{pending:"pending",success:"success",failure:"failure",error:"failure"}[o]??"unknown"}}async createProject(e){let t=`${this.baseUrl}/user/repos`,s=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",private:(e.visibility??"private")==="private"})});if(!s.ok){let n=await s.text();throw new Error(`GitHub project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.html_url,cloneUrl:r.clone_url}}},Qa=class extends Xt{static{p(this,"GitLabForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://gitlab.com"}async createPullRequest(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/merge_requests`,n=await fetch(r,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({title:t.title,description:t.body,source_branch:t.head,target_branch:t.base})});if(!n.ok){let i=await n.text();throw new Error(`GitLab MR creation failed (${n.status}): ${i}`)}let o=await n.json();return{id:o.id,url:o.web_url,number:o.iid,state:o.state}}async getPipelineStatus(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/pipelines?ref=${encodeURIComponent(t)}&per_page=1`,n=await fetch(r,{headers:{"PRIVATE-TOKEN":this.config.token}});if(!n.ok)return{state:"unknown"};let o=await n.json();if(o.length===0)return{state:"unknown"};let i=o[0],a=i.status;return{state:{pending:"pending",running:"running",success:"success",failed:"failure",canceled:"failure"}[a]??"unknown",url:i.web_url}}async createProject(e){let t=`${this.baseUrl}/api/v4/projects`,s=await fetch(t,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",visibility:e.visibility??"private"})});if(!s.ok){let n=await s.text();throw new Error(`GitLab project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.web_url,cloneUrl:r.http_url_to_repo}}};p(sr,"createForgeClient")});function dp(l,e){return l.length<=e?l:l.slice(0,e)+`
1101
+ `).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function Va(l,e,t){await Xe(["push","-u",l,e],t)}function Ya(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function er(l,e){try{return await Xe(["remote","get-url",l],e)}catch{return null}}function tr(l){let e=l.match(/^git@([^:]+):(.+?)(?:\.git)?$/);if(e){let s=e[1],n=e[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}let t=l.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);if(t){let s=t[1],n=t[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}return null}async function tn(l){await Xe(["init"],l)}async function sn(l,e,t){await Xe(["remote","add",l,e],t)}var Ja=T(()=>{"use strict";p(Xe,"git");p(Xo,"gitStatus");p(Ga,"gitCreateBranch");p(Ka,"gitStageAll");p(Xa,"gitCommit");p(Va,"gitPush");p(Ya,"slugifyBranch");p(er,"gitGetRemoteUrl");p(tr,"parseRemoteUrl");p(tn,"gitInitRepo");p(sn,"gitAddRemote")});function sr(l){switch(l.provider){case"github":{if(!l.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Za(l.github)}case"gitlab":{if(!l.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new Qa(l.gitlab)}default:throw new Error(`Unknown forge provider: ${l.provider}`)}}var Xt,Za,Qa,ec=T(()=>{"use strict";Xt=class{static{p(this,"ForgeClient")}},Za=class extends Xt{static{p(this,"GitHubForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://api.github.com"}async createPullRequest(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/pulls`,r=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({title:t.title,body:t.body,head:t.head,base:t.base})});if(!r.ok){let o=await r.text();throw new Error(`GitHub PR creation failed (${r.status}): ${o}`)}let n=await r.json();return{id:n.id,url:n.html_url,number:n.number,state:n.state}}async getPipelineStatus(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/commits/${t}/status`,r=await fetch(s,{headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json"}});if(!r.ok)return{state:"unknown"};let o=(await r.json()).state;return{state:{pending:"pending",success:"success",failure:"failure",error:"failure"}[o]??"unknown"}}async createProject(e){let t=`${this.baseUrl}/user/repos`,s=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",private:(e.visibility??"private")==="private"})});if(!s.ok){let n=await s.text();throw new Error(`GitHub project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.html_url,cloneUrl:r.clone_url}}},Qa=class extends Xt{static{p(this,"GitLabForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://gitlab.com"}async createPullRequest(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/merge_requests`,n=await fetch(r,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({title:t.title,description:t.body,source_branch:t.head,target_branch:t.base})});if(!n.ok){let i=await n.text();throw new Error(`GitLab MR creation failed (${n.status}): ${i}`)}let o=await n.json();return{id:o.id,url:o.web_url,number:o.iid,state:o.state}}async getPipelineStatus(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/pipelines?ref=${encodeURIComponent(t)}&per_page=1`,n=await fetch(r,{headers:{"PRIVATE-TOKEN":this.config.token}});if(!n.ok)return{state:"unknown"};let o=await n.json();if(o.length===0)return{state:"unknown"};let i=o[0],a=i.status;return{state:{pending:"pending",running:"running",success:"success",failed:"failure",canceled:"failure"}[a]??"unknown",url:i.web_url}}async createProject(e){let t=`${this.baseUrl}/api/v4/projects`,s=await fetch(t,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",visibility:e.visibility??"private"})});if(!s.ok){let n=await s.text();throw new Error(`GitLab project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.web_url,cloneUrl:r.http_url_to_repo}}};p(sr,"createForgeClient")});function dp(l,e){return l.length<=e?l:l.slice(0,e)+`
1102
1102
  [...truncated]`}function up(l){let e=l.replace(/^```(?:json)?\s*\n?/m,"").replace(/\n?```\s*$/m,"");return JSON.parse(e)}async function og(l,e,t){let r=`Available agents:
1103
1103
  ${e.map(a=>`- ${a.name}: command="${a.command}"`).join(`
1104
1104
  `)}
@@ -1113,7 +1113,7 @@ ${a}`:""].filter(Boolean).join(`
1113
1113
  ${l}
1114
1114
 
1115
1115
  Results:
1116
- ${s}`,n=await t.complete({system:ng,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=up(n.content);return{approved:o.approved??!0,summary:o.summary??"",fixTasks:Array.isArray(o.fixTasks)?o.fixTasks:[]}}catch{return{approved:!0,summary:n.content,fixTasks:[]}}}async function Vt(l,e,t,s={}){let r=Math.min(s.maxIterations??Zf,Qf),n=s.maxConcurrent??eg,o=s.onProgress,i=Date.now(),a=new Map(e.map(g=>[g.name,g]));o?.("Planning subtasks...");let c=await og(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,m=0,h="";for(;m<r;){m++,o?.(`Iteration ${m}: executing ${u.length} subtask(s)...`);let g=await ig(u,a,n,o);d=d.concat(g),o?.(`Iteration ${m}: validating results...`);let y=await ag(l,d,t);if(h=y.summary,y.approved||y.fixTasks.length===0)break;let _=y.fixTasks.filter(S=>a.has(S.agent)?!0:(o?.(`Warning: fix task "${S.id}" references unknown agent "${S.agent}", skipping`),!1));if(_.length===0)break;u=_,o?.(`Validation requested ${_.length} fix task(s), iterating...`)}let f=[...new Set(d.flatMap(g=>g.execution.modifiedFiles))].sort();return{plan:c,iterations:m,subtaskResults:d,allModifiedFiles:f,summary:h,totalDurationMs:Date.now()-i}}async function sn(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await Xo({cwd:n});if(!i.isRepo)try{await en({cwd:n}),i=await Xo({cwd:n}),r?.("Initialised new git repository")}catch{return o.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await Vt(l,e,t,s),git:o}}let a=null,c=await er("origin",{cwd:n});if(c){let f=tr(c);f?(a={owner:f.owner,repo:f.repo},r?.(`Detected remote: ${f.owner}/${f.repo} (${f.baseUrl})`)):o.warnings.push(`Could not parse remote URL: ${c}`)}let d=s.forge;if(!c&&d)try{let f=sr(d),g=n.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${g}" on forge...`);let y=await f.createProject({name:g,visibility:"private"});await tn("origin",y.cloneUrl,{cwd:n});let _=tr(y.cloneUrl);_&&(a={owner:_.owner,repo:_.repo}),r?.(`Project created: ${y.url} \u2014 remote "origin" set`)}catch(f){let g=f instanceof Error?f.message:String(f);o.warnings.push(`Project creation failed: ${g}`),r?.(`Warning: project creation failed \u2014 ${g}`)}let u=Ya(l);try{await Ga(u,{cwd:n}),o.branch=u,r?.(`Created branch: ${u}`)}catch(f){throw new Error(`Failed to create branch "${u}": ${f instanceof Error?f.message:String(f)}`)}let m=await Vt(l,e,t,s);try{await Ka({cwd:n});let f=`feat: ${l.slice(0,72)}
1116
+ ${s}`,n=await t.complete({system:ng,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=up(n.content);return{approved:o.approved??!0,summary:o.summary??"",fixTasks:Array.isArray(o.fixTasks)?o.fixTasks:[]}}catch{return{approved:!0,summary:n.content,fixTasks:[]}}}async function Vt(l,e,t,s={}){let r=Math.min(s.maxIterations??Zf,Qf),n=s.maxConcurrent??eg,o=s.onProgress,i=Date.now(),a=new Map(e.map(g=>[g.name,g]));o?.("Planning subtasks...");let c=await og(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,m=0,h="";for(;m<r;){m++,o?.(`Iteration ${m}: executing ${u.length} subtask(s)...`);let g=await ig(u,a,n,o);d=d.concat(g),o?.(`Iteration ${m}: validating results...`);let y=await ag(l,d,t);if(h=y.summary,y.approved||y.fixTasks.length===0)break;let _=y.fixTasks.filter(S=>a.has(S.agent)?!0:(o?.(`Warning: fix task "${S.id}" references unknown agent "${S.agent}", skipping`),!1));if(_.length===0)break;u=_,o?.(`Validation requested ${_.length} fix task(s), iterating...`)}let f=[...new Set(d.flatMap(g=>g.execution.modifiedFiles))].sort();return{plan:c,iterations:m,subtaskResults:d,allModifiedFiles:f,summary:h,totalDurationMs:Date.now()-i}}async function rn(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await Xo({cwd:n});if(!i.isRepo)try{await tn({cwd:n}),i=await Xo({cwd:n}),r?.("Initialised new git repository")}catch{return o.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await Vt(l,e,t,s),git:o}}let a=null,c=await er("origin",{cwd:n});if(c){let f=tr(c);f?(a={owner:f.owner,repo:f.repo},r?.(`Detected remote: ${f.owner}/${f.repo} (${f.baseUrl})`)):o.warnings.push(`Could not parse remote URL: ${c}`)}let d=s.forge;if(!c&&d)try{let f=sr(d),g=n.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${g}" on forge...`);let y=await f.createProject({name:g,visibility:"private"});await sn("origin",y.cloneUrl,{cwd:n});let _=tr(y.cloneUrl);_&&(a={owner:_.owner,repo:_.repo}),r?.(`Project created: ${y.url} \u2014 remote "origin" set`)}catch(f){let g=f instanceof Error?f.message:String(f);o.warnings.push(`Project creation failed: ${g}`),r?.(`Warning: project creation failed \u2014 ${g}`)}let u=Ya(l);try{await Ga(u,{cwd:n}),o.branch=u,r?.(`Created branch: ${u}`)}catch(f){throw new Error(`Failed to create branch "${u}": ${f instanceof Error?f.message:String(f)}`)}let m=await Vt(l,e,t,s);try{await Ka({cwd:n});let f=`feat: ${l.slice(0,72)}
1117
1117
 
1118
1118
  Orchestrated by Alfred (${m.iterations} iteration(s), ${m.allModifiedFiles.length} file(s))`,g=await Xa(f,{cwd:n});o.commit=g,r?.(`Committed: ${g.sha} (${g.filesChanged} files changed)`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Commit failed: ${g}`),r?.(`Warning: commit failed \u2014 ${g}`),{...m,git:o}}if(!await er("origin",{cwd:n}))return o.warnings.push("No remote configured \u2014 skipping push and PR creation"),r?.("No remote configured, skipping push and PR"),{...m,git:o};try{await Va("origin",u,{cwd:n}),r?.(`Pushed branch: ${u}`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Push failed: ${g}`),r?.(`Warning: push failed \u2014 ${g}`),{...m,git:o}}if(d&&a)try{let f=sr(d),g=s.baseBranch??d.baseBranch??"main",y=s.prTitle??`feat: ${l.slice(0,72)}`,_=["## Summary",m.summary,"",`**Iterations:** ${m.iterations}`,`**Modified files:** ${m.allModifiedFiles.length}`,m.allModifiedFiles.map(E=>`- \`${E}\``).join(`
1119
1119
  `),"","_Automated by Alfred_"].join(`
@@ -1147,7 +1147,7 @@ Respond with ONLY valid JSON (no markdown fences):
1147
1147
  "fixTasks": [
1148
1148
  { "id": "fix-1", "agent": "<agent-name>", "prompt": "<detailed fix prompt>", "description": "<short description>" }
1149
1149
  ]
1150
- }`;p(dp,"truncate");p(up,"parseJSON");tc=class{static{p(this,"Semaphore")}max;queue=[];active=0;constructor(e){this.max=e}async acquire(){if(this.active<this.max){this.active++;return}return new Promise(e=>{this.queue.push(()=>{this.active++,e()})})}release(){this.active--;let e=this.queue.shift();e&&e()}};p(og,"planSubtasks");p(ig,"executeSubtasksParallel");p(ag,"validateResults");p(Vt,"orchestrate");p(sn,"orchestrateWithGit")});var rn,pp=T(()=>{"use strict";B();Ko();sc();rn=class extends x{static{p(this,"CodeAgentSkill")}llm;metadata={name:"code_agent",category:"automation",description:'Run a CLI-based coding agent (e.g. Claude Code, Codex, Gemini CLI, Aider) as a subprocess. Use action "list_agents" to see available agents, "run" to execute one with a prompt, or "orchestrate" to have the LLM decompose a task into parallel subtasks. The agent runs in a specified working directory and returns stdout, stderr, exit code, duration, and a list of files it modified.',riskLevel:"admin",version:"1.0.0",timeoutMs:6e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_agents","run","orchestrate"],description:"The action to perform"},task:{type:"string",description:'High-level task description for "orchestrate" action'},agents:{type:"array",items:{type:"string"},description:'Optional agent name filter for "orchestrate" (uses all agents if omitted)'},maxIterations:{type:"number",description:'Max validation iterations for "orchestrate" (1-5, default 3)'},agent:{type:"string",description:'Name of the agent to run (required for "run" action)'},prompt:{type:"string",description:'The prompt / task description to send to the agent (required for "run" action)'},cwd:{type:"string",description:"Working directory for the agent (optional, uses agent default or process.cwd())"},timeout:{type:"number",description:"Timeout in milliseconds (optional, max 900000)"},git:{type:"boolean",description:'Enable git workflow: auto-branch, commit, push, and PR creation (for "orchestrate")'},prTitle:{type:"string",description:"Custom PR/MR title (used with git=true)"},baseBranch:{type:"string",description:'Target branch for the PR/MR (default: "main")'}},required:["action"]}};agents;forgeConfig;constructor(e,t){super(),this.llm=t,this.agents=new Map(e.agents.map(s=>[s.name,s])),this.forgeConfig=e.forge}async execute(e,t){let s=e.action;switch(s){case"list_agents":return this.listAgents();case"run":return this.runAgent(e,t);case"orchestrate":return this.orchestrateTask(e,t);default:return{success:!1,error:`Unknown action "${s}". Use "list_agents", "run", or "orchestrate".`}}}listAgents(){let e=[...this.agents.values()].map(s=>({name:s.name,command:s.command,promptVia:s.promptVia??"arg",timeoutMs:s.timeoutMs})),t=e.length===0?"No code agents configured.":e.map(s=>`- **${s.name}**: \`${s.command}\` (prompt via ${s.promptVia})`).join(`
1150
+ }`;p(dp,"truncate");p(up,"parseJSON");tc=class{static{p(this,"Semaphore")}max;queue=[];active=0;constructor(e){this.max=e}async acquire(){if(this.active<this.max){this.active++;return}return new Promise(e=>{this.queue.push(()=>{this.active++,e()})})}release(){this.active--;let e=this.queue.shift();e&&e()}};p(og,"planSubtasks");p(ig,"executeSubtasksParallel");p(ag,"validateResults");p(Vt,"orchestrate");p(rn,"orchestrateWithGit")});var nn,pp=T(()=>{"use strict";B();Ko();sc();nn=class extends x{static{p(this,"CodeAgentSkill")}llm;metadata={name:"code_agent",category:"automation",description:'Run a CLI-based coding agent (e.g. Claude Code, Codex, Gemini CLI, Aider) as a subprocess. Use action "list_agents" to see available agents, "run" to execute one with a prompt, or "orchestrate" to have the LLM decompose a task into parallel subtasks. The agent runs in a specified working directory and returns stdout, stderr, exit code, duration, and a list of files it modified.',riskLevel:"admin",version:"1.0.0",timeoutMs:6e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_agents","run","orchestrate"],description:"The action to perform"},task:{type:"string",description:'High-level task description for "orchestrate" action'},agents:{type:"array",items:{type:"string"},description:'Optional agent name filter for "orchestrate" (uses all agents if omitted)'},maxIterations:{type:"number",description:'Max validation iterations for "orchestrate" (1-5, default 3)'},agent:{type:"string",description:'Name of the agent to run (required for "run" action)'},prompt:{type:"string",description:'The prompt / task description to send to the agent (required for "run" action)'},cwd:{type:"string",description:"Working directory for the agent (optional, uses agent default or process.cwd())"},timeout:{type:"number",description:"Timeout in milliseconds (optional, max 900000)"},git:{type:"boolean",description:'Enable git workflow: auto-branch, commit, push, and PR creation (for "orchestrate")'},prTitle:{type:"string",description:"Custom PR/MR title (used with git=true)"},baseBranch:{type:"string",description:'Target branch for the PR/MR (default: "main")'}},required:["action"]}};agents;forgeConfig;constructor(e,t){super(),this.llm=t,this.agents=new Map(e.agents.map(s=>[s.name,s])),this.forgeConfig=e.forge}async execute(e,t){let s=e.action;switch(s){case"list_agents":return this.listAgents();case"run":return this.runAgent(e,t);case"orchestrate":return this.orchestrateTask(e,t);default:return{success:!1,error:`Unknown action "${s}". Use "list_agents", "run", or "orchestrate".`}}}listAgents(){let e=[...this.agents.values()].map(s=>({name:s.name,command:s.command,promptVia:s.promptVia??"arg",timeoutMs:s.timeoutMs})),t=e.length===0?"No code agents configured.":e.map(s=>`- **${s.name}**: \`${s.command}\` (prompt via ${s.promptVia})`).join(`
1151
1151
  `);return{success:!0,data:{agents:e},display:`Available code agents:
1152
1152
  ${t}`}}async runAgent(e,t){let s=e.agent,r=e.prompt;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "agent"'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "prompt"'};let n=this.agents.get(s);if(!n){let d=[...this.agents.keys()].join(", ");return{success:!1,error:`Unknown agent "${s}". Available: ${d}`}}let o=typeof e.cwd=="string"?e.cwd:void 0,i=typeof e.timeout=="number"?e.timeout:void 0,a=await Ze(n,r,{cwd:o,timeoutMs:i,onProgress:t.onProgress}),c=[];return a.stdout&&c.push(`**stdout:**
1153
1153
  \`\`\`
@@ -1159,7 +1159,7 @@ ${a.stderr}
1159
1159
  ${a.modifiedFiles.map(d=>`- ${d}`).join(`
1160
1160
  `)}`),{success:a.exitCode===0,data:{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,durationMs:a.durationMs,modifiedFiles:a.modifiedFiles},display:c.join(`
1161
1161
 
1162
- `),...a.exitCode!==0&&{error:a.exitCode===124?`Agent "${s}" timed out`:`Agent "${s}" exited with code ${a.exitCode}`}}}async orchestrateTask(e,t){if(!this.llm)return{success:!1,error:"Orchestration requires an LLM provider but none was configured."};let s=e.task;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task" for orchestrate action.'};let r=[...this.agents.values()],n=e.agents;if(Array.isArray(n)&&n.length>0&&(r=n.map(d=>this.agents.get(d)).filter(d=>d!==void 0),r.length===0))return{success:!1,error:`None of the specified agents exist. Available: ${[...this.agents.keys()].join(", ")}`};let o=typeof e.maxIterations=="number"?e.maxIterations:void 0,i=e.git===!0,a=typeof e.prTitle=="string"?e.prTitle:void 0,c=typeof e.baseBranch=="string"?e.baseBranch:void 0;try{if(i){let u=await sn(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress,forge:this.forgeConfig,prTitle:a,baseBranch:c});return this.formatGitOrchestrationResult(u)}let d=await Vt(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress});return this.formatOrchestrationResult(d)}catch(d){return{success:!1,error:`Orchestration failed: ${d instanceof Error?d.message:String(d)}`}}}formatOrchestrationResult(e){let t=[];t.push(`**Orchestration completed in ${e.iterations} iteration(s)**`),t.push(`**Plan:** ${e.plan.reasoning}`),t.push(`**Duration:** ${(e.totalDurationMs/1e3).toFixed(1)}s`);for(let r of e.subtaskResults){let n=r.execution.exitCode===0?"OK":`FAIL (exit ${r.execution.exitCode})`;t.push(`- **${r.subtask.id}** [${r.subtask.agent}]: ${r.subtask.description} \u2014 ${n}`)}return e.allModifiedFiles.length>0&&t.push(`
1162
+ `),...a.exitCode!==0&&{error:a.exitCode===124?`Agent "${s}" timed out`:`Agent "${s}" exited with code ${a.exitCode}`}}}async orchestrateTask(e,t){if(!this.llm)return{success:!1,error:"Orchestration requires an LLM provider but none was configured."};let s=e.task;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task" for orchestrate action.'};let r=[...this.agents.values()],n=e.agents;if(Array.isArray(n)&&n.length>0&&(r=n.map(d=>this.agents.get(d)).filter(d=>d!==void 0),r.length===0))return{success:!1,error:`None of the specified agents exist. Available: ${[...this.agents.keys()].join(", ")}`};let o=typeof e.maxIterations=="number"?e.maxIterations:void 0,i=e.git===!0,a=typeof e.prTitle=="string"?e.prTitle:void 0,c=typeof e.baseBranch=="string"?e.baseBranch:void 0;try{if(i){let u=await rn(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress,forge:this.forgeConfig,prTitle:a,baseBranch:c});return this.formatGitOrchestrationResult(u)}let d=await Vt(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress});return this.formatOrchestrationResult(d)}catch(d){return{success:!1,error:`Orchestration failed: ${d instanceof Error?d.message:String(d)}`}}}formatOrchestrationResult(e){let t=[];t.push(`**Orchestration completed in ${e.iterations} iteration(s)**`),t.push(`**Plan:** ${e.plan.reasoning}`),t.push(`**Duration:** ${(e.totalDurationMs/1e3).toFixed(1)}s`);for(let r of e.subtaskResults){let n=r.execution.exitCode===0?"OK":`FAIL (exit ${r.execution.exitCode})`;t.push(`- **${r.subtask.id}** [${r.subtask.agent}]: ${r.subtask.description} \u2014 ${n}`)}return e.allModifiedFiles.length>0&&t.push(`
1163
1163
  **Modified files:**
1164
1164
  ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
1165
1165
  `)}`),e.summary&&t.push(`
@@ -1168,7 +1168,7 @@ ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
1168
1168
 
1169
1169
  **Git:**
1170
1170
  ${s.join(`
1171
- `)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+n}}}});function nn(l,e){let t=Vo.get(l)??[];t.push(e),Vo.set(l,t)}function an(l){let e=Vo.get(l)??[];return Vo.delete(l),e}function cn(l,e){rc.set(l,e)}function ln(l){rc.delete(l)}var Vo,rc,on,mp=T(()=>{"use strict";B();Vo=new Map,rc=new Map;p(nn,"pushInterjection");p(an,"drainInterjections");p(cn,"registerAbortController");p(ln,"removeAbortController");on=class extends x{static{p(this,"ProjectAgentSkill")}llm;sessionRepo;metadata={name:"project_agent",category:"automation",description:`Autonomous coding agent that creates and develops software projects end-to-end. Runs indefinitely until the goal is reached.
1171
+ `)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+n}}}});function on(l,e){let t=Vo.get(l)??[];t.push(e),Vo.set(l,t)}function cn(l){let e=Vo.get(l)??[];return Vo.delete(l),e}function ln(l,e){rc.set(l,e)}function dn(l){rc.delete(l)}var Vo,rc,an,mp=T(()=>{"use strict";B();Vo=new Map,rc=new Map;p(on,"pushInterjection");p(cn,"drainInterjections");p(ln,"registerAbortController");p(dn,"removeAbortController");an=class extends x{static{p(this,"ProjectAgentSkill")}llm;sessionRepo;metadata={name:"project_agent",category:"automation",description:`Autonomous coding agent that creates and develops software projects end-to-end. Runs indefinitely until the goal is reached.
1172
1172
  Actions:
1173
1173
  - start: Start a new project agent session. Params: goal (what to build), cwd (directory), agent (which code agent to use, e.g. "claude-code"), buildCommands (optional, e.g. ["npm install", "npm run build"]), testCommands (optional), template (optional, e.g. "nextjs")
1174
1174
  - status: Check current status of a running project agent. Params: task_id
@@ -1184,13 +1184,13 @@ Iteration: ${s.currentIteration}
1184
1184
  Dateien ge\xE4ndert: ${s.totalFilesChanged}
1185
1185
  Letzter Build: ${s.lastBuildPassed?"\u2705 passed":"\u274C failed"}
1186
1186
  Letzter Commit: ${s.lastCommitSha??"\u2014"}
1187
- `+(s.milestones.length>0?`Milestones: ${s.milestones.join(", ")}`:"")}:{success:!1,error:`No project agent session found for task ${t}`}}interject(e){let t=e.task_id,s=e.message;return t?s?(nn(t,s),{success:!0,data:{taskId:t,message:s},display:`\u{1F4DD} Nachricht eingereiht f\xFCr Project Agent (${t}). Wird in der n\xE4chsten Iteration ber\xFCcksichtigt.`}):{success:!1,error:'Missing "message"'}:{success:!1,error:'Missing "task_id"'}}stopProject(e){let t=e.task_id;if(!t)return{success:!1,error:'Missing "task_id"'};nn(t,"__STOP__");let s=rc.get(t);return s&&s.abort(),{success:!0,data:{taskId:t,stopped:!0},display:`\u23F9 Stop-Signal gesendet an Project Agent (${t}). Agent wird nach dem aktuellen Schritt sauber beendet.`}}}});import{spawn as cg}from"node:child_process";function dn(l,e=dg){return l.length<=e?l:`[...truncated...]
1188
- `+l.slice(-e)}async function ug(l,e,t){let s=Date.now(),r=l.split(/\s+/),n=r[0],o=r.slice(1);return new Promise(i=>{let a="",c="",d=!1,u=cg(n,o,{cwd:e,shell:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,CI:"true",FORCE_COLOR:"0"}}),m=setTimeout(()=>{d=!0,u.kill("SIGTERM"),setTimeout(()=>{try{u.kill("SIGKILL")}catch{}},5e3)},t);u.stdout?.on("data",h=>{a+=h.toString()}),u.stderr?.on("data",h=>{c+=h.toString()}),u.on("close",h=>{clearTimeout(m),i({command:l,exitCode:d?124:h??1,stdout:dn(a),stderr:dn(c),timedOut:d,durationMs:Date.now()-s})}),u.on("error",h=>{clearTimeout(m),i({command:l,exitCode:127,stdout:dn(a),stderr:dn(c+`
1189
- `+h.message),timedOut:!1,durationMs:Date.now()-s})})})}async function un(l,e,t,s=lg){let r=Date.now(),n=[],o=[...e,...t];for(let c of o){let d=await ug(c,l,s);if(n.push(d),d.exitCode!==0)break}let i=n.every(c=>c.exitCode===0),a=n.map(c=>`$ ${c.command} (exit ${c.exitCode}, ${c.durationMs}ms)
1187
+ `+(s.milestones.length>0?`Milestones: ${s.milestones.join(", ")}`:"")}:{success:!1,error:`No project agent session found for task ${t}`}}interject(e){let t=e.task_id,s=e.message;return t?s?(on(t,s),{success:!0,data:{taskId:t,message:s},display:`\u{1F4DD} Nachricht eingereiht f\xFCr Project Agent (${t}). Wird in der n\xE4chsten Iteration ber\xFCcksichtigt.`}):{success:!1,error:'Missing "message"'}:{success:!1,error:'Missing "task_id"'}}stopProject(e){let t=e.task_id;if(!t)return{success:!1,error:'Missing "task_id"'};on(t,"__STOP__");let s=rc.get(t);return s&&s.abort(),{success:!0,data:{taskId:t,stopped:!0},display:`\u23F9 Stop-Signal gesendet an Project Agent (${t}). Agent wird nach dem aktuellen Schritt sauber beendet.`}}}});import{spawn as cg}from"node:child_process";function un(l,e=dg){return l.length<=e?l:`[...truncated...]
1188
+ `+l.slice(-e)}async function ug(l,e,t){let s=Date.now(),r=l.split(/\s+/),n=r[0],o=r.slice(1);return new Promise(i=>{let a="",c="",d=!1,u=cg(n,o,{cwd:e,shell:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,CI:"true",FORCE_COLOR:"0"}}),m=setTimeout(()=>{d=!0,u.kill("SIGTERM"),setTimeout(()=>{try{u.kill("SIGKILL")}catch{}},5e3)},t);u.stdout?.on("data",h=>{a+=h.toString()}),u.stderr?.on("data",h=>{c+=h.toString()}),u.on("close",h=>{clearTimeout(m),i({command:l,exitCode:d?124:h??1,stdout:un(a),stderr:un(c),timedOut:d,durationMs:Date.now()-s})}),u.on("error",h=>{clearTimeout(m),i({command:l,exitCode:127,stdout:un(a),stderr:un(c+`
1189
+ `+h.message),timedOut:!1,durationMs:Date.now()-s})})})}async function pn(l,e,t,s=lg){let r=Date.now(),n=[],o=[...e,...t];for(let c of o){let d=await ug(c,l,s);if(n.push(d),d.exitCode!==0)break}let i=n.every(c=>c.exitCode===0),a=n.map(c=>`$ ${c.command} (exit ${c.exitCode}, ${c.durationMs}ms)
1190
1190
  ${[c.stderr,c.stdout].filter(Boolean).join(`
1191
1191
  `)}`).join(`
1192
1192
 
1193
- `);return{passed:i,commands:n,combinedOutput:dn(a),durationMs:Date.now()-r}}var lg,dg,hp=T(()=>{"use strict";lg=3e5,dg=8e3;p(dn,"truncateOutput");p(ug,"runCommand");p(un,"validateBuild")});async function pn(l,e){try{let r=(await e.complete({system:pg,messages:[{role:"user",content:l}],maxTokens:1024,temperature:.3})).content.match(/\{[\s\S]*\}/);if(r){let n=JSON.parse(r[0]);if(Array.isArray(n.phases)&&n.phases.length>0)return{phases:n.phases,buildStrategy:n.buildStrategy??"npm install && npm run build",estimatedIterations:n.estimatedIterations??n.phases.length}}}catch{}return{phases:[`Implementiere: ${l}`],buildStrategy:"npm install && npm run build",estimatedIterations:1}}var pg,fp=T(()=>{"use strict";pg=`Du bist ein Software-Architekt. Deine Aufgabe: Zerlege das folgende Projektziel in geordnete Build-Phasen.
1193
+ `);return{passed:i,commands:n,combinedOutput:un(a),durationMs:Date.now()-r}}var lg,dg,hp=T(()=>{"use strict";lg=3e5,dg=8e3;p(un,"truncateOutput");p(ug,"runCommand");p(pn,"validateBuild")});async function mn(l,e){try{let r=(await e.complete({system:pg,messages:[{role:"user",content:l}],maxTokens:1024,temperature:.3})).content.match(/\{[\s\S]*\}/);if(r){let n=JSON.parse(r[0]);if(Array.isArray(n.phases)&&n.phases.length>0)return{phases:n.phases,buildStrategy:n.buildStrategy??"npm install && npm run build",estimatedIterations:n.estimatedIterations??n.phases.length}}}catch{}return{phases:[`Implementiere: ${l}`],buildStrategy:"npm install && npm run build",estimatedIterations:1}}var pg,fp=T(()=>{"use strict";pg=`Du bist ein Software-Architekt. Deine Aufgabe: Zerlege das folgende Projektziel in geordnete Build-Phasen.
1194
1194
 
1195
1195
  Regeln:
1196
1196
  - Jede Phase ist ein konkreter, ausf\xFChrbarer Schritt (z.B. "Projekt-Setup mit package.json und tsconfig", nicht "Planung")
@@ -1204,7 +1204,7 @@ Antworte als JSON:
1204
1204
  "phases": ["Phase 1: ...", "Phase 2: ...", ...],
1205
1205
  "buildStrategy": "npm install && npm run build && npm test",
1206
1206
  "estimatedIterations": 4
1207
- }`;p(pn,"createProjectPlan")});var gp=T(()=>{"use strict";pp();Ko();sc();Ja();ec();mp();hp();fp()});var ie={};me(ie,{ActivityTracker:()=>Bt,BMWSkill:()=>Do,BackgroundTaskSkill:()=>Bs,BriefingSkill:()=>Ho,BrowserSkill:()=>Us,CalculatorSkill:()=>Ss,CalendarProvider:()=>ze,CalendarSkill:()=>Ht,ClipboardSkill:()=>Os,CodeAgentSkill:()=>rn,CodeExecutionSkill:()=>Gr,CodeExecutor:()=>qt,ConfigureSkill:()=>Ys,ContactsProvider:()=>Ke,ContactsSkill:()=>Vr,CrossPlatformSkill:()=>js,DelegateSkill:()=>Ns,DockerSkill:()=>No,DocumentSkill:()=>Ws,EmailProvider:()=>ct,EmailSkill:()=>wt,EnergyPriceSkill:()=>Oo,FeedReaderSkill:()=>Qs,FileSkill:()=>Ds,ForgeClient:()=>Xt,HomeAssistantSkill:()=>Ao,HttpSkill:()=>Ls,ImageGenerateSkill:()=>qs,MCPClient:()=>Wt,MCPManager:()=>qr,MCPSkillAdapter:()=>zt,MarketplaceSkill:()=>Qr,MemorySkill:()=>Cs,MicrosoftTodoSkill:()=>Uo,MonitorSkill:()=>Po,NoteSkill:()=>Is,PluginLoader:()=>yo,ProfileSkill:()=>Fs,ProjectAgentSkill:()=>on,ProxmoxSkill:()=>$o,ReminderSkill:()=>As,RoutingSkill:()=>Mo,ScheduledTaskSkill:()=>Hs,ScreenshotSkill:()=>Ps,ShellSkill:()=>xs,Skill:()=>x,SkillRegistry:()=>bs,SkillSandbox:()=>Es,SystemInfoSkill:()=>$s,TTSSkill:()=>zs,TodoSkill:()=>Gs,TransitSkill:()=>Xs,UniFiSkill:()=>vo,WatchSkill:()=>Js,WeatherSkill:()=>Rs,WebSearchSkill:()=>vs,WorkflowSkill:()=>Zs,YouTubeSkill:()=>qo,allUserIds:()=>J,createCalendarProvider:()=>zr,createContactsProvider:()=>Da,createEmailProvider:()=>Br,createForgeClient:()=>sr,createProjectPlan:()=>pn,drainInterjections:()=>an,effectiveUserId:()=>de,executeAgent:()=>Ze,gitAddRemote:()=>tn,gitGetRemoteUrl:()=>er,gitInitRepo:()=>en,orchestrate:()=>Vt,orchestrateWithGit:()=>sn,parseRemoteUrl:()=>tr,pushInterjection:()=>nn,registerAbortController:()=>cn,removeAbortController:()=>ln,validateBuild:()=>un});var re=T(()=>{"use strict";B();Oe();Sd();$d();wa();vd();Rd();xd();Cd();Nd();Ld();Dd();Pd();Ud();Fd();Wd();qd();Kd();Xd();Yd();Zd();Qd();ou();iu();au();cu();du();pu();mu();hu();fu();gu();yu();wu();Su();$u();xu();Pu();Uu();qu();Gu();Vu();Yu();Ju();Zu();Qu();sp();rp();np();op();gp()});var mn,nc=T(()=>{"use strict";mn=class{static{p(this,"ConversationManager")}conversations;constructor(e){this.conversations=e}getOrCreateConversation(e,t,s){let r=this.conversations.findByPlatformChat(e,t);return r?(this.conversations.updateTimestamp(r.id),r):this.conversations.create(e,t,s)}addMessage(e,t,s,r){return this.conversations.addMessage(e,t,s,r)}getHistory(e,t=20){return this.conversations.getMessages(e,t)}pruneMessages(e,t){return this.conversations.pruneMessages(e,t)}}});function Ie(l,e){let t;if(e.platformUserId)t=l.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=l.findById(e.userId)??l.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in l?l.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in l&&(r=l.getLinkedUsers(s).map(a=>a.platformUserId));let n;try{"getProfile"in l?n=l.getProfile(s)?.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone:n=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{n=Intl.DateTimeFormat().resolvedOptions().timeZone}return{context:{userId:t.platformUserId,masterUserId:s,linkedPlatformUserIds:r,chatId:e.chatId,chatType:e.chatType,platform:e.platform,conversationId:e.conversationId??"",timezone:n},user:t,masterUserId:s,linkedPlatformUserIds:r}}var _t=T(()=>{"use strict";p(Ie,"buildSkillContext")});function yp(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(mg))e.has(r)&&n.test(l)&&(t.add(r),s=!0);if(t.has("automation")){for(let r of e)t.add(r);return t}if(!s){let r=["productivity","information","media","automation","files"];for(let n of r)e.has(n)&&t.add(n)}return t}function wp(l,e){return l.filter(t=>e.has(t.category??"core"))}var mg,Tp=T(()=>{"use strict";mg={productivity:/\b(todo|note|notiz|remind|erinner|calendar|kalender|termin|event|email|e-mail|mail|contact|kontakt|briefing|morgenbriefing|tagesbriefing)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info|transit|bahn|zug|bus|tram|u.?bahn|s.?bahn|abfahrt|verbindung|haltestelle|öffi|fahrplan|strom|energy|preis|price|kwh|awattar|marktpreis|spot|günstig|cheapest|netzentgelt|rss|feed|atom|news|nachricht|schlagzeil|headline|youtube|video|transkript|transcript|channel|kanal|zusammenfass)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows|bild|image|generier|photo|foto)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|script|skript|befehl|kommando|tägliche?r?s?|stündliche?r?s?|wöchentliche?r?s?|monatliche?r?s?|jeden\s+(tag|morgen|abend|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag)|um\s+\d{1,2}\s*(uhr|:|h)|alle\s+\d+\s*(min|stund|sekund)|in\s+\d+\s*(minuten?|stunden?|sekunden?|hours?|minutes?|seconds?|min)|daily|hourly|weekly|every\s+(day|hour|morning|evening|night|\d+\s*min)|führ.{0,5}aus|execut|ausführ)\b/i,files:/\b(file|datei|document|dokument|pdf|http|download|upload|herunterlad|hochlad|anhang|attachment)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|netzwerk|network|homeassistant|home.?assistant|smarthome|smart.?home|licht|light|schalter|switch|solar|photovoltaik|pv|wechselrichter|inverter|batterie.?speicher|wallbox|energieverbrauch|stromverbrauch|verbrauch.{0,5}kwh|einspeis|netzeinspeis|autarkie|eigenverbrauch|bmw|auto|fahrzeug|ladestand|reichweite|laden(?!e)|charging|vehicle|soc|ladehistorie|ladesession|ladevorgang|ladezyklus|ladekurve|km|kilometer|kilometerstand|mileage|tachostand)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};p(yp,"selectCategories");p(wp,"filterSkills")});import oc from"node:fs";import _p from"node:path";function wg(l,e){if(l.length<=e)return l;let t=l.split(`
1207
+ }`;p(mn,"createProjectPlan")});var gp=T(()=>{"use strict";pp();Ko();sc();Ja();ec();mp();hp();fp()});var ie={};me(ie,{ActivityTracker:()=>Bt,BMWSkill:()=>Mo,BackgroundTaskSkill:()=>Bs,BriefingSkill:()=>Wo,BrowserSkill:()=>Us,CalculatorSkill:()=>Ss,CalendarProvider:()=>ze,CalendarSkill:()=>Ht,ClipboardSkill:()=>Os,CodeAgentSkill:()=>nn,CodeExecutionSkill:()=>Gr,CodeExecutor:()=>qt,ConfigureSkill:()=>Ys,ContactsProvider:()=>Ke,ContactsSkill:()=>Vr,CrossPlatformSkill:()=>js,DelegateSkill:()=>Ns,DockerSkill:()=>Lo,DocumentSkill:()=>Ws,EmailProvider:()=>ct,EmailSkill:()=>wt,EnergyPriceSkill:()=>Po,FeedReaderSkill:()=>Qs,FileSkill:()=>Ds,ForgeClient:()=>Xt,HomeAssistantSkill:()=>Io,HttpSkill:()=>Ls,ImageGenerateSkill:()=>qs,MCPClient:()=>Wt,MCPManager:()=>qr,MCPSkillAdapter:()=>zt,MarketplaceSkill:()=>Qr,MemorySkill:()=>Cs,MicrosoftTodoSkill:()=>Fo,MonitorSkill:()=>Uo,NoteSkill:()=>Is,PluginLoader:()=>wo,ProfileSkill:()=>Fs,ProjectAgentSkill:()=>an,ProxmoxSkill:()=>vo,ReminderSkill:()=>As,RoutingSkill:()=>Oo,ScheduledTaskSkill:()=>Hs,ScreenshotSkill:()=>Ps,ShellSkill:()=>xs,Skill:()=>x,SkillRegistry:()=>bs,SkillSandbox:()=>Es,SystemInfoSkill:()=>$s,TTSSkill:()=>zs,TodoSkill:()=>Gs,TransitSkill:()=>Xs,UniFiSkill:()=>Ao,WatchSkill:()=>Js,WeatherSkill:()=>Rs,WebSearchSkill:()=>vs,WorkflowSkill:()=>Zs,YouTubeSkill:()=>qo,allUserIds:()=>J,createCalendarProvider:()=>zr,createContactsProvider:()=>Da,createEmailProvider:()=>Br,createForgeClient:()=>sr,createProjectPlan:()=>mn,drainInterjections:()=>cn,effectiveUserId:()=>de,executeAgent:()=>Ze,gitAddRemote:()=>sn,gitGetRemoteUrl:()=>er,gitInitRepo:()=>tn,orchestrate:()=>Vt,orchestrateWithGit:()=>rn,parseRemoteUrl:()=>tr,pushInterjection:()=>on,registerAbortController:()=>ln,removeAbortController:()=>dn,validateBuild:()=>pn});var re=T(()=>{"use strict";B();Oe();Sd();$d();wa();vd();Rd();xd();Cd();Nd();Ld();Dd();Pd();Ud();Fd();Wd();qd();Kd();Xd();Yd();Zd();Qd();ou();iu();au();cu();du();pu();mu();hu();fu();gu();yu();wu();Su();$u();xu();Pu();Uu();qu();Gu();Vu();Yu();Ju();Zu();Qu();sp();rp();np();op();gp()});var hn,nc=T(()=>{"use strict";hn=class{static{p(this,"ConversationManager")}conversations;constructor(e){this.conversations=e}getOrCreateConversation(e,t,s){let r=this.conversations.findByPlatformChat(e,t);return r?(this.conversations.updateTimestamp(r.id),r):this.conversations.create(e,t,s)}addMessage(e,t,s,r){return this.conversations.addMessage(e,t,s,r)}getHistory(e,t=20){return this.conversations.getMessages(e,t)}pruneMessages(e,t){return this.conversations.pruneMessages(e,t)}}});function Ie(l,e){let t;if(e.platformUserId)t=l.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=l.findById(e.userId)??l.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in l?l.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in l&&(r=l.getLinkedUsers(s).map(a=>a.platformUserId));let n;try{"getProfile"in l?n=l.getProfile(s)?.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone:n=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{n=Intl.DateTimeFormat().resolvedOptions().timeZone}return{context:{userId:t.platformUserId,masterUserId:s,linkedPlatformUserIds:r,chatId:e.chatId,chatType:e.chatType,platform:e.platform,conversationId:e.conversationId??"",timezone:n},user:t,masterUserId:s,linkedPlatformUserIds:r}}var _t=T(()=>{"use strict";p(Ie,"buildSkillContext")});function yp(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(mg))e.has(r)&&n.test(l)&&(t.add(r),s=!0);if(t.has("automation")){for(let r of e)t.add(r);return t}if(!s){let r=["productivity","information","media","automation","files"];for(let n of r)e.has(n)&&t.add(n)}return t}function wp(l,e){return l.filter(t=>e.has(t.category??"core"))}var mg,Tp=T(()=>{"use strict";mg={productivity:/\b(todo|note|notiz|remind|erinner|calendar|kalender|termin|event|email|e-mail|mail|contact|kontakt|briefing|morgenbriefing|tagesbriefing)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info|transit|bahn|zug|bus|tram|u.?bahn|s.?bahn|abfahrt|verbindung|haltestelle|öffi|fahrplan|strom|energy|preis|price|kwh|awattar|marktpreis|spot|günstig|cheapest|netzentgelt|rss|feed|atom|news|nachricht|schlagzeil|headline|youtube|video|transkript|transcript|channel|kanal|zusammenfass)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows|bild|image|generier|photo|foto)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|script|skript|befehl|kommando|tägliche?r?s?|stündliche?r?s?|wöchentliche?r?s?|monatliche?r?s?|jeden\s+(tag|morgen|abend|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag)|um\s+\d{1,2}\s*(uhr|:|h)|alle\s+\d+\s*(min|stund|sekund)|in\s+\d+\s*(minuten?|stunden?|sekunden?|hours?|minutes?|seconds?|min)|daily|hourly|weekly|every\s+(day|hour|morning|evening|night|\d+\s*min)|führ.{0,5}aus|execut|ausführ)\b/i,files:/\b(file|datei|document|dokument|pdf|http|download|upload|herunterlad|hochlad|anhang|attachment)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|netzwerk|network|homeassistant|home.?assistant|smarthome|smart.?home|licht|light|schalter|switch|solar|photovoltaik|pv|wechselrichter|inverter|batterie.?speicher|wallbox|energieverbrauch|stromverbrauch|verbrauch.{0,5}kwh|einspeis|netzeinspeis|autarkie|eigenverbrauch|bmw|auto|fahrzeug|ladestand|reichweite|laden(?!e)|charging|vehicle|soc|ladehistorie|ladesession|ladevorgang|ladezyklus|ladekurve|km|kilometer|kilometerstand|mileage|tachostand)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};p(yp,"selectCategories");p(wp,"filterSkills")});import oc from"node:fs";import _p from"node:path";function wg(l,e){if(l.length<=e)return l;let t=l.split(`
1208
1208
  `);if(t.length<=10)return l.slice(0,e)+`
1209
1209
 
1210
1210
  [... truncated, total `+l.length+" chars]";let s=Math.floor(t.length*.7),r=Math.max(Math.floor(t.length*.2),5),n=t.length-s-r,o=t.slice(0,s),i=t.slice(t.length-r),a=`
@@ -1215,9 +1215,9 @@ Antworte als JSON:
1215
1215
 
1216
1216
  [... truncated, total `+l.length+` chars]
1217
1217
 
1218
- `+l.slice(l.length-Math.floor(e*.2))}return c}var hg,kp,fg,gg,yg,bp,Tg,_g,kg,Ep,bg,hn,ic=T(()=>{"use strict";ga();_t();Tp();hg=900*1e3,kp=50,fg=2,gg=12e3,yg=3,bp=.85;p(wg,"truncateToolResult");Tg=1e5,_g=2e3,kg=.1,Ep=3,bg=10,hn=class{static{p(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;confirmationQueue;activityLogger;skillHealthTracker;activeAgents=new Map;agentIdCounter=0;metrics={requestsTotal:0,requestsSuccess:0,requestsFailed:0,avgDurationMs:0,totalInputTokens:0,totalOutputTokens:0,totalCostUsd:0};getMetrics(){return{...this.metrics}}setConfirmationQueue(e){this.confirmationQueue=e}setActivityLogger(e){this.activityLogger=e}setSkillHealthTracker(e){this.skillHealthTracker=e}recordMetric(e,t,s){this.metrics.requestsTotal++,e?this.metrics.requestsSuccess++:this.metrics.requestsFailed++,this.metrics.avgDurationMs=Math.round(this.metrics.avgDurationMs+(t-this.metrics.avgDurationMs)/this.metrics.requestsTotal),this.metrics.lastRequestAt=new Date().toISOString(),s&&(this.metrics.totalInputTokens+=s.input,this.metrics.totalOutputTokens+=s.output,this.metrics.totalCostUsd+=s.costUsd)}constructor(e){this.llm=e.llm,this.conversationManager=e.conversationManager,this.users=e.users,this.logger=e.logger,this.skillRegistry=e.skillRegistry,this.skillSandbox=e.skillSandbox,this.securityManager=e.securityManager,this.memoryRepo=e.memoryRepo,this.speechTranscriber=e.speechTranscriber,this.inboxPath=e.inboxPath,this.embeddingService=e.embeddingService,this.activeLearning=e.activeLearning,this.memoryRetriever=e.memoryRetriever,this.maxHistoryMessages=e.maxHistoryMessages??30,this.documentProcessor=e.documentProcessor,this.conversationSummarizer=e.conversationSummarizer,this.promptBuilder=new Pr}async process(e,t){let s=Date.now();if(this.logger.info({platform:e.platform,userId:e.userId,chatId:e.chatId},"Processing message"),this.confirmationQueue&&e.text){let{context:r}=Ie(this.users,{platformUserId:e.userId,platform:e.platform,chatId:e.chatId,chatType:e.chatType,userName:e.userName,displayName:e.displayName});if(await this.confirmationQueue.checkForConfirmation(e.chatId,e.platform,e.text,r))return{text:""}}try{let r=e.metadata?.originalChatId??e.chatId,{user:n,masterUserId:o,linkedPlatformUserIds:i,context:a}=Ie(this.users,{platformUserId:e.userId,platform:e.platform,chatId:r,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),c=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,n.id),d=!e.metadata?.skipHistory&&this.conversationSummarizer?this.conversationSummarizer.getSummary(c.id):void 0,u=d?bg:this.maxHistoryMessages,m=e.metadata?.skipHistory?[]:this.conversationManager.getHistory(c.id,u);this.conversationManager.addMessage(c.id,"user",e.text);let h,f=this.isSyntheticLabel(e.text),g=e.attachments?.some(K=>K.type==="audio")??!1,y=f&&!g;if(this.memoryRetriever&&e.text&&!y)try{h=await this.memoryRetriever.retrieve(o,e.text,15,i)}catch(K){this.logger.debug({err:K},"Hybrid memory retrieval failed")}if(!h&&this.memoryRepo&&!y)try{let K=[o,...(i??[]).filter(z=>z!==o)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let z=new Set;h=[];for(let C of K)for(let j of await this.embeddingService.semanticSearch(C,e.text,10))z.has(j.key)||(z.add(j.key),h.push(j));for(let C of K)for(let j of this.memoryRepo.getRecentForPrompt(C,5))z.has(j.key)||(z.add(j.key),h.push(j))}else{let z=new Set;h=[];for(let C of K)for(let j of this.memoryRepo.getRecentForPrompt(C,20))z.has(j.key)||(z.add(j.key),h.push(j))}}catch(K){this.logger.debug({err:K},"Memory loading failed")}h&&h.length>0&&(h=this.applyMemoryBudget(h));let _;try{"getProfile"in this.users&&(_=this.users.getProfile(o),_&&!_.displayName&&(_.displayName=n.displayName??n.username))}catch(K){this.logger.debug({err:K},"Profile loading failed")}let S=a.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,E=this.skillRegistry?this.skillRegistry.getAll().map(K=>K.metadata):void 0,$=E;if(E&&e.text){let K=new Set(E.map(Z=>Z.category??"core")),z=m.filter(Z=>Z.role==="user").slice(-3).map(Z=>Z.content).join(" "),C=z?`${e.text} ${z}`:e.text,j=yp(C,K);$=wp(E,j)}let R=$?this.promptBuilder.buildTools($):void 0,M=this.promptBuilder.buildSystemPrompt({memories:h,skills:$,userProfile:_,conversationSummary:d?.summary}),q=this.buildActiveAgentStatus();q&&(M+=`
1218
+ `+l.slice(l.length-Math.floor(e*.2))}return c}var hg,kp,fg,gg,yg,bp,Tg,_g,kg,Ep,bg,fn,ic=T(()=>{"use strict";ga();_t();Tp();hg=900*1e3,kp=50,fg=2,gg=12e3,yg=3,bp=.85;p(wg,"truncateToolResult");Tg=1e5,_g=2e3,kg=.1,Ep=3,bg=10,fn=class{static{p(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;confirmationQueue;activityLogger;skillHealthTracker;activeAgents=new Map;agentIdCounter=0;metrics={requestsTotal:0,requestsSuccess:0,requestsFailed:0,avgDurationMs:0,totalInputTokens:0,totalOutputTokens:0,totalCostUsd:0};getMetrics(){return{...this.metrics}}setConfirmationQueue(e){this.confirmationQueue=e}setActivityLogger(e){this.activityLogger=e}setSkillHealthTracker(e){this.skillHealthTracker=e}recordMetric(e,t,s){this.metrics.requestsTotal++,e?this.metrics.requestsSuccess++:this.metrics.requestsFailed++,this.metrics.avgDurationMs=Math.round(this.metrics.avgDurationMs+(t-this.metrics.avgDurationMs)/this.metrics.requestsTotal),this.metrics.lastRequestAt=new Date().toISOString(),s&&(this.metrics.totalInputTokens+=s.input,this.metrics.totalOutputTokens+=s.output,this.metrics.totalCostUsd+=s.costUsd)}constructor(e){this.llm=e.llm,this.conversationManager=e.conversationManager,this.users=e.users,this.logger=e.logger,this.skillRegistry=e.skillRegistry,this.skillSandbox=e.skillSandbox,this.securityManager=e.securityManager,this.memoryRepo=e.memoryRepo,this.speechTranscriber=e.speechTranscriber,this.inboxPath=e.inboxPath,this.embeddingService=e.embeddingService,this.activeLearning=e.activeLearning,this.memoryRetriever=e.memoryRetriever,this.maxHistoryMessages=e.maxHistoryMessages??30,this.documentProcessor=e.documentProcessor,this.conversationSummarizer=e.conversationSummarizer,this.promptBuilder=new Pr}async process(e,t){let s=Date.now();if(this.logger.info({platform:e.platform,userId:e.userId,chatId:e.chatId},"Processing message"),this.confirmationQueue&&e.text){let{context:r}=Ie(this.users,{platformUserId:e.userId,platform:e.platform,chatId:e.chatId,chatType:e.chatType,userName:e.userName,displayName:e.displayName});if(await this.confirmationQueue.checkForConfirmation(e.chatId,e.platform,e.text,r))return{text:""}}try{let r=e.metadata?.originalChatId??e.chatId,{user:n,masterUserId:o,linkedPlatformUserIds:i,context:a}=Ie(this.users,{platformUserId:e.userId,platform:e.platform,chatId:r,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),c=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,n.id),d=!e.metadata?.skipHistory&&this.conversationSummarizer?this.conversationSummarizer.getSummary(c.id):void 0,u=d?bg:this.maxHistoryMessages,m=e.metadata?.skipHistory?[]:this.conversationManager.getHistory(c.id,u);this.conversationManager.addMessage(c.id,"user",e.text);let h,f=this.isSyntheticLabel(e.text),g=e.attachments?.some(K=>K.type==="audio")??!1,y=f&&!g;if(this.memoryRetriever&&e.text&&!y)try{h=await this.memoryRetriever.retrieve(o,e.text,15,i)}catch(K){this.logger.debug({err:K},"Hybrid memory retrieval failed")}if(!h&&this.memoryRepo&&!y)try{let K=[o,...(i??[]).filter(z=>z!==o)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let z=new Set;h=[];for(let C of K)for(let j of await this.embeddingService.semanticSearch(C,e.text,10))z.has(j.key)||(z.add(j.key),h.push(j));for(let C of K)for(let j of this.memoryRepo.getRecentForPrompt(C,5))z.has(j.key)||(z.add(j.key),h.push(j))}else{let z=new Set;h=[];for(let C of K)for(let j of this.memoryRepo.getRecentForPrompt(C,20))z.has(j.key)||(z.add(j.key),h.push(j))}}catch(K){this.logger.debug({err:K},"Memory loading failed")}h&&h.length>0&&(h=this.applyMemoryBudget(h));let _;try{"getProfile"in this.users&&(_=this.users.getProfile(o),_&&!_.displayName&&(_.displayName=n.displayName??n.username))}catch(K){this.logger.debug({err:K},"Profile loading failed")}let S=a.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,E=this.skillRegistry?this.skillRegistry.getAll().map(K=>K.metadata):void 0,$=E;if(E&&e.text){let K=new Set(E.map(Z=>Z.category??"core")),z=m.filter(Z=>Z.role==="user").slice(-3).map(Z=>Z.content).join(" "),C=z?`${e.text} ${z}`:e.text,j=yp(C,K);$=wp(E,j)}let R=$?this.promptBuilder.buildTools($):void 0,M=this.promptBuilder.buildSystemPrompt({memories:h,skills:$,userProfile:_,conversationSummary:d?.summary}),q=this.buildActiveAgentStatus();q&&(M+=`
1219
1219
 
1220
- `+q);let G=this.promptBuilder.buildMessages(m),F=this.collapseRepeatedToolErrors(G),ee=fa(F),ue=F.reduce((K,z)=>K+jt(z),0)-ee.reduce((K,z)=>K+jt(z),0);ue>100&&this.logger.debug(`Tool result trimming saved ~${ue} tokens`);let L=await this.buildUserContent(e,t);ee.push({role:"user",content:L});let ne=R?We(JSON.stringify(R)):0,ae=1,Q=this.trimToContextWindow(M,ee,ne,ae),W,he=0,Ve=Date.now(),le="",Se=0,pe=0,Ue=0,Qe=[],Ye=[],et=[];for(t?.("Thinking...");;){he>0&&this.compressToolLoop(Q,M,ne);try{W=await this.llm.complete({messages:Q,system:M,tools:R&&R.length>0?R:void 0,tier:e.metadata?.tier}),pe+=W.usage?.inputTokens??0,Ue+=W.usage?.outputTokens??0}catch(te){if((te instanceof Error?te.message:String(te)).includes("prompt is too long")&&ae>.3){ae*=.5,this.logger.warn({budgetMultiplier:ae},"Prompt too long, retrimming with reduced budget"),Q=this.trimToContextWindow(M,ee,ne,ae);continue}throw te}if(W.stopReason==="max_tokens"&&W.toolCalls?.length&&(this.logger.warn({toolCallCount:W.toolCalls.length},"Discarding truncated tool calls due to max_tokens"),W={...W,toolCalls:[]}),!W.toolCalls||W.toolCalls.length===0){if(W.stopReason==="max_tokens"){let te=0,$e=W.content??"";for(;W.stopReason==="max_tokens"&&te<yg;){te++,this.logger.info({continuationRounds:te,textLength:$e.length},"Output truncated, requesting continuation"),$e?(Q.push({role:"assistant",content:$e}),Q.push({role:"user",content:"Fahre exakt dort fort wo du aufgeh\xF6rt hast. Keine Wiederholung, nur der Rest."})):Q.push({role:"user",content:"Deine Antwort war zu lang und wurde abgeschnitten. Bitte antworte k\xFCrzer und kompakter. Fasse zusammen statt alles aufzulisten."});try{W=await this.llm.complete({messages:Q,system:M,tools:R&&R.length>0?R:void 0,tier:e.metadata?.tier}),pe+=W.usage?.inputTokens??0,Ue+=W.usage?.outputTokens??0,W.content&&($e+=W.content)}catch{break}}W={...W,content:$e,stopReason:"end_turn"}}break}let K=Date.now()-Ve;if(K>=hg){let te=Math.round(K/6e4);this.logger.warn({iteration:he,elapsedMin:te,pendingToolCalls:W.toolCalls.length},"Tool loop timeout reached"),W=await this.abortToolLoop(Q,W,c.id,M,`Das Zeitlimit von ${te} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(he>=kp){this.logger.warn({iteration:he,pendingToolCalls:W.toolCalls.length},"Tool loop iteration cap reached"),W=await this.abortToolLoop(Q,W,c.id,M,`Das Iterationslimit von ${kp} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}he++,this.logger.info({iteration:he,toolCalls:W.toolCalls.length},"Processing tool calls");let z=[];W.content&&z.push({type:"text",text:W.content});for(let te of W.toolCalls)z.push({type:"tool_use",id:te.id,name:te.name,input:te.input});Q.push({role:"assistant",content:z});let C=await this.executeToolCallsParallel(W.toolCalls,{...a,conversationId:c.id,timezone:S},t),j=C.blocks;C.attachments.length>0&&Qe.push(...C.attachments),Ye.push(...W.toolCalls),et.push(...j);let Z=this.buildErrorSignature(j);if(Z){if(Z===le?Se++:(Se=1,le=Z),Se>=fg){this.logger.warn({iteration:he,consecutiveErrors:Se,errorSignature:Z},"Tool loop aborted: same error repeated consecutively"),W=await this.abortToolLoop(Q,W,c.id,M,`Der gleiche Tool-Fehler ist ${Se}x hintereinander aufgetreten: "${le.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else Se=0,le="";Q.push({role:"user",content:j}),t?.("Thinking...")}let Me=W.content;if(!Me)for(let K=Q.length-1;K>=0;K--){let z=Q[K];if(z.role==="assistant"&&Array.isArray(z.content)){let C=z.content.find(j=>j.type==="text");if(C&&"text"in C&&C.text){Me=C.text;break}}}if(Me||(Me="(no response)"),Ye.length>0&&(this.conversationManager.addMessage(c.id,"assistant","",JSON.stringify(Ye)),this.conversationManager.addMessage(c.id,"user","",JSON.stringify(et))),this.conversationManager.addMessage(c.id,"assistant",Me),this.activeLearning&&this.activeLearning.onMessageProcessed(o,e.text,Me),this.conversationSummarizer&&!e.metadata?.skipHistory){let K=m.slice(-8).map(z=>({role:z.role,content:z.content}));this.conversationSummarizer.onMessageProcessed(c.id,m.length+2,e.text,Me,K)}let $t=Date.now()-s,vt=W.model??"unknown",tt=ho(vt,{inputTokens:pe,outputTokens:Ue});return this.logger.info({duration:$t,model:vt,tokens:W.usage,totalTokens:{inputTokens:pe,outputTokens:Ue},costUsd:Math.round(tt*1e6)/1e6,stopReason:W.stopReason,toolIterations:he},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:pe,output:Ue,costUsd:tt}),{text:Me,attachments:Qe.length>0?Qe:void 0}}catch(r){throw this.recordMetric(!1,Date.now()-s),this.logger.error({err:r},"Failed to process message"),r}}async abortToolLoop(e,t,s,r,n,o=!1,i){if(!o){let d=[];t.content&&d.push({type:"text",text:t.content});for(let u of t.toolCalls)d.push({type:"tool_use",id:u.id,name:u.name,input:u.input});e.push({role:"assistant",content:d})}let a=t.toolCalls.map(d=>({type:"tool_result",tool_use_id:d.id,content:`Error: tool loop aborted \u2014 ${n}`,is_error:!0}));e.push({role:"user",content:a}),o||this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),this.conversationManager.addMessage(s,"user","",JSON.stringify(a));let c=e[e.length-1];return c&&c.role==="user"&&Array.isArray(c.content)?c.content.push({type:"text",text:`[System: ${n} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}):e.push({role:"user",content:`[System: ${n} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}),await this.llm.complete({messages:e,system:r,tier:i})}buildErrorSignature(e){let t=[];for(let s of e)s.type==="tool_result"&&s.is_error&&t.push(s.content);return t.length>0?t.join("|"):""}collapseRepeatedToolErrors(e){let t=[],s=0;for(;s<e.length;){let r=e[s];if(r.role==="assistant"&&Array.isArray(r.content)&&r.content.some(n=>n.type==="tool_use")){let n=s+1<e.length?e[s+1]:null;if(n&&n.role==="user"&&Array.isArray(n.content)&&n.content.every(o=>o.type==="tool_result"&&o.is_error)){let o=this.toolPairSignature(r,n),i=1,a=s+2;for(;a+1<e.length;){let c=e[a],d=e[a+1];if(c.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(c,d)===o)i++,a+=2;else break}if(i>1){t.push(r),t.push(n),t.push({role:"user",content:`[System: The above tool error repeated ${i} times with identical input. The loop was aborted.]`}),s=a;continue}}}t.push(r),s++}return t}toolPairSignature(e,t){let s=Array.isArray(e.content)?e.content.filter(n=>n.type==="tool_use").map(n=>`${n.name}:${JSON.stringify(n.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(n=>n.type==="tool_result").map(n=>n.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],n=p((u,m)=>{let h=m.content;if(m.attachments&&m.attachments.length>0){r.push(...m.attachments);let f=m.attachments.map(g=>g.fileName).join(", ");h+=`
1220
+ `+q);let G=this.promptBuilder.buildMessages(m),F=this.collapseRepeatedToolErrors(G),ee=fa(F),ue=F.reduce((K,z)=>K+jt(z),0)-ee.reduce((K,z)=>K+jt(z),0);ue>100&&this.logger.debug(`Tool result trimming saved ~${ue} tokens`);let L=await this.buildUserContent(e,t);ee.push({role:"user",content:L});let ne=R?We(JSON.stringify(R)):0,ae=1,Q=this.trimToContextWindow(M,ee,ne,ae),W,he=0,Ve=Date.now(),le="",Se=0,pe=0,Ue=0,Qe=[],Ye=[],et=[];for(t?.("Thinking...");;){he>0&&this.compressToolLoop(Q,M,ne);try{W=await this.llm.complete({messages:Q,system:M,tools:R&&R.length>0?R:void 0,tier:e.metadata?.tier}),pe+=W.usage?.inputTokens??0,Ue+=W.usage?.outputTokens??0}catch(te){if((te instanceof Error?te.message:String(te)).includes("prompt is too long")&&ae>.3){ae*=.5,this.logger.warn({budgetMultiplier:ae},"Prompt too long, retrimming with reduced budget"),Q=this.trimToContextWindow(M,ee,ne,ae);continue}throw te}if(W.stopReason==="max_tokens"&&W.toolCalls?.length&&(this.logger.warn({toolCallCount:W.toolCalls.length},"Discarding truncated tool calls due to max_tokens"),W={...W,toolCalls:[]}),!W.toolCalls||W.toolCalls.length===0){if(W.stopReason==="max_tokens"){let te=0,$e=W.content??"";for(;W.stopReason==="max_tokens"&&te<yg;){te++,this.logger.info({continuationRounds:te,textLength:$e.length},"Output truncated, requesting continuation"),$e?(Q.push({role:"assistant",content:$e}),Q.push({role:"user",content:"Fahre exakt dort fort wo du aufgeh\xF6rt hast. Keine Wiederholung, nur der Rest."})):Q.push({role:"user",content:"Deine Antwort war zu lang und wurde abgeschnitten. Bitte antworte k\xFCrzer und kompakter. Fasse zusammen statt alles aufzulisten."});try{W=await this.llm.complete({messages:Q,system:M,tools:R&&R.length>0?R:void 0,tier:e.metadata?.tier}),pe+=W.usage?.inputTokens??0,Ue+=W.usage?.outputTokens??0,W.content&&($e+=W.content)}catch{break}}W={...W,content:$e,stopReason:"end_turn"}}break}let K=Date.now()-Ve;if(K>=hg){let te=Math.round(K/6e4);this.logger.warn({iteration:he,elapsedMin:te,pendingToolCalls:W.toolCalls.length},"Tool loop timeout reached"),W=await this.abortToolLoop(Q,W,c.id,M,`Das Zeitlimit von ${te} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(he>=kp){this.logger.warn({iteration:he,pendingToolCalls:W.toolCalls.length},"Tool loop iteration cap reached"),W=await this.abortToolLoop(Q,W,c.id,M,`Das Iterationslimit von ${kp} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}he++,this.logger.info({iteration:he,toolCalls:W.toolCalls.length},"Processing tool calls");let z=[];W.content&&z.push({type:"text",text:W.content});for(let te of W.toolCalls)z.push({type:"tool_use",id:te.id,name:te.name,input:te.input});Q.push({role:"assistant",content:z});let C=await this.executeToolCallsParallel(W.toolCalls,{...a,conversationId:c.id,timezone:S},t),j=C.blocks;C.attachments.length>0&&Qe.push(...C.attachments),Ye.push(...W.toolCalls),et.push(...j);let Z=this.buildErrorSignature(j);if(Z){if(Z===le?Se++:(Se=1,le=Z),Se>=fg){this.logger.warn({iteration:he,consecutiveErrors:Se,errorSignature:Z},"Tool loop aborted: same error repeated consecutively"),W=await this.abortToolLoop(Q,W,c.id,M,`Der gleiche Tool-Fehler ist ${Se}x hintereinander aufgetreten: "${le.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else Se=0,le="";Q.push({role:"user",content:j}),t?.("Thinking...")}let Me=W.content;if(!Me)for(let K=Q.length-1;K>=0;K--){let z=Q[K];if(z.role==="assistant"&&Array.isArray(z.content)){let C=z.content.find(j=>j.type==="text");if(C&&"text"in C&&C.text){Me=C.text;break}}}if(Me||(Me="(no response)"),Ye.length>0&&(this.conversationManager.addMessage(c.id,"assistant","",JSON.stringify(Ye)),this.conversationManager.addMessage(c.id,"user","",JSON.stringify(et))),this.conversationManager.addMessage(c.id,"assistant",Me),this.activeLearning&&this.activeLearning.onMessageProcessed(o,e.text,Me),this.conversationSummarizer&&!e.metadata?.skipHistory){let K=m.slice(-8).map(z=>({role:z.role,content:z.content}));this.conversationSummarizer.onMessageProcessed(c.id,m.length+2,e.text,Me,K)}let $t=Date.now()-s,vt=W.model??"unknown",tt=fo(vt,{inputTokens:pe,outputTokens:Ue});return this.logger.info({duration:$t,model:vt,tokens:W.usage,totalTokens:{inputTokens:pe,outputTokens:Ue},costUsd:Math.round(tt*1e6)/1e6,stopReason:W.stopReason,toolIterations:he},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:pe,output:Ue,costUsd:tt}),{text:Me,attachments:Qe.length>0?Qe:void 0}}catch(r){throw this.recordMetric(!1,Date.now()-s),this.logger.error({err:r},"Failed to process message"),r}}async abortToolLoop(e,t,s,r,n,o=!1,i){if(!o){let d=[];t.content&&d.push({type:"text",text:t.content});for(let u of t.toolCalls)d.push({type:"tool_use",id:u.id,name:u.name,input:u.input});e.push({role:"assistant",content:d})}let a=t.toolCalls.map(d=>({type:"tool_result",tool_use_id:d.id,content:`Error: tool loop aborted \u2014 ${n}`,is_error:!0}));e.push({role:"user",content:a}),o||this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),this.conversationManager.addMessage(s,"user","",JSON.stringify(a));let c=e[e.length-1];return c&&c.role==="user"&&Array.isArray(c.content)?c.content.push({type:"text",text:`[System: ${n} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}):e.push({role:"user",content:`[System: ${n} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}),await this.llm.complete({messages:e,system:r,tier:i})}buildErrorSignature(e){let t=[];for(let s of e)s.type==="tool_result"&&s.is_error&&t.push(s.content);return t.length>0?t.join("|"):""}collapseRepeatedToolErrors(e){let t=[],s=0;for(;s<e.length;){let r=e[s];if(r.role==="assistant"&&Array.isArray(r.content)&&r.content.some(n=>n.type==="tool_use")){let n=s+1<e.length?e[s+1]:null;if(n&&n.role==="user"&&Array.isArray(n.content)&&n.content.every(o=>o.type==="tool_result"&&o.is_error)){let o=this.toolPairSignature(r,n),i=1,a=s+2;for(;a+1<e.length;){let c=e[a],d=e[a+1];if(c.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(c,d)===o)i++,a+=2;else break}if(i>1){t.push(r),t.push(n),t.push({role:"user",content:`[System: The above tool error repeated ${i} times with identical input. The loop was aborted.]`}),s=a;continue}}}t.push(r),s++}return t}toolPairSignature(e,t){let s=Array.isArray(e.content)?e.content.filter(n=>n.type==="tool_use").map(n=>`${n.name}:${JSON.stringify(n.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(n=>n.type==="tool_result").map(n=>n.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],n=p((u,m)=>{let h=m.content;if(m.attachments&&m.attachments.length>0){r.push(...m.attachments);let f=m.attachments.map(g=>g.fileName).join(", ");h+=`
1221
1221
 
1222
1222
  [${m.attachments.length} Datei(en) werden dem User gesendet: ${f}]`}return h=wg(h,gg),{type:"tool_result",tool_use_id:u.id,content:h,is_error:m.isError}},"buildBlock");if(e.length===1){let u=e[0],m=this.getToolLabel(u.name,u.input);s?.(m);let h=await this.executeToolCall(u,t,s);return{blocks:[n(u,h)],attachments:r}}let o=3;s?.(`Running ${e.length} tools...`);let i=new Map;for(let u=0;u<e.length;u++){let m=e[u].name,h=i.get(m);h||(h=[],i.set(m,h)),h.push(u)}let a=[...i.values()].some(u=>u.length>o),c;if(a){c=new Map;let u=[...i.entries()].map(async([m,h])=>{for(let f=0;f<h.length;f+=o){let g=h.slice(f,f+o),y=await Promise.allSettled(g.map(_=>this.executeToolCall(e[_],t,s)));for(let _=0;_<g.length;_++)c.set(g[_],y[_])}});await Promise.all(u)}else{let u=await Promise.allSettled(e.map(m=>this.executeToolCall(m,t,s)));c=new Map(u.map((m,h)=>[h,m]))}return{blocks:e.map((u,m)=>{let h=c.get(m);return h.status==="fulfilled"?n(u,h.value):{type:"tool_result",tool_use_id:u.id,content:`Tool execution failed: ${h.reason}`,is_error:!0}}),attachments:r}}async executeToolCall(e,t,s){let r=this.skillRegistry?.get(e.name);if(!r)return this.logger.warn({tool:e.name},"Unknown skill requested"),{content:`Error: Unknown tool "${e.name}"`,isError:!0};if(this.skillHealthTracker){let n=this.skillHealthTracker.isDisabled(e.name);if(n){let o=n.disabledUntil?new Date(n.disabledUntil).toISOString():"unknown";return this.logger.warn({tool:e.name,disabledUntil:o,consecutiveFails:n.consecutiveFails},"Skill is auto-disabled due to repeated failures"),{content:`Skill "${e.name}" is temporarily disabled due to repeated failures (${n.consecutiveFails} consecutive). Re-enabled at ${o}.`,isError:!0}}}if(this.securityManager){let n=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:r.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!n.allowed)return this.logger.warn({tool:e.name,reason:n.reason,rule:n.matchedRule?.id},"Skill execution denied by security rules"),this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:"denied",error:n.reason}),{content:`Access denied: ${n.reason}`,isError:!0}}if(this.skillSandbox){let n,o;if(e.name==="delegate"){let{ActivityTracker:c}=await Promise.resolve().then(()=>(re(),ie));n=new c(s),o=`agent-${++this.agentIdCounter}`,this.activeAgents.set(o,{chatId:t.chatId,task:String(e.input.task??"").slice(0,200),tracker:n,startedAt:Date.now()})}let i=e.name==="delegate"?{...t,tracker:n,onProgress:s}:s?{...t,onProgress:s}:t,a=Date.now();try{let c=await this.skillSandbox.execute(r,e.input,i,void 0,n);return this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:c.success?"success":"error",durationMs:Date.now()-a,error:c.error}),this.skillHealthTracker&&(c.success?this.skillHealthTracker.recordSuccess(e.name):this.skillHealthTracker.recordFailure(e.name,c.error??"Unknown error")),{content:c.display??(c.success?JSON.stringify(c.data):c.error??"Unknown error"),isError:!c.success,attachments:c.attachments}}catch(c){let d=c instanceof Error?c.message:String(c);throw this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:"error",durationMs:Date.now()-a,error:d}),this.skillHealthTracker?.recordFailure(e.name,d),c}finally{o&&this.activeAgents.delete(o)}}try{let n=await r.execute(e.input,t);return n.success?this.skillHealthTracker?.recordSuccess(e.name):this.skillHealthTracker?.recordFailure(e.name,n.error??"Unknown error"),{content:n.display??(n.success?JSON.stringify(n.data):n.error??"Unknown error"),isError:!n.success,attachments:n.attachments}}catch(n){let o=n instanceof Error?n.message:String(n);return this.skillHealthTracker?.recordFailure(e.name,o),{content:`Skill execution failed: ${o}`,isError:!0}}}getToolLabel(e,t){switch(e){case"shell":return`Running: ${String(t.command??"").slice(0,60)}`;case"web_search":return`Searching: ${String(t.query??"")}`;case"email":return`Email: ${String(t.action??"")}`;case"memory":return`Memory: ${String(t.action??"")}`;case"reminder":return`Reminder: ${String(t.action??"")}`;case"calculator":return"Calculating...";case"system_info":return"Getting system info...";case"delegate":return"Delegating sub-task...";case"http":return`Fetching: ${String(t.url??"").slice(0,60)}`;case"file":return`File: ${String(t.action??"")} ${String(t.path??"").slice(0,50)}`;case"clipboard":return`Clipboard: ${String(t.action??"")}`;case"screenshot":return"Taking screenshot...";case"browser":return`Browser: ${String(t.action??"")} ${String(t.url??"").slice(0,50)}`;case"weather":return`Weather: ${String(t.location??"")}`;case"note":return`Note: ${String(t.action??"")}`;case"profile":return`Profile: ${String(t.action??"")}`;case"calendar":return`Calendar: ${String(t.action??"")}`;case"background_task":return`Background task: ${String(t.action??"")}`;case"scheduled_task":return`Scheduled task: ${String(t.action??"")}`;case"cross_platform":return`Cross-platform: ${String(t.action??"")}`;case"code_sandbox":return"Running code...";case"document":return`Document: ${String(t.action??"")}`;default:return`Using ${e}...`}}buildActiveAgentStatus(){if(this.activeAgents.size===0)return;let e=["## Currently running sub-agents"];for(let[t,s]of this.activeAgents){let r=s.tracker.getSnapshot(),n=Math.round(r.totalElapsedMs/1e3);e.push(`- **${t}**: "${s.task}"`,` Status: ${s.tracker.formatStatus()}`,` Running for ${n}s | Last activity ${Math.round(r.idleMs/1e3)}s ago`)}return e.push(""),e.push("If the user asks what you or the agent is doing, describe the above status in natural language."),e.join(`
1223
1223
  `)}applyMemoryBudget(e){let t=e.some(o=>o.score!=null&&o.score>0),s=e;t&&(s=e.filter(o=>(o.score??1)>=kg));let r=0,n=[];for(let o of s){let i=We(`[${o.category}] ${o.key}: ${o.value}`);if(r+i>_g)break;r+=i,n.push(o)}return n.length<e.length&&this.logger.info({original:e.length,kept:n.length,tokenCount:r,droppedByScore:e.length-s.length},"Memory budget applied"),n}compressToolLoop(e,t,s=0){let r=this.llm.getContextWindow(),n=Math.floor(r.maxInputTokens*bp);if(We(t)+s+e.reduce((g,y)=>g+jt(y),0)<=n)return;let a=[];for(let g=0;g<e.length-1;g++){let y=e[g],_=e[g+1];y.role==="assistant"&&Array.isArray(y.content)&&y.content.some(S=>S.type==="tool_use")&&_.role==="user"&&Array.isArray(_.content)&&_.content.some(S=>S.type==="tool_result")&&a.push({start:g,end:g+1})}if(a.length<=Ep)return;let c=a.length-Ep,d=a.slice(0,c),u=[];for(let g of d){let y=e[g.start],_=[];if(Array.isArray(y.content))for(let $ of y.content)$.type==="tool_use"&&_.push($.name);let S=e[g.end],E="ok";Array.isArray(S.content)&&S.content.some(R=>R.type==="tool_result"&&R.is_error)&&(E="error"),u.push(`- ${_.join(", ")}: ${E}`)}let m=d[0].start,f=d[d.length-1].end-m+1;e.splice(m,f,{role:"assistant",content:`[Earlier tool interactions compressed (${d.length} pairs):
@@ -1235,24 +1235,24 @@ The conversation continues below with the most recent messages.]`})}return y.pus
1235
1235
  [File content]:
1236
1236
  ${u}`}if(this.documentProcessor&&this.isIngestable(i.mimeType))try{let u=await this.documentProcessor.ingest(e.userId,a,i.fileName??"unknown",i.mimeType??"application/octet-stream");if(u.existing){try{oc.unlinkSync(a)}catch{}d=`[File received: "${i.fileName??"unknown"}" (duplicate, not saved again)]
1237
1237
  [IMPORTANT: This document is already indexed (${u.chunkCount} chunks). To read or answer questions about it, use the "document" skill with action "search" and a relevant query. Do NOT use shell/file tools to read the PDF.]`}else d+=`
1238
- [IMPORTANT: Document has been indexed (${u.chunkCount} chunks). To read or answer questions about it, use the "document" skill with action "search" and a relevant query. Do NOT use shell/file tools to read the PDF.]`}catch(u){this.logger.warn({err:u,fileName:i.fileName},"Auto-ingest failed")}r.push({type:"text",text:d}),this.logger.info({fileName:i.fileName,savedPath:a,size:i.data.length},"File saved to inbox")}}let n=this.isSyntheticLabel(e.text);e.text&&!n&&r.push({type:"text",text:e.text});let o=r.some(i=>i.type==="text");if(r.some(i=>i.type==="image")&&!o)r.push({type:"text",text:"What do you see in this image?"});else if(n&&r.some(i=>i.type==="text"&&i.text.startsWith("[File received:"))){let i=r.some(c=>c.type==="text"&&c.text.includes("document is already indexed")),a=r.some(c=>c.type==="text"&&c.text.includes("Document has been indexed"));i||a?r.push({type:"text",text:"The user sent this document. It has been automatically indexed. Acknowledge receipt and tell the user the document is ready \u2014 they can ask questions about its content anytime."}):r.push({type:"text",text:"The user sent this file without any instructions. Ask them what they would like you to do with it. Do NOT take any other actions, do NOT use any tools, and do NOT act on conversation history or memories. ONLY ask what the user wants."})}else r.length===0&&r.push({type:"text",text:e.text||"(empty message)"});return r}isSyntheticLabel(e){return e?["[Photo","[Voice message","[Video","[Document","[File","[Sticker","[Audio"].some(s=>e.startsWith(s)):!0}saveToInbox(e){if(!e.data)return;let t=this.inboxPath??_p.resolve("./data/inbox");try{oc.mkdirSync(t,{recursive:!0})}catch{this.logger.error({inboxDir:t},"Cannot create inbox directory");return}let s=new Date().toISOString().replace(/[:.]/g,"-"),n=(e.fileName??`file_${s}`).replace(/[<>:"/\\|?*]/g,"_"),o=`${s}_${n}`,i=_p.join(t,o);try{return oc.writeFileSync(i,e.data),i}catch(a){this.logger.error({err:a,filePath:i},"Failed to save file to inbox");return}}isIngestable(e){return e?["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword","text/plain","text/csv","text/markdown","text/html","application/json","application/xml"].includes(e)||e.startsWith("text/"):!1}isTextMimeType(e){return e?["text/","application/json","application/xml","application/javascript","application/typescript","application/x-yaml","application/yaml","application/toml","application/x-sh","application/sql","application/csv","application/x-csv"].some(s=>e.startsWith(s)):!1}formatBytes(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var fn,ac=T(()=>{"use strict";fn=class l{static{p(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;failCounts=new Map;static MAX_SEND_RETRIES=5;constructor(e,t,s,r=15e3,n){this.reminderRepo=e,this.sendMessage=t,this.logger=s,this.linkedUsers=n,this.checkIntervalMs=r}start(){this.logger.info("Reminder scheduler started"),this.intervalId=setInterval(()=>this.checkDueReminders(),this.checkIntervalMs),this.checkDueReminders()}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=void 0),this.failCounts.clear(),this.logger.info("Reminder scheduler stopped")}async checkDueReminders(){try{let e=this.reminderRepo.getDue();for(let t of e)try{let s=`\u23F0 Reminder: ${t.message}`,r=!1;try{await this.sendMessage(t.platform,t.chatId,s),r=!0}catch(n){this.logger.warn({err:n,reminderId:t.id},"Primary platform delivery failed, trying cross-platform")}if(this.linkedUsers)try{let n=this.linkedUsers.getMasterUserId(t.userId),o=this.linkedUsers.getLinkedUsers(n);for(let i of o){if(i.platform===t.platform)continue;let a=this.linkedUsers.findConversation(i.platform,i.id);if(a)try{await this.sendMessage(i.platform,a.chatId,s),r=!0}catch(c){this.logger.debug({err:c,reminderId:t.id,platform:i.platform},"Cross-platform delivery failed")}}}catch(n){this.logger.debug({err:n,reminderId:t.id},"Cross-platform user lookup failed")}if(!r)throw new Error("No platform could deliver reminder");this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.info({reminderId:t.id},"Reminder fired")}catch(s){let r=(this.failCounts.get(t.id)??0)+1;this.failCounts.set(t.id,r),r>=l.MAX_SEND_RETRIES?(this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.error({reminderId:t.id,attempts:r,chatId:t.chatId},"Reminder abandoned after max retries \u2014 marked as fired")):this.logger.warn({err:s,reminderId:t.id,attempt:r,maxRetries:l.MAX_SEND_RETRIES},"Failed to send reminder, will retry")}}catch(e){this.logger.error({err:e},"Error checking due reminders")}}}});var gn,cc=T(()=>{"use strict";gn=class{static{p(this,"SpeechTranscriber")}logger;apiKey;baseUrl;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,e.provider==="groq"?this.baseUrl=e.baseUrl??"https://api.groq.com/openai/v1":this.baseUrl=e.baseUrl??"https://api.openai.com/v1"}async transcribe(e,t){let s=this.mimeToExtension(t),r=new FormData;r.append("file",new Blob([e],{type:t}),`audio.${s}`),r.append("model","whisper-1");try{let n=await fetch(`${this.baseUrl}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:r});if(!n.ok){let i=await n.text();throw new Error(`Whisper API ${n.status}: ${i}`)}let o=await n.json();return this.logger.info({textLength:o.text.length},"Voice transcribed"),o.text}catch(n){throw this.logger.error({err:n},"Voice transcription failed"),n}}mimeToExtension(e){return{"audio/ogg":"ogg","audio/mpeg":"mp3","audio/mp4":"m4a","audio/wav":"wav","audio/webm":"webm","audio/x-m4a":"m4a"}[e]??"ogg"}}});var yn,lc=T(()=>{"use strict";yn=class{static{p(this,"SpeechSynthesizer")}logger;apiKey;baseUrl;model;voice;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,this.baseUrl=e.baseUrl??"https://api.openai.com/v1",this.model=e.ttsModel??"tts-1",this.voice=e.ttsVoice??"alloy"}async synthesize(e){this.logger.info({textLength:e.length,model:this.model,voice:this.voice},"Synthesizing speech");let t=await fetch(`${this.baseUrl}/audio/speech`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:this.model,input:e,voice:this.voice,response_format:"opus"})});if(!t.ok){let r=await t.text();throw new Error(`TTS failed: ${t.status} ${r}`)}let s=Buffer.from(await t.arrayBuffer());return this.logger.info({audioBytes:s.length},"Speech synthesized"),s}}});var wn,dc=T(()=>{"use strict";wn=class{static{p(this,"ImageGenerator")}config;logger;constructor(e,t){this.config=e,this.logger=t}async generate(e,t={}){return this.logger.info({provider:this.config.provider,model:t.model,size:t.size},"Generating image"),this.config.provider==="openai"?this.generateOpenAI(e,t):this.generateGoogle(e,t)}async generateOpenAI(e,t){let{default:s}=await import("openai"),r=new s({apiKey:this.config.apiKey,...this.config.baseUrl&&{baseURL:this.config.baseUrl}}),n=t.model??"gpt-image-1",i=(await r.images.generate({model:n,prompt:e,n:1,size:t.size??"1024x1024",quality:t.quality??"medium"})).data?.[0]?.b64_json;if(!i)throw new Error("OpenAI image generation returned no data");let a=Buffer.from(i,"base64");return this.logger.info({model:n,bytes:a.length},"Image generated via OpenAI"),{data:a,mimeType:"image/png"}}async generateGoogle(e,t){let{GoogleGenAI:s}=await import("@google/genai"),r=new s({apiKey:this.config.apiKey}),n=t.model??"gemini-2.0-flash-exp",a=(await r.models.generateContent({model:n,contents:[{role:"user",parts:[{text:e}]}],config:{responseModalities:["IMAGE","TEXT"]}})).candidates?.[0]?.content?.parts?.find(u=>u.inlineData?.mimeType?.startsWith("image/"));if(!a?.inlineData)throw new Error("Google image generation returned no image data");let c=Buffer.from(a.inlineData.data,"base64"),d=a.inlineData.mimeType??"image/png";return this.logger.info({model:n,bytes:c.length,mimeType:d},"Image generated via Google"),{data:c,mimeType:d}}}});var Tn,uc=T(()=>{"use strict";Tn=class{static{p(this,"TransitClient")}logger;hafasClient;constructor(e){this.logger=e}async getClient(){if(this.hafasClient)return this.hafasClient;let{createClient:e}=await import("hafas-client"),{profile:t}=await import("hafas-client/p/oebb/index.js");return this.hafasClient=e(t,"alfred-ai-assistant"),this.hafasClient}async searchStops(e){return(await(await this.getClient()).locations(e,{results:10})).filter(r=>r.type==="stop"||r.type==="station").map(r=>({id:r.id,name:r.name,location:r.location?{latitude:r.location.latitude,longitude:r.location.longitude}:void 0}))}async journeys(e,t,s){let r=await this.getClient(),n={results:s?.results??3};return s?.departure&&(n.departure=s.departure),s?.arrival&&(n.arrival=s.arrival),((await r.journeys(e,t,n)).journeys||[]).map(i=>{let a=(i.legs||[]).map(f=>({origin:f.origin?.name||f.origin?.id||"Unknown",destination:f.destination?.name||f.destination?.id||"Unknown",departure:f.departure||f.plannedDeparture||"",arrival:f.arrival||f.plannedArrival||"",line:f.line?.name,direction:f.direction,mode:f.line?.mode||(f.walking?"walking":"unknown"),walking:f.walking===!0})),c=a[0]?.departure||"",d=a[a.length-1]?.arrival||"",u=c&&d?Math.round((new Date(d).getTime()-new Date(c).getTime())/6e4):0,m=a.filter(f=>!f.walking),h=Math.max(0,m.length-1);return{legs:a,departure:c,arrival:d,duration:u,transfers:h}})}async departures(e,t){let s=await this.getClient(),r={duration:t?.duration??30};t?.when&&(r.when=t.when);let n=await s.departures(e,r);return(n.departures||n||[]).map(o=>{let i=o.plannedWhen?new Date(o.plannedWhen):null,a=o.when?new Date(o.when):null,c=i&&a?Math.round((a.getTime()-i.getTime())/6e4):o.delay!=null?Math.round(o.delay/60):void 0;return{line:o.line?.name||o.line?.fahrtNr||"Unknown",direction:o.direction||o.destination?.name||"Unknown",when:o.when||o.plannedWhen||"",delay:c&&c>0?c:void 0,platform:o.platform||void 0}})}}});var _n,pc=T(()=>{"use strict";_n=class{static{p(this,"ResponseFormatter")}format(e,t){switch(t){case"telegram":return{text:this.toTelegramHTML(e),parseMode:"html"};case"discord":return{text:this.toMarkdown(e),parseMode:"markdown"};case"matrix":return{text:this.toTelegramHTML(e),parseMode:"html"};case"whatsapp":return{text:this.toWhatsApp(e),parseMode:"text"};case"signal":return{text:this.stripFormatting(e),parseMode:"text"};default:return{text:e,parseMode:"text"}}}toTelegramHTML(e){let t=e,s=[];t=t.replace(/```(\w*)\n([\s\S]*?)```/g,(n,o,i)=>(s.push(`<pre>${this.escapeHTML(i.trimEnd())}</pre>`),`\0CB${s.length-1}\0`));let r=[];t=t.replace(/`([^`]+)`/g,(n,o)=>(r.push(`<code>${this.escapeHTML(o)}</code>`),`\0IC${r.length-1}\0`)),t=t.replace(/^#{1,6}\s+(.+)$/gm,"<b>$1</b>"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"<b>$1</b>"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"<i>$1</i>"),t=t.replace(/~~(.+?)~~/g,"<s>$1</s>"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2">$1</a>'),t=t.replace(/<(\/?)(?:strong)>/gi,"<$1b>"),t=t.replace(/<(\/?)(?:em)>/gi,"<$1i>"),t=t.replace(/<(\/?)(?:del|strike)>/gi,"<$1s>");for(let n of["b","i","s","u"]){let o="";for(;o!==t;)o=t,t=this.flattenNestedTag(t,n)}return t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))[^>]*>/gi,""),t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))/gi,"&lt;"),t=t.replace(/\x00CB(\d+)\x00/g,(n,o)=>s[parseInt(o)]),t=t.replace(/\x00IC(\d+)\x00/g,(n,o)=>r[parseInt(o)]),t=t.replace(/\n{3,}/g,`
1238
+ [IMPORTANT: Document has been indexed (${u.chunkCount} chunks). To read or answer questions about it, use the "document" skill with action "search" and a relevant query. Do NOT use shell/file tools to read the PDF.]`}catch(u){this.logger.warn({err:u,fileName:i.fileName},"Auto-ingest failed")}r.push({type:"text",text:d}),this.logger.info({fileName:i.fileName,savedPath:a,size:i.data.length},"File saved to inbox")}}let n=this.isSyntheticLabel(e.text);e.text&&!n&&r.push({type:"text",text:e.text});let o=r.some(i=>i.type==="text");if(r.some(i=>i.type==="image")&&!o)r.push({type:"text",text:"What do you see in this image?"});else if(n&&r.some(i=>i.type==="text"&&i.text.startsWith("[File received:"))){let i=r.some(c=>c.type==="text"&&c.text.includes("document is already indexed")),a=r.some(c=>c.type==="text"&&c.text.includes("Document has been indexed"));i||a?r.push({type:"text",text:"The user sent this document. It has been automatically indexed. Acknowledge receipt and tell the user the document is ready \u2014 they can ask questions about its content anytime."}):r.push({type:"text",text:"The user sent this file without any instructions. Ask them what they would like you to do with it. Do NOT take any other actions, do NOT use any tools, and do NOT act on conversation history or memories. ONLY ask what the user wants."})}else r.length===0&&r.push({type:"text",text:e.text||"(empty message)"});return r}isSyntheticLabel(e){return e?["[Photo","[Voice message","[Video","[Document","[File","[Sticker","[Audio"].some(s=>e.startsWith(s)):!0}saveToInbox(e){if(!e.data)return;let t=this.inboxPath??_p.resolve("./data/inbox");try{oc.mkdirSync(t,{recursive:!0})}catch{this.logger.error({inboxDir:t},"Cannot create inbox directory");return}let s=new Date().toISOString().replace(/[:.]/g,"-"),n=(e.fileName??`file_${s}`).replace(/[<>:"/\\|?*]/g,"_"),o=`${s}_${n}`,i=_p.join(t,o);try{return oc.writeFileSync(i,e.data),i}catch(a){this.logger.error({err:a,filePath:i},"Failed to save file to inbox");return}}isIngestable(e){return e?["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword","text/plain","text/csv","text/markdown","text/html","application/json","application/xml"].includes(e)||e.startsWith("text/"):!1}isTextMimeType(e){return e?["text/","application/json","application/xml","application/javascript","application/typescript","application/x-yaml","application/yaml","application/toml","application/x-sh","application/sql","application/csv","application/x-csv"].some(s=>e.startsWith(s)):!1}formatBytes(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var gn,ac=T(()=>{"use strict";gn=class l{static{p(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;failCounts=new Map;static MAX_SEND_RETRIES=5;constructor(e,t,s,r=15e3,n){this.reminderRepo=e,this.sendMessage=t,this.logger=s,this.linkedUsers=n,this.checkIntervalMs=r}start(){this.logger.info("Reminder scheduler started"),this.intervalId=setInterval(()=>this.checkDueReminders(),this.checkIntervalMs),this.checkDueReminders()}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=void 0),this.failCounts.clear(),this.logger.info("Reminder scheduler stopped")}async checkDueReminders(){try{let e=this.reminderRepo.getDue();for(let t of e)try{let s=`\u23F0 Reminder: ${t.message}`,r=!1;try{await this.sendMessage(t.platform,t.chatId,s),r=!0}catch(n){this.logger.warn({err:n,reminderId:t.id},"Primary platform delivery failed, trying cross-platform")}if(this.linkedUsers)try{let n=this.linkedUsers.getMasterUserId(t.userId),o=this.linkedUsers.getLinkedUsers(n);for(let i of o){if(i.platform===t.platform)continue;let a=this.linkedUsers.findConversation(i.platform,i.id);if(a)try{await this.sendMessage(i.platform,a.chatId,s),r=!0}catch(c){this.logger.debug({err:c,reminderId:t.id,platform:i.platform},"Cross-platform delivery failed")}}}catch(n){this.logger.debug({err:n,reminderId:t.id},"Cross-platform user lookup failed")}if(!r)throw new Error("No platform could deliver reminder");this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.info({reminderId:t.id},"Reminder fired")}catch(s){let r=(this.failCounts.get(t.id)??0)+1;this.failCounts.set(t.id,r),r>=l.MAX_SEND_RETRIES?(this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.error({reminderId:t.id,attempts:r,chatId:t.chatId},"Reminder abandoned after max retries \u2014 marked as fired")):this.logger.warn({err:s,reminderId:t.id,attempt:r,maxRetries:l.MAX_SEND_RETRIES},"Failed to send reminder, will retry")}}catch(e){this.logger.error({err:e},"Error checking due reminders")}}}});var yn,cc=T(()=>{"use strict";yn=class{static{p(this,"SpeechTranscriber")}logger;apiKey;baseUrl;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,e.provider==="groq"?this.baseUrl=e.baseUrl??"https://api.groq.com/openai/v1":this.baseUrl=e.baseUrl??"https://api.openai.com/v1"}async transcribe(e,t){let s=this.mimeToExtension(t),r=new FormData;r.append("file",new Blob([e],{type:t}),`audio.${s}`),r.append("model","whisper-1");try{let n=await fetch(`${this.baseUrl}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:r});if(!n.ok){let i=await n.text();throw new Error(`Whisper API ${n.status}: ${i}`)}let o=await n.json();return this.logger.info({textLength:o.text.length},"Voice transcribed"),o.text}catch(n){throw this.logger.error({err:n},"Voice transcription failed"),n}}mimeToExtension(e){return{"audio/ogg":"ogg","audio/mpeg":"mp3","audio/mp4":"m4a","audio/wav":"wav","audio/webm":"webm","audio/x-m4a":"m4a"}[e]??"ogg"}}});var wn,lc=T(()=>{"use strict";wn=class{static{p(this,"SpeechSynthesizer")}logger;apiKey;baseUrl;model;voice;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,this.baseUrl=e.baseUrl??"https://api.openai.com/v1",this.model=e.ttsModel??"tts-1",this.voice=e.ttsVoice??"alloy"}async synthesize(e){this.logger.info({textLength:e.length,model:this.model,voice:this.voice},"Synthesizing speech");let t=await fetch(`${this.baseUrl}/audio/speech`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:this.model,input:e,voice:this.voice,response_format:"opus"})});if(!t.ok){let r=await t.text();throw new Error(`TTS failed: ${t.status} ${r}`)}let s=Buffer.from(await t.arrayBuffer());return this.logger.info({audioBytes:s.length},"Speech synthesized"),s}}});var Tn,dc=T(()=>{"use strict";Tn=class{static{p(this,"ImageGenerator")}config;logger;constructor(e,t){this.config=e,this.logger=t}async generate(e,t={}){return this.logger.info({provider:this.config.provider,model:t.model,size:t.size},"Generating image"),this.config.provider==="openai"?this.generateOpenAI(e,t):this.generateGoogle(e,t)}async generateOpenAI(e,t){let{default:s}=await import("openai"),r=new s({apiKey:this.config.apiKey,...this.config.baseUrl&&{baseURL:this.config.baseUrl}}),n=t.model??"gpt-image-1",i=(await r.images.generate({model:n,prompt:e,n:1,size:t.size??"1024x1024",quality:t.quality??"medium"})).data?.[0]?.b64_json;if(!i)throw new Error("OpenAI image generation returned no data");let a=Buffer.from(i,"base64");return this.logger.info({model:n,bytes:a.length},"Image generated via OpenAI"),{data:a,mimeType:"image/png"}}async generateGoogle(e,t){let{GoogleGenAI:s}=await import("@google/genai"),r=new s({apiKey:this.config.apiKey}),n=t.model??"gemini-2.0-flash-exp",a=(await r.models.generateContent({model:n,contents:[{role:"user",parts:[{text:e}]}],config:{responseModalities:["IMAGE","TEXT"]}})).candidates?.[0]?.content?.parts?.find(u=>u.inlineData?.mimeType?.startsWith("image/"));if(!a?.inlineData)throw new Error("Google image generation returned no image data");let c=Buffer.from(a.inlineData.data,"base64"),d=a.inlineData.mimeType??"image/png";return this.logger.info({model:n,bytes:c.length,mimeType:d},"Image generated via Google"),{data:c,mimeType:d}}}});var _n,uc=T(()=>{"use strict";_n=class{static{p(this,"TransitClient")}logger;hafasClient;constructor(e){this.logger=e}async getClient(){if(this.hafasClient)return this.hafasClient;let{createClient:e}=await import("hafas-client"),{profile:t}=await import("hafas-client/p/oebb/index.js");return this.hafasClient=e(t,"alfred-ai-assistant"),this.hafasClient}async searchStops(e){return(await(await this.getClient()).locations(e,{results:10})).filter(r=>r.type==="stop"||r.type==="station").map(r=>({id:r.id,name:r.name,location:r.location?{latitude:r.location.latitude,longitude:r.location.longitude}:void 0}))}async journeys(e,t,s){let r=await this.getClient(),n={results:s?.results??3};return s?.departure&&(n.departure=s.departure),s?.arrival&&(n.arrival=s.arrival),((await r.journeys(e,t,n)).journeys||[]).map(i=>{let a=(i.legs||[]).map(f=>({origin:f.origin?.name||f.origin?.id||"Unknown",destination:f.destination?.name||f.destination?.id||"Unknown",departure:f.departure||f.plannedDeparture||"",arrival:f.arrival||f.plannedArrival||"",line:f.line?.name,direction:f.direction,mode:f.line?.mode||(f.walking?"walking":"unknown"),walking:f.walking===!0})),c=a[0]?.departure||"",d=a[a.length-1]?.arrival||"",u=c&&d?Math.round((new Date(d).getTime()-new Date(c).getTime())/6e4):0,m=a.filter(f=>!f.walking),h=Math.max(0,m.length-1);return{legs:a,departure:c,arrival:d,duration:u,transfers:h}})}async departures(e,t){let s=await this.getClient(),r={duration:t?.duration??30};t?.when&&(r.when=t.when);let n=await s.departures(e,r);return(n.departures||n||[]).map(o=>{let i=o.plannedWhen?new Date(o.plannedWhen):null,a=o.when?new Date(o.when):null,c=i&&a?Math.round((a.getTime()-i.getTime())/6e4):o.delay!=null?Math.round(o.delay/60):void 0;return{line:o.line?.name||o.line?.fahrtNr||"Unknown",direction:o.direction||o.destination?.name||"Unknown",when:o.when||o.plannedWhen||"",delay:c&&c>0?c:void 0,platform:o.platform||void 0}})}}});var kn,pc=T(()=>{"use strict";kn=class{static{p(this,"ResponseFormatter")}format(e,t){switch(t){case"telegram":return{text:this.toTelegramHTML(e),parseMode:"html"};case"discord":return{text:this.toMarkdown(e),parseMode:"markdown"};case"matrix":return{text:this.toTelegramHTML(e),parseMode:"html"};case"whatsapp":return{text:this.toWhatsApp(e),parseMode:"text"};case"signal":return{text:this.stripFormatting(e),parseMode:"text"};default:return{text:e,parseMode:"text"}}}toTelegramHTML(e){let t=e,s=[];t=t.replace(/```(\w*)\n([\s\S]*?)```/g,(n,o,i)=>(s.push(`<pre>${this.escapeHTML(i.trimEnd())}</pre>`),`\0CB${s.length-1}\0`));let r=[];t=t.replace(/`([^`]+)`/g,(n,o)=>(r.push(`<code>${this.escapeHTML(o)}</code>`),`\0IC${r.length-1}\0`)),t=t.replace(/^#{1,6}\s+(.+)$/gm,"<b>$1</b>"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"<b>$1</b>"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"<i>$1</i>"),t=t.replace(/~~(.+?)~~/g,"<s>$1</s>"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2">$1</a>'),t=t.replace(/<(\/?)(?:strong)>/gi,"<$1b>"),t=t.replace(/<(\/?)(?:em)>/gi,"<$1i>"),t=t.replace(/<(\/?)(?:del|strike)>/gi,"<$1s>");for(let n of["b","i","s","u"]){let o="";for(;o!==t;)o=t,t=this.flattenNestedTag(t,n)}return t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))[^>]*>/gi,""),t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))/gi,"&lt;"),t=t.replace(/\x00CB(\d+)\x00/g,(n,o)=>s[parseInt(o)]),t=t.replace(/\x00IC(\d+)\x00/g,(n,o)=>r[parseInt(o)]),t=t.replace(/\n{3,}/g,`
1239
1239
 
1240
- `),t}flattenNestedTag(e,t){let s=`<${t}>`,r=`</${t}>`,n=0,o="",i=0;for(;i<e.length;){if(e.slice(i,i+s.length).toLowerCase()===s){n++,n===1&&(o+=s),i+=s.length;continue}if(e.slice(i,i+r.length).toLowerCase()===r){n--,n<=0&&(o+=r,n=0),i+=r.length;continue}o+=e[i],i++}return o}toMarkdown(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<code>([^<]*)<\/code>/gi,"`$1`"),t=t.replace(/<pre>([^<]*)<\/pre>/gi,"```\n$1\n```"),t=t.replace(/<a\s+href="([^"]*)"[^>]*>([^<]*)<\/a>/gi,"[$2]($1)"),t=t.replace(/<[^>]+>/g,""),t}toWhatsApp(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<[^>]+>/g,""),t=t.replace(/^#{1,6}\s+(.+)$/gm,"*$1*"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"*$1*"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"_$1_"),t=t.replace(/~~(.+?)~~/g,"~$1~"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}stripFormatting(e){let t=e;return t=t.replace(/<[^>]+>/g,""),t=t.replace(/```\w*\n?/g,""),t=t.replace(/`([^`]+)`/g,"$1"),t=t.replace(/^#{1,6}\s+/gm,""),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"$1"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"$1"),t=t.replace(/~~(.+?)~~/g,"$1"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}escapeHTML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}}});var kn,mc=T(()=>{"use strict";kn=class{static{p(this,"EmbeddingService")}llm;embeddingRepo;logger;constructor(e,t,s){this.llm=e,this.embeddingRepo=t,this.logger=s}async embedAndStore(e,t,s,r){if(this.llm.supportsEmbeddings())try{let n=await this.llm.embed(t);if(!n)return;let o=this.embeddingRepo.store({userId:e,sourceType:s,sourceId:r,content:t,embedding:n.embedding,model:n.model,dimensions:n.dimensions});return this.logger.debug({userId:e,sourceType:s,sourceId:r},"Embedding stored"),o.id}catch(n){this.logger.error({err:n,userId:e,sourceType:s,sourceId:r},"Failed to embed content");return}}async semanticSearch(e,t,s=10){if(!this.llm.supportsEmbeddings())return[];try{let r=await this.llm.embed(t);if(!r)return[];let n=this.embeddingRepo.findByUser(e);if(n.length===0)return[];let o=n.map(a=>{let c=this.cosineSimilarity(r.embedding,a.embedding);return{...a,score:c}});return o.sort((a,c)=>c.score-a.score),o.slice(0,s).map(a=>({key:a.sourceId,value:a.content,category:a.sourceType,score:a.score}))}catch(r){return this.logger.error({err:r},"Semantic search failed"),[]}}cosineSimilarity(e,t){if(e.length!==t.length)return 0;let s=0,r=0,n=0;for(let i=0;i<e.length;i++)s+=e[i]*t[i],r+=e[i]*e[i],n+=t[i]*t[i];let o=Math.sqrt(r)*Math.sqrt(n);return o===0?0:s/o}}});import{createHash as Eg}from"node:crypto";var bn,hc=T(()=>{"use strict";bn=class{static{p(this,"DocumentProcessor")}docRepo;embeddingService;logger;constructor(e,t,s){this.docRepo=e,this.embeddingService=t,this.logger=s}async ingest(e,t,s,r){let n=await import("node:fs"),o=n.readFileSync(t),i=Eg("sha256").update(o).digest("hex"),a=this.docRepo.findByContentHash(e,i);if(a&&a.chunkCount>0)return this.logger.info({documentId:a.id,filename:s,contentHash:i.slice(0,12)},"Document already ingested (duplicate)"),{documentId:a.id,chunkCount:a.chunkCount,existing:!0};a&&a.chunkCount===0&&(this.logger.info({documentId:a.id,filename:s},"Removing failed previous ingest attempt"),this.docRepo.deleteDocument(a.id));let c=await this.extractText(t,r),d=n.statSync(t),u=this.docRepo.createDocument(e,s,r,d.size,i),m=this.chunkText(c,500,50);for(let h=0;h<m.length;h++){let f;try{f=await this.embeddingService.embedAndStore(e,m[h],"document",`${u.id}:${h}`)}catch(g){this.logger.warn({documentId:u.id,chunkIndex:h,err:g},"Embedding failed for chunk, continuing")}this.docRepo.addChunk(u.id,h,m[h],f)}return this.docRepo.updateChunkCount(u.id,m.length),this.logger.info({documentId:u.id,filename:s,chunkCount:m.length},"Document ingested"),{documentId:u.id,chunkCount:m.length}}async extractText(e,t){let s=await import("node:fs");if(t==="application/pdf")try{let r=(await import("pdf-parse")).default,n=s.readFileSync(e);return(await r(n)).text}catch(r){throw this.logger.error({err:r},"PDF parsing failed"),new Error("Failed to parse PDF")}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")try{return(await(await import("mammoth")).extractRawText({path:e})).value}catch(r){throw this.logger.error({err:r},"DOCX parsing failed"),new Error("Failed to parse DOCX")}return s.readFileSync(e,"utf-8")}chunkText(e,t,s){let n=Math.round(t*3.5),o=Math.round(s*3.5),i=[],a=0;for(;a<e.length;){let c=a+n;if(c>=e.length){i.push(e.slice(a).trim());break}let d=Math.max(c-200,a),u=e.slice(d,c+200),m=u.lastIndexOf(`
1240
+ `),t}flattenNestedTag(e,t){let s=`<${t}>`,r=`</${t}>`,n=0,o="",i=0;for(;i<e.length;){if(e.slice(i,i+s.length).toLowerCase()===s){n++,n===1&&(o+=s),i+=s.length;continue}if(e.slice(i,i+r.length).toLowerCase()===r){n--,n<=0&&(o+=r,n=0),i+=r.length;continue}o+=e[i],i++}return o}toMarkdown(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<code>([^<]*)<\/code>/gi,"`$1`"),t=t.replace(/<pre>([^<]*)<\/pre>/gi,"```\n$1\n```"),t=t.replace(/<a\s+href="([^"]*)"[^>]*>([^<]*)<\/a>/gi,"[$2]($1)"),t=t.replace(/<[^>]+>/g,""),t}toWhatsApp(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<[^>]+>/g,""),t=t.replace(/^#{1,6}\s+(.+)$/gm,"*$1*"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"*$1*"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"_$1_"),t=t.replace(/~~(.+?)~~/g,"~$1~"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}stripFormatting(e){let t=e;return t=t.replace(/<[^>]+>/g,""),t=t.replace(/```\w*\n?/g,""),t=t.replace(/`([^`]+)`/g,"$1"),t=t.replace(/^#{1,6}\s+/gm,""),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"$1"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"$1"),t=t.replace(/~~(.+?)~~/g,"$1"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}escapeHTML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}}});var bn,mc=T(()=>{"use strict";bn=class{static{p(this,"EmbeddingService")}llm;embeddingRepo;logger;constructor(e,t,s){this.llm=e,this.embeddingRepo=t,this.logger=s}async embedAndStore(e,t,s,r){if(this.llm.supportsEmbeddings())try{let n=await this.llm.embed(t);if(!n)return;let o=this.embeddingRepo.store({userId:e,sourceType:s,sourceId:r,content:t,embedding:n.embedding,model:n.model,dimensions:n.dimensions});return this.logger.debug({userId:e,sourceType:s,sourceId:r},"Embedding stored"),o.id}catch(n){this.logger.error({err:n,userId:e,sourceType:s,sourceId:r},"Failed to embed content");return}}async semanticSearch(e,t,s=10){if(!this.llm.supportsEmbeddings())return[];try{let r=await this.llm.embed(t);if(!r)return[];let n=this.embeddingRepo.findByUser(e);if(n.length===0)return[];let o=n.map(a=>{let c=this.cosineSimilarity(r.embedding,a.embedding);return{...a,score:c}});return o.sort((a,c)=>c.score-a.score),o.slice(0,s).map(a=>({key:a.sourceId,value:a.content,category:a.sourceType,score:a.score}))}catch(r){return this.logger.error({err:r},"Semantic search failed"),[]}}cosineSimilarity(e,t){if(e.length!==t.length)return 0;let s=0,r=0,n=0;for(let i=0;i<e.length;i++)s+=e[i]*t[i],r+=e[i]*e[i],n+=t[i]*t[i];let o=Math.sqrt(r)*Math.sqrt(n);return o===0?0:s/o}}});import{createHash as Eg}from"node:crypto";var En,hc=T(()=>{"use strict";En=class{static{p(this,"DocumentProcessor")}docRepo;embeddingService;logger;constructor(e,t,s){this.docRepo=e,this.embeddingService=t,this.logger=s}async ingest(e,t,s,r){let n=await import("node:fs"),o=n.readFileSync(t),i=Eg("sha256").update(o).digest("hex"),a=this.docRepo.findByContentHash(e,i);if(a&&a.chunkCount>0)return this.logger.info({documentId:a.id,filename:s,contentHash:i.slice(0,12)},"Document already ingested (duplicate)"),{documentId:a.id,chunkCount:a.chunkCount,existing:!0};a&&a.chunkCount===0&&(this.logger.info({documentId:a.id,filename:s},"Removing failed previous ingest attempt"),this.docRepo.deleteDocument(a.id));let c=await this.extractText(t,r),d=n.statSync(t),u=this.docRepo.createDocument(e,s,r,d.size,i),m=this.chunkText(c,500,50);for(let h=0;h<m.length;h++){let f;try{f=await this.embeddingService.embedAndStore(e,m[h],"document",`${u.id}:${h}`)}catch(g){this.logger.warn({documentId:u.id,chunkIndex:h,err:g},"Embedding failed for chunk, continuing")}this.docRepo.addChunk(u.id,h,m[h],f)}return this.docRepo.updateChunkCount(u.id,m.length),this.logger.info({documentId:u.id,filename:s,chunkCount:m.length},"Document ingested"),{documentId:u.id,chunkCount:m.length}}async extractText(e,t){let s=await import("node:fs");if(t==="application/pdf")try{let r=(await import("pdf-parse")).default,n=s.readFileSync(e);return(await r(n)).text}catch(r){throw this.logger.error({err:r},"PDF parsing failed"),new Error("Failed to parse PDF")}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")try{return(await(await import("mammoth")).extractRawText({path:e})).value}catch(r){throw this.logger.error({err:r},"DOCX parsing failed"),new Error("Failed to parse DOCX")}return s.readFileSync(e,"utf-8")}chunkText(e,t,s){let n=Math.round(t*3.5),o=Math.round(s*3.5),i=[],a=0;for(;a<e.length;){let c=a+n;if(c>=e.length){i.push(e.slice(a).trim());break}let d=Math.max(c-200,a),u=e.slice(d,c+200),m=u.lastIndexOf(`
1241
1241
 
1242
- `);if(m>0)c=d+m;else{let f=u.lastIndexOf(". ");f>0&&(c=d+f+1)}let h=e.slice(a,c).trim();h&&i.push(h),a=c-o}return i.filter(c=>c.length>0)}}});var En,fc=T(()=>{"use strict";_t();En=class{static{p(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;skillHealthTracker;pollTimer;running=0;polling=!1;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;persistentRunner;constructor(e,t,s,r,n,o,i,a){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o,this.activityLogger=i,this.skillHealthTracker=a}setPersistentRunner(e){this.persistentRunner=e}start(){this.pollTimer=setInterval(()=>this.poll(),this.pollIntervalMs),this.logger.info("Background task runner started"),this.persistentRunner?.recoverInterrupted().catch(e=>{this.logger.error({err:e},"Failed to recover interrupted persistent tasks")})}stop(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0),this.logger.info("Background task runner stopped")}async poll(){if(!(this.polling||this.running>=this.maxConcurrent)){this.polling=!0;try{let e=this.maxConcurrent-this.running,t=this.taskRepo.claimPending(e);for(let s of t)this.running++,this.runTask(s).finally(()=>{this.running--})}catch(e){this.logger.error({err:e},"Error polling for background tasks")}finally{this.polling=!1}}}async runTask(e){if(e.maxDurationHours&&this.persistentRunner){await this.persistentRunner.runPersistent(e);return}let t=Date.now();try{let s=this.skillRegistry.get(e.skillName);if(!s){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}if(this.skillHealthTracker?.isDisabled(e.skillName)){this.taskRepo.updateStatus(e.id,"failed",void 0,`Skill "${e.skillName}" is temporarily disabled due to repeated failures`);return}let r;try{r=JSON.parse(e.skillInput)}catch(u){this.logger.warn({taskId:e.id,err:u},"Malformed skill input JSON"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:n}=Ie(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o,i=new Promise((u,m)=>{o=setTimeout(()=>m(new Error("Background task timed out")),this.taskTimeoutMs)}),a=await Promise.race([this.skillSandbox.execute(s,r,n),i]).finally(()=>{o&&clearTimeout(o)}),c=JSON.stringify(a.data??a.display??a.error);this.taskRepo.updateStatus(e.id,a.success?"completed":"failed",c,a.error),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:a.success?"success":"error",durationMs:Date.now()-t,error:a.error}),this.skillHealthTracker&&(a.success?this.skillHealthTracker.recordSuccess(e.skillName):this.skillHealthTracker.recordFailure(e.skillName,a.error??"Unknown error"));let d=this.adapters.get(e.platform);if(d){let u=a.success?`\u2705 Background task completed: ${e.description}
1242
+ `);if(m>0)c=d+m;else{let f=u.lastIndexOf(". ");f>0&&(c=d+f+1)}let h=e.slice(a,c).trim();h&&i.push(h),a=c-o}return i.filter(c=>c.length>0)}}});var Sn,fc=T(()=>{"use strict";_t();Sn=class{static{p(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;skillHealthTracker;pollTimer;running=0;polling=!1;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;persistentRunner;constructor(e,t,s,r,n,o,i,a){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o,this.activityLogger=i,this.skillHealthTracker=a}setPersistentRunner(e){this.persistentRunner=e}start(){this.pollTimer=setInterval(()=>this.poll(),this.pollIntervalMs),this.logger.info("Background task runner started"),this.persistentRunner?.recoverInterrupted().catch(e=>{this.logger.error({err:e},"Failed to recover interrupted persistent tasks")})}stop(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0),this.logger.info("Background task runner stopped")}async poll(){if(!(this.polling||this.running>=this.maxConcurrent)){this.polling=!0;try{let e=this.maxConcurrent-this.running,t=this.taskRepo.claimPending(e);for(let s of t)this.running++,this.runTask(s).finally(()=>{this.running--})}catch(e){this.logger.error({err:e},"Error polling for background tasks")}finally{this.polling=!1}}}async runTask(e){if(e.maxDurationHours&&this.persistentRunner){await this.persistentRunner.runPersistent(e);return}let t=Date.now();try{let s=this.skillRegistry.get(e.skillName);if(!s){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}if(this.skillHealthTracker?.isDisabled(e.skillName)){this.taskRepo.updateStatus(e.id,"failed",void 0,`Skill "${e.skillName}" is temporarily disabled due to repeated failures`);return}let r;try{r=JSON.parse(e.skillInput)}catch(u){this.logger.warn({taskId:e.id,err:u},"Malformed skill input JSON"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:n}=Ie(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o,i=new Promise((u,m)=>{o=setTimeout(()=>m(new Error("Background task timed out")),this.taskTimeoutMs)}),a=await Promise.race([this.skillSandbox.execute(s,r,n),i]).finally(()=>{o&&clearTimeout(o)}),c=JSON.stringify(a.data??a.display??a.error);this.taskRepo.updateStatus(e.id,a.success?"completed":"failed",c,a.error),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:a.success?"success":"error",durationMs:Date.now()-t,error:a.error}),this.skillHealthTracker&&(a.success?this.skillHealthTracker.recordSuccess(e.skillName):this.skillHealthTracker.recordFailure(e.skillName,a.error??"Unknown error"));let d=this.adapters.get(e.platform);if(d){let u=a.success?`\u2705 Background task completed: ${e.description}
1243
1243
 
1244
1244
  Result: ${a.display??JSON.stringify(a.data)}`:`\u274C Background task failed: ${e.description}
1245
1245
 
1246
1246
  Error: ${a.error}`;await d.sendMessage(e.chatId,u)}}catch(s){let r=s instanceof Error?s.message:String(s);this.taskRepo.updateStatus(e.id,"failed",void 0,r),this.logger.error({taskId:e.id,err:s},"Background task failed"),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:"error",durationMs:Date.now()-t,error:r}),this.skillHealthTracker?.recordFailure(e.skillName,r);let n=this.adapters.get(e.platform);n&&await n.sendMessage(e.chatId,`\u274C Background task failed: ${e.description}
1247
1247
 
1248
- Error: ${r}`)}}}});var Sg,Sn,gc=T(()=>{"use strict";_t();Sg=5,Sn=class{static{p(this,"PersistentAgentRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;activeAbortControllers=new Map;constructor(e,t,s,r,n,o,i){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o,this.activityLogger=i}async recoverInterrupted(){try{let e=this.taskRepo.getInterrupted();for(let t of e)t.agentState?(this.logger.info({taskId:t.id,resumeCount:t.resumeCount},"Recovering interrupted persistent task"),this.resume(t).catch(s=>{this.logger.error({err:s,taskId:t.id},"Failed to recover interrupted task")})):(this.taskRepo.updateStatus(t.id,"failed",void 0,"Process restarted without checkpoint"),this.logger.warn({taskId:t.id},"Interrupted task without checkpoint marked as failed"),this.notifyUser(t,"\u274C Hintergrund-Task abgebrochen (Prozess-Neustart ohne Checkpoint)"))}catch(e){this.logger.error({err:e},"Failed to recover interrupted tasks")}}async runPersistent(e){if(!this.taskRepo.claimTask(e.id)){this.logger.info({taskId:e.id},"Task already claimed by another runner, skipping");return}let t=(e.maxDurationHours??24)*36e5,s=new AbortController;this.activeAbortControllers.set(e.id,s);try{let r=this.skillRegistry.get(e.skillName);if(!r){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}let n;try{n=JSON.parse(e.skillInput)}catch{this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:o}=Ie(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),i=Date.now()-new Date(e.createdAt).getTime();if(i>t){this.taskRepo.updateStatus(e.id,"failed",void 0,`Max duration of ${e.maxDurationHours}h exceeded`),this.notifyUser(e,`\u274C Persistenter Task "${e.description}" abgebrochen: maximale Laufzeit \xFCberschritten.`),this.logLifecycle(e,"expired");return}let a;if(e.agentState)try{let y=JSON.parse(e.agentState);y.conversationHistory?.length>0&&(a={conversationHistory:y.conversationHistory,currentIteration:y.currentIteration,totalIterations:y.totalIterations,dataStore:y.dataStore},this.logger.info({taskId:e.id,iteration:y.currentIteration,totalIterations:y.totalIterations},"Resuming persistent task from checkpoint"))}catch(y){this.logger.warn({taskId:e.id,err:y},"Failed to parse checkpoint, starting fresh")}let c=a?.currentIteration??0,d={...o,resumeState:a,abortSignal:s.signal,onIteration:p(y=>{if(y.iteration-c>=Sg||s.signal.aborted){c=y.iteration;let _={conversationHistory:y.messages,partialResults:[],currentIteration:y.iteration,totalIterations:y.maxIterations,startedAt:e.startedAt??e.createdAt,lastActivityAt:new Date().toISOString(),dataStore:y.dataStore};try{this.taskRepo.checkpoint(e.id,JSON.stringify(_)),this.logLifecycle(e,"checkpoint"),this.logger.debug({taskId:e.id,iteration:y.iteration},"Persistent task checkpointed")}catch(S){this.logger.warn({err:S,taskId:e.id},"Failed to write checkpoint, retrying once");try{this.taskRepo.checkpoint(e.id,JSON.stringify(_)),this.logger.info({taskId:e.id},"Checkpoint retry succeeded")}catch(E){this.logger.error({err:E,taskId:e.id},"Checkpoint retry failed, aborting task"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Checkpoint write failed after retry"),s.abort()}}}},"onIteration")},u=t-i,m,h=new Promise((y,_)=>{m=setTimeout(()=>_(new Error(`Max duration of ${e.maxDurationHours}h exceeded`)),u)}),f=await Promise.race([this.skillSandbox.execute(r,n,d),h]).finally(()=>{m&&clearTimeout(m)});if(this.activeAbortControllers.delete(e.id),s.signal.aborted){this.logger.info({taskId:e.id},"Persistent task paused via abort"),this.notifyUser(e,`\u23F8\uFE0F Persistenter Task pausiert: ${e.description}`);return}let g=JSON.stringify(f.data??f.display??f.error);this.taskRepo.updateStatus(e.id,f.success?"completed":"failed",g,f.error),this.notifyUser(e,f.success?`\u2705 Persistenter Task abgeschlossen: ${e.description}
1248
+ Error: ${r}`)}}}});var Sg,$n,gc=T(()=>{"use strict";_t();Sg=5,$n=class{static{p(this,"PersistentAgentRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;activeAbortControllers=new Map;constructor(e,t,s,r,n,o,i){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o,this.activityLogger=i}async recoverInterrupted(){try{let e=this.taskRepo.getInterrupted();for(let t of e)t.agentState?(this.logger.info({taskId:t.id,resumeCount:t.resumeCount},"Recovering interrupted persistent task"),this.resume(t).catch(s=>{this.logger.error({err:s,taskId:t.id},"Failed to recover interrupted task")})):(this.taskRepo.updateStatus(t.id,"failed",void 0,"Process restarted without checkpoint"),this.logger.warn({taskId:t.id},"Interrupted task without checkpoint marked as failed"),this.notifyUser(t,"\u274C Hintergrund-Task abgebrochen (Prozess-Neustart ohne Checkpoint)"))}catch(e){this.logger.error({err:e},"Failed to recover interrupted tasks")}}async runPersistent(e){if(!this.taskRepo.claimTask(e.id)){this.logger.info({taskId:e.id},"Task already claimed by another runner, skipping");return}let t=(e.maxDurationHours??24)*36e5,s=new AbortController;this.activeAbortControllers.set(e.id,s);try{let r=this.skillRegistry.get(e.skillName);if(!r){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}let n;try{n=JSON.parse(e.skillInput)}catch{this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:o}=Ie(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),i=Date.now()-new Date(e.createdAt).getTime();if(i>t){this.taskRepo.updateStatus(e.id,"failed",void 0,`Max duration of ${e.maxDurationHours}h exceeded`),this.notifyUser(e,`\u274C Persistenter Task "${e.description}" abgebrochen: maximale Laufzeit \xFCberschritten.`),this.logLifecycle(e,"expired");return}let a;if(e.agentState)try{let y=JSON.parse(e.agentState);y.conversationHistory?.length>0&&(a={conversationHistory:y.conversationHistory,currentIteration:y.currentIteration,totalIterations:y.totalIterations,dataStore:y.dataStore},this.logger.info({taskId:e.id,iteration:y.currentIteration,totalIterations:y.totalIterations},"Resuming persistent task from checkpoint"))}catch(y){this.logger.warn({taskId:e.id,err:y},"Failed to parse checkpoint, starting fresh")}let c=a?.currentIteration??0,d={...o,resumeState:a,abortSignal:s.signal,onIteration:p(y=>{if(y.iteration-c>=Sg||s.signal.aborted){c=y.iteration;let _={conversationHistory:y.messages,partialResults:[],currentIteration:y.iteration,totalIterations:y.maxIterations,startedAt:e.startedAt??e.createdAt,lastActivityAt:new Date().toISOString(),dataStore:y.dataStore};try{this.taskRepo.checkpoint(e.id,JSON.stringify(_)),this.logLifecycle(e,"checkpoint"),this.logger.debug({taskId:e.id,iteration:y.iteration},"Persistent task checkpointed")}catch(S){this.logger.warn({err:S,taskId:e.id},"Failed to write checkpoint, retrying once");try{this.taskRepo.checkpoint(e.id,JSON.stringify(_)),this.logger.info({taskId:e.id},"Checkpoint retry succeeded")}catch(E){this.logger.error({err:E,taskId:e.id},"Checkpoint retry failed, aborting task"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Checkpoint write failed after retry"),s.abort()}}}},"onIteration")},u=t-i,m,h=new Promise((y,_)=>{m=setTimeout(()=>_(new Error(`Max duration of ${e.maxDurationHours}h exceeded`)),u)}),f=await Promise.race([this.skillSandbox.execute(r,n,d),h]).finally(()=>{m&&clearTimeout(m)});if(this.activeAbortControllers.delete(e.id),s.signal.aborted){this.logger.info({taskId:e.id},"Persistent task paused via abort"),this.notifyUser(e,`\u23F8\uFE0F Persistenter Task pausiert: ${e.description}`);return}let g=JSON.stringify(f.data??f.display??f.error);this.taskRepo.updateStatus(e.id,f.success?"completed":"failed",g,f.error),this.notifyUser(e,f.success?`\u2705 Persistenter Task abgeschlossen: ${e.description}
1249
1249
 
1250
1250
  Ergebnis: ${f.display??JSON.stringify(f.data)}`:`\u274C Persistenter Task fehlgeschlagen: ${e.description}
1251
1251
 
1252
1252
  Fehler: ${f.error}`)}catch(r){this.activeAbortControllers.delete(e.id);let n=r instanceof Error?r.message:String(r);if(s.signal.aborted){this.logger.info({taskId:e.id},"Persistent task paused via abort"),this.notifyUser(e,`\u23F8\uFE0F Persistenter Task pausiert: ${e.description}`);return}this.taskRepo.updateStatus(e.id,"failed",void 0,n),this.logger.error({taskId:e.id,err:r},"Persistent task failed"),this.notifyUser(e,`\u274C Persistenter Task fehlgeschlagen: ${e.description}
1253
1253
 
1254
- Fehler: ${n}`)}}async resume(e){this.taskRepo.markResuming(e.id),this.logLifecycle(e,"resume");let t=this.taskRepo.getById(e.id);if(!t){this.logger.warn({taskId:e.id},"Task disappeared during resume");return}await this.runPersistent(t)}async pause(e){this.taskRepo.updateStatus(e,"checkpointed");let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.logLifecycle({id:e,skillName:"",platform:"",chatId:"",userId:""},"pause"),this.logger.info({taskId:e},"Persistent task paused")}async cancel(e){let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.taskRepo.cancelTask(e),this.logger.info({taskId:e},"Persistent task cancelled")}async notifyUser(e,t){let s=this.adapters.get(e.platform);if(s)try{await s.sendMessage(e.chatId,t)}catch{}}logLifecycle(e,t){this.activityLogger?.logAgentLifecycle({taskId:e.id,skillName:e.skillName,event:t,platform:e.platform,chatId:e.chatId,userId:e.userId})}}});import $g from"node:crypto";var $n,yc=T(()=>{"use strict";ra();_t();$n=class{static{p(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;activityLogger;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,n,o,i,a,c,d,u){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=n,this.users=o,this.logger=i,this.pipeline=a,this.formatter=c,this.conversationManager=d,this.activityLogger=u}start(){this.tickTimer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Proactive scheduler started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0),this.logger.info("Proactive scheduler stopped")}async tick(){try{let e=this.actionRepo.getDue();for(let t of e)try{await this.executeAction(t)}catch(s){this.logger.error({err:s,actionId:t.id},"Failed to execute scheduled action")}}catch(e){this.logger.error({err:e},"Error during proactive scheduler tick")}}async executeAction(e){let t=new Date().toISOString(),s=Date.now();this.logger.info({actionId:e.id,name:e.name},"Executing scheduled action");let r,n="text";if(e.skillName&&this.skillRegistry.has(e.skillName)){let h=this.skillRegistry.get(e.skillName);try{let f;try{f=JSON.parse(e.skillInput)}catch{f={},this.logger.warn({actionId:e.id},"Invalid skillInput JSON, using empty input")}let{context:g}=Ie(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),y=await this.skillSandbox.execute(h,f,g);if(y.success){let _=y.display??JSON.stringify(y.data);if(this.formatter){let S=this.formatter.format(_,e.platform);r=S.text,n=S.parseMode}else r=_}else r=`\u274C Scheduled action "${e.name}" failed: ${y.error}`}catch(f){let g=f instanceof Error?f.message:String(f);r=`\u274C Scheduled action "${e.name}" failed: ${g}`}}else if(e.promptTemplate&&this.pipeline)try{let h=`scheduled-${e.id}`,f=this.users.findById(e.userId),g=f?.platformUserId??e.userId,y={id:`scheduled-${$g.randomUUID()}`,platform:e.platform,chatId:h,chatType:"dm",userId:g,userName:f?.username??g,text:e.promptTemplate+"\n\n[Format: Use only Markdown (**, *, ~~, `, ```). Do NOT use HTML tags like <b>, <i>, <code>. The system converts Markdown to platform-specific formatting automatically.]",timestamp:new Date,metadata:{scheduled:!0,skipHistory:!0,tier:"fast",originalChatId:e.chatId}},_=await this.pipeline.process(y),S=this.formatter?this.formatter.format(_.text,e.platform):{text:_.text,parseMode:"text"};r=S.text,n=S.parseMode;let E=this.adapters.get(e.platform);if(E&&_.attachments)for(let $ of _.attachments)try{let R=$.mimeType.startsWith("image/"),M=$.mimeType==="audio/ogg"||$.mimeType==="audio/opus";R?await E.sendPhoto(e.chatId,$.data,$.fileName):M?await E.sendVoice(e.chatId,$.data):await E.sendFile(e.chatId,$.data,$.fileName)}catch(R){this.logger.warn({err:R,fileName:$.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(h){let f=h instanceof Error?h.message:String(h);this.logger.error({actionId:e.id,err:h},"Pipeline execution failed for scheduled action"),r=`Scheduled action "${e.name}" failed: ${f}`}else if(e.promptTemplate)try{r=(await this.llm.complete({messages:[{role:"user",content:e.promptTemplate}],maxTokens:1024,tier:"fast"})).content}catch(h){let f=h instanceof Error?h.message:String(h);this.logger.error({actionId:e.id,err:h},"LLM call failed for scheduled action"),r=`Scheduled action "${e.name}" failed: ${f}`}else this.logger.warn({actionId:e.id,skillName:e.skillName},"Unknown skill for scheduled action"),r=`Scheduled action "${e.name}" failed: unknown skill "${e.skillName}"`;let o=r.startsWith("\u274C");this.activityLogger?.logScheduledExec({actionId:e.id,actionName:e.name,skillName:e.skillName??void 0,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:o?"error":"success",durationMs:Date.now()-s,error:o?r:void 0});let i=r.trim(),a=(e.promptTemplate??"").toLowerCase(),c=/nichts|silent|no\s*output|don't\s*respond|do\s*not\s*respond/i.test(a),d=/offline|down|fehler|error|warn|critical|alert|fail|nicht\s+(erreichbar|verf[uü]gbar|gefunden|online)|ausgefallen|stopped|unreachable|unavailable|⚠|❌|🚨|🔴/i.test(i)&&!/keine\s+(probleme|fehler|auff[aä]lligkeiten)/i.test(i);if(!i||i.length<3||c&&!d)this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let h=this.adapters.get(e.platform);if(h)try{if(await h.sendMessage(e.chatId,r,{parseMode:n!=="text"?n:void 0}),e.promptTemplate&&this.conversationManager){let f=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),g=`[Automated Scheduled Alert: ${e.name}]
1255
- ${r}`;this.conversationManager.addMessage(f.id,"assistant",g)}}catch(f){this.logger.error({err:f,actionId:e.id},"Failed to send scheduled action result")}}if(e.promptTemplate&&this.conversationManager)try{let h=`scheduled-${e.id}`,f=this.conversationManager.getOrCreateConversation(e.platform,h,e.userId);this.conversationManager.pruneMessages(f.id,20)}catch{}let m=this.calculateNextRun(e);m?this.actionRepo.updateLastRun(e.id,t,m):(this.actionRepo.updateLastRun(e.id,t,null),this.actionRepo.setEnabled(e.id,!1))}calculateNextRun(e){let t=new Date;switch(e.scheduleType){case"interval":{let s=parseInt(e.scheduleValue,10);return isNaN(s)||s<=0?null:new Date(t.getTime()+s*6e4).toISOString()}case"once":return null;case"cron":return uo(e.scheduleValue,t)?.toISOString()??null;default:return null}}}});function kt(l,e){let t=e.split("."),s=l;for(let r of t){if(s==null)return;if(typeof s=="object"){if(r==="length"&&Array.isArray(s)){s=s.length;continue}s=s[r]}else return}return s}function Yo(l,e,t,s){let r=vg(l);if(s===null)return{triggered:!1,displayValue:r};switch(e){case"lt":case"gt":case"lte":case"gte":{let n=Le(l),o=Le(t);if(n===null||o===null)return{triggered:!1,displayValue:r};if(!(e==="lt"?n<o:e==="gt"?n>o:e==="lte"?n<=o:n>=o))return{triggered:!1,displayValue:r};let a=Le(s);return a!==null&&(e==="lt"?a<o:e==="gt"?a>o:e==="lte"?a<=o:a>=o)?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"eq":{let n=Le(l),o=Le(t);if(n!==null&&o!==null){if(n!==o)return{triggered:!1,displayValue:r};let c=Le(s);return c!==null&&c===o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let i=String(l),a=String(t);return i!==a?{triggered:!1,displayValue:r}:String(s)===a?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"neq":{let n=Le(l),o=Le(t);if(n!==null&&o!==null){if(n===o)return{triggered:!1,displayValue:r};let c=Le(s);return c!==null&&c!==o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let i=String(l),a=String(t);return i===a?{triggered:!1,displayValue:r}:String(s)!==a?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"contains":return String(l).includes(String(t??""))?String(s).includes(String(t??""))?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}:{triggered:!1,displayValue:r};case"not_contains":return String(l).includes(String(t??""))?{triggered:!1,displayValue:r}:String(s).includes(String(t??""))?{triggered:!0,displayValue:r}:{triggered:!1,displayValue:r};case"changed":return{triggered:JSON.stringify(l)!==JSON.stringify(s),displayValue:r};case"increased":{let n=Le(l),o=Le(s);return n===null||o===null?{triggered:!1,displayValue:r}:{triggered:n>o,displayValue:r}}case"decreased":{let n=Le(l),o=Le(s);return n===null||o===null?{triggered:!1,displayValue:r}:{triggered:n<o,displayValue:r}}default:return{triggered:!1,displayValue:r}}}function wc(l,e,t){let s={},r={},n=[];for(let i of e.conditions){let a=kt(l,i.field),c=t?.[i.field]??null,{triggered:d,displayValue:u}=Yo(a,i.operator,i.value,c);n.push(d),s[i.field]=u,r[i.field]=a}return{triggered:e.logic==="and"?n.every(Boolean):n.some(Boolean),displayValues:s,newLastValues:r}}function Le(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}function vg(l){return l==null?"null":typeof l=="object"?JSON.stringify(l):String(l)}var vn=T(()=>{"use strict";p(kt,"extractField");p(Yo,"evaluateCondition");p(wc,"evaluateCompositeCondition");p(Le,"toNumber");p(vg,"formatValue")});function An(l,e){return l.replace(/\{\{([^}]+)\}\}/g,(t,s)=>{let r=kt(e,s.trim());return r==null?"":typeof r=="object"?JSON.stringify(r):String(r)})}function Yt(l,e){let t={};for(let[s,r]of Object.entries(l))typeof r=="string"?t[s]=An(r,e):r!==null&&typeof r=="object"&&!Array.isArray(r)?t[s]=Yt(r,e):Array.isArray(r)?t[s]=r.map(n=>typeof n=="string"?An(n,e):n!==null&&typeof n=="object"&&!Array.isArray(n)?Yt(n,e):n):t[s]=r;return t}var Jo=T(()=>{"use strict";vn();p(An,"resolveTemplates");p(Yt,"resolveTemplatesInObject")});var Ag,Ig,Zo,Sp=T(()=>{"use strict";vn();Jo();_t();Ag=5,Ig={lt:"<",gt:">",lte:"<=",gte:">=",eq:"=",neq:"!=",contains:"contains",not_contains:"not contains",changed:"changed",increased:"increased",decreased:"decreased"},Zo=class{static{p(this,"WatchEngine")}watchRepo;skillRegistry;skillSandbox;adapters;users;logger;confirmationQueue;activityLogger;skillHealthTracker;llmProvider;timer=null;tickIntervalMs=6e4;constructor(e,t,s,r,n,o,i,a,c,d){this.watchRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.users=n,this.logger=o,this.confirmationQueue=i,this.activityLogger=a,this.skillHealthTracker=c,this.llmProvider=d}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Watch engine started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Watch engine stopped")}async triggerWatch(e){let t=this.watchRepo.getById(e);if(!t)throw new Error(`Watch ${e} not found`);if(!t.enabled)throw new Error(`Watch ${e} is disabled`);this.logger.info({watchId:e,name:t.name},"Watch triggered via webhook"),await this.checkWatch(t)}async tick(){try{let e=this.watchRepo.getDue();for(let t of e)try{await this.checkWatch(t)}catch(s){this.logger.error({err:s,watchId:t.id},"Failed to check watch")}}catch(e){this.logger.error({err:e},"Error during watch engine tick")}}async checkWatch(e,t=0){let s=new Date().toISOString();this.logger.debug({watchId:e.id,name:e.name,skill:e.skillName},"Checking watch");let r=this.skillRegistry.get(e.skillName);if(!r){this.logger.warn({watchId:e.id,skillName:e.skillName},"Unknown skill for watch"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}if(this.skillHealthTracker?.isDisabled(e.skillName)){this.logger.debug({watchId:e.id,skillName:e.skillName},"Watch poll skill is auto-disabled, skipping"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}let{context:n}=Ie(this.users,{platformUserId:e.chatId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o=await this.skillSandbox.execute(r,e.skillParams,n);if(!o.success){this.logger.warn({watchId:e.id,error:o.error},"Watch skill execution failed"),this.skillHealthTracker?.recordFailure(e.skillName,o.error??"Watch poll failed"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}this.skillHealthTracker?.recordSuccess(e.skillName);let i,a,c;if(e.compositeCondition){let d=null;if(e.lastValue!==null)try{let m=JSON.parse(e.lastValue);d=m!==null&&typeof m=="object"&&!Array.isArray(m)?m:null}catch{}let u=wc(o.data,e.compositeCondition,d);i=u.triggered,c=JSON.stringify(u.newLastValues),a=Object.entries(u.displayValues).map(([m,h])=>`${m}=${h}`).join(", ")}else{let d=kt(o.data,e.condition.field),u=null;if(e.lastValue!==null)try{u=JSON.parse(e.lastValue)}catch{}let m=Yo(d,e.condition.operator,e.condition.value,u);i=m.triggered,a=m.displayValue,c=JSON.stringify(d)}if(i&&this.isCooldownExpired(e)){let d=e.actionOnTrigger??"alert",u={result:o.data,currentValue:a,watchName:e.name},m=e.actionSkillParams?Yt(e.actionSkillParams,u):{},h=e.messageTemplate?An(e.messageTemplate,u):void 0;if(e.requiresConfirmation&&this.confirmationQueue&&(d==="action_only"||d==="alert_and_action")&&e.actionSkillName){if(await this.confirmationQueue.enqueue({chatId:e.chatId,platform:e.platform,source:"watch",sourceId:e.id,description:`Watch "${e.name}": ${e.actionSkillName} ausf\xFChren`,skillName:e.actionSkillName,skillParams:m}),d==="alert_and_action"){let g=await this.buildAlertText(e,a,o.data,h);g+=`
1254
+ Fehler: ${n}`)}}async resume(e){this.taskRepo.markResuming(e.id),this.logLifecycle(e,"resume");let t=this.taskRepo.getById(e.id);if(!t){this.logger.warn({taskId:e.id},"Task disappeared during resume");return}await this.runPersistent(t)}async pause(e){this.taskRepo.updateStatus(e,"checkpointed");let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.logLifecycle({id:e,skillName:"",platform:"",chatId:"",userId:""},"pause"),this.logger.info({taskId:e},"Persistent task paused")}async cancel(e){let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.taskRepo.cancelTask(e),this.logger.info({taskId:e},"Persistent task cancelled")}async notifyUser(e,t){let s=this.adapters.get(e.platform);if(s)try{await s.sendMessage(e.chatId,t)}catch{}}logLifecycle(e,t){this.activityLogger?.logAgentLifecycle({taskId:e.id,skillName:e.skillName,event:t,platform:e.platform,chatId:e.chatId,userId:e.userId})}}});import $g from"node:crypto";var vn,yc=T(()=>{"use strict";ra();_t();vn=class{static{p(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;activityLogger;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,n,o,i,a,c,d,u){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=n,this.users=o,this.logger=i,this.pipeline=a,this.formatter=c,this.conversationManager=d,this.activityLogger=u}start(){this.tickTimer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Proactive scheduler started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0),this.logger.info("Proactive scheduler stopped")}async tick(){try{let e=this.actionRepo.getDue();for(let t of e)try{await this.executeAction(t)}catch(s){this.logger.error({err:s,actionId:t.id},"Failed to execute scheduled action")}}catch(e){this.logger.error({err:e},"Error during proactive scheduler tick")}}async executeAction(e){let t=new Date().toISOString(),s=Date.now();this.logger.info({actionId:e.id,name:e.name},"Executing scheduled action");let r,n="text";if(e.skillName&&this.skillRegistry.has(e.skillName)){let h=this.skillRegistry.get(e.skillName);try{let f;try{f=JSON.parse(e.skillInput)}catch{f={},this.logger.warn({actionId:e.id},"Invalid skillInput JSON, using empty input")}let{context:g}=Ie(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),y=await this.skillSandbox.execute(h,f,g);if(y.success){let _=y.display??JSON.stringify(y.data);if(this.formatter){let S=this.formatter.format(_,e.platform);r=S.text,n=S.parseMode}else r=_}else r=`\u274C Scheduled action "${e.name}" failed: ${y.error}`}catch(f){let g=f instanceof Error?f.message:String(f);r=`\u274C Scheduled action "${e.name}" failed: ${g}`}}else if(e.promptTemplate&&this.pipeline)try{let h=`scheduled-${e.id}`,f=this.users.findById(e.userId),g=f?.platformUserId??e.userId,y={id:`scheduled-${$g.randomUUID()}`,platform:e.platform,chatId:h,chatType:"dm",userId:g,userName:f?.username??g,text:e.promptTemplate+"\n\n[Format: Use only Markdown (**, *, ~~, `, ```). Do NOT use HTML tags like <b>, <i>, <code>. The system converts Markdown to platform-specific formatting automatically.]",timestamp:new Date,metadata:{scheduled:!0,skipHistory:!0,tier:"fast",originalChatId:e.chatId}},_=await this.pipeline.process(y),S=this.formatter?this.formatter.format(_.text,e.platform):{text:_.text,parseMode:"text"};r=S.text,n=S.parseMode;let E=this.adapters.get(e.platform);if(E&&_.attachments)for(let $ of _.attachments)try{let R=$.mimeType.startsWith("image/"),M=$.mimeType==="audio/ogg"||$.mimeType==="audio/opus";R?await E.sendPhoto(e.chatId,$.data,$.fileName):M?await E.sendVoice(e.chatId,$.data):await E.sendFile(e.chatId,$.data,$.fileName)}catch(R){this.logger.warn({err:R,fileName:$.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(h){let f=h instanceof Error?h.message:String(h);this.logger.error({actionId:e.id,err:h},"Pipeline execution failed for scheduled action"),r=`Scheduled action "${e.name}" failed: ${f}`}else if(e.promptTemplate)try{r=(await this.llm.complete({messages:[{role:"user",content:e.promptTemplate}],maxTokens:1024,tier:"fast"})).content}catch(h){let f=h instanceof Error?h.message:String(h);this.logger.error({actionId:e.id,err:h},"LLM call failed for scheduled action"),r=`Scheduled action "${e.name}" failed: ${f}`}else this.logger.warn({actionId:e.id,skillName:e.skillName},"Unknown skill for scheduled action"),r=`Scheduled action "${e.name}" failed: unknown skill "${e.skillName}"`;let o=r.startsWith("\u274C");this.activityLogger?.logScheduledExec({actionId:e.id,actionName:e.name,skillName:e.skillName??void 0,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:o?"error":"success",durationMs:Date.now()-s,error:o?r:void 0});let i=r.trim(),a=(e.promptTemplate??"").toLowerCase(),c=/nichts|silent|no\s*output|don't\s*respond|do\s*not\s*respond/i.test(a),d=/offline|down|fehler|error|warn|critical|alert|fail|nicht\s+(erreichbar|verf[uü]gbar|gefunden|online)|ausgefallen|stopped|unreachable|unavailable|⚠|❌|🚨|🔴/i.test(i)&&!/keine\s+(probleme|fehler|auff[aä]lligkeiten)/i.test(i);if(!i||i.length<3||c&&!d)this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let h=this.adapters.get(e.platform);if(h)try{if(await h.sendMessage(e.chatId,r,{parseMode:n!=="text"?n:void 0}),e.promptTemplate&&this.conversationManager){let f=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),g=`[Automated Scheduled Alert: ${e.name}]
1255
+ ${r}`;this.conversationManager.addMessage(f.id,"assistant",g)}}catch(f){this.logger.error({err:f,actionId:e.id},"Failed to send scheduled action result")}}if(e.promptTemplate&&this.conversationManager)try{let h=`scheduled-${e.id}`,f=this.conversationManager.getOrCreateConversation(e.platform,h,e.userId);this.conversationManager.pruneMessages(f.id,20)}catch{}let m=this.calculateNextRun(e);m?this.actionRepo.updateLastRun(e.id,t,m):(this.actionRepo.updateLastRun(e.id,t,null),this.actionRepo.setEnabled(e.id,!1))}calculateNextRun(e){let t=new Date;switch(e.scheduleType){case"interval":{let s=parseInt(e.scheduleValue,10);return isNaN(s)||s<=0?null:new Date(t.getTime()+s*6e4).toISOString()}case"once":return null;case"cron":return po(e.scheduleValue,t)?.toISOString()??null;default:return null}}}});function kt(l,e){let t=e.split("."),s=l;for(let r of t){if(s==null)return;if(typeof s=="object"){if(r==="length"&&Array.isArray(s)){s=s.length;continue}s=s[r]}else return}return s}function Yo(l,e,t,s){let r=vg(l);if(s===null)return{triggered:!1,displayValue:r};switch(e){case"lt":case"gt":case"lte":case"gte":{let n=Le(l),o=Le(t);if(n===null||o===null)return{triggered:!1,displayValue:r};if(!(e==="lt"?n<o:e==="gt"?n>o:e==="lte"?n<=o:n>=o))return{triggered:!1,displayValue:r};let a=Le(s);return a!==null&&(e==="lt"?a<o:e==="gt"?a>o:e==="lte"?a<=o:a>=o)?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"eq":{let n=Le(l),o=Le(t);if(n!==null&&o!==null){if(n!==o)return{triggered:!1,displayValue:r};let c=Le(s);return c!==null&&c===o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let i=String(l),a=String(t);return i!==a?{triggered:!1,displayValue:r}:String(s)===a?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"neq":{let n=Le(l),o=Le(t);if(n!==null&&o!==null){if(n===o)return{triggered:!1,displayValue:r};let c=Le(s);return c!==null&&c!==o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let i=String(l),a=String(t);return i===a?{triggered:!1,displayValue:r}:String(s)!==a?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"contains":return String(l).includes(String(t??""))?String(s).includes(String(t??""))?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}:{triggered:!1,displayValue:r};case"not_contains":return String(l).includes(String(t??""))?{triggered:!1,displayValue:r}:String(s).includes(String(t??""))?{triggered:!0,displayValue:r}:{triggered:!1,displayValue:r};case"changed":return{triggered:JSON.stringify(l)!==JSON.stringify(s),displayValue:r};case"increased":{let n=Le(l),o=Le(s);return n===null||o===null?{triggered:!1,displayValue:r}:{triggered:n>o,displayValue:r}}case"decreased":{let n=Le(l),o=Le(s);return n===null||o===null?{triggered:!1,displayValue:r}:{triggered:n<o,displayValue:r}}default:return{triggered:!1,displayValue:r}}}function wc(l,e,t){let s={},r={},n=[];for(let i of e.conditions){let a=kt(l,i.field),c=t?.[i.field]??null,{triggered:d,displayValue:u}=Yo(a,i.operator,i.value,c);n.push(d),s[i.field]=u,r[i.field]=a}return{triggered:e.logic==="and"?n.every(Boolean):n.some(Boolean),displayValues:s,newLastValues:r}}function Le(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}function vg(l){return l==null?"null":typeof l=="object"?JSON.stringify(l):String(l)}var An=T(()=>{"use strict";p(kt,"extractField");p(Yo,"evaluateCondition");p(wc,"evaluateCompositeCondition");p(Le,"toNumber");p(vg,"formatValue")});function In(l,e){return l.replace(/\{\{([^}]+)\}\}/g,(t,s)=>{let r=kt(e,s.trim());return r==null?"":typeof r=="object"?JSON.stringify(r):String(r)})}function Yt(l,e){let t={};for(let[s,r]of Object.entries(l))typeof r=="string"?t[s]=In(r,e):r!==null&&typeof r=="object"&&!Array.isArray(r)?t[s]=Yt(r,e):Array.isArray(r)?t[s]=r.map(n=>typeof n=="string"?In(n,e):n!==null&&typeof n=="object"&&!Array.isArray(n)?Yt(n,e):n):t[s]=r;return t}var Jo=T(()=>{"use strict";An();p(In,"resolveTemplates");p(Yt,"resolveTemplatesInObject")});var Ag,Ig,Zo,Sp=T(()=>{"use strict";An();Jo();_t();Ag=5,Ig={lt:"<",gt:">",lte:"<=",gte:">=",eq:"=",neq:"!=",contains:"contains",not_contains:"not contains",changed:"changed",increased:"increased",decreased:"decreased"},Zo=class{static{p(this,"WatchEngine")}watchRepo;skillRegistry;skillSandbox;adapters;users;logger;confirmationQueue;activityLogger;skillHealthTracker;llmProvider;timer=null;tickIntervalMs=6e4;constructor(e,t,s,r,n,o,i,a,c,d){this.watchRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.users=n,this.logger=o,this.confirmationQueue=i,this.activityLogger=a,this.skillHealthTracker=c,this.llmProvider=d}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Watch engine started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Watch engine stopped")}async triggerWatch(e){let t=this.watchRepo.getById(e);if(!t)throw new Error(`Watch ${e} not found`);if(!t.enabled)throw new Error(`Watch ${e} is disabled`);this.logger.info({watchId:e,name:t.name},"Watch triggered via webhook"),await this.checkWatch(t)}async tick(){try{let e=this.watchRepo.getDue();for(let t of e)try{await this.checkWatch(t)}catch(s){this.logger.error({err:s,watchId:t.id},"Failed to check watch")}}catch(e){this.logger.error({err:e},"Error during watch engine tick")}}async checkWatch(e,t=0){let s=new Date().toISOString();this.logger.debug({watchId:e.id,name:e.name,skill:e.skillName},"Checking watch");let r=this.skillRegistry.get(e.skillName);if(!r){this.logger.warn({watchId:e.id,skillName:e.skillName},"Unknown skill for watch"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}if(this.skillHealthTracker?.isDisabled(e.skillName)){this.logger.debug({watchId:e.id,skillName:e.skillName},"Watch poll skill is auto-disabled, skipping"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}let{context:n}=Ie(this.users,{platformUserId:e.chatId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o=await this.skillSandbox.execute(r,e.skillParams,n);if(!o.success){this.logger.warn({watchId:e.id,error:o.error},"Watch skill execution failed"),this.skillHealthTracker?.recordFailure(e.skillName,o.error??"Watch poll failed"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}this.skillHealthTracker?.recordSuccess(e.skillName);let i,a,c;if(e.compositeCondition){let d=null;if(e.lastValue!==null)try{let m=JSON.parse(e.lastValue);d=m!==null&&typeof m=="object"&&!Array.isArray(m)?m:null}catch{}let u=wc(o.data,e.compositeCondition,d);i=u.triggered,c=JSON.stringify(u.newLastValues),a=Object.entries(u.displayValues).map(([m,h])=>`${m}=${h}`).join(", ")}else{let d=kt(o.data,e.condition.field),u=null;if(e.lastValue!==null)try{u=JSON.parse(e.lastValue)}catch{}let m=Yo(d,e.condition.operator,e.condition.value,u);i=m.triggered,a=m.displayValue,c=JSON.stringify(d)}if(i&&this.isCooldownExpired(e)){let d=e.actionOnTrigger??"alert",u={result:o.data,currentValue:a,watchName:e.name},m=e.actionSkillParams?Yt(e.actionSkillParams,u):{},h=e.messageTemplate?In(e.messageTemplate,u):void 0;if(e.requiresConfirmation&&this.confirmationQueue&&(d==="action_only"||d==="alert_and_action")&&e.actionSkillName){if(await this.confirmationQueue.enqueue({chatId:e.chatId,platform:e.platform,source:"watch",sourceId:e.id,description:`Watch "${e.name}": ${e.actionSkillName} ausf\xFChren`,skillName:e.actionSkillName,skillParams:m}),d==="alert_and_action"){let g=await this.buildAlertText(e,a,o.data,h);g+=`
1256
1256
 
1257
1257
  (Aktion wartet auf Best\xE4tigung)`;let y=this.adapters.get(e.platform);if(y)try{await y.sendMessage(e.chatId,g)}catch(_){this.logger.error({err:_,watchId:e.id,chatId:e.chatId},"Failed to send watch alert message")}}this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}if(d==="trigger_watch"&&e.triggerWatchId){if(t>=Ag){this.logger.warn({watchId:e.id,targetId:e.triggerWatchId,chainDepth:t},"Watch chain depth limit reached, aborting chain"),this.activityLogger?.logWatchChain({watchId:e.id,watchName:e.name,targetWatchId:e.triggerWatchId,platform:e.platform,chatId:e.chatId,outcome:"depth_limit",chainDepth:t}),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}let g=this.watchRepo.getById(e.triggerWatchId);if(!g){this.logger.warn({watchId:e.id,targetId:e.triggerWatchId},"Chained watch not found"),this.watchRepo.updateActionError(e.id,`Chained watch "${e.triggerWatchId}" not found`),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}if(!g.enabled){this.logger.warn({watchId:e.id,targetId:g.id},"Chained watch is disabled, skipping"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}this.activityLogger?.logWatchChain({watchId:e.id,watchName:e.name,targetWatchId:g.id,targetWatchName:g.name,platform:e.platform,chatId:e.chatId,outcome:"success",chainDepth:t}),this.logger.info({watchId:e.id,targetId:g.id,targetName:g.name,chainDepth:t+1},"Watch chain: triggering downstream watch");try{await this.checkWatch(g,t+1),this.watchRepo.updateActionError(e.id,null)}catch(y){let _=y instanceof Error?y.message:String(y);this.watchRepo.updateActionError(e.id,_),this.logger.warn({watchId:e.id,targetId:g.id,err:y},"Watch chain execution failed")}this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}let f=null;if((d==="action_only"||d==="alert_and_action")&&e.actionSkillName)if(this.skillHealthTracker?.isDisabled(e.actionSkillName))f=`Action skill "${e.actionSkillName}" is temporarily disabled due to repeated failures`,this.watchRepo.updateActionError(e.id,f),this.logger.warn({watchId:e.id,skillName:e.actionSkillName},"Watch action skill is auto-disabled");else{let g=this.skillRegistry.get(e.actionSkillName);if(g)try{await this.skillSandbox.execute(g,m,n),this.watchRepo.updateActionError(e.id,null),this.skillHealthTracker?.recordSuccess(e.actionSkillName),this.activityLogger?.logWatchAction({watchId:e.id,watchName:e.name,skillName:e.actionSkillName,platform:e.platform,chatId:e.chatId,outcome:"success"})}catch(y){f=y instanceof Error?y.message:String(y),this.watchRepo.updateActionError(e.id,f),this.skillHealthTracker?.recordFailure(e.actionSkillName,f),this.logger.warn({watchId:e.id,err:y},"Watch action failed"),this.activityLogger?.logWatchAction({watchId:e.id,watchName:e.name,skillName:e.actionSkillName,platform:e.platform,chatId:e.chatId,outcome:"error",error:f})}else f=`Action skill "${e.actionSkillName}" not found`,this.watchRepo.updateActionError(e.id,f),this.logger.warn({watchId:e.id,skillName:e.actionSkillName},"Unknown action skill for watch")}if(d==="alert"||d==="alert_and_action"){let g=await this.buildAlertText(e,a,o.data,h);f&&(g+=`
1258
1258
 
@@ -1279,10 +1279,10 @@ Regeln:
1279
1279
  Insgesamt: ${e.count} Inserate`),n.join(`
1280
1280
  `)}if(Array.isArray(e.cheapest)&&e.cheapest.length>0){let s=e.cheapest,r=[`G\xFCnstigste ${s.length}:`];for(let n of s){let o=String(n.title??"").slice(0,60),i=typeof n.price=="number"?`${n.price}\xA0\u20AC`:"k.A.",a=n.url?`
1281
1281
  ${n.url}`:"";r.push(`\u2022 ${o} \u2014 ${i}${a}`)}return r.join(`
1282
- `)}return null}}});var In,Tc=T(()=>{"use strict";In=class{static{p(this,"ConfirmationQueue")}confirmRepo;skillRegistry;skillSandbox;adapters;logger;activityLogger;expireTimer=null;feedbackService;constructor(e,t,s,r,n,o){this.confirmRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.logger=n,this.activityLogger=o}setFeedbackService(e){this.feedbackService=e}start(){this.expireTimer=setInterval(()=>this.expireTick(),6e4)}stop(){this.expireTimer&&(clearInterval(this.expireTimer),this.expireTimer=null)}async enqueue(e){let t=new Date(Date.now()+(e.timeoutMinutes??30)*6e4).toISOString(),s=this.confirmRepo.create({chatId:e.chatId,platform:e.platform,source:e.source,sourceId:e.sourceId,description:e.description,skillName:e.skillName,skillParams:e.skillParams,expiresAt:t}),r=this.adapters.get(e.platform);if(r){let n=s.id,o=`\u2753 Best\xE4tigung erforderlich:
1282
+ `)}return null}}});var Rn,Tc=T(()=>{"use strict";Rn=class{static{p(this,"ConfirmationQueue")}confirmRepo;skillRegistry;skillSandbox;adapters;logger;activityLogger;expireTimer=null;feedbackService;constructor(e,t,s,r,n,o){this.confirmRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.logger=n,this.activityLogger=o}setFeedbackService(e){this.feedbackService=e}start(){this.expireTimer=setInterval(()=>this.expireTick(),6e4)}stop(){this.expireTimer&&(clearInterval(this.expireTimer),this.expireTimer=null)}async enqueue(e){let t=new Date(Date.now()+(e.timeoutMinutes??30)*6e4).toISOString(),s=this.confirmRepo.create({chatId:e.chatId,platform:e.platform,source:e.source,sourceId:e.sourceId,description:e.description,skillName:e.skillName,skillParams:e.skillParams,expiresAt:t}),r=this.adapters.get(e.platform);if(r){let n=s.id,o=`\u2753 Best\xE4tigung erforderlich:
1283
1283
  ${e.description}
1284
1284
 
1285
- Antworte "ja" oder "nein".`;try{e.platform==="telegram"&&n?await r.sendMessage(e.chatId,o,{replyMarkup:{inlineKeyboard:[[{text:"\u2705 Approve",callbackData:`confirm:${n}:approve`},{text:"\u274C Reject",callbackData:`confirm:${n}:reject`}]]}}):await r.sendMessage(e.chatId,o)}catch(i){this.logger.error({err:i},"Failed to send confirmation request")}}}async checkForConfirmation(e,t,s,r){let n=s.trim().toLowerCase(),o=/^confirm:([^:]+):(approve|reject)$/.exec(n),i=o?o[2]==="approve":["ja","ok","yes","best\xE4tigen","j"].includes(n),a=o?o[2]==="reject":["nein","no","abbrechen","n","n\xF6"].includes(n);if(!i&&!a)return!1;let c=this.confirmRepo.findPending(e,t);if(!c)return!1;let d=this.adapters.get(t);if(i){this.confirmRepo.resolve(c.id,"approved");let u=this.skillRegistry.get(c.skillName);if(u)try{await this.skillSandbox.execute(u,c.skillParams,r),d&&await d.sendMessage(e,`\u2705 Aktion ausgef\xFChrt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"approved",userId:r.userId,platform:t,chatId:e})}catch(m){this.logger.error({err:m,confirmationId:c.id},"Confirmed action failed"),d&&await d.sendMessage(e,`\u274C Aktion fehlgeschlagen: ${m instanceof Error?m.message:String(m)}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"error",userId:r.userId,platform:t,chatId:e,error:m instanceof Error?m.message:String(m)})}else d&&await d.sendMessage(e,`\u274C Skill "${c.skillName}" nicht gefunden.`)}else this.confirmRepo.resolve(c.id,"rejected"),d&&await d.sendMessage(e,`\u274C Aktion abgelehnt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"rejected",userId:r.userId,platform:t,chatId:e}),this.feedbackService?.onWatchRejected({userId:r.userId,watchId:c.sourceId,watchName:c.description,skillName:c.skillName,skillParams:c.skillParams??{},description:c.description});return!0}async expireTick(){try{let e=this.confirmRepo.expireOld();for(let t of e){this.activityLogger?.logConfirmation({confirmationId:t.id,skillName:t.skillName,description:t.description,source:t.source,sourceId:t.sourceId,outcome:"expired",platform:t.platform,chatId:t.chatId});let s=this.adapters.get(t.platform);if(s)try{await s.sendMessage(t.chatId,`\u23F0 Best\xE4tigung abgelaufen: ${t.description}`)}catch{}}}catch(e){this.logger.error({err:e},"Confirmation expire tick failed")}}}});function _c(l){let e=l.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of Rg)if(s.test(e))return{level:"low",matchedPatterns:[]};let t=[];for(let s of xg)for(let r of s.patterns)if(r.test(e)){t.push(s.name);break}return t.length>0?{level:"high",matchedPatterns:t}:{level:"low",matchedPatterns:[]}}var Rg,xg,kc=T(()=>{"use strict";Rg=[/^(what|where|when|who|why|how|which|can you|could you|do you|is there|are there|was |wer |wo |wann |warum |wie |welch|kannst du|könntest du|gibt es)/i,/^(hi|hey|hello|hallo|guten (morgen|tag|abend)|moin|servus|grüß|na\b|yo\b|sup\b|good (morning|evening|night))\b/i,/^(tell me|show me|find|search|help|explain|describe|translate|summarize|zeig|such|hilf|erklär|beschreib|übersetze|fass zusammen)/i,/^(ok|okay|yes|no|ja|nein|danke|thanks|thank you|sure|alright|klar|gut|cool|nice|great|perfect|genau|stimmt|richtig)\b/i],xg=[{name:"fact:name",patterns:[/\b(my name is|i'm called|i am called|ich heiße|ich bin der|ich bin die|mein name ist)\b/i]},{name:"fact:location",patterns:[/\b(i live in|i'm from|i am from|ich wohne|ich lebe in|ich komme aus|ich bin aus)\b/i]},{name:"fact:work",patterns:[/\b(i work at|i work as|i work for|ich arbeite|mein job|mein beruf|ich bin .{0,20}(entwickler|ingenieur|lehrer|arzt|designer))\b/i]},{name:"fact:birthday",patterns:[/\b(my birthday|i was born|ich bin geboren|mein geburtstag|ich habe am .{1,15} geburtstag)\b/i]},{name:"fact:age",patterns:[/\b(i'm \d+ years|i am \d+ years|ich bin \d+ (jahre|jahr))\b/i]},{name:"preference:like",patterns:[/\b(i love|i really like|i enjoy|ich liebe|ich mag|mir gefällt|mir gefallen)\b/i]},{name:"preference:dislike",patterns:[/\b(i hate|i dislike|i can't stand|ich hasse|ich mag .{0,5} nicht|ich kann .{0,10} nicht leiden)\b/i]},{name:"preference:prefer",patterns:[/\b(i prefer|i'd rather|ich bevorzuge|ich nehme lieber|mir ist .{0,10} lieber)\b/i]},{name:"preference:favorite",patterns:[/\b(my fav|my favorite|my favourite|mein lieblings|meine lieblings|am liebsten)\b/i]},{name:"correction",patterns:[/\b(actually|actually,? (i|my|it)|eigentlich|das stimmt nicht|nein,? ich|that's not right|that's wrong|nicht ganz)\b/i]},{name:"relationship:family",patterns:[/\b(my wife|my husband|my partner|meine frau|mein mann|mein partner|meine partnerin|my daughter|my son|mein sohn|meine tochter|my kids|meine kinder|my mother|my father|meine mutter|mein vater)\b/i]},{name:"relationship:professional",patterns:[/\b(my boss|my manager|my colleague|mein chef|mein vorgesetzter|mein kollege|meine kollegin)\b/i]},{name:"relationship:social",patterns:[/\b(my friend|my best friend|mein freund|meine freundin|mein bester freund)\b/i]},{name:"fact:language",patterns:[/\b(i speak|ich spreche|my native|meine muttersprache)\b/i]},{name:"fact:education",patterns:[/\b(i studied|i went to|ich habe .{0,10} studiert|ich war auf der|mein studium)\b/i]},{name:"fact:hobby",patterns:[/\b(my hobby|i play .{0,10}(guitar|piano|football|tennis|chess)|mein hobby|ich spiele|in my free time|in meiner freizeit)\b/i]},{name:"decision",patterns:[/\b(i've decided|i decided|i will always|ich habe (mich )?entschieden|ich werde immer)\b/i]},{name:"commitment",patterns:[/\b(i always|i never|ich mache immer|ich mache nie|i'm trying to|ich versuche)\b/i]}];p(_c,"scanSignal")});var Cg,Ng,Rn,bc=T(()=>{"use strict";Cg=["fact","preference","correction","entity","decision","relationship","principle","commitment","moment","skill"],Ng=`You are a memory extraction system. Analyze the user message and extract personal facts about the USER (not about what they're asking).
1285
+ Antworte "ja" oder "nein".`;try{e.platform==="telegram"&&n?await r.sendMessage(e.chatId,o,{replyMarkup:{inlineKeyboard:[[{text:"\u2705 Approve",callbackData:`confirm:${n}:approve`},{text:"\u274C Reject",callbackData:`confirm:${n}:reject`}]]}}):await r.sendMessage(e.chatId,o)}catch(i){this.logger.error({err:i},"Failed to send confirmation request")}}}async checkForConfirmation(e,t,s,r){let n=s.trim().toLowerCase(),o=/^confirm:([^:]+):(approve|reject)$/.exec(n),i=o?o[2]==="approve":["ja","ok","yes","best\xE4tigen","j"].includes(n),a=o?o[2]==="reject":["nein","no","abbrechen","n","n\xF6"].includes(n);if(!i&&!a)return!1;let c=this.confirmRepo.findPending(e,t);if(!c)return!1;let d=this.adapters.get(t);if(i){this.confirmRepo.resolve(c.id,"approved");let u=this.skillRegistry.get(c.skillName);if(u)try{await this.skillSandbox.execute(u,c.skillParams,r),d&&await d.sendMessage(e,`\u2705 Aktion ausgef\xFChrt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"approved",userId:r.userId,platform:t,chatId:e})}catch(m){this.logger.error({err:m,confirmationId:c.id},"Confirmed action failed"),d&&await d.sendMessage(e,`\u274C Aktion fehlgeschlagen: ${m instanceof Error?m.message:String(m)}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"error",userId:r.userId,platform:t,chatId:e,error:m instanceof Error?m.message:String(m)})}else d&&await d.sendMessage(e,`\u274C Skill "${c.skillName}" nicht gefunden.`)}else this.confirmRepo.resolve(c.id,"rejected"),d&&await d.sendMessage(e,`\u274C Aktion abgelehnt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"rejected",userId:r.userId,platform:t,chatId:e}),this.feedbackService?.onWatchRejected({userId:r.userId,watchId:c.sourceId,watchName:c.description,skillName:c.skillName,skillParams:c.skillParams??{},description:c.description});return!0}async expireTick(){try{let e=this.confirmRepo.expireOld();for(let t of e){this.activityLogger?.logConfirmation({confirmationId:t.id,skillName:t.skillName,description:t.description,source:t.source,sourceId:t.sourceId,outcome:"expired",platform:t.platform,chatId:t.chatId});let s=this.adapters.get(t.platform);if(s)try{await s.sendMessage(t.chatId,`\u23F0 Best\xE4tigung abgelaufen: ${t.description}`)}catch{}}}catch(e){this.logger.error({err:e},"Confirmation expire tick failed")}}}});function _c(l){let e=l.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of Rg)if(s.test(e))return{level:"low",matchedPatterns:[]};let t=[];for(let s of xg)for(let r of s.patterns)if(r.test(e)){t.push(s.name);break}return t.length>0?{level:"high",matchedPatterns:t}:{level:"low",matchedPatterns:[]}}var Rg,xg,kc=T(()=>{"use strict";Rg=[/^(what|where|when|who|why|how|which|can you|could you|do you|is there|are there|was |wer |wo |wann |warum |wie |welch|kannst du|könntest du|gibt es)/i,/^(hi|hey|hello|hallo|guten (morgen|tag|abend)|moin|servus|grüß|na\b|yo\b|sup\b|good (morning|evening|night))\b/i,/^(tell me|show me|find|search|help|explain|describe|translate|summarize|zeig|such|hilf|erklär|beschreib|übersetze|fass zusammen)/i,/^(ok|okay|yes|no|ja|nein|danke|thanks|thank you|sure|alright|klar|gut|cool|nice|great|perfect|genau|stimmt|richtig)\b/i],xg=[{name:"fact:name",patterns:[/\b(my name is|i'm called|i am called|ich heiße|ich bin der|ich bin die|mein name ist)\b/i]},{name:"fact:location",patterns:[/\b(i live in|i'm from|i am from|ich wohne|ich lebe in|ich komme aus|ich bin aus)\b/i]},{name:"fact:work",patterns:[/\b(i work at|i work as|i work for|ich arbeite|mein job|mein beruf|ich bin .{0,20}(entwickler|ingenieur|lehrer|arzt|designer))\b/i]},{name:"fact:birthday",patterns:[/\b(my birthday|i was born|ich bin geboren|mein geburtstag|ich habe am .{1,15} geburtstag)\b/i]},{name:"fact:age",patterns:[/\b(i'm \d+ years|i am \d+ years|ich bin \d+ (jahre|jahr))\b/i]},{name:"preference:like",patterns:[/\b(i love|i really like|i enjoy|ich liebe|ich mag|mir gefällt|mir gefallen)\b/i]},{name:"preference:dislike",patterns:[/\b(i hate|i dislike|i can't stand|ich hasse|ich mag .{0,5} nicht|ich kann .{0,10} nicht leiden)\b/i]},{name:"preference:prefer",patterns:[/\b(i prefer|i'd rather|ich bevorzuge|ich nehme lieber|mir ist .{0,10} lieber)\b/i]},{name:"preference:favorite",patterns:[/\b(my fav|my favorite|my favourite|mein lieblings|meine lieblings|am liebsten)\b/i]},{name:"correction",patterns:[/\b(actually|actually,? (i|my|it)|eigentlich|das stimmt nicht|nein,? ich|that's not right|that's wrong|nicht ganz)\b/i]},{name:"relationship:family",patterns:[/\b(my wife|my husband|my partner|meine frau|mein mann|mein partner|meine partnerin|my daughter|my son|mein sohn|meine tochter|my kids|meine kinder|my mother|my father|meine mutter|mein vater)\b/i]},{name:"relationship:professional",patterns:[/\b(my boss|my manager|my colleague|mein chef|mein vorgesetzter|mein kollege|meine kollegin)\b/i]},{name:"relationship:social",patterns:[/\b(my friend|my best friend|mein freund|meine freundin|mein bester freund)\b/i]},{name:"fact:language",patterns:[/\b(i speak|ich spreche|my native|meine muttersprache)\b/i]},{name:"fact:education",patterns:[/\b(i studied|i went to|ich habe .{0,10} studiert|ich war auf der|mein studium)\b/i]},{name:"fact:hobby",patterns:[/\b(my hobby|i play .{0,10}(guitar|piano|football|tennis|chess)|mein hobby|ich spiele|in my free time|in meiner freizeit)\b/i]},{name:"decision",patterns:[/\b(i've decided|i decided|i will always|ich habe (mich )?entschieden|ich werde immer)\b/i]},{name:"commitment",patterns:[/\b(i always|i never|ich mache immer|ich mache nie|i'm trying to|ich versuche)\b/i]}];p(_c,"scanSignal")});var Cg,Ng,xn,bc=T(()=>{"use strict";Cg=["fact","preference","correction","entity","decision","relationship","principle","commitment","moment","skill"],Ng=`You are a memory extraction system. Analyze the user message and extract personal facts about the USER (not about what they're asking).
1286
1286
 
1287
1287
  Rules:
1288
1288
  - Only extract information the user STATES about themselves
@@ -1302,7 +1302,7 @@ Extract memories from this conversation:
1302
1302
  User: {USER_MESSAGE}
1303
1303
  Assistant: {ASSISTANT_RESPONSE}
1304
1304
 
1305
- Return ONLY a valid JSON array, no explanation:`,Rn=class{static{p(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,n=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=n}async extract(e,t,s){try{let r=Ng.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),n=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),o=this.parseResponse(n.content);if(o.length===0)return 0;let i=0;for(let a of o)if(!(a.confidence<this.minConfidence))try{let c=this.memoryRepo.saveWithMetadata(e,a.key,a.value,a.category,a.type,a.confidence,"auto");this.embeddingService&&this.embeddingService.embedAndStore(e,`${a.key}: ${a.value}`,"memory",c.id).catch(d=>this.logger.debug({err:d},"Auto-embed failed")),i++,this.logger.info({key:a.key,type:a.type,confidence:a.confidence},"Auto-extracted memory saved")}catch(c){this.logger.warn({err:c,key:a.key},"Failed to save extracted memory")}return i}catch(r){return this.logger.error({err:r},"Memory extraction failed"),0}}parseResponse(e){try{let t=e.match(/\[[\s\S]*\]/);if(!t)return[];let s=JSON.parse(t[0]);return Array.isArray(s)?s.filter(r=>typeof r=="object"&&r!==null).map(r=>({key:String(r.key||""),value:String(r.value||""),type:this.validateType(String(r.type||"fact")),confidence:this.clampConfidence(Number(r.confidence)||.5),category:String(r.category||"general")})).filter(r=>r.key&&r.value):[]}catch{return this.logger.debug({content:e.slice(0,200)},"Failed to parse extraction response"),[]}}validateType(e){return Cg.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});function Qo(l){let e=l.trim();if(e.length<8)return{level:"low"};for(let t of Lg)if(t.test(e))return{level:"high"};return{level:"low"}}var Lg,Ec=T(()=>{"use strict";Lg=[/\b(nein,?\s*(nicht so|das ist falsch|das stimmt nicht|anders))\b/i,/\b(das war falsch|das ist falsch|das solltest du nicht)\b/i,/\b(ich meinte|ich wollte|ich habe gemeint)\b/i,/\b(tu das nicht|mach das nicht|lass das)\b/i,/\b(beim nächsten [Mm]al|in [Zz]ukunft|ab jetzt|ab sofort)\b/i,/\b(nicht wenn|nur wenn|nur falls|nur dann)\b/i,/\b(hör auf|stop|stopp).*\b(damit|das|mit)\b/i,/\b(das will ich nicht|das brauche ich nicht)\b/i,/\b(falsche?r?\s+(antwort|ergebnis|aktion|reaktion))\b/i,/\b(zu (oft|viel|aggressiv|häufig|früh|spät))\b/i,/\b(schwellenwert|threshold|grenzwert).*(ändern|anpassen|erhöhen|senken)\b/i,/\b(no,?\s*(not like that|that's wrong|don't do that))\b/i,/\b(that was wrong|that's incorrect|that's not what I)\b/i,/\b(I meant|I wanted|what I meant was)\b/i,/\b(don't do that|stop doing|never do)\b/i,/\b(next time|from now on|in the future|going forward)\b/i,/\b(not when|only when|only if|only then)\b/i,/\b(too (often|much|aggressive|frequent|early|late))\b/i];p(Qo,"scanCorrectionSignal")});var xn,Sc=T(()=>{"use strict";kc();bc();Ec();xn=class{static{p(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;feedbackService;setFeedbackService(e){this.feedbackService=e}constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new Rn(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;this.feedbackService&&Qo(t).level==="high"&&this.feedbackService.onConversationCorrection({userId:e,userMessage:t,assistantResponse:s});let r=_c(t);if(r.level==="low"){this.logger.debug({signal:"low"},"Skipping extraction \u2014 low signal");return}if(!this.checkRateLimit(e)){this.logger.debug({userId:e},"Skipping extraction \u2014 rate limit reached");return}this.logger.info({signal:r.level,patterns:r.matchedPatterns},"High signal detected, triggering extraction"),this.extractor.extract(e,t,s).then(n=>{n>0&&this.logger.info({userId:e,extractedCount:n},"Auto-extraction complete")}).catch(n=>{this.logger.error({err:n},"Auto-extraction failed")})}checkRateLimit(e){let t=Date.now(),s=t-6e4,r=this.extractionTimestamps.get(e);r||(r=[],this.extractionTimestamps.set(e,r));let n=r.filter(o=>o>s);return n.length===0?(this.extractionTimestamps.delete(e),!0):(this.extractionTimestamps.set(e,n),n.length>=this.maxExtractionsPerMinute?!1:(n.push(t),!0))}}});var rr,$c=T(()=>{"use strict";rr=class{static{p(this,"FeedbackService")}feedbackRepo;memoryRepo;logger;threshold;staleDays;constructor(e,t,s,r){this.feedbackRepo=e,this.memoryRepo=t,this.logger=s,this.threshold=r?.rejectionThreshold??3,this.staleDays=r?.staleDays??90}onWatchRejected(e){this.handleWatchRejection(e).catch(t=>{this.logger.error({err:t},"Feedback: watch rejection handling failed")})}onConversationCorrection(e){this.handleCorrection(e).catch(t=>{this.logger.error({err:t},"Feedback: conversation correction handling failed")})}async runMaintenance(){try{let e=this.feedbackRepo.pruneOldEvents(this.staleDays*2);e>0&&this.logger.info({pruned:e},"Feedback: pruned old events")}catch(e){this.logger.error({err:e},"Feedback: maintenance failed")}}async handleWatchRejection(e){let t=`watch:${e.watchName.toLowerCase().replace(/\s+/g,"_")}:${e.skillName}`;this.feedbackRepo.recordEvent(e.userId,"watch_rejection",e.watchId,t,e.description,{skillName:e.skillName,skillParams:e.skillParams});let s=this.feedbackRepo.countEvents(e.userId,t);if(this.logger.debug({contextKey:t,count:s,threshold:this.threshold},"Feedback: watch rejection recorded"),s>=this.threshold){let r=`feedback:${t}`,n=`Watch "${e.watchName}" wurde ${s}\xD7 abgelehnt. Schwellenwert oder Parameter \xFCberpr\xFCfen bevor diese Aktion vorgeschlagen wird.`;this.memoryRepo.saveWithMetadata(e.userId,r,n,"automation","feedback",.9,"auto"),this.logger.info({contextKey:t,count:s,memoryKey:r},"Feedback: watch rejection promoted to feedback memory")}}async handleCorrection(e){let t=new Date().toISOString().slice(0,10),s=`correction:${e.userId}:${t}`,r=this.extractCorrectionRule(e.userMessage);if(!r)return;this.feedbackRepo.recordEvent(e.userId,"conversation_correction",void 0,s,r,{userMessage:e.userMessage.slice(0,500)});let n=`feedback:correction:${Date.now()}`;this.memoryRepo.saveWithMetadata(e.userId,n,r,"general","feedback",.8,"auto"),this.logger.info({rule:r},"Feedback: conversation correction saved as feedback memory")}extractCorrectionRule(e){let t=e.trim();return t.length>10&&t.length<300?`Nutzer-Korrektur: ${t}`:t.length>=300?`Nutzer-Korrektur: ${t.slice(0,280)}...`:null}}});var Dg,Mg,Og,Pg,Cn,vc=T(()=>{"use strict";Dg=Math.LN2,Mg=.3,Og=.7,Pg=3,Cn=class{static{p(this,"MemoryRetriever")}memoryRepo;logger;embeddingService;constructor(e,t,s){this.memoryRepo=e,this.logger=t,this.embeddingService=s}async retrieve(e,t,s=15,r){let n=[e];if(r)for(let o of r)o!==e&&n.push(o);try{let o=new Set,i=[];for(let g of n)for(let y of this.memoryRepo.keywordSearch(g,t,30))o.has(y.id)||(o.add(y.id),i.push(y));let a=[],c=!1;if(this.embeddingService)try{let g=new Set;for(let y of n)for(let _ of await this.embeddingService.semanticSearch(y,t,30))g.has(_.key)||(g.add(_.key),a.push(_));c=a.length>0}catch(g){this.logger.debug({err:g},"Semantic search failed, falling back to keyword-only")}let d=new Map,u=i.length;for(let g=0;g<i.length;g++){let y=i[g],_=u>0?1-g/u:0,S=c?Mg:1,E=this.applyBoosts(_*S,y);d.set(y.key,{memory:{key:y.key,value:y.value,category:y.category,type:y.type,score:E},score:E}),this.memoryRepo.recordAccess(y.id)}if(c)for(let g of a){let y=g.score*Og,_=d.get(g.key);if(_)_.score+=y,_.memory.score=_.score;else{let S=this.memoryRepo.recall(e,g.key),E=this.applyBoosts(y,S||void 0);d.set(g.key,{memory:{key:g.key,value:g.value,category:g.category,type:S?.type||"general",score:E},score:E}),S&&this.memoryRepo.recordAccess(S.id)}}let m=Array.from(d.values()).sort((g,y)=>y.score-g.score),h=new Map,f=[];for(let{memory:g}of m){let y=h.get(g.type)||0;if(!(y>=Pg)&&(h.set(g.type,y+1),f.push(g),f.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:f.length,hasSemanticSearch:c},"Hybrid memory retrieval complete"),f}catch(o){this.logger.error({err:o},"Memory retrieval failed");let i=new Set,a=[];for(let c of n)for(let d of this.memoryRepo.getRecentForPrompt(c,s))i.has(d.key)||(i.add(d.key),a.push({key:d.key,value:d.value,category:d.category,type:d.type,score:0}));return a.slice(0,s)}}applyBoosts(e,t){let s=e;if(t){s*=.5+.5*t.confidence;let r=new Date(t.updatedAt).getTime(),n=Date.now()-r,o=Math.exp(-Dg*n/2592e6);s*=o}return s}}});var Nn,Ac=T(()=>{"use strict";Nn=class{static{p(this,"ConversationSummarizer")}llm;summaryRepo;logger;constructor(e,t,s){this.llm=e,this.summaryRepo=t,this.logger=s}getSummary(e){return this.summaryRepo.get(e)}onMessageProcessed(e,t,s,r,n){let o=this.summaryRepo.get(e);!o&&t<6||o&&t-o.messageCount<3||this.updateSummary(e,t,s,r,n,o).catch(i=>this.logger.warn({err:i,conversationId:e},"Failed to update conversation summary"))}async updateSummary(e,t,s,r,n,o){let i=this.buildSummaryPrompt(o?.summary,n,s,r),c=(await this.llm.complete({messages:[{role:"user",content:i}],temperature:.1,tier:"fast",maxTokens:512})).content?.trim();if(!c||c.length<10){this.logger.debug({conversationId:e},"Summary response too short, skipping upsert");return}this.summaryRepo.upsert({conversationId:e,summary:c,messageCount:t,lastUserMessage:s.slice(0,500),lastAssistantMessage:r.slice(0,500),updatedAt:new Date().toISOString()}),this.logger.debug({conversationId:e,messageCount:t,summaryLength:c.length},"Conversation summary updated")}buildSummaryPrompt(e,t,s,r){let n=`Du bist ein Zusammenfassungs-Assistent. Erstelle eine strukturierte Zusammenfassung des Gespr\xE4chsverlaufs.
1305
+ Return ONLY a valid JSON array, no explanation:`,xn=class{static{p(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,n=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=n}async extract(e,t,s){try{let r=Ng.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),n=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),o=this.parseResponse(n.content);if(o.length===0)return 0;let i=0;for(let a of o)if(!(a.confidence<this.minConfidence))try{let c=this.memoryRepo.saveWithMetadata(e,a.key,a.value,a.category,a.type,a.confidence,"auto");this.embeddingService&&this.embeddingService.embedAndStore(e,`${a.key}: ${a.value}`,"memory",c.id).catch(d=>this.logger.debug({err:d},"Auto-embed failed")),i++,this.logger.info({key:a.key,type:a.type,confidence:a.confidence},"Auto-extracted memory saved")}catch(c){this.logger.warn({err:c,key:a.key},"Failed to save extracted memory")}return i}catch(r){return this.logger.error({err:r},"Memory extraction failed"),0}}parseResponse(e){try{let t=e.match(/\[[\s\S]*\]/);if(!t)return[];let s=JSON.parse(t[0]);return Array.isArray(s)?s.filter(r=>typeof r=="object"&&r!==null).map(r=>({key:String(r.key||""),value:String(r.value||""),type:this.validateType(String(r.type||"fact")),confidence:this.clampConfidence(Number(r.confidence)||.5),category:String(r.category||"general")})).filter(r=>r.key&&r.value):[]}catch{return this.logger.debug({content:e.slice(0,200)},"Failed to parse extraction response"),[]}}validateType(e){return Cg.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});function Qo(l){let e=l.trim();if(e.length<8)return{level:"low"};for(let t of Lg)if(t.test(e))return{level:"high"};return{level:"low"}}var Lg,Ec=T(()=>{"use strict";Lg=[/\b(nein,?\s*(nicht so|das ist falsch|das stimmt nicht|anders))\b/i,/\b(das war falsch|das ist falsch|das solltest du nicht)\b/i,/\b(ich meinte|ich wollte|ich habe gemeint)\b/i,/\b(tu das nicht|mach das nicht|lass das)\b/i,/\b(beim nächsten [Mm]al|in [Zz]ukunft|ab jetzt|ab sofort)\b/i,/\b(nicht wenn|nur wenn|nur falls|nur dann)\b/i,/\b(hör auf|stop|stopp).*\b(damit|das|mit)\b/i,/\b(das will ich nicht|das brauche ich nicht)\b/i,/\b(falsche?r?\s+(antwort|ergebnis|aktion|reaktion))\b/i,/\b(zu (oft|viel|aggressiv|häufig|früh|spät))\b/i,/\b(schwellenwert|threshold|grenzwert).*(ändern|anpassen|erhöhen|senken)\b/i,/\b(no,?\s*(not like that|that's wrong|don't do that))\b/i,/\b(that was wrong|that's incorrect|that's not what I)\b/i,/\b(I meant|I wanted|what I meant was)\b/i,/\b(don't do that|stop doing|never do)\b/i,/\b(next time|from now on|in the future|going forward)\b/i,/\b(not when|only when|only if|only then)\b/i,/\b(too (often|much|aggressive|frequent|early|late))\b/i];p(Qo,"scanCorrectionSignal")});var Cn,Sc=T(()=>{"use strict";kc();bc();Ec();Cn=class{static{p(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;feedbackService;setFeedbackService(e){this.feedbackService=e}constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new xn(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;this.feedbackService&&Qo(t).level==="high"&&this.feedbackService.onConversationCorrection({userId:e,userMessage:t,assistantResponse:s});let r=_c(t);if(r.level==="low"){this.logger.debug({signal:"low"},"Skipping extraction \u2014 low signal");return}if(!this.checkRateLimit(e)){this.logger.debug({userId:e},"Skipping extraction \u2014 rate limit reached");return}this.logger.info({signal:r.level,patterns:r.matchedPatterns},"High signal detected, triggering extraction"),this.extractor.extract(e,t,s).then(n=>{n>0&&this.logger.info({userId:e,extractedCount:n},"Auto-extraction complete")}).catch(n=>{this.logger.error({err:n},"Auto-extraction failed")})}checkRateLimit(e){let t=Date.now(),s=t-6e4,r=this.extractionTimestamps.get(e);r||(r=[],this.extractionTimestamps.set(e,r));let n=r.filter(o=>o>s);return n.length===0?(this.extractionTimestamps.delete(e),!0):(this.extractionTimestamps.set(e,n),n.length>=this.maxExtractionsPerMinute?!1:(n.push(t),!0))}}});var rr,$c=T(()=>{"use strict";rr=class{static{p(this,"FeedbackService")}feedbackRepo;memoryRepo;logger;threshold;staleDays;constructor(e,t,s,r){this.feedbackRepo=e,this.memoryRepo=t,this.logger=s,this.threshold=r?.rejectionThreshold??3,this.staleDays=r?.staleDays??90}onWatchRejected(e){this.handleWatchRejection(e).catch(t=>{this.logger.error({err:t},"Feedback: watch rejection handling failed")})}onConversationCorrection(e){this.handleCorrection(e).catch(t=>{this.logger.error({err:t},"Feedback: conversation correction handling failed")})}async runMaintenance(){try{let e=this.feedbackRepo.pruneOldEvents(this.staleDays*2);e>0&&this.logger.info({pruned:e},"Feedback: pruned old events")}catch(e){this.logger.error({err:e},"Feedback: maintenance failed")}}async handleWatchRejection(e){let t=`watch:${e.watchName.toLowerCase().replace(/\s+/g,"_")}:${e.skillName}`;this.feedbackRepo.recordEvent(e.userId,"watch_rejection",e.watchId,t,e.description,{skillName:e.skillName,skillParams:e.skillParams});let s=this.feedbackRepo.countEvents(e.userId,t);if(this.logger.debug({contextKey:t,count:s,threshold:this.threshold},"Feedback: watch rejection recorded"),s>=this.threshold){let r=`feedback:${t}`,n=`Watch "${e.watchName}" wurde ${s}\xD7 abgelehnt. Schwellenwert oder Parameter \xFCberpr\xFCfen bevor diese Aktion vorgeschlagen wird.`;this.memoryRepo.saveWithMetadata(e.userId,r,n,"automation","feedback",.9,"auto"),this.logger.info({contextKey:t,count:s,memoryKey:r},"Feedback: watch rejection promoted to feedback memory")}}async handleCorrection(e){let t=new Date().toISOString().slice(0,10),s=`correction:${e.userId}:${t}`,r=this.extractCorrectionRule(e.userMessage);if(!r)return;this.feedbackRepo.recordEvent(e.userId,"conversation_correction",void 0,s,r,{userMessage:e.userMessage.slice(0,500)});let n=`feedback:correction:${Date.now()}`;this.memoryRepo.saveWithMetadata(e.userId,n,r,"general","feedback",.8,"auto"),this.logger.info({rule:r},"Feedback: conversation correction saved as feedback memory")}extractCorrectionRule(e){let t=e.trim();return t.length>10&&t.length<300?`Nutzer-Korrektur: ${t}`:t.length>=300?`Nutzer-Korrektur: ${t.slice(0,280)}...`:null}}});var Dg,Mg,Og,Pg,Nn,vc=T(()=>{"use strict";Dg=Math.LN2,Mg=.3,Og=.7,Pg=3,Nn=class{static{p(this,"MemoryRetriever")}memoryRepo;logger;embeddingService;constructor(e,t,s){this.memoryRepo=e,this.logger=t,this.embeddingService=s}async retrieve(e,t,s=15,r){let n=[e];if(r)for(let o of r)o!==e&&n.push(o);try{let o=new Set,i=[];for(let g of n)for(let y of this.memoryRepo.keywordSearch(g,t,30))o.has(y.id)||(o.add(y.id),i.push(y));let a=[],c=!1;if(this.embeddingService)try{let g=new Set;for(let y of n)for(let _ of await this.embeddingService.semanticSearch(y,t,30))g.has(_.key)||(g.add(_.key),a.push(_));c=a.length>0}catch(g){this.logger.debug({err:g},"Semantic search failed, falling back to keyword-only")}let d=new Map,u=i.length;for(let g=0;g<i.length;g++){let y=i[g],_=u>0?1-g/u:0,S=c?Mg:1,E=this.applyBoosts(_*S,y);d.set(y.key,{memory:{key:y.key,value:y.value,category:y.category,type:y.type,score:E},score:E}),this.memoryRepo.recordAccess(y.id)}if(c)for(let g of a){let y=g.score*Og,_=d.get(g.key);if(_)_.score+=y,_.memory.score=_.score;else{let S=this.memoryRepo.recall(e,g.key),E=this.applyBoosts(y,S||void 0);d.set(g.key,{memory:{key:g.key,value:g.value,category:g.category,type:S?.type||"general",score:E},score:E}),S&&this.memoryRepo.recordAccess(S.id)}}let m=Array.from(d.values()).sort((g,y)=>y.score-g.score),h=new Map,f=[];for(let{memory:g}of m){let y=h.get(g.type)||0;if(!(y>=Pg)&&(h.set(g.type,y+1),f.push(g),f.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:f.length,hasSemanticSearch:c},"Hybrid memory retrieval complete"),f}catch(o){this.logger.error({err:o},"Memory retrieval failed");let i=new Set,a=[];for(let c of n)for(let d of this.memoryRepo.getRecentForPrompt(c,s))i.has(d.key)||(i.add(d.key),a.push({key:d.key,value:d.value,category:d.category,type:d.type,score:0}));return a.slice(0,s)}}applyBoosts(e,t){let s=e;if(t){s*=.5+.5*t.confidence;let r=new Date(t.updatedAt).getTime(),n=Date.now()-r,o=Math.exp(-Dg*n/2592e6);s*=o}return s}}});var Ln,Ac=T(()=>{"use strict";Ln=class{static{p(this,"ConversationSummarizer")}llm;summaryRepo;logger;constructor(e,t,s){this.llm=e,this.summaryRepo=t,this.logger=s}getSummary(e){return this.summaryRepo.get(e)}onMessageProcessed(e,t,s,r,n){let o=this.summaryRepo.get(e);!o&&t<6||o&&t-o.messageCount<3||this.updateSummary(e,t,s,r,n,o).catch(i=>this.logger.warn({err:i,conversationId:e},"Failed to update conversation summary"))}async updateSummary(e,t,s,r,n,o){let i=this.buildSummaryPrompt(o?.summary,n,s,r),c=(await this.llm.complete({messages:[{role:"user",content:i}],temperature:.1,tier:"fast",maxTokens:512})).content?.trim();if(!c||c.length<10){this.logger.debug({conversationId:e},"Summary response too short, skipping upsert");return}this.summaryRepo.upsert({conversationId:e,summary:c,messageCount:t,lastUserMessage:s.slice(0,500),lastAssistantMessage:r.slice(0,500),updatedAt:new Date().toISOString()}),this.logger.debug({conversationId:e,messageCount:t,summaryLength:c.length},"Conversation summary updated")}buildSummaryPrompt(e,t,s,r){let n=`Du bist ein Zusammenfassungs-Assistent. Erstelle eine strukturierte Zusammenfassung des Gespr\xE4chsverlaufs.
1306
1306
  `;if(e&&(n+=`
1307
1307
  ## Bisherige Zusammenfassung
1308
1308
  ${e}
@@ -1328,10 +1328,10 @@ Regeln:
1328
1328
  - Maximal 120 W\xF6rter
1329
1329
  - Nur relevante Fakten, kein Smalltalk
1330
1330
  - Leere Punkte: "\u2014"
1331
- - Sprache: Deutsch (oder Sprache des Gespr\xE4chs)`,n}}});var Ln,Ic=T(()=>{"use strict";Ln=class{static{p(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(`
1331
+ - Sprache: Deutsch (oder Sprache des Gespr\xE4chs)`,n}}});var Dn,Ic=T(()=>{"use strict";Dn=class{static{p(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(`
1332
1332
  ${c.slice(0,200)}`)}let a=this.adapters.get(this.defaultPlatform);if(a)try{await a.sendMessage(this.defaultChatId,n.join(`
1333
- `)),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 Dn,Rc=T(()=>{"use strict";Dn=class{static{p(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"}),m=[`${o==="overdue"?"\u26A0\uFE0F":"\u2705"} **${o==="overdue"?"\xDCberf\xE4llig":"Bald f\xE4llig"}:** ${t}`,`F\xE4llig: ${c}`];r!=="default"&&m.push(`Liste: ${r}`),n!=="normal"&&m.push(`Priorit\xE4t: ${n}`);let h=this.adapters.get(this.defaultPlatform);if(!h)return;let f=o==="overdue"?new Date().toISOString():s;try{await h.sendMessage(this.defaultChatId,m.join(`
1334
- `)),this.notifRepo.markNotified(i,this.defaultChatId,this.defaultPlatform,f),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(g){this.logger.error({err:g,todoId:e},"Failed to send todo reminder"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:g instanceof Error?g.message:String(g)})}}}});var Mn,xc=T(()=>{"use strict";Mn=class{static{p(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}}))}logWatchChain(e){this.safe(()=>this.repo.log({eventType:"watch_chain",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:`${e.watchName} -> ${e.targetWatchName??e.targetWatchId}`,outcome:e.outcome==="success"?"success":"error",errorMessage:e.error??(e.outcome==="depth_limit"?"Chain depth limit reached":void 0),details:{targetWatchId:e.targetWatchId,targetWatchName:e.targetWatchName,chainDepth:e.chainDepth}}))}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 Ug,On,Cc=T(()=>{"use strict";Ug=[{fails:20,durationMinutes:1440},{fails:10,durationMinutes:120},{fails:5,durationMinutes:30}],On=class{static{p(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 Ug)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")}}}});function Nc(l,e){let t=kt(e,l.field);if(t==null)return!1;let s=l.value;switch(l.operator){case"eq":return String(t)===String(s);case"neq":return String(t)!==String(s);case"gt":case"gte":case"lt":case"lte":{let r=$p(t),n=$p(s);return r===null||n===null?!1:l.operator==="gt"?r>n:l.operator==="gte"?r>=n:l.operator==="lt"?r<n:r<=n}case"contains":return String(t).toLowerCase().includes(String(s??"").toLowerCase());case"not_contains":return!String(t).toLowerCase().includes(String(s??"").toLowerCase());case"changed":return!0;case"increased":case"decreased":return!1;default:return!1}}function $p(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}var Lc=T(()=>{"use strict";vn();p(Nc,"evaluateWorkflowCondition");p($p,"toNumber")});var Pn,Dc=T(()=>{"use strict";Jo();Lc();Pn=class{static{p(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??{},i=0,a=0,c=new Map,d=e.steps.length+2;for(;i<e.steps.length;){let u=(c.get(i)??0)+1;if(c.set(i,u),u>d){let $=`Workflow cycle detected at step ${i} (visited ${u} times)`;return this.finishExecution(r.id,"failed",a,n,$),this.logWorkflow(e,r.id,"failed",a,$),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let m=e.steps[i];if(a++,m.type==="condition"){let $=m,R={prev:o,steps:n.map(F=>F.data)};s&&(R.trigger=s);let M=Nc($.condition,R),q=M?"then":"else",G=M?$.then:$.else;if(n.push({skillName:$.label??"__condition__",success:!0,data:{branch:q,field:$.condition.field,conditionMet:M,target:G}}),this.logger.debug({workflowId:e.id,step:i,branch:q,target:G,field:$.condition.field,conditionMet:M},"Workflow condition evaluated"),G==="end")return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n};if(typeof G=="number"){if(G<0||G>=e.steps.length){let F=`Condition step ${i}: jump target ${G} is out of range (0-${e.steps.length-1})`;return this.finishExecution(r.id,"failed",a,n,F),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:F}}i=G}else i++;this.workflowRepo.updateExecution(r.id,{stepsCompleted:a,stepResults:JSON.stringify(n)});continue}let h=m;if(this.healthTracker?.isDisabled(h.skillName)){let $=`Skill "${h.skillName}" is temporarily disabled`;if(h.onError==="skip"){n.push({skillName:h.skillName,success:!1,error:$}),i++;continue}let R=a>1?"partial":"failed";return this.finishExecution(r.id,R,a,n,$),{executionId:r.id,status:R,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let f=this.skillRegistry.get(h.skillName);if(!f){let $=`Skill "${h.skillName}" not found`;if(h.onError==="skip"){n.push({skillName:h.skillName,success:!1,error:$}),i++;continue}let R=a>1?"partial":"failed";return this.finishExecution(r.id,R,a,n,$),{executionId:r.id,status:R,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let g={prev:o,steps:n.map($=>$.data)};s&&(g.trigger=s);let y=Yt(h.inputMapping,g),_=h.onError==="retry"?(h.maxRetries??1)+1:1,S,E=!1;for(let $=0;$<_;$++)try{let R=await this.skillSandbox.execute(f,y,t);if(R.success){o=R.data,n.push({skillName:h.skillName,success:!0,data:R.data}),this.healthTracker?.recordSuccess(h.skillName),E=!0;break}else S=R.error??"Unknown error",this.healthTracker?.recordFailure(h.skillName,S)}catch(R){S=R instanceof Error?R.message:String(R),this.healthTracker?.recordFailure(h.skillName,S)}if(!E){if(n.push({skillName:h.skillName,success:!1,error:S}),h.onError==="skip"){i++;continue}let $=a>1?"partial":"failed";return this.finishExecution(r.id,$,a,n,S),this.logWorkflow(e,r.id,$,a,S),{executionId:r.id,status:$,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:S}}if(this.workflowRepo.updateExecution(r.id,{stepsCompleted:a,stepResults:JSON.stringify(n)}),h.jumpTo==="end")return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n};if(typeof h.jumpTo=="number"){if(h.jumpTo<0||h.jumpTo>=e.steps.length){let $=`Action step ${i}: jumpTo ${h.jumpTo} is out of range`;return this.finishExecution(r.id,"failed",a,n,$),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}i=h.jumpTo}else i++}return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,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 vp from"node:crypto";var Fg,jg,Un,Fn,Mc=T(()=>{"use strict";_t();Fg=[7,12,18],jg=1536,Un="---ACTIONS---",Fn=class{static{p(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;defaultLocation;feedbackRepo;confirmationQueue;tickTimer;lastRunHour=-1;enabled;schedule;tier;deduplicationHours;constructor(e,t,s,r,n,o,i,a,c,d,u,m,h,f,g,y,_,S,E,$){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=m,this.defaultChatId=h,this.defaultPlatform=f,this.logger=y,this.activityLogger=_,this.defaultLocation=S,this.feedbackRepo=E,this.confirmationQueue=$,this.enabled=g?.enabled!==!1,this.schedule=g?.schedule??"morning_noon_evening",this.tier=g?.tier??"fast",this.deduplicationHours=g?.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!!(Fg.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:jg,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.parseReasoningResponse(n),a=i.insights.filter(c=>!this.wasRecentlySent(c));if(a.length===0&&i.actions.length===0){this.logger.info({durationMs:o,total:i.insights.length},"Reasoning pass: all deduplicated");return}if(a.length>0){let c=`\u{1F4A1} **Alfred Insights**
1333
+ `)),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 Mn,Rc=T(()=>{"use strict";Mn=class{static{p(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"}),m=[`${o==="overdue"?"\u26A0\uFE0F":"\u2705"} **${o==="overdue"?"\xDCberf\xE4llig":"Bald f\xE4llig"}:** ${t}`,`F\xE4llig: ${c}`];r!=="default"&&m.push(`Liste: ${r}`),n!=="normal"&&m.push(`Priorit\xE4t: ${n}`);let h=this.adapters.get(this.defaultPlatform);if(!h)return;let f=o==="overdue"?new Date().toISOString():s;try{await h.sendMessage(this.defaultChatId,m.join(`
1334
+ `)),this.notifRepo.markNotified(i,this.defaultChatId,this.defaultPlatform,f),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(g){this.logger.error({err:g,todoId:e},"Failed to send todo reminder"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:g instanceof Error?g.message:String(g)})}}}});var On,xc=T(()=>{"use strict";On=class{static{p(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}}))}logWatchChain(e){this.safe(()=>this.repo.log({eventType:"watch_chain",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:`${e.watchName} -> ${e.targetWatchName??e.targetWatchId}`,outcome:e.outcome==="success"?"success":"error",errorMessage:e.error??(e.outcome==="depth_limit"?"Chain depth limit reached":void 0),details:{targetWatchId:e.targetWatchId,targetWatchName:e.targetWatchName,chainDepth:e.chainDepth}}))}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 Ug,Pn,Cc=T(()=>{"use strict";Ug=[{fails:20,durationMinutes:1440},{fails:10,durationMinutes:120},{fails:5,durationMinutes:30}],Pn=class{static{p(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 Ug)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")}}}});function Nc(l,e){let t=kt(e,l.field);if(t==null)return!1;let s=l.value;switch(l.operator){case"eq":return String(t)===String(s);case"neq":return String(t)!==String(s);case"gt":case"gte":case"lt":case"lte":{let r=$p(t),n=$p(s);return r===null||n===null?!1:l.operator==="gt"?r>n:l.operator==="gte"?r>=n:l.operator==="lt"?r<n:r<=n}case"contains":return String(t).toLowerCase().includes(String(s??"").toLowerCase());case"not_contains":return!String(t).toLowerCase().includes(String(s??"").toLowerCase());case"changed":return!0;case"increased":case"decreased":return!1;default:return!1}}function $p(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}var Lc=T(()=>{"use strict";An();p(Nc,"evaluateWorkflowCondition");p($p,"toNumber")});var Un,Dc=T(()=>{"use strict";Jo();Lc();Un=class{static{p(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??{},i=0,a=0,c=new Map,d=e.steps.length+2;for(;i<e.steps.length;){let u=(c.get(i)??0)+1;if(c.set(i,u),u>d){let $=`Workflow cycle detected at step ${i} (visited ${u} times)`;return this.finishExecution(r.id,"failed",a,n,$),this.logWorkflow(e,r.id,"failed",a,$),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let m=e.steps[i];if(a++,m.type==="condition"){let $=m,R={prev:o,steps:n.map(F=>F.data)};s&&(R.trigger=s);let M=Nc($.condition,R),q=M?"then":"else",G=M?$.then:$.else;if(n.push({skillName:$.label??"__condition__",success:!0,data:{branch:q,field:$.condition.field,conditionMet:M,target:G}}),this.logger.debug({workflowId:e.id,step:i,branch:q,target:G,field:$.condition.field,conditionMet:M},"Workflow condition evaluated"),G==="end")return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n};if(typeof G=="number"){if(G<0||G>=e.steps.length){let F=`Condition step ${i}: jump target ${G} is out of range (0-${e.steps.length-1})`;return this.finishExecution(r.id,"failed",a,n,F),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:F}}i=G}else i++;this.workflowRepo.updateExecution(r.id,{stepsCompleted:a,stepResults:JSON.stringify(n)});continue}let h=m;if(this.healthTracker?.isDisabled(h.skillName)){let $=`Skill "${h.skillName}" is temporarily disabled`;if(h.onError==="skip"){n.push({skillName:h.skillName,success:!1,error:$}),i++;continue}let R=a>1?"partial":"failed";return this.finishExecution(r.id,R,a,n,$),{executionId:r.id,status:R,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let f=this.skillRegistry.get(h.skillName);if(!f){let $=`Skill "${h.skillName}" not found`;if(h.onError==="skip"){n.push({skillName:h.skillName,success:!1,error:$}),i++;continue}let R=a>1?"partial":"failed";return this.finishExecution(r.id,R,a,n,$),{executionId:r.id,status:R,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let g={prev:o,steps:n.map($=>$.data)};s&&(g.trigger=s);let y=Yt(h.inputMapping,g),_=h.onError==="retry"?(h.maxRetries??1)+1:1,S,E=!1;for(let $=0;$<_;$++)try{let R=await this.skillSandbox.execute(f,y,t);if(R.success){o=R.data,n.push({skillName:h.skillName,success:!0,data:R.data}),this.healthTracker?.recordSuccess(h.skillName),E=!0;break}else S=R.error??"Unknown error",this.healthTracker?.recordFailure(h.skillName,S)}catch(R){S=R instanceof Error?R.message:String(R),this.healthTracker?.recordFailure(h.skillName,S)}if(!E){if(n.push({skillName:h.skillName,success:!1,error:S}),h.onError==="skip"){i++;continue}let $=a>1?"partial":"failed";return this.finishExecution(r.id,$,a,n,S),this.logWorkflow(e,r.id,$,a,S),{executionId:r.id,status:$,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:S}}if(this.workflowRepo.updateExecution(r.id,{stepsCompleted:a,stepResults:JSON.stringify(n)}),h.jumpTo==="end")return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n};if(typeof h.jumpTo=="number"){if(h.jumpTo<0||h.jumpTo>=e.steps.length){let $=`Action step ${i}: jumpTo ${h.jumpTo} is out of range`;return this.finishExecution(r.id,"failed",a,n,$),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}i=h.jumpTo}else i++}return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,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 vp from"node:crypto";var Fg,jg,Fn,jn,Mc=T(()=>{"use strict";_t();Fg=[7,12,18],jg=1536,Fn="---ACTIONS---",jn=class{static{p(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;defaultLocation;feedbackRepo;confirmationQueue;tickTimer;lastRunHour=-1;enabled;schedule;tier;deduplicationHours;constructor(e,t,s,r,n,o,i,a,c,d,u,m,h,f,g,y,_,S,E,$){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=m,this.defaultChatId=h,this.defaultPlatform=f,this.logger=y,this.activityLogger=_,this.defaultLocation=S,this.feedbackRepo=E,this.confirmationQueue=$,this.enabled=g?.enabled!==!1,this.schedule=g?.schedule??"morning_noon_evening",this.tier=g?.tier??"fast",this.deduplicationHours=g?.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!!(Fg.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:jg,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.parseReasoningResponse(n),a=i.insights.filter(c=>!this.wasRecentlySent(c));if(a.length===0&&i.actions.length===0){this.logger.info({durationMs:o,total:i.insights.length},"Reasoning pass: all deduplicated");return}if(a.length>0){let c=`\u{1F4A1} **Alfred Insights**
1335
1335
 
1336
1336
  ${a.join(`
1337
1337
 
@@ -1398,12 +1398,12 @@ ${this.confirmationQueue?`
1398
1398
  Wenn du eine sinnvolle, sofort ausf\xFChrbare Aktion erkennst, kannst du sie vorschlagen.
1399
1399
  Regeln: Max 2 Aktionen, nur wenn JETZT sinnvoll (nicht hypothetisch).
1400
1400
  Aktionstypen: "execute_skill" (Skill ausf\xFChren) oder "create_reminder" (Erinnerung anlegen).
1401
- Format: nach deinen Text-Insights, trenne mit "${Un}", dann ein JSON-Array:
1402
- ${Un}
1401
+ Format: nach deinen Text-Insights, trenne mit "${Fn}", dann ein JSON-Array:
1402
+ ${Fn}
1403
1403
  [{"type":"execute_skill","description":"Wallbox ein (Strom <5ct, BMW 45%)","skillName":"homeassistant","skillParams":{"action":"turn_on","entity_id":"switch.wallbox"}}]
1404
- Wenn keine Aktionen sinnvoll: lass den ${Un} Block weg.`:""}`}parseInsights(e){let t=e.split(/\n{2,}|\n(?=\d+\.\s)/).map(s=>s.trim()).filter(s=>s.length>10);return t.length<=1?[e.trim()]:t}insightHash(e){let t=e.slice(0,100).toLowerCase().replace(/\s+/g," ");return vp.createHash("sha256").update(t).digest("hex").slice(0,16)}wasRecentlySent(e){let s=`reasoning:${this.insightHash(e)}`;return this.notifRepo.wasNotified(s,this.defaultChatId)}markSent(e){let s=`reasoning:${this.insightHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}parseReasoningResponse(e){let t=e.indexOf(Un);if(t===-1)return{insights:this.parseInsights(e),actions:[]};let s=e.slice(0,t).trim(),r=e.slice(t+Un.length).trim(),n=s?this.parseInsights(s):[],o=[];try{let i=JSON.parse(r);Array.isArray(i)&&(o=i.filter(a=>a&&typeof a=="object"&&typeof a.type=="string"&&typeof a.description=="string"&&typeof a.skillName=="string"&&typeof a.skillParams=="object"&&a.skillParams!==null))}catch{this.logger.warn("Reasoning: failed to parse actions JSON, ignoring")}return{insights:n,actions:o}}actionHash(e){let t=`${e.type}:${e.skillName}:${JSON.stringify(e.skillParams)}`.slice(0,150).toLowerCase().replace(/\s+/g," ");return vp.createHash("sha256").update(t).digest("hex").slice(0,16)}actionWasRecentlyProposed(e){let t=this.actionHash(e);return this.notifRepo.wasNotified(`reasoning-action:${t}`,this.defaultChatId)}markActionProposed(e){let s=`reasoning-action:${this.actionHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}async processActions(e){if(!this.confirmationQueue||e.length===0)return;let t=e.slice(0,2);for(let s of t){if(this.actionWasRecentlyProposed(s)){this.logger.info({action:s.description},"Reasoning: action deduplicated, skipping");continue}try{await this.confirmationQueue.enqueue({chatId:this.defaultChatId,platform:this.defaultPlatform,source:"reasoning",sourceId:"reasoning-engine",description:s.description,skillName:s.skillName,skillParams:s.skillParams,timeoutMinutes:60}),this.markActionProposed(s),this.logger.info({action:s.description},"Reasoning: action enqueued for confirmation")}catch(r){this.logger.error({err:r,action:s.description},"Reasoning: failed to enqueue action")}}}}});var Ip={};me(Ip,{ProjectAgentRunner:()=>ei});import{execFile as Bg}from"node:child_process";import{promisify as Hg}from"node:util";var Ap,ei,Oc=T(()=>{"use strict";re();Ap=Hg(Bg),ei=class{static{p(this,"ProjectAgentRunner")}agents;llm;sessionRepo;adapters;logger;lastProgressAt=0;throttleMs=3e4;constructor(e,t,s,r,n){this.agents=e,this.llm=t,this.sessionRepo=s,this.adapters=r,this.logger=n}async run(e,t,s,r){let n={goal:t.goal,cwd:t.cwd,agentName:t.agentName,buildCommands:t.buildCommands,testCommands:t.testCommands,maxDurationHours:t.maxDurationHours??8,maxFixAttempts:t.maxFixAttempts??3,buildTimeoutMs:t.buildTimeoutMs??3e5},o=this.agents.get(n.agentName);if(!o){this.logger.error({sessionId:e,agent:n.agentName},"Project agent not found"),await this.sendProgress(s,r,`\u{1F4A5} Agent "${n.agentName}" nicht gefunden.`);return}let i=new AbortController;cn(e,i);let a={projectPhase:"planning",projectIteration:0,projectGoal:n.goal,buildCommands:n.buildCommands,testCommands:n.testCommands,projectCwd:n.cwd,lastBuildOutput:"",injectedMessages:[],totalFilesChanged:0,milestonesReached:[],consecutiveFixFailures:0,agentName:n.agentName},c=!1;try{await this.sendProgress(s,r,`\u{1F680} Project Agent gestartet: ${n.goal}`),a.projectPhase="planning",this.updateSession(e,a,c),await this.sendProgress(s,r,"\u{1F4CB} Erstelle Projekt-Plan...");let d=await pn(n.goal,this.llm);await this.sendProgress(s,r,`\u{1F4CB} Plan erstellt: ${d.phases.length} Phasen
1404
+ Wenn keine Aktionen sinnvoll: lass den ${Fn} Block weg.`:""}`}parseInsights(e){let t=e.split(/\n{2,}|\n(?=\d+\.\s)/).map(s=>s.trim()).filter(s=>s.length>10);return t.length<=1?[e.trim()]:t}insightHash(e){let t=e.slice(0,100).toLowerCase().replace(/\s+/g," ");return vp.createHash("sha256").update(t).digest("hex").slice(0,16)}wasRecentlySent(e){let s=`reasoning:${this.insightHash(e)}`;return this.notifRepo.wasNotified(s,this.defaultChatId)}markSent(e){let s=`reasoning:${this.insightHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}parseReasoningResponse(e){let t=e.indexOf(Fn);if(t===-1)return{insights:this.parseInsights(e),actions:[]};let s=e.slice(0,t).trim(),r=e.slice(t+Fn.length).trim(),n=s?this.parseInsights(s):[],o=[];try{let i=JSON.parse(r);Array.isArray(i)&&(o=i.filter(a=>a&&typeof a=="object"&&typeof a.type=="string"&&typeof a.description=="string"&&typeof a.skillName=="string"&&typeof a.skillParams=="object"&&a.skillParams!==null))}catch{this.logger.warn("Reasoning: failed to parse actions JSON, ignoring")}return{insights:n,actions:o}}actionHash(e){let t=`${e.type}:${e.skillName}:${JSON.stringify(e.skillParams)}`.slice(0,150).toLowerCase().replace(/\s+/g," ");return vp.createHash("sha256").update(t).digest("hex").slice(0,16)}actionWasRecentlyProposed(e){let t=this.actionHash(e);return this.notifRepo.wasNotified(`reasoning-action:${t}`,this.defaultChatId)}markActionProposed(e){let s=`reasoning-action:${this.actionHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}async processActions(e){if(!this.confirmationQueue||e.length===0)return;let t=e.slice(0,2);for(let s of t){if(this.actionWasRecentlyProposed(s)){this.logger.info({action:s.description},"Reasoning: action deduplicated, skipping");continue}try{await this.confirmationQueue.enqueue({chatId:this.defaultChatId,platform:this.defaultPlatform,source:"reasoning",sourceId:"reasoning-engine",description:s.description,skillName:s.skillName,skillParams:s.skillParams,timeoutMinutes:60}),this.markActionProposed(s),this.logger.info({action:s.description},"Reasoning: action enqueued for confirmation")}catch(r){this.logger.error({err:r,action:s.description},"Reasoning: failed to enqueue action")}}}}});var Ip={};me(Ip,{ProjectAgentRunner:()=>ei});import{execFile as Bg}from"node:child_process";import{promisify as Hg}from"node:util";var Ap,ei,Oc=T(()=>{"use strict";re();Ap=Hg(Bg),ei=class{static{p(this,"ProjectAgentRunner")}agents;llm;sessionRepo;adapters;logger;lastProgressAt=0;throttleMs=3e4;constructor(e,t,s,r,n){this.agents=e,this.llm=t,this.sessionRepo=s,this.adapters=r,this.logger=n}async run(e,t,s,r){let n={goal:t.goal,cwd:t.cwd,agentName:t.agentName,buildCommands:t.buildCommands,testCommands:t.testCommands,maxDurationHours:t.maxDurationHours??8,maxFixAttempts:t.maxFixAttempts??3,buildTimeoutMs:t.buildTimeoutMs??3e5},o=this.agents.get(n.agentName);if(!o){this.logger.error({sessionId:e,agent:n.agentName},"Project agent not found"),await this.sendProgress(s,r,`\u{1F4A5} Agent "${n.agentName}" nicht gefunden.`);return}let i=new AbortController;ln(e,i);let a={projectPhase:"planning",projectIteration:0,projectGoal:n.goal,buildCommands:n.buildCommands,testCommands:n.testCommands,projectCwd:n.cwd,lastBuildOutput:"",injectedMessages:[],totalFilesChanged:0,milestonesReached:[],consecutiveFixFailures:0,agentName:n.agentName},c=!1;try{await this.sendProgress(s,r,`\u{1F680} Project Agent gestartet: ${n.goal}`),a.projectPhase="planning",this.updateSession(e,a,c),await this.sendProgress(s,r,"\u{1F4CB} Erstelle Projekt-Plan...");let d=await mn(n.goal,this.llm);await this.sendProgress(s,r,`\u{1F4CB} Plan erstellt: ${d.phases.length} Phasen
1405
1405
  ${d.phases.map((h,f)=>` ${f+1}. ${h}`).join(`
1406
- `)}`),a.milestonesReached.push("Plan erstellt"),this.sessionRepo.addMilestone(e,"Plan erstellt");let u=Date.now(),m=n.maxDurationHours*60*60*1e3;for(let h=0;h<d.phases.length;h++){if(i.signal.aborted){await this.sendProgress(s,r,"\u23F9 Project Agent abgebrochen.");return}if(Date.now()-u>m){await this.sendProgress(s,r,`\u23F0 Max-Dauer (${n.maxDurationHours}h) \xFCberschritten. Agent gestoppt.`);return}let f=an(e);if(f.includes("__STOP__")){await this.sendProgress(s,r,`\u23F9 Project Agent gestoppt nach Phase ${h}/${d.phases.length}.`);return}a.projectIteration=h+1,a.projectPhase="coding",a.consecutiveFixFailures=0,c=!1,this.updateSession(e,a,c);let g=d.phases[h],y=f.filter($=>$!=="__STOP__"),_=this.assemblePrompt(n.goal,g,a,y);await this.sendProgress(s,r,`\u{1F528} Phase ${h+1}/${d.phases.length}: ${g}`),this.logger.info({sessionId:e,phase:h+1,description:g},"Project agent: coding phase");let S=await Ze(o,_,{cwd:n.cwd,onProgress:p($=>{this.sendProgressThrottled(s,r,` [${n.agentName}] ${$}`)},"onProgress")});a.totalFilesChanged+=S.modifiedFiles.length;let E=!1;for(let $=0;$<=n.maxFixAttempts&&!i.signal.aborted;$++){if(a.projectPhase="validating",this.updateSession(e,a,c),n.buildCommands.length===0&&n.testCommands.length===0){E=!0;break}let R=await un(n.cwd,n.buildCommands,n.testCommands,n.buildTimeoutMs);if(a.lastBuildOutput=R.combinedOutput,R.passed){E=!0,c=!0,await this.sendProgress(s,r,`\u2705 Build passed (Phase ${h+1}). ${S.modifiedFiles.length} Dateien ge\xE4ndert.`);break}if(a.consecutiveFixFailures++,$>=n.maxFixAttempts){await this.sendProgress(s,r,`\u274C Build failed nach ${n.maxFixAttempts} Fix-Versuchen.
1406
+ `)}`),a.milestonesReached.push("Plan erstellt"),this.sessionRepo.addMilestone(e,"Plan erstellt");let u=Date.now(),m=n.maxDurationHours*60*60*1e3;for(let h=0;h<d.phases.length;h++){if(i.signal.aborted){await this.sendProgress(s,r,"\u23F9 Project Agent abgebrochen.");return}if(Date.now()-u>m){await this.sendProgress(s,r,`\u23F0 Max-Dauer (${n.maxDurationHours}h) \xFCberschritten. Agent gestoppt.`);return}let f=cn(e);if(f.includes("__STOP__")){await this.sendProgress(s,r,`\u23F9 Project Agent gestoppt nach Phase ${h}/${d.phases.length}.`);return}a.projectIteration=h+1,a.projectPhase="coding",a.consecutiveFixFailures=0,c=!1,this.updateSession(e,a,c);let g=d.phases[h],y=f.filter($=>$!=="__STOP__"),_=this.assemblePrompt(n.goal,g,a,y);await this.sendProgress(s,r,`\u{1F528} Phase ${h+1}/${d.phases.length}: ${g}`),this.logger.info({sessionId:e,phase:h+1,description:g},"Project agent: coding phase");let S=await Ze(o,_,{cwd:n.cwd,onProgress:p($=>{this.sendProgressThrottled(s,r,` [${n.agentName}] ${$}`)},"onProgress")});a.totalFilesChanged+=S.modifiedFiles.length;let E=!1;for(let $=0;$<=n.maxFixAttempts&&!i.signal.aborted;$++){if(a.projectPhase="validating",this.updateSession(e,a,c),n.buildCommands.length===0&&n.testCommands.length===0){E=!0;break}let R=await pn(n.cwd,n.buildCommands,n.testCommands,n.buildTimeoutMs);if(a.lastBuildOutput=R.combinedOutput,R.passed){E=!0,c=!0,await this.sendProgress(s,r,`\u2705 Build passed (Phase ${h+1}). ${S.modifiedFiles.length} Dateien ge\xE4ndert.`);break}if(a.consecutiveFixFailures++,$>=n.maxFixAttempts){await this.sendProgress(s,r,`\u274C Build failed nach ${n.maxFixAttempts} Fix-Versuchen.
1407
1407
  Letzter Fehler:
1408
1408
  ${R.combinedOutput.slice(-500)}
1409
1409
  Sende "interject" mit Hinweisen oder "stop" zum Abbrechen.`),a.projectPhase="awaiting_user",this.updateSession(e,a,c);break}a.projectPhase="fixing",this.updateSession(e,a,c),await this.sendProgress(s,r,`\u{1F527} Fix-Versuch ${$+1}/${n.maxFixAttempts}...`);let M=`Der Build ist fehlgeschlagen. Hier ist der Output:
@@ -1412,7 +1412,7 @@ ${R.combinedOutput}
1412
1412
 
1413
1413
  Bitte behebe die Fehler. Das Ziel war: ${g}`,q=await Ze(o,M,{cwd:n.cwd,onProgress:p(G=>{this.sendProgressThrottled(s,r,` [fix] ${G}`)},"onProgress")});a.totalFilesChanged+=q.modifiedFiles.length}if(E){a.projectPhase="committing",this.updateSession(e,a,c);try{await Ap("git",["add","-A"],{cwd:n.cwd});let R=`Phase ${h+1}: ${g}`,{stdout:M}=await Ap("git",["commit","-m",R,"--allow-empty"],{cwd:n.cwd}),q=M.match(/\[[\w-]+ ([a-f0-9]+)\]/);a.lastCommitSha=q?.[1],a.lastCommitSha&&await this.sendProgress(s,r,`\u{1F4E6} Commit: ${a.lastCommitSha} \u2014 ${g}`)}catch(R){this.logger.warn({err:R,sessionId:e},"Project agent: git commit failed")}let $=`Phase ${h+1}: ${g}`;a.milestonesReached.push($),this.sessionRepo.addMilestone(e,$),this.updateSession(e,a,c)}}a.projectPhase="done",this.updateSession(e,a,c),await this.sendProgress(s,r,`\u{1F389} Project Agent fertig!
1414
1414
  ${a.projectIteration} Phasen, ${a.totalFilesChanged} Dateien ge\xE4ndert.
1415
- Milestones: ${a.milestonesReached.join(", ")}`)}catch(d){let u=d instanceof Error?d.message:String(d);this.logger.error({err:d,sessionId:e},"Project agent failed"),a.projectPhase="done",this.updateSession(e,a,c),await this.sendProgress(s,r,`\u{1F4A5} Project Agent Fehler: ${u}`)}finally{ln(e)}}assemblePrompt(e,t,s,r){let n=[`PROJEKT-ZIEL: ${e}`,`AKTUELLE PHASE (${s.projectIteration}): ${t}`,`ARBEITSVERZEICHNIS: ${s.projectCwd}`];return s.lastBuildOutput&&n.push(`LETZTER BUILD-OUTPUT:
1415
+ Milestones: ${a.milestonesReached.join(", ")}`)}catch(d){let u=d instanceof Error?d.message:String(d);this.logger.error({err:d,sessionId:e},"Project agent failed"),a.projectPhase="done",this.updateSession(e,a,c),await this.sendProgress(s,r,`\u{1F4A5} Project Agent Fehler: ${u}`)}finally{dn(e)}}assemblePrompt(e,t,s,r){let n=[`PROJEKT-ZIEL: ${e}`,`AKTUELLE PHASE (${s.projectIteration}): ${t}`,`ARBEITSVERZEICHNIS: ${s.projectCwd}`];return s.lastBuildOutput&&n.push(`LETZTER BUILD-OUTPUT:
1416
1416
  ${s.lastBuildOutput.slice(-2e3)}`),r.length>0&&n.push(`USER-ANFORDERUNGEN:
1417
1417
  ${r.map(o=>`- ${o}`).join(`
1418
1418
  `)}`),n.push("ANWEISUNGEN:","- Implementiere nur diese Phase, nicht das ganze Projekt","- Erstelle alle n\xF6tigen Dateien und Verzeichnisse","- Wenn ein package.json existiert, nutze die vorhandene Struktur","- Wenn Build-Fehler im Output stehen, behebe sie zuerst","- Schreibe produktionsreifen Code"),n.join(`
@@ -1425,18 +1425,18 @@ Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leav
1425
1425
  Goodbye!
1426
1426
  `),this.emit("disconnected");return}this.messageCounter++;let s={id:`cli-${this.messageCounter}`,platform:"cli",chatId:"cli-chat",chatType:"dm",userId:"cli-user",userName:"cli-user",displayName:"You",text:t,timestamp:new Date};this.emit("message",s)}),this.rl.on("close",()=>{this.emit("disconnected")}),this.status="connected",this.emit("connected"),this.prompt()}async disconnect(){this.rl?.close(),this.rl=void 0,this.status="disconnected"}async sendMessage(e,t,s){let r=`cli-resp-${++this.messageCounter}`;return process.stdout.write(`
1427
1427
  Alfred: ${t}
1428
- `),this.prompt(),r}async editMessage(e,t,s,r){Fc.clearLine(process.stdout,0),Fc.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import Xg from"node:http";import Vg from"node:https";import _e from"node:fs";import dt from"node:path";import ci from"node:crypto";var Yg,Op,li,Pp=T(()=>{"use strict";lt();Yg={".html":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"application/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".txt":"text/plain; charset=utf-8"},Op=1048576,li=class extends ye{static{p(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;dashboardFn;webUiPath;tls;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,this.dashboardFn=s?.dashboardCallback,this.webUiPath=s?.webUiPath,this.tls=s?.tls,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";let e=p((s,r)=>{this.handleRequest(s,r)},"handler"),t=this.resolveTls();t?this.server=Vg.createServer(t,e):this.server=Xg.createServer(e),await new Promise((s,r)=>{this.server.listen(this.port,this.host,()=>{s()}),this.server.once("error",r)}),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))}resolveTls(){if(!this.tls?.enabled)return null;if(this.tls.cert&&this.tls.key)try{return{cert:_e.readFileSync(this.tls.cert),key:_e.readFileSync(this.tls.key)}}catch(r){throw new Error(`TLS cert/key read failed: ${r instanceof Error?r.message:String(r)}`)}let e=dt.join(process.env.HOME??process.env.USERPROFILE??".",".alfred","tls"),t=dt.join(e,"cert.pem"),s=dt.join(e,"key.pem");if(_e.existsSync(t)&&_e.existsSync(s))return{cert:_e.readFileSync(t),key:_e.readFileSync(s)};try{let{generateKeyPairSync:r,createSign:n,randomBytes:o}=io("node:crypto"),{privateKey:i,publicKey:a}=r("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}}),c=new Date,d=new Date(c.getTime()+365*24*60*60*1e3),u=o(8).toString("hex"),{execSync:m}=io("node:child_process");return _e.mkdirSync(e,{recursive:!0}),_e.writeFileSync(s,i,{mode:384}),m(`openssl req -new -x509 -key "${s}" -out "${t}" -days 365 -subj "/CN=Alfred AI/O=Alfred" -addext "subjectAltName=IP:127.0.0.1,IP:0.0.0.0,DNS:localhost"`,{stdio:"pipe"}),{cert:_e.readFileSync(t),key:_e.readFileSync(s)}}catch(r){return console.warn(`[HttpAdapter] Self-signed TLS cert generation failed: ${r instanceof Error?r.message:String(r)}. Running without TLS.`),null}}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==="/api/dashboard"&&e.method==="GET")this.handleDashboard(e,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let r=s.pathname.slice(13);this.handleWebhook(e,t,r)}else this.webUiPath&&s.pathname.startsWith("/alfred/")&&e.method==="GET"?this.serveStaticFile(s.pathname,t):this.webUiPath&&s.pathname==="/alfred"&&e.method==="GET"?(t.writeHead(302,{Location:"/alfred/"}),t.end()):(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||!ci.timingSafeEqual(Buffer.from(s),Buffer.from(r))?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleDashboard(e,t){if(this.checkAuth(e,t)){if(!this.dashboardFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard not configured"}));return}try{let s=this.dashboardFn();t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}catch{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard data fetch failed"}))}}}serveStaticFile(e,t){if(!this.webUiPath){t.writeHead(404),t.end();return}let s=e.replace(/^\/alfred/,"");(!s||s==="/")&&(s="/index.html");let r=dt.resolve(this.webUiPath,"."+s);if(!r.startsWith(dt.resolve(this.webUiPath))){t.writeHead(403),t.end();return}let n=r;if(!_e.existsSync(n))if(_e.existsSync(n+".html"))n=n+".html";else if(_e.existsSync(dt.join(n,"index.html")))n=dt.join(n,"index.html");else{t.writeHead(404,{"Content-Type":"text/html"}),t.end("Not found");return}try{if(_e.statSync(n).isDirectory()){let u=dt.join(n,"index.html");if(_e.existsSync(u))n=u;else{t.writeHead(404),t.end();return}}}catch{t.writeHead(404),t.end();return}let o=_e.statSync(n),i=dt.extname(n).toLowerCase(),a=Yg[i]??"application/octet-stream",c=i===".html"?"no-cache":"public, max-age=31536000, immutable";t.writeHead(200,{"Content-Type":a,"Content-Length":o.size,"Cache-Control":c}),_e.createReadStream(n).pipe(t)}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>Op){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-${ci.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","Access-Control-Allow-Origin":this.corsOrigin,"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","X-Content-Type-Options":"nosniff"}),t.flushHeaders(),this.streams.set(a,t),t.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>Op){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=ci.createHmac("sha256",r.secret).update(n).digest(),d=Buffer.from(a,"hex");if(d.length!==c.length||!ci.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}
1428
+ `),this.prompt(),r}async editMessage(e,t,s,r){Fc.clearLine(process.stdout,0),Fc.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import Xg from"node:http";import Vg from"node:https";import _e from"node:fs";import dt from"node:path";import ci from"node:crypto";var Yg,Op,li,Pp=T(()=>{"use strict";lt();Yg={".html":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"application/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".txt":"text/plain; charset=utf-8"},Op=1048576,li=class extends ye{static{p(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;dashboardFn;webUiPath;tls;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,this.dashboardFn=s?.dashboardCallback,this.webUiPath=s?.webUiPath,this.tls=s?.tls,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";let e=p((s,r)=>{this.handleRequest(s,r)},"handler"),t=this.resolveTls();t?this.server=Vg.createServer(t,e):this.server=Xg.createServer(e),await new Promise((s,r)=>{this.server.listen(this.port,this.host,()=>{s()}),this.server.once("error",r)}),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))}resolveTls(){if(!this.tls?.enabled)return null;if(this.tls.cert&&this.tls.key)try{return{cert:_e.readFileSync(this.tls.cert),key:_e.readFileSync(this.tls.key)}}catch(r){throw new Error(`TLS cert/key read failed: ${r instanceof Error?r.message:String(r)}`)}let e=dt.join(process.env.HOME??process.env.USERPROFILE??".",".alfred","tls"),t=dt.join(e,"cert.pem"),s=dt.join(e,"key.pem");if(_e.existsSync(t)&&_e.existsSync(s))return{cert:_e.readFileSync(t),key:_e.readFileSync(s)};try{let{generateKeyPairSync:r,createSign:n,randomBytes:o}=ao("node:crypto"),{privateKey:i,publicKey:a}=r("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}}),c=new Date,d=new Date(c.getTime()+365*24*60*60*1e3),u=o(8).toString("hex"),{execSync:m}=ao("node:child_process");return _e.mkdirSync(e,{recursive:!0}),_e.writeFileSync(s,i,{mode:384}),m(`openssl req -new -x509 -key "${s}" -out "${t}" -days 365 -subj "/CN=Alfred AI/O=Alfred" -addext "subjectAltName=IP:127.0.0.1,IP:0.0.0.0,DNS:localhost"`,{stdio:"pipe"}),{cert:_e.readFileSync(t),key:_e.readFileSync(s)}}catch(r){return console.warn(`[HttpAdapter] Self-signed TLS cert generation failed: ${r instanceof Error?r.message:String(r)}. Running without TLS.`),null}}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==="/api/dashboard"&&e.method==="GET")this.handleDashboard(e,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let r=s.pathname.slice(13);this.handleWebhook(e,t,r)}else this.webUiPath&&s.pathname.startsWith("/alfred/")&&e.method==="GET"?this.serveStaticFile(s.pathname,t):this.webUiPath&&s.pathname==="/alfred"&&e.method==="GET"?(t.writeHead(302,{Location:"/alfred/"}),t.end()):(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||!ci.timingSafeEqual(Buffer.from(s),Buffer.from(r))?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleDashboard(e,t){if(this.checkAuth(e,t)){if(!this.dashboardFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard not configured"}));return}try{let s=this.dashboardFn();t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}catch{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard data fetch failed"}))}}}serveStaticFile(e,t){if(!this.webUiPath){t.writeHead(404),t.end();return}let s=e.replace(/^\/alfred/,"");(!s||s==="/")&&(s="/index.html");let r=dt.resolve(this.webUiPath,"."+s);if(!r.startsWith(dt.resolve(this.webUiPath))){t.writeHead(403),t.end();return}let n=r;if(!_e.existsSync(n))if(_e.existsSync(n+".html"))n=n+".html";else if(_e.existsSync(dt.join(n,"index.html")))n=dt.join(n,"index.html");else{t.writeHead(404,{"Content-Type":"text/html"}),t.end("Not found");return}try{if(_e.statSync(n).isDirectory()){let u=dt.join(n,"index.html");if(_e.existsSync(u))n=u;else{t.writeHead(404),t.end();return}}}catch{t.writeHead(404),t.end();return}let o=_e.statSync(n),i=dt.extname(n).toLowerCase(),a=Yg[i]??"application/octet-stream",c=i===".html"?"no-cache":"public, max-age=31536000, immutable";t.writeHead(200,{"Content-Type":a,"Content-Length":o.size,"Cache-Control":c}),_e.createReadStream(n).pipe(t)}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>Op){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-${ci.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","Access-Control-Allow-Origin":this.corsOrigin,"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","X-Content-Type-Options":"nosniff"}),t.flushHeaders(),this.streams.set(a,t),t.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>Op){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=ci.createHmac("sha256",r.secret).update(n).digest(),d=Buffer.from(a,"hex");if(d.length!==c.length||!ci.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}
1429
1429
  data: ${JSON.stringify(s)}
1430
1430
 
1431
- `)}}});var bt={};me(bt,{CLIAdapter:()=>ai,DiscordAdapter:()=>ri,HttpAdapter:()=>li,MatrixAdapter:()=>ni,MessagingAdapter:()=>ye,SignalAdapter:()=>ii,TelegramAdapter:()=>ti,WhatsAppAdapter:()=>oi});var Et=T(()=>{"use strict";lt();xp();Cp();Np();Lp();Dp();Mp();Pp()});import nr from"node:fs";import Pe from"node:path";import Jg from"js-yaml";var Jt,Up=T(()=>{"use strict";ta();mo();ot();ga();go();re();nc();ic();ac();cc();lc();dc();uc();pc();mc();hc();fc();gc();yc();Sp();Tc();Sc();$c();vc();Ac();Ic();Rc();xc();Cc();Dc();Mc();Jt=class{static{p(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new _n;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=Ir("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new ht(this.config.storage.path);let e=this.database.getDb(),t=new ss(e),s=new rs(e);this.userRepo=s;let r=new ft(e);this.auditRepo=r;let n=new ns(e);this.memoryRepo=n;let o=new os(e),i=new is(e),a=new as(e),c=new cs(e),d=new ls(e),u=new us(e);this.scheduledActionRepo=u;let m=new yt(e);this.activityRepo=m;let h=new Mn(m,this.logger.child({component:"activity"})),f=new ws(e);this.skillHealthRepo=f;let g=new On(f,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new Fr,_=this.loadSecurityRules();y.loadRules(_);let S=new jr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:_.length},"Security engine initialized");let E=ha(this.config.llm,this.logger.child({component:"llm"}));await E.initialize(),this.llmProvider=E;let $=new ys(e);this.usageRepo=$,E.setPersist((C,j,Z,te,$e,ir)=>{$.record(C,j,Z,te,$e,ir)});let R=new kn(E,a,this.logger.child({component:"embeddings"})),M=this.config.activeLearning?.enabled!==!1,q,G;M&&(q=new xn({llm:E,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:R,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),G=new Cn(n,this.logger.child({component:"memory-retriever"}),R),this.logger.info("Active learning & memory retriever initialized"));let F=new gs(e);this.summaryRepo=F;let ee=new Nn(E,F,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ue=new Es(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new bs;L.register(new Ss),L.register(new $s),L.register(new vs(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new As(o)),L.register(new Is(i));let ne=new ms(e);if(L.register(new Gs(ne)),L.register(new Rs),L.register(new xs),L.register(new Cs(n,R)),L.register(new Ns(E,L,ue,S)),this.config.email?.accounts?.length){let C=new Map;for(let Z of this.config.email.accounts)try{Z.provider==="microsoft"&&!Z.microsoft?.clientId&&this.config.calendar?.microsoft&&(Z.microsoft={...this.config.calendar.microsoft});let te=await Br(Z);C.set(Z.name,te),this.logger.info({account:Z.name,provider:Z.provider??"imap-smtp"},"Email account initialized")}catch(te){this.logger.warn({err:te,account:Z.name},"Email account initialization failed, skipping")}let j=C.size>0?new wt(C):new wt;j.setLLM(E),L.register(j)}else{let C=new wt;C.setLLM(E),L.register(C)}L.register(new Ls),L.register(new Ds);let ae=new Ys;ae.setReloadCallback(C=>this.reloadService(C)),L.register(ae),L.register(new Os),L.register(new Ps),L.register(new Us),L.register(new Fs(s)),L.register(new js(s,c,this.adapters,(C,j)=>t.findByPlatformAndUser(C,j)));let Q=new Bs(d);L.register(Q),L.register(new Hs(u));let W=new ps(e),he=new bn(W,R,this.logger.child({component:"documents"}));L.register(new Ws(W,he,R));let Ve,le;if(this.config.calendar)try{le=await zr(this.config.calendar),Ve=new Ht(le),L.register(Ve),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(C){this.logger.warn({err:C},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Ve,le&&this.config.calendar?.vorlauf?.enabled){let C=new gt(e),j=this.config.security?.ownerUserId;j&&(this.calendarWatcher=new Ln(le,C,this.adapters,j,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let C=this.config.security?.ownerUserId;if(C){let j=new gt(e);this.todoWatcher=new Dn(ne,j,this.adapters,C,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(re(),ie));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let j of this.mcpManager.getSkills())L.register(j);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},E)),this.logger.info({agents:this.config.codeAgents.agents.map(j=>j.name)},"Code agent skill enabled")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:C}=await Promise.resolve().then(()=>(re(),ie)),{ProjectAgentSessionRepository:j}=await Promise.resolve().then(()=>(mo(),md)),Z=new j(e),te=new C({...this.config.projectAgents,agents:this.config.codeAgents.agents},E,Z),{ProjectAgentRunner:$e}=await Promise.resolve().then(()=>(Oc(),Ip)),ir=new $e(new Map(this.config.codeAgents.agents.map(ar=>[ar.name,ar])),E,Z,this.adapters,this.logger.child({component:"project-agent"}));te.setRunner(ir),L.register(te),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:C,createContactsProvider:j}=await Promise.resolve().then(()=>(re(),ie)),Z=await j(this.config.contacts);L.register(new C(Z)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(C){this.logger.warn({err:C},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(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:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C({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:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(L,this.config,n)),this.logger.info("Briefing skill registered")}if(L.register(new Qs(n)),this.logger.info("Feed reader skill registered"),this.config.youtube?.apiKey){let{YouTubeSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let Se;if(this.config.speech?.apiKey&&(Se=new gn(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 C=new yn(this.config.speech,this.logger.child({component:"tts"}));L.register(new zs(C)),this.logger.info("Text-to-speech skill registered")}let pe=this.detectImageGenProvider();if(pe){let C=new wn(pe,this.logger.child({component:"image-gen"}));L.register(new qs(C)),this.logger.info({provider:pe.provider},"Image generation skill registered")}try{let C=new Tn(this.logger.child({component:"transit"}));L.register(new Xs(C)),this.logger.info("Public transit skill registered")}catch(C){this.logger.warn({err:C},"Failed to register transit skill")}let Ue=new mn(t),Qe=Pe.resolve(Pe.dirname(this.config.storage.path),"inbox");this.pipeline=new hn({llm:E,conversationManager:Ue,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:ue,securityManager:S,memoryRepo:n,speechTranscriber:Se,inboxPath:Qe,embeddingService:R,activeLearning:q,memoryRetriever:G,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:he,conversationSummarizer:ee}),this.reminderScheduler=new fn(o,async(C,j,Z)=>{let te=this.adapters.get(C);te?await te.sendMessage(j,Z):this.logger.warn({platform:C,chatId:j},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:p(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:p(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:p((C,j)=>t.findByPlatformAndUser(C,j),"findConversation")}),this.backgroundTaskRunner=new En(L,ue,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,g);let Ye=new Sn(L,ue,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ye),Q.setPersistentRunner(Ye),this.proactiveScheduler=new $n(u,L,ue,E,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Ue,h);let et=new hs(e);this.watchRepo=et,L.register(new Js(et,L));let Me=new fs(e);this.confirmationQueue=new In(Me,L,ue,this.adapters,this.logger.child({component:"confirmation-queue"}),h);let $t=new _s(e),vt=new rr($t,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(vt),q&&q.setFeedbackService(vt),this.watchEngine=new Zo(et,L,ue,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,g,E);let tt=new Ts(e),K=new Zs(tt);L.register(K);let z=new Pn(tt,L,ue,this.logger.child({component:"workflow-runner"}),h,g);K.setRunner(z);{let C=this.config.security?.ownerUserId;if(C&&this.config.reasoning?.enabled!==!1){let j=new gt(e);this.reasoningEngine=new Fn(le,ne,et,n,m,f,j,L,ue,E,this.adapters,s,C,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h,this.config.briefing?.location,$t,this.confirmationQueue)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(g),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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt)),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,tls:e.api?.tls,healthCheck:p(()=>{let n;try{let o=this.config.storage.path,i=nr.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:p(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:p(()=>{let n=new Date().toISOString().slice(0,10),o=new Date(Date.now()-10080*6e4).toISOString().slice(0,10);return{watches:this.watchRepo?.getEnabled()??[],scheduled:this.scheduledActionRepo?.getAll()??[],skillHealth:this.skillHealthRepo?.getAll()??[],usage:{today:this.usageRepo?.getDaily(n)??null,week:this.usageRepo?.getRange(o,n)??[],total:this.usageRepo?.getTotal()??[]},uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters.entries()].map(([i,a])=>[i,a.getStatus()]))}},"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:r,webUi:e.api?.webUi!==!1},"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:p(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(()=>(Et(),bt)),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{Qi();let t=new fe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie)),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(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie));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}}}resolveWebUiPath(){let e;try{e=Pe.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Pe.join(process.cwd(),"web-ui"),Pe.join(e,"..","web-ui"),Pe.join(e,"web-ui"),Pe.join(e,"..","..","web-ui"),Pe.join(e,"..","..","apps","web","out")];for(let s of t)try{let r=Pe.resolve(s);if(nr.existsSync(Pe.join(r,"index.html")))return this.logger.info({path:r},"Web UI found"),r}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}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(`
1432
- `)}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=p(async a=>{if(a!==n){n=a;try{e==="api"?await t.editMessage(s.chatId,r??"",a):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=Pe.resolve(this.config.security.rulesPath),t=[];if(!nr.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!nr.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=nr.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=Pe.join(e,n),i=nr.readFileSync(o,"utf-8"),a=Jg.load(i);if(a?.rules&&Array.isArray(a.rules)){let d=new at().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 Fp=T(()=>{"use strict"});var jc=T(()=>{"use strict";$c();Ec()});var Bc=T(()=>{"use strict";Up();ic();nc();ac();cc();lc();pc();mc();fc();gc();yc();_t();hc();dc();uc();Sc();vc();bc();Fp();kc();Ac();vn();Lc();Tc();jc();Oc();jc();Ic();Rc();xc();Jo();Cc();Dc();Mc()});import di from"node:fs";import jp from"node:path";import Zg from"node:os";function Bp(){try{let l=di.readFileSync(Hc,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Hp(l){try{let e=jp.dirname(Hc);di.existsSync(e)||di.mkdirSync(e,{recursive:!0}),di.writeFileSync(Hc,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Zt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),ey);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function Wp(l,e,t){switch(l){case"anthropic":{let s=await Zt("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 Zt(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 Zt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await Zt("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 Zt("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 Zt(`${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 Zt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function Wc(l,e,t){let s=Bp(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<Qg)return r.models;try{let n=await Wp(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Hp(s),n}catch{}return r?r.models:[]}function ui(l,e,t){Wp(l,e,t).then(s=>{if(s.length>0){let r=Bp();r.providers[l]={fetchedAt:Date.now(),models:s},Hp(r)}}).catch(()=>{})}function zc(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 Qg,ey,Hc,qc=T(()=>{"use strict";Qg=1440*60*1e3,ey=5e3,Hc=jp.join(Zg.homedir(),".alfred","model-cache.json");p(Bp,"readCache");p(Hp,"writeCache");p(Zt,"fetchWithTimeout");p(Wp,"fetchModelsFromAPI");p(Wc,"getModels");p(ui,"refreshCacheInBackground");p(zc,"mergeModels")});var zp={};me(zp,{startCommand:()=>ty});async function ty(){let l=new fe,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=Ir("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new Jt(e),r=!1,n=p(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?ui(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&ui(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&ui(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 qp=T(()=>{"use strict";ot();ta();Bc();qc();p(ty,"startCommand")});var Kp={};me(Kp,{chatCommand:()=>ny});import Gp from"node:http";import jn from"node:readline";function sy(l,e){return new Promise(t=>{let s=Gp.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 ry(l,e){let t=jn.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
1431
+ `)}}});var bt={};me(bt,{CLIAdapter:()=>ai,DiscordAdapter:()=>ri,HttpAdapter:()=>li,MatrixAdapter:()=>ni,MessagingAdapter:()=>ye,SignalAdapter:()=>ii,TelegramAdapter:()=>ti,WhatsAppAdapter:()=>oi});var Et=T(()=>{"use strict";lt();xp();Cp();Np();Lp();Dp();Mp();Pp()});import nr from"node:fs";import Pe from"node:path";import Jg from"js-yaml";var Jt,Up=T(()=>{"use strict";ta();ho();ot();ga();yo();re();nc();ic();ac();cc();lc();dc();uc();pc();mc();hc();fc();gc();yc();Sp();Tc();Sc();$c();vc();Ac();Ic();Rc();xc();Cc();Dc();Mc();Jt=class{static{p(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new kn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=Ir("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new ht(this.config.storage.path);let e=this.database.getDb(),t=new ss(e),s=new rs(e);this.userRepo=s;let r=new ft(e);this.auditRepo=r;let n=new ns(e);this.memoryRepo=n;let o=new os(e),i=new is(e),a=new as(e),c=new cs(e),d=new ls(e),u=new us(e);this.scheduledActionRepo=u;let m=new yt(e);this.activityRepo=m;let h=new On(m,this.logger.child({component:"activity"})),f=new ws(e);this.skillHealthRepo=f;let g=new Pn(f,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new Fr,_=this.loadSecurityRules();y.loadRules(_);let S=new jr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:_.length},"Security engine initialized");let E=ha(this.config.llm,this.logger.child({component:"llm"}));await E.initialize(),this.llmProvider=E;let $=new ys(e);this.usageRepo=$,E.setPersist((C,j,Z,te,$e,ir)=>{$.record(C,j,Z,te,$e,ir)});let R=new bn(E,a,this.logger.child({component:"embeddings"})),M=this.config.activeLearning?.enabled!==!1,q,G;M&&(q=new Cn({llm:E,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:R,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),G=new Nn(n,this.logger.child({component:"memory-retriever"}),R),this.logger.info("Active learning & memory retriever initialized"));let F=new gs(e);this.summaryRepo=F;let ee=new Ln(E,F,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ue=new Es(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new bs;L.register(new Ss),L.register(new $s),L.register(new vs(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new As(o)),L.register(new Is(i));let ne=new ms(e);if(L.register(new Gs(ne)),L.register(new Rs),L.register(new xs),L.register(new Cs(n,R)),L.register(new Ns(E,L,ue,S)),this.config.email?.accounts?.length){let C=new Map;for(let Z of this.config.email.accounts)try{Z.provider==="microsoft"&&!Z.microsoft?.clientId&&this.config.calendar?.microsoft&&(Z.microsoft={...this.config.calendar.microsoft});let te=await Br(Z);C.set(Z.name,te),this.logger.info({account:Z.name,provider:Z.provider??"imap-smtp"},"Email account initialized")}catch(te){this.logger.warn({err:te,account:Z.name},"Email account initialization failed, skipping")}let j=C.size>0?new wt(C):new wt;j.setLLM(E),L.register(j)}else{let C=new wt;C.setLLM(E),L.register(C)}L.register(new Ls),L.register(new Ds);let ae=new Ys;ae.setReloadCallback(C=>this.reloadService(C)),L.register(ae),L.register(new Os),L.register(new Ps),L.register(new Us),L.register(new Fs(s)),L.register(new js(s,c,this.adapters,(C,j)=>t.findByPlatformAndUser(C,j)));let Q=new Bs(d);L.register(Q),L.register(new Hs(u));let W=new ps(e),he=new En(W,R,this.logger.child({component:"documents"}));L.register(new Ws(W,he,R));let Ve,le;if(this.config.calendar)try{le=await zr(this.config.calendar),Ve=new Ht(le),L.register(Ve),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(C){this.logger.warn({err:C},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Ve,le&&this.config.calendar?.vorlauf?.enabled){let C=new gt(e),j=this.config.security?.ownerUserId;j&&(this.calendarWatcher=new Dn(le,C,this.adapters,j,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let C=this.config.security?.ownerUserId;if(C){let j=new gt(e);this.todoWatcher=new Mn(ne,j,this.adapters,C,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(re(),ie));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let j of this.mcpManager.getSkills())L.register(j);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},E)),this.logger.info({agents:this.config.codeAgents.agents.map(j=>j.name)},"Code agent skill enabled")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:C}=await Promise.resolve().then(()=>(re(),ie)),{ProjectAgentSessionRepository:j}=await Promise.resolve().then(()=>(ho(),md)),Z=new j(e),te=new C({...this.config.projectAgents,agents:this.config.codeAgents.agents},E,Z),{ProjectAgentRunner:$e}=await Promise.resolve().then(()=>(Oc(),Ip)),ir=new $e(new Map(this.config.codeAgents.agents.map(ar=>[ar.name,ar])),E,Z,this.adapters,this.logger.child({component:"project-agent"}));te.setRunner(ir),L.register(te),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:C,createContactsProvider:j}=await Promise.resolve().then(()=>(re(),ie)),Z=await j(this.config.contacts);L.register(new C(Z)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(C){this.logger.warn({err:C},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(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:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C({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:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(L,this.config,n)),this.logger.info("Briefing skill registered")}if(L.register(new Qs(n)),this.logger.info("Feed reader skill registered"),this.config.youtube?.apiKey){let{YouTubeSkill:C}=await Promise.resolve().then(()=>(re(),ie));L.register(new C(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let Se;if(this.config.speech?.apiKey&&(Se=new yn(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 C=new wn(this.config.speech,this.logger.child({component:"tts"}));L.register(new zs(C)),this.logger.info("Text-to-speech skill registered")}let pe=this.detectImageGenProvider();if(pe){let C=new Tn(pe,this.logger.child({component:"image-gen"}));L.register(new qs(C)),this.logger.info({provider:pe.provider},"Image generation skill registered")}try{let C=new _n(this.logger.child({component:"transit"}));L.register(new Xs(C)),this.logger.info("Public transit skill registered")}catch(C){this.logger.warn({err:C},"Failed to register transit skill")}let Ue=new hn(t),Qe=Pe.resolve(Pe.dirname(this.config.storage.path),"inbox");this.pipeline=new fn({llm:E,conversationManager:Ue,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:ue,securityManager:S,memoryRepo:n,speechTranscriber:Se,inboxPath:Qe,embeddingService:R,activeLearning:q,memoryRetriever:G,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:he,conversationSummarizer:ee}),this.reminderScheduler=new gn(o,async(C,j,Z)=>{let te=this.adapters.get(C);te?await te.sendMessage(j,Z):this.logger.warn({platform:C,chatId:j},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:p(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:p(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:p((C,j)=>t.findByPlatformAndUser(C,j),"findConversation")}),this.backgroundTaskRunner=new Sn(L,ue,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,g);let Ye=new $n(L,ue,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ye),Q.setPersistentRunner(Ye),this.proactiveScheduler=new vn(u,L,ue,E,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Ue,h);let et=new hs(e);this.watchRepo=et,L.register(new Js(et,L));let Me=new fs(e);this.confirmationQueue=new Rn(Me,L,ue,this.adapters,this.logger.child({component:"confirmation-queue"}),h);let $t=new _s(e),vt=new rr($t,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(vt),q&&q.setFeedbackService(vt),this.watchEngine=new Zo(et,L,ue,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,g,E);let tt=new Ts(e),K=new Zs(tt);L.register(K);let z=new Un(tt,L,ue,this.logger.child({component:"workflow-runner"}),h,g);K.setRunner(z);{let C=this.config.security?.ownerUserId;if(C&&this.config.reasoning?.enabled!==!1){let j=new gt(e);this.reasoningEngine=new jn(le,ne,et,n,m,f,j,L,ue,E,this.adapters,s,C,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h,this.config.briefing?.location,$t,this.confirmationQueue)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(g),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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt));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(()=>(Et(),bt)),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,tls:e.api?.tls,healthCheck:p(()=>{let n;try{let o=this.config.storage.path,i=nr.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:p(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:p(()=>{let n=new Date().toISOString().slice(0,10),o=new Date(Date.now()-10080*6e4).toISOString().slice(0,10);return{watches:this.watchRepo?.getEnabled()??[],scheduled:this.scheduledActionRepo?.getAll()??[],skillHealth:this.skillHealthRepo?.getAll()??[],usage:{today:this.usageRepo?.getDaily(n)??null,week:this.usageRepo?.getRange(o,n)??[],total:this.usageRepo?.getTotal()??[]},uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters.entries()].map(([i,a])=>[i,a.getStatus()]))}},"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:r,webUi:e.api?.webUi!==!1},"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:p(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(()=>(Et(),bt)),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{Qi();let t=new fe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie)),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(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie));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(()=>(re(),ie));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}}}resolveWebUiPath(){let e;try{e=Pe.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Pe.join(process.cwd(),"web-ui"),Pe.join(e,"..","web-ui"),Pe.join(e,"web-ui"),Pe.join(e,"..","..","web-ui"),Pe.join(e,"..","..","apps","web","out")];for(let s of t)try{let r=Pe.resolve(s);if(nr.existsSync(Pe.join(r,"index.html")))return this.logger.info({path:r},"Web UI found"),r}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}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(`
1432
+ `)}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=p(async a=>{if(a!==n){n=a;try{e==="api"?await t.editMessage(s.chatId,r??"",a):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=Pe.resolve(this.config.security.rulesPath),t=[];if(!nr.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!nr.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=nr.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=Pe.join(e,n),i=nr.readFileSync(o,"utf-8"),a=Jg.load(i);if(a?.rules&&Array.isArray(a.rules)){let d=new at().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 Fp=T(()=>{"use strict"});var jc=T(()=>{"use strict";$c();Ec()});var Bc=T(()=>{"use strict";Up();ic();nc();ac();cc();lc();pc();mc();fc();gc();yc();_t();hc();dc();uc();Sc();vc();bc();Fp();kc();Ac();An();Lc();Tc();jc();Oc();jc();Ic();Rc();xc();Jo();Cc();Dc();Mc()});import di from"node:fs";import jp from"node:path";import Zg from"node:os";function Bp(){try{let l=di.readFileSync(Hc,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Hp(l){try{let e=jp.dirname(Hc);di.existsSync(e)||di.mkdirSync(e,{recursive:!0}),di.writeFileSync(Hc,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Zt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),ey);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function Wp(l,e,t){switch(l){case"anthropic":{let s=await Zt("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 Zt(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 Zt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await Zt("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 Zt("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 Zt(`${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 Zt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function Wc(l,e,t){let s=Bp(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<Qg)return r.models;try{let n=await Wp(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Hp(s),n}catch{}return r?r.models:[]}function ui(l,e,t){Wp(l,e,t).then(s=>{if(s.length>0){let r=Bp();r.providers[l]={fetchedAt:Date.now(),models:s},Hp(r)}}).catch(()=>{})}function zc(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 Qg,ey,Hc,qc=T(()=>{"use strict";Qg=1440*60*1e3,ey=5e3,Hc=jp.join(Zg.homedir(),".alfred","model-cache.json");p(Bp,"readCache");p(Hp,"writeCache");p(Zt,"fetchWithTimeout");p(Wp,"fetchModelsFromAPI");p(Wc,"getModels");p(ui,"refreshCacheInBackground");p(zc,"mergeModels")});var zp={};me(zp,{startCommand:()=>ty});async function ty(){let l=new fe,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=Ir("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new Jt(e),r=!1,n=p(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?ui(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&ui(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&ui(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 qp=T(()=>{"use strict";ot();ta();Bc();qc();p(ty,"startCommand")});var Kp={};me(Kp,{chatCommand:()=>ny});import Gp from"node:http";import Bn from"node:readline";function sy(l,e){return new Promise(t=>{let s=Gp.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 ry(l,e){let t=Bn.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
1433
1433
  Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
1434
1434
  `),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
1435
1435
  Goodbye!
1436
1436
  `),t.close(),process.exit(0));let n=JSON.stringify({text:r,chatId:"api-chat",userId:"api-user"}),o=Gp.request({hostname:l,port:e,path:"/api/message",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n)}},i=>{let a="";i.on("data",c=>{a+=c.toString();let d=a.split(`
1437
1437
 
1438
1438
  `);a=d.pop()??"";for(let u of d){let m=u.split(`
1439
- `).find(h=>h.startsWith("data: "));if(m)try{let h=JSON.parse(m.slice(6));switch(h.type){case"status":jn.clearLine(process.stdout,0),jn.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${h.text??""}`);break;case"response":jn.clearLine(process.stdout,0),jn.cursorTo(process.stdout,0),process.stdout.write(`
1439
+ `).find(h=>h.startsWith("data: "));if(m)try{let h=JSON.parse(m.slice(6));switch(h.type){case"status":Bn.clearLine(process.stdout,0),Bn.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${h.text??""}`);break;case"response":Bn.clearLine(process.stdout,0),Bn.cursorTo(process.stdout,0),process.stdout.write(`
1440
1440
  Alfred: ${h.text??""}
1441
1441
  `);break;case"attachment":{let f=h.fileName??h.attachmentType??"file";process.stdout.write(`[Attachment: ${f}]
1442
1442
  `);break}case"done":t.prompt();break;case"error":process.stdout.write(`
@@ -1451,39 +1451,39 @@ ${St}Only change what you need to update.${A}
1451
1451
  ${St}This will walk you through configuring your AI assistant.${A}
1452
1452
  ${St}Press Enter to accept defaults shown in [brackets].${A}
1453
1453
  `);let r=await H(l,"What should your bot be called?",t.config.name??"Alfred"),n=t.config.llm?.provider?ut.findIndex(k=>k.name===t.config.llm?.provider):-1,o=n>=0?n+1:1;console.log(`
1454
- ${D("Which LLM provider would you like to use?")}`);for(let k=0;k<ut.length;k++){let v=k===n?` ${b("(current)")}`:"";console.log(` ${ke(String(k+1)+")")} ${ut[k].label}${v}`)}let i=await Bn(l,"> ",1,ut.length,o),a=ut[i-1];console.log(` ${P(">")} Selected: ${D(a.label)}`);let c="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?c=await H(l,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):c=await De(l,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${P(">")} API key set: ${b(be(c))}`));let u=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let v=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if(v){let N={ollama:"Ollama URL (use a remote address if Ollama runs on another machine)",openwebui:"OpenWebUI URL",openai:"OpenAI-compatible API URL (leave default for official API)",openrouter:"OpenRouter API URL",google:"Google Gemini API URL (leave default for official API)"};console.log(""),u=await H(l,N[a.name]??"API Base URL",v.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${P(">")} URL: ${b(u)}`)}}let h=t.config.llm?.model??a.defaultModel;console.log("");let f,g=await Wc(a.name,c,u),y=zc(g,a.models??[]);if(y.length>0){console.log(`${D("Available models:")}`);for(let N=0;N<y.length;N++){let Y=y[N],O=Y.desc??Y.name??"",X=Y.id===h?` ${P("(current)")}`:"";console.log(` ${ke(`${N+1})`)} ${Y.id}${O?` ${b(`\u2014 ${O}`)}`:""}${X}`)}console.log(` ${ke(`${y.length+1})`)} ${b("Other (enter manually)")}`);let k=await H(l,"Choose model","1"),v=parseInt(k,10)-1;v>=0&&v<y.length?f=y[v].id:f=await H(l,"Model ID",h)}else f=await H(l,"Which model?",h);let _=Object.keys(t.multiModelTiers).length>0,S=_?"Y/n":"y/N";console.log(`
1454
+ ${D("Which LLM provider would you like to use?")}`);for(let k=0;k<ut.length;k++){let v=k===n?` ${b("(current)")}`:"";console.log(` ${ke(String(k+1)+")")} ${ut[k].label}${v}`)}let i=await Hn(l,"> ",1,ut.length,o),a=ut[i-1];console.log(` ${P(">")} Selected: ${D(a.label)}`);let c="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?c=await H(l,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):c=await De(l,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${P(">")} API key set: ${b(be(c))}`));let u=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let v=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if(v){let N={ollama:"Ollama URL (use a remote address if Ollama runs on another machine)",openwebui:"OpenWebUI URL",openai:"OpenAI-compatible API URL (leave default for official API)",openrouter:"OpenRouter API URL",google:"Google Gemini API URL (leave default for official API)"};console.log(""),u=await H(l,N[a.name]??"API Base URL",v.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${P(">")} URL: ${b(u)}`)}}let h=t.config.llm?.model??a.defaultModel;console.log("");let f,g=await Wc(a.name,c,u),y=zc(g,a.models??[]);if(y.length>0){console.log(`${D("Available models:")}`);for(let N=0;N<y.length;N++){let Y=y[N],O=Y.desc??Y.name??"",X=Y.id===h?` ${P("(current)")}`:"";console.log(` ${ke(`${N+1})`)} ${Y.id}${O?` ${b(`\u2014 ${O}`)}`:""}${X}`)}console.log(` ${ke(`${y.length+1})`)} ${b("Other (enter manually)")}`);let k=await H(l,"Choose model","1"),v=parseInt(k,10)-1;v>=0&&v<y.length?f=y[v].id:f=await H(l,"Model ID",h)}else f=await H(l,"Which model?",h);let _=Object.keys(t.multiModelTiers).length>0,S=_?"Y/n":"y/N";console.log(`
1455
1455
  ${D("Configure additional model tiers for specialized tasks?")}`),console.log(`${b("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let E=(await l.question(`${U}> ${A}${b(`[${S}] `)}`)).trim().toLowerCase(),$=E===""?_:E==="y"||E==="yes",R={};if($){let k=[{key:"strong",label:"Strong",hint:"complex reasoning, coding, long documents",defaultModel:"claude-opus-4-20250514"},{key:"fast",label:"Fast",hint:"quick responses, simple tasks",defaultModel:"claude-haiku-4-5-20251001"},{key:"embeddings",label:"Embeddings",hint:"semantic search & memory",defaultModel:"text-embedding-3-small"},{key:"local",label:"Local",hint:"offline fallback via Ollama",defaultModel:"llama3.2"}];for(let v of k){let N=t.multiModelTiers[v.key],Y=!!N?.model;console.log(`
1456
- ${D(`${v.label} model`)} ${b(`(${v.hint})`)}`),Y&&console.log(` ${b(`Current: ${N.provider}/${N.model}`)}`);let O=N?.provider??a.name,X=ut.map(Ce=>Ce.name).join(", ");console.log(` ${b(`Providers: ${X}`)}`);let ve=(await l.question(` ${U}Provider: ${A}${b(`[${O}] `)}`)).trim()||O;if(!ve&&!Y){console.log(` ${b("Skipped.")}`);continue}let se=ve,Ae,Be;if(se!==a.name){let Ce=N?.apiKey??t.env[`ALFRED_LLM_${v.key.toUpperCase()}_API_KEY`]??"";if(Ce?Ae=await H(l,` API key for ${se}`,Ce):(ut.find(nt=>nt.name===se)?.needsApiKey??!0)&&(Ae=await De(l,` API key for ${se}`)),["ollama","openwebui"].includes(se)){let nt=(N?.baseUrl??"")||ut.find(oo=>oo.name===se)?.baseUrl||"";nt&&(Be=await H(l,` ${se} URL`,nt))}}let Ot=Ae??(se===a.name?c:void 0),Ar=Be??(se===a.name?u:void 0),Gi=ut.find(Ce=>Ce.name===se),Ki=await Wc(se,Ot,Ar),mt=zc(Ki,Gi?.models??[]),rt;if(mt.length>0){console.log(` ${D("Available models:")}`);for(let ts=0;ts<mt.length;ts++){let nt=mt[ts],oo=nt.desc??nt.name??"",Wm=nt.id===N?.model?` ${P("(current)")}`:"";console.log(` ${ke(`${ts+1})`)} ${nt.id}${oo?` ${b(`\u2014 ${oo}`)}`:""}${Wm}`)}console.log(` ${ke(`${mt.length+1})`)} ${b("Other (enter manually)")}`),console.log(` ${ke("0)")} ${b("Skip this tier")}`);let Ce=(await l.question(` ${U}> ${A}${Y?b(`[${N.model}] `):""}`)).trim();if(Ce==="0"){console.log(` ${b("Skipped.")}`);continue}let no=parseInt(Ce,10)-1;no>=0&&no<mt.length?rt=mt[no].id:!Ce&&Y?rt=N.model:rt=await H(l," Model ID",Y?N.model:v.defaultModel)}else if(console.log(` ${b("Press Enter to skip.")}`),rt=(await l.question(` ${U}Model: ${A}${Y?b(`[${N.model}] `):""}`)).trim()||(Y?N.model:""),!rt){console.log(` ${b("Skipped.")}`);continue}R[v.key]={provider:se,model:rt,...Ae?{apiKey:Ae}:{},...Be?{baseUrl:Be}:{}},console.log(` ${P(">")} ${v.label}: ${D(se)}/${D(rt)}`)}Object.keys(R).length===0&&console.log(`
1456
+ ${D(`${v.label} model`)} ${b(`(${v.hint})`)}`),Y&&console.log(` ${b(`Current: ${N.provider}/${N.model}`)}`);let O=N?.provider??a.name,X=ut.map(Ce=>Ce.name).join(", ");console.log(` ${b(`Providers: ${X}`)}`);let ve=(await l.question(` ${U}Provider: ${A}${b(`[${O}] `)}`)).trim()||O;if(!ve&&!Y){console.log(` ${b("Skipped.")}`);continue}let se=ve,Ae,Be;if(se!==a.name){let Ce=N?.apiKey??t.env[`ALFRED_LLM_${v.key.toUpperCase()}_API_KEY`]??"";if(Ce?Ae=await H(l,` API key for ${se}`,Ce):(ut.find(nt=>nt.name===se)?.needsApiKey??!0)&&(Ae=await De(l,` API key for ${se}`)),["ollama","openwebui"].includes(se)){let nt=(N?.baseUrl??"")||ut.find(io=>io.name===se)?.baseUrl||"";nt&&(Be=await H(l,` ${se} URL`,nt))}}let Ot=Ae??(se===a.name?c:void 0),Ar=Be??(se===a.name?u:void 0),Gi=ut.find(Ce=>Ce.name===se),Ki=await Wc(se,Ot,Ar),mt=zc(Ki,Gi?.models??[]),rt;if(mt.length>0){console.log(` ${D("Available models:")}`);for(let ts=0;ts<mt.length;ts++){let nt=mt[ts],io=nt.desc??nt.name??"",Wm=nt.id===N?.model?` ${P("(current)")}`:"";console.log(` ${ke(`${ts+1})`)} ${nt.id}${io?` ${b(`\u2014 ${io}`)}`:""}${Wm}`)}console.log(` ${ke(`${mt.length+1})`)} ${b("Other (enter manually)")}`),console.log(` ${ke("0)")} ${b("Skip this tier")}`);let Ce=(await l.question(` ${U}> ${A}${Y?b(`[${N.model}] `):""}`)).trim();if(Ce==="0"){console.log(` ${b("Skipped.")}`);continue}let oo=parseInt(Ce,10)-1;oo>=0&&oo<mt.length?rt=mt[oo].id:!Ce&&Y?rt=N.model:rt=await H(l," Model ID",Y?N.model:v.defaultModel)}else if(console.log(` ${b("Press Enter to skip.")}`),rt=(await l.question(` ${U}Model: ${A}${Y?b(`[${N.model}] `):""}`)).trim()||(Y?N.model:""),!rt){console.log(` ${b("Skipped.")}`);continue}R[v.key]={provider:se,model:rt,...Ae?{apiKey:Ae}:{},...Be?{baseUrl:Be}:{}},console.log(` ${P(">")} ${v.label}: ${D(se)}/${D(rt)}`)}Object.keys(R).length===0&&console.log(`
1457
1457
  ${b("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${b("Using single model for all tasks.")}`);let M=["brave","tavily","duckduckgo","searxng"],q=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",G=M.indexOf(q),F=G>=0?G+1:0;console.log(`
1458
- ${D("Web Search provider (for searching the internet):")}`);let ee=["Brave Search \u2014 recommended, free tier (2,000/month)","Tavily \u2014 built for AI agents, free tier (1,000/month)","DuckDuckGo \u2014 free, no API key needed","SearXNG \u2014 self-hosted, no API key needed"],ue=p(k=>G===k?` ${b("(current)")}`:"","mark");console.log(` ${ke("0)")} None (disable web search)${G===-1&&q===""?` ${b("(current)")}`:""}`);for(let k=0;k<ee.length;k++)console.log(` ${ke(String(k+1)+")")} ${ee[k]}${ue(k)}`);let L=await Bn(l,"> ",0,M.length,F),ne,ae="",Q="";if(L>=1&&L<=M.length&&(ne=M[L-1]),ne==="brave"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ae=await H(l," Brave Search API key",k):(console.log(` ${b("Get your free API key at: https://brave.com/search/api/")}`),ae=await De(l," Brave Search API key")),console.log(` ${P(">")} Brave Search: ${b(be(ae))}`)}else if(ne==="tavily"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ae=await H(l," Tavily API key",k):(console.log(` ${b("Get your free API key at: https://tavily.com/")}`),ae=await De(l," Tavily API key")),console.log(` ${P(">")} Tavily: ${b(be(ae))}`)}else if(ne==="duckduckgo")console.log(` ${P(">")} DuckDuckGo: ${b("no API key needed")}`);else if(ne==="searxng"){let k=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";Q=await H(l," SearXNG URL",k),Q=Q.replace(/\/+$/,""),console.log(` ${P(">")} SearXNG: ${b(Q)}`)}else console.log(` ${b("Web search disabled \u2014 you can configure it later.")}`);let W=[];for(let k=0;k<or.length;k++){let v=or[k];t.config[v.configKey]?.enabled&&W.push(k+1)}let he=W.length>0?W.join(","):"";console.log(`
1458
+ ${D("Web Search provider (for searching the internet):")}`);let ee=["Brave Search \u2014 recommended, free tier (2,000/month)","Tavily \u2014 built for AI agents, free tier (1,000/month)","DuckDuckGo \u2014 free, no API key needed","SearXNG \u2014 self-hosted, no API key needed"],ue=p(k=>G===k?` ${b("(current)")}`:"","mark");console.log(` ${ke("0)")} None (disable web search)${G===-1&&q===""?` ${b("(current)")}`:""}`);for(let k=0;k<ee.length;k++)console.log(` ${ke(String(k+1)+")")} ${ee[k]}${ue(k)}`);let L=await Hn(l,"> ",0,M.length,F),ne,ae="",Q="";if(L>=1&&L<=M.length&&(ne=M[L-1]),ne==="brave"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ae=await H(l," Brave Search API key",k):(console.log(` ${b("Get your free API key at: https://brave.com/search/api/")}`),ae=await De(l," Brave Search API key")),console.log(` ${P(">")} Brave Search: ${b(be(ae))}`)}else if(ne==="tavily"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ae=await H(l," Tavily API key",k):(console.log(` ${b("Get your free API key at: https://tavily.com/")}`),ae=await De(l," Tavily API key")),console.log(` ${P(">")} Tavily: ${b(be(ae))}`)}else if(ne==="duckduckgo")console.log(` ${P(">")} DuckDuckGo: ${b("no API key needed")}`);else if(ne==="searxng"){let k=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";Q=await H(l," SearXNG URL",k),Q=Q.replace(/\/+$/,""),console.log(` ${P(">")} SearXNG: ${b(Q)}`)}else console.log(` ${b("Web search disabled \u2014 you can configure it later.")}`);let W=[];for(let k=0;k<or.length;k++){let v=or[k];t.config[v.configKey]?.enabled&&W.push(k+1)}let he=W.length>0?W.join(","):"";console.log(`
1459
1459
  ${D("Which messaging platforms do you want to enable?")}`),console.log(`${b("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let k=0;k<or.length;k++){let v=W.includes(k+1)?` ${b("(enabled)")}`:"";console.log(` ${ke(String(k+1)+")")} ${or[k].label}${v}`)}console.log(` ${ke("0)")} None (configure later)`);let Ve=(await l.question(`${U}> ${A}${he?b(`[${he}] `):""}`)).trim(),le=[],Se=Ve||he;if(Se&&Se!=="0"){let k=Se.split(",").map(v=>parseInt(v.trim(),10));for(let v of k)if(v>=1&&v<=or.length){let N=or[v-1];le.includes(N)||le.push(N)}}le.length>0?console.log(` ${P(">")} Enabling: ${le.map(k=>D(k.label)).join(", ")}`):console.log(` ${b("No platforms selected \u2014 you can configure them later.")}`);let pe={},Ue={};for(let k of le){if(k.credentials.length===0){k.name==="whatsapp"&&console.log(`
1460
1460
  ${py("i")} WhatsApp: a QR code will be displayed on first start.`);continue}console.log(`
1461
1461
  ${D(k.label+" configuration:")}`);let v={};for(let N of k.credentials){let Y=t.env[N.envKey]??"",O;Y?O=await H(l,` ${N.prompt}`,Y):N.defaultValue?O=await H(l,` ${N.prompt}`,N.defaultValue):N.required?O=await De(l,` ${N.prompt}`):(O=(await l.question(` ${N.prompt}: ${U}`)).trim(),process.stdout.write(A)),v[N.configField]=O,Ue[N.envKey]=O,N.configField==="token"||N.configField==="accessToken"?console.log(` ${P(">")} Set: ${b(be(O))}`):console.log(` ${P(">")} Set: ${b(O)}`)}pe[k.configKey]=v}let Qe=t.config.email?.accounts??[],Ye=Qe[0],et=Ye?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",Me=Ye?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",$t=Qe.length>0||!!et||Me==="microsoft",vt=$t?"Y/n":"y/N";console.log(`
1462
1462
  ${D("Email access (read & send emails)?")}`),console.log(`${b("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let tt=(await l.question(`${U}> ${A}${b(`[${vt}] `)}`)).trim().toLowerCase(),K=tt===""?$t:tt==="y"||tt==="yes",z=[],C={"gmail.com":{imap:"imap.gmail.com",smtp:"smtp.gmail.com"},"googlemail.com":{imap:"imap.gmail.com",smtp:"smtp.gmail.com"},"outlook.com":{imap:"outlook.office365.com",smtp:"smtp.office365.com"},"hotmail.com":{imap:"outlook.office365.com",smtp:"smtp.office365.com"},"live.com":{imap:"outlook.office365.com",smtp:"smtp.office365.com"},"yahoo.com":{imap:"imap.mail.yahoo.com",smtp:"smtp.mail.yahoo.com"},"icloud.com":{imap:"imap.mail.me.com",smtp:"smtp.mail.me.com"},"me.com":{imap:"imap.mail.me.com",smtp:"smtp.mail.me.com"},"gmx.de":{imap:"imap.gmx.net",smtp:"mail.gmx.net"},"gmx.net":{imap:"imap.gmx.net",smtp:"mail.gmx.net"},"web.de":{imap:"imap.web.de",smtp:"smtp.web.de"},"posteo.de":{imap:"posteo.de",smtp:"posteo.de"},"mailbox.org":{imap:"imap.mailbox.org",smtp:"smtp.mailbox.org"},"protonmail.com":{imap:"127.0.0.1",smtp:"127.0.0.1"},"proton.me":{imap:"127.0.0.1",smtp:"127.0.0.1"}},j=p(async(k,v)=>{let N={name:k,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},Y=v?.provider??"",O=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],X=Y==="microsoft"?1:0;console.log("");for(let se=0;se<O.length;se++){let Ae=se===X?` ${b("(current)")}`:"";console.log(` ${ke(`${se+1})`)} ${O[se]}${Ae}`)}let oe=(await l.question(`${U}> ${A}${b(`[${X+1}] `)}`)).trim(),ve=oe===""?X:parseInt(oe,10)-1;if(N.provider=ve===1?"microsoft":"imap-smtp",N.provider==="microsoft"){let se=t.config.calendar?.microsoft,Ae=v?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Be=v?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",Ot=v?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(se&&!Ae)console.log(` ${P(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${b("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${b("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${b("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),N.msClientId=await H(l," Client ID",Ae),N.msClientId||(N.msClientId=await De(l," Client ID"));let Ar=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";N.msClientSecret=await H(l," Client Secret",Ar),N.msClientSecret||(N.msClientSecret=await De(l," Client Secret")),N.msTenantId=await H(l," Tenant ID",Be),N.msTenantId||(N.msTenantId=await De(l," Tenant ID")),console.log(` ${b("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),N.msRefreshToken=await H(l," Refresh Token",Ot),N.msRefreshToken||(N.msRefreshToken=await De(l," Refresh Token"))}console.log(` ${P(">")} Email [${k}]: Microsoft 365 (Graph API)`)}else{let se=v?.auth?.user??"";console.log(""),N.user=await H(l," Email address",se||""),N.user||(N.user=await De(l," Email address"));let Ae=v?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";Ae?N.pass=await H(l," Password / App password",Ae):(console.log(` ${b("For Gmail: use an App Password (not your regular password)")}`),console.log(` ${b(" \u2192 Google Account \u2192 Security \u2192 2-Step \u2192 App passwords")}`),N.pass=await De(l," Password / App password"));let Be=N.user.split("@")[1]?.toLowerCase()??"",Ot=C[Be],Ar=v?.imap?.host??Ot?.imap??`imap.${Be}`,Gi=v?.smtp?.host??Ot?.smtp??`smtp.${Be}`,Ki=v?.imap?.port??993,mt=v?.smtp?.port??587;Ot&&console.log(` ${P(">")} Detected ${Be} \u2014 using preset server settings`),N.imapHost=await H(l," IMAP server",Ar);let rt=await H(l," IMAP port",String(Ki));N.imapPort=parseInt(rt,10)||993,N.smtpHost=await H(l," SMTP server",Gi);let Ce=await H(l," SMTP port",String(mt));N.smtpPort=parseInt(Ce,10)||587,console.log(` ${P(">")} Email [${k}]: ${b(N.user)} via ${b(N.imapHost)}`)}return N},"configureEmailAccount");if(K){let k=Ye??(t.config.email?.auth?{provider:t.config.email.provider,auth:t.config.email.auth,imap:t.config.email.imap,smtp:t.config.email.smtp,microsoft:t.config.email.microsoft}:void 0);z.push(await j("default",k));let v=!0;for(;v;){let N=(await l.question(`
1463
1463
  ${D("Add another email account?")} ${b("[y/N]")} `)).trim().toLowerCase();if(N==="y"||N==="yes"){let O=(await l.question(` ${D("Account name:")} `)).trim()||`account${z.length+1}`,X=Qe.find(oe=>oe.name===O);z.push(await j(O,X))}else v=!1}}else console.log(` ${b("Email disabled \u2014 you can configure it later.")}`);let Z=["openai","groq"],te=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",$e=Z.indexOf(te),ir=$e>=0?$e+1:0;console.log(`
1464
- ${D("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${b("Transcribes voice messages from Telegram, Discord, etc.")}`);let ar=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${ke("0)")} None (disable voice transcription)${$e===-1?` ${b("(current)")}`:""}`);for(let k=0;k<ar.length;k++){let v=$e===k?` ${b("(current)")}`:"";console.log(` ${ke(String(k+1)+")")} ${ar[k]}${v}`)}let fi=await Bn(l,"> ",0,Z.length,ir),Je,pt="",cr="";if(fi>=1&&fi<=Z.length&&(Je=Z[fi-1]),Je==="openai"){let k=t.env.ALFRED_SPEECH_API_KEY??"";k?pt=await H(l," OpenAI API key (for Whisper)",k):(console.log(` ${b("Uses your OpenAI API key for Whisper transcription.")}`),pt=await De(l," OpenAI API key")),console.log(` ${P(">")} OpenAI Whisper: ${b(be(pt))}`)}else if(Je==="groq"){let k=t.env.ALFRED_SPEECH_API_KEY??"";k?pt=await H(l," Groq API key",k):(console.log(` ${b("Get your free API key at: https://console.groq.com/")}`),pt=await De(l," Groq API key"));let v=t.env.ALFRED_SPEECH_BASE_URL??"";v&&(cr=await H(l," Groq API URL",v)),console.log(` ${P(">")} Groq Whisper: ${b(be(pt))}`)}else console.log(` ${b("Voice transcription disabled \u2014 you can configure it later.")}`);let lr=!1,dr="alloy";if(Je){let k=t.config.speech?.ttsEnabled??!1,v=k?"Y/n":"y/N";console.log(`
1464
+ ${D("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${b("Transcribes voice messages from Telegram, Discord, etc.")}`);let ar=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${ke("0)")} None (disable voice transcription)${$e===-1?` ${b("(current)")}`:""}`);for(let k=0;k<ar.length;k++){let v=$e===k?` ${b("(current)")}`:"";console.log(` ${ke(String(k+1)+")")} ${ar[k]}${v}`)}let fi=await Hn(l,"> ",0,Z.length,ir),Je,pt="",cr="";if(fi>=1&&fi<=Z.length&&(Je=Z[fi-1]),Je==="openai"){let k=t.env.ALFRED_SPEECH_API_KEY??"";k?pt=await H(l," OpenAI API key (for Whisper)",k):(console.log(` ${b("Uses your OpenAI API key for Whisper transcription.")}`),pt=await De(l," OpenAI API key")),console.log(` ${P(">")} OpenAI Whisper: ${b(be(pt))}`)}else if(Je==="groq"){let k=t.env.ALFRED_SPEECH_API_KEY??"";k?pt=await H(l," Groq API key",k):(console.log(` ${b("Get your free API key at: https://console.groq.com/")}`),pt=await De(l," Groq API key"));let v=t.env.ALFRED_SPEECH_BASE_URL??"";v&&(cr=await H(l," Groq API URL",v)),console.log(` ${P(">")} Groq Whisper: ${b(be(pt))}`)}else console.log(` ${b("Voice transcription disabled \u2014 you can configure it later.")}`);let lr=!1,dr="alloy";if(Je){let k=t.config.speech?.ttsEnabled??!1,v=k?"Y/n":"y/N";console.log(`
1465
1465
  ${D("Voice responses (Text-to-Speech)?")}`),console.log(`${b("Alfred can reply as a voice message when the user asks for it.")}`);let N=(await l.question(`${U}> ${A}${b(`[${v}] `)}`)).trim().toLowerCase();if(lr=N===""?k:N==="y"||N==="yes",lr){let Y=["alloy","echo","fable","onyx","nova","shimmer"],O=t.config.speech?.ttsVoice??"alloy",X=Y.indexOf(O),oe=X>=0?X+1:1;console.log(`
1466
- ${D("Which voice?")}`);for(let se=0;se<Y.length;se++){let Ae=X===se?` ${b("(current)")}`:"";console.log(` ${ke(String(se+1)+")")} ${Y[se]}${Ae}`)}let ve=await Bn(l," > ",1,Y.length,oe);dr=Y[ve-1],console.log(` ${P(">")} TTS voice: ${D(dr)}`)}else console.log(` ${b("Voice responses disabled.")}`)}let hm=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
1466
+ ${D("Which voice?")}`);for(let se=0;se<Y.length;se++){let Ae=X===se?` ${b("(current)")}`:"";console.log(` ${ke(String(se+1)+")")} ${Y[se]}${Ae}`)}let ve=await Hn(l," > ",1,Y.length,oe);dr=Y[ve-1],console.log(` ${P(">")} TTS voice: ${D(dr)}`)}else console.log(` ${b("Voice responses disabled.")}`)}let hm=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
1467
1467
  ${D("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${b("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let gi=(await l.question(`${U}> ${A}${b(`[${hm}] `)}`)).trim().toLowerCase(),yi=gi===""?t.codeSandboxEnabled:gi==="y"||gi==="yes";console.log(yi?` ${P(">")} Code Sandbox ${D("enabled")} (JavaScript + Python)`:` ${b("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
1468
1468
  ${D("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${b("Scanning for known coding agents on this system...")}`);let wi=[];for(let k of Vp){let v=my(k.whichCmd);v?(wi.push({...k,resolvedPath:v}),console.log(` ${P("\u2713")} ${D(k.label)} ${b(`(${v})`)}`)):console.log(` ${b("\xB7")} ${b(k.label)} ${b("\u2014 not found")}`)}let Ti=(t.config.codeAgents?.agents??[]).filter(k=>!Vp.some(v=>v.name===k.name));for(let k of Ti)console.log(` ${P("\u2713")} ${D(k.name)} ${b(`(${k.command}) \u2014 from existing config`)}`);let At=[];if(wi.length===0&&Ti.length===0)console.log(`
1469
1469
  ${b("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let k=[...wi.map(O=>({name:O.name,command:O.resolvedPath??O.command,argsTemplate:O.argsTemplate,promptVia:O.promptVia,label:O.label,detected:!0})),...Ti.map(O=>({name:O.name,command:O.command,argsTemplate:O.argsTemplate,promptVia:O.promptVia??"arg",label:O.name,detected:!1}))];console.log(`
1470
1470
  ${D("Which agents should Alfred use?")} ${b("(comma-separated, e.g. 1,2)")}`);let v=new Set((t.config.codeAgents?.agents??[]).map(O=>O.name));for(let O=0;O<k.length;O++){let X=k[O],oe=v.has(X.name)?` ${b("(current)")}`:"";console.log(` ${U}${O+1}${A}) ${X.label}${oe}`)}console.log(` ${U}0${A}) None`);let N=k.map((O,X)=>v.size>0?v.has(O.name)?String(X+1):null:O.detected?String(X+1):null).filter(Boolean).join(",")||"0",Y=(await l.question(` ${U}> ${A}${b(`[${N}] `)}`)).trim()||N;Y!=="0"&&(At=Y.split(",").map(X=>parseInt(X.trim(),10)).filter(X=>!isNaN(X)&&X>=1&&X<=k.length).map(X=>{let oe=k[X-1];return{name:oe.name,command:oe.command,argsTemplate:oe.argsTemplate,promptVia:oe.promptVia}})),At.length>0?console.log(` ${P(">")} ${D(String(At.length))} agent(s) selected: ${At.map(O=>O.name).join(", ")}`):console.log(` ${b("No agents selected.")}`)}let _i=t.config.codeAgents?.forge,ki=_i?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
1471
1471
  ${D("Forge Integration (auto-create PRs/MRs after code agent orchestration)?")}`),console.log(`${b("Connects to GitHub or GitLab to push branches and create pull/merge requests.")}`),console.log(`${b("Owner/repo are detected automatically from the git remote at runtime.")}`);let Yc=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let k of Yc){let v=k.name===ki?` ${b("(current)")}`:"";console.log(` ${U}${k.num}${A}) ${k.label}${v}`)}let Jc=ki==="github"?"2":ki==="gitlab"?"3":"1",fm=(await l.question(`${U}> ${A}${b(`[${Jc}] `)}`)).trim()||Jc,It=Yc.find(k=>k.num===fm)?.name??"",ur="",pr="";if(It==="github"){console.log(` ${P(">")} Forge: ${D("GitHub")}`);let k=t.env.ALFRED_GITHUB_TOKEN??_i?.github?.token??"";k&&console.log(` ${b(`Current token: ${be(k)}`)}`),console.log(` ${b("Create a token at https://github.com/settings/tokens (scope: repo)")}`),ur=(await l.question(` ${V}GitHub Token${A}: ${U}`)).trim(),process.stdout.write(A),!ur&&k&&(ur=k)}else if(It==="gitlab"){console.log(` ${P(">")} Forge: ${D("GitLab")}`);let k=t.env.ALFRED_GITLAB_TOKEN??_i?.gitlab?.token??"";k&&console.log(` ${b(`Current token: ${be(k)}`)}`),console.log(` ${b("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),pr=(await l.question(` ${V}GitLab Token${A}: ${U}`)).trim(),process.stdout.write(A),!pr&&k&&(pr=k)}else console.log(` ${b("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);let gm=t.webUiEnabled!==!1?"Y/n":"y/N";console.log(`
1472
- ${D("Web Chat UI (browser-based chat interface)?")}`),console.log(`${b("Serves a web UI at http://host:port/alfred/ \u2014 chat, dashboard, skill health.")}`);let bi=(await l.question(`${U}> ${A}${b(`[${gm}] `)}`)).trim().toLowerCase(),Ei=bi===""?t.webUiEnabled!==!1:bi==="y"||bi==="yes";console.log(Ei?` ${P(">")} Web Chat UI ${D("enabled")} \u2014 accessible at /alfred/`:` ${b("Web Chat UI disabled.")}`);let Wn=!1;console.log(`
1473
- ${D("TLS/HTTPS f\xFCr die HTTP API?")}`),console.log(`${b("Verschl\xFCsselt die Verbindung. Selbstsigniertes Zertifikat wird automatisch generiert.")}`);let Zc=(await l.question(`${U}> ${A}${b("[y/N] ")}`)).trim().toLowerCase();Wn=Zc==="y"||Zc==="yes",console.log(Wn?` ${P(">")} TLS ${D("enabled")} \u2014 selbstsigniertes Zertifikat in ~/.alfred/tls/`:` ${b("TLS disabled \u2014 API l\xE4uft \xFCber HTTP.")}`),console.log(`
1474
- ${D("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${b("Control VMs, containers, network devices, and smart home through Alfred.")}`);let mr=t.config.proxmox,Si=t.env.ALFRED_PROXMOX_BASE_URL??mr?.baseUrl??"",ym=Si?"Y/n":"y/N",Qc=(await l.question(` ${V}Enable Proxmox VE?${A} ${b(`[${ym}]`)}: ${U}`)).trim().toLowerCase()||(Si?"y":"n");process.stdout.write(A);let zn=Qc==="y"||Qc==="yes",hr="",$i="",fr="",vi=!0;if(zn){hr=await H(l," Proxmox URL (e.g. https://pve.local:8006)",Si||"https://pve.local:8006");let k=t.env.ALFRED_PROXMOX_TOKEN_ID??mr?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),$i=await H(l," API Token ID (user@realm!name)",k);let v=t.env.ALFRED_PROXMOX_TOKEN_SECRET??mr?.tokenSecret??"";v&&console.log(` ${b(`Current secret: ${be(v)}`)}`),fr=(await l.question(` ${V}API Token Secret${A}: ${U}`)).trim(),process.stdout.write(A),!fr&&v&&(fr=v);let N=mr?.verifyTls===!1?"y/N":"Y/n",Y=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${N}]`)}: ${U}`)).trim().toLowerCase()||(mr?.verifyTls===!1?"n":"y");process.stdout.write(A),vi=Y==="y"||Y==="yes",console.log(` ${P(">")} Proxmox: ${D(hr)} ${b(`(TLS verify: ${vi?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox disabled.")}`);let Qt=t.config.proxmoxBackup,Ai=t.env.ALFRED_PBS_BASE_URL??Qt?.baseUrl??"",wm=Ai?"Y/n":"y/N",el=(await l.question(`
1475
- ${V}Enable Proxmox Backup Server?${A} ${b(`[${wm}]`)}: ${U}`)).trim().toLowerCase()||(Ai?"y":"n");process.stdout.write(A);let qn=el==="y"||el==="yes",gr="",Ii="",yr="",wr=24,Gn=!0;if(qn){gr=await H(l," PBS URL (e.g. https://pbs.local:8007)",Ai||"https://pbs.local:8007");let k=t.env.ALFRED_PBS_TOKEN_ID??Qt?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Configuration \u2192 Access Control \u2192 API Token")}`),Ii=await H(l," API Token ID (user@realm!name)",k);let v=t.env.ALFRED_PBS_TOKEN_SECRET??Qt?.tokenSecret??"";v&&console.log(` ${b(`Current secret: ${be(v)}`)}`),yr=(await l.question(` ${V}API Token Secret${A}: ${U}`)).trim(),process.stdout.write(A),!yr&&v&&(yr=v);let N=t.env.ALFRED_PBS_MAX_AGE_HOURS??Qt?.maxAgeHours?.toString()??"24";wr=parseInt(await H(l," Max backup age (hours, alert if older)",N),10)||24;let Y=Qt?.verifyTls===!1?"y/N":"Y/n",O=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${Y}]`)}: ${U}`)).trim().toLowerCase()||(Qt?.verifyTls===!1?"n":"y");process.stdout.write(A),Gn=O==="y"||O==="yes",console.log(` ${P(">")} PBS: ${D(gr)} ${b(`(max age: ${wr}h, TLS verify: ${Gn?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox Backup Server disabled.")}`);let Rt=t.config.unifi,Ri=t.env.ALFRED_UNIFI_BASE_URL??Rt?.baseUrl??"",Tm=Ri?"Y/n":"y/N",tl=(await l.question(`
1476
- ${V}Enable UniFi Network?${A} ${b(`[${Tm}]`)}: ${U}`)).trim().toLowerCase()||(Ri?"y":"n");process.stdout.write(A);let Tr=tl==="y"||tl==="yes",es="",xt="",xi="",_r="",Ci=!0;if(Tr){es=await H(l," UniFi URL (e.g. https://unifi.local)",Ri||"https://unifi.local"),console.log(` ${b("Auth: API Key (recommended) or Username/Password")}`);let k=t.env.ALFRED_UNIFI_API_KEY??Rt?.apiKey??"",v=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],N=k?"1":Rt?.username?"2":"1";for(let oe of v)console.log(` ${U}${oe.num}${A}) ${oe.label}`);if(((await l.question(` ${U}> ${A}${b(`[${N}] `)}`)).trim()||N)==="1")k&&console.log(` ${b(`Current key: ${be(k)}`)}`),console.log(` ${b("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),xt=(await l.question(` ${V}API Key${A}: ${U}`)).trim(),process.stdout.write(A),!xt&&k&&(xt=k);else{let oe=t.env.ALFRED_UNIFI_USERNAME??Rt?.username??"";xi=await H(l," Username",oe||"alfred");let ve=t.env.ALFRED_UNIFI_PASSWORD??Rt?.password??"";ve&&console.log(` ${b(`Current password: ${be(ve)}`)}`),_r=(await l.question(` ${V}Password${A}: ${U}`)).trim(),process.stdout.write(A),!_r&&ve&&(_r=ve)}let O=Rt?.verifyTls===!1?"y/N":"Y/n",X=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${O}]`)}: ${U}`)).trim().toLowerCase()||(Rt?.verifyTls===!1?"n":"y");process.stdout.write(A),Ci=X==="y"||X==="yes",console.log(` ${P(">")} UniFi: ${D(es)} ${b(`(TLS verify: ${Ci?"yes":"no"})`)}`)}else console.log(` ${b("UniFi disabled.")}`);let Kn=t.config.homeassistant,Ni=t.env.ALFRED_HOMEASSISTANT_URL??Kn?.baseUrl??"",_m=Ni?"Y/n":"y/N",sl=(await l.question(`
1477
- ${V}Enable Home Assistant?${A} ${b(`[${_m}]`)}: ${U}`)).trim().toLowerCase()||(Ni?"y":"n");process.stdout.write(A);let Xn=sl==="y"||sl==="yes",kr="",br="",Li=!0;if(Xn){kr=await H(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",Ni||"http://homeassistant.local:8123");let k=t.env.ALFRED_HOMEASSISTANT_TOKEN??Kn?.accessToken??"";k&&console.log(` ${b(`Current token: ${be(k)}`)}`),console.log(` ${b("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),br=(await l.question(` ${V}Long-Lived Access Token${A}: ${U}`)).trim(),process.stdout.write(A),!br&&k&&(br=k);let v=Kn?.verifyTls===!1?"y/N":"Y/n",N=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${v}]`)}: ${U}`)).trim().toLowerCase()||(Kn?.verifyTls===!1?"n":"y");process.stdout.write(A),Li=N==="y"||N==="yes",console.log(` ${P(">")} Home Assistant: ${D(kr)} ${b(`(TLS verify: ${Li?"yes":"no"})`)}`)}else console.log(` ${b("Home Assistant disabled.")}`);let Fe=t.config.contacts,Di=t.env.ALFRED_CONTACTS_PROVIDER??Fe?.provider??"",km=Di?"Y/n":"y/N",rl=(await l.question(`
1478
- ${V}Enable Contacts management?${A} ${b(`[${km}]`)}: ${U}`)).trim().toLowerCase()||(Di?"y":"n");process.stdout.write(A);let Vn=rl==="y"||rl==="yes",je="",we={};if(Vn){let k=["carddav","google","microsoft"],v=k.indexOf(Di),N=v>=0?v+1:1;console.log(` ${ke("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${ke("2)")} Google Contacts`),console.log(` ${ke("3)")} Microsoft 365`);let Y=await Bn(l," > ",1,3,N);if(je=k[Y-1],we.ALFRED_CONTACTS_PROVIDER=je,je==="carddav"){let O=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Fe?.carddav?.serverUrl??"";we.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await H(l," CardDAV Server URL",O||"https://cloud.example.com/remote.php/dav");let X=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Fe?.carddav?.username??"";we.ALFRED_CARDDAV_CONTACTS_USERNAME=await H(l," Username",X);let oe=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Fe?.carddav?.password??"";oe&&console.log(` ${b(`Current password: ${be(oe)}`)}`);let ve=(await l.question(` ${V}Password${A}: ${U}`)).trim();process.stdout.write(A),we.ALFRED_CARDDAV_CONTACTS_PASSWORD=ve||oe}else if(je==="google"){let O=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Fe?.google?.clientId??"";O&&console.log(` ${b(`Current client ID: ${be(O)}`)}`),we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${V}Google Client ID${A}: ${U}`)).trim()||O,process.stdout.write(A);let X=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Fe?.google?.clientSecret??"";we.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${V}Google Client Secret${A}: ${U}`)).trim()||X,process.stdout.write(A);let oe=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Fe?.google?.refreshToken??"";we.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${V}Refresh Token${A}: ${U}`)).trim()||oe,process.stdout.write(A)}else if(je==="microsoft"){let O=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Fe?.microsoft?.clientId??"";O&&console.log(` ${b(`Current client ID: ${be(O)}`)}`),we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${V}Microsoft Client ID${A}: ${U}`)).trim()||O,process.stdout.write(A);let X=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Fe?.microsoft?.clientSecret??"";we.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${V}Microsoft Client Secret${A}: ${U}`)).trim()||X,process.stdout.write(A);let oe=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Fe?.microsoft?.tenantId??"";we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await H(l," Tenant ID",oe||"common");let ve=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Fe?.microsoft?.refreshToken??"";console.log(` ${b("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),we.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${V}Refresh Token${A}: ${U}`)).trim()||ve,process.stdout.write(A)}console.log(` ${P(">")} Contacts: ${D(je)}`)}else console.log(` ${b("Contacts disabled.")}`);let nl=t.config.docker,Mi=t.env.ALFRED_DOCKER_SOCKET_PATH??nl?.socketPath??"",Oi=t.env.ALFRED_DOCKER_HOST??nl?.host??"",bm=Mi||Oi?"Y/n":"y/N",ol=(await l.question(`
1479
- ${V}Enable Docker management?${A} ${b(`[${bm}]`)}: ${U}`)).trim().toLowerCase()||(Mi||Oi?"y":"n");process.stdout.write(A);let Yn=ol==="y"||ol==="yes",Ct="",Nt="";if(Yn){let k=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${b("Use socket path for local Docker, or host URL for remote.")}`),Ct=await H(l," Docker socket path",Mi||k);let v=(await l.question(` ${V}Docker host URL (optional, for remote)${A}: ${U}`)).trim();process.stdout.write(A),Nt=v||Oi,console.log(` ${P(">")} Docker: ${D(Nt||Ct)}`)}else console.log(` ${b("Docker disabled.")}`);let Em=t.config.bmw,Pi=t.env.ALFRED_BMW_CLIENT_ID??Em?.clientId??"",Sm=Pi?"Y/n":"y/N",il=(await l.question(`
1480
- ${V}Enable BMW CarData (vehicle status, charging)?${A} ${b(`[${Sm}]`)}: ${U}`)).trim().toLowerCase()||(Pi?"y":"n");process.stdout.write(A);let Jn=il==="y"||il==="yes",Ui="";Jn?(console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${b(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${b(" 3. Client-ID generieren")}`),console.log(` ${b(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),Ui=await H(l," BMW CarData Client ID",Pi),console.log(` ${P(">")} BMW CarData: ${D("enabled")}`)):console.log(` ${b("BMW CarData disabled.")}`);let $m=t.config.routing,Fi=t.env.ALFRED_ROUTING_API_KEY??$m?.apiKey??"",vm=Fi?"Y/n":"y/N",al=(await l.question(`
1481
- ${V}Enable route planning with live traffic (Google Routes)?${A} ${b(`[${vm}]`)}: ${U}`)).trim().toLowerCase()||(Fi?"y":"n");process.stdout.write(A);let Zn=al==="y"||al==="yes",ji="";Zn?(console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${b(" 2. Routes API aktivieren")}`),console.log(` ${b(" 3. API Key erstellen")}`),ji=await H(l," Google Maps API Key",Fi),console.log(` ${P(">")} Routing: ${D("enabled")}`)):console.log(` ${b("Routing disabled.")}`);let cl=t.config.youtube,Bi=t.env.ALFRED_YOUTUBE_API_KEY??cl?.apiKey??"",Am=t.env.ALFRED_SUPADATA_API_KEY??cl?.supadata?.apiKey??"",Im=Bi?"Y/n":"y/N",ll=(await l.question(`
1482
- ${V}Enable YouTube (search, video info, transcripts)?${A} ${b(`[${Im}]`)}: ${U}`)).trim().toLowerCase()||(Bi?"y":"n");process.stdout.write(A);let Qn=ll==="y"||ll==="yes",Hi="",Lt="";if(Qn){console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${b(" 2. YouTube Data API v3 aktivieren")}`),console.log(` ${b(" 3. API Key erstellen (gleicher Key wie f\xFCr Routing m\xF6glich)")}`),Hi=await H(l," YouTube API Key",Bi);let k=(await l.question(` ${V}Supadata API Key (optional, Transkript-Fallback)?${A} ${b("[Enter to skip]")}: ${U}`)).trim();process.stdout.write(A),Lt=k||Am,console.log(` ${P(">")} YouTube: ${D("enabled")}${Lt?" + Supadata Fallback":""}`)}else console.log(` ${b("YouTube disabled.")}`);let st=t.config.energy,Rm=t.env.ALFRED_ENERGY_GRID_NAME??st?.gridName??"",Wi=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(st?.gridUsageCt!=null?String(st.gridUsageCt):""),xm=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(st?.gridLossCt!=null?String(st.gridLossCt):""),Cm=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(st?.gridCapacityFee!=null?String(st.gridCapacityFee):""),Nm=t.env.ALFRED_ENERGY_GRID_METER_FEE??(st?.gridMeterFee!=null?String(st.gridMeterFee):""),Lm=Wi?"Y/n":"y/N",dl=(await l.question(`
1483
- ${V}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${A} ${b(`[${Lm}]`)}: ${U}`)).trim().toLowerCase()||(Wi?"y":"n");process.stdout.write(A);let eo=dl==="y"||dl==="yes",Dt="",Mt="",to="",Er="",Sr="";eo?(console.log(` ${b('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${b("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),Dt=await H(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",Rm),Mt=await H(l," Netznutzungsentgelt (ct/kWh netto)",Wi),to=await H(l," Netzverlustentgelt (ct/kWh netto)",xm||"0.38"),Er=await H(l," Leistungspauschale (\u20AC/Monat netto)",Cm),Sr=await H(l," Messentgelt (\u20AC/Monat netto)",Nm||"2.22"),console.log(` ${P(">")} Energy: ${D(Dt||"enabled")} (${Mt} + ${to} ct/kWh)`)):console.log(` ${b("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
1484
- ${D("Security configuration:")}`);let ul=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",xe;if(ul)xe=await H(l,"Owner user ID (for elevated permissions)",ul);else{let k=(await l.question(`${V}Owner user ID${A} ${b("(optional, for elevated permissions)")}: ${U}`)).trim();process.stdout.write(A),xe=k}let $r=!1;if(xe){let k=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${D("Enable shell access (admin commands) for the owner?")}`),console.log(` ${b("Allows Alfred to execute shell commands. Only for the owner.")}`);let v=(await l.question(` ${U}> ${A}${b(`[${k}] `)}`)).trim().toLowerCase();v===""?$r=t.shellEnabled:$r=v==="y"||v==="yes",console.log($r?` ${P(">")} Shell access ${D("enabled")} for owner ${b(xe)}`:` ${b("Shell access disabled.")}`)}let Dm=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${D("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${b("By default, write actions are only allowed in DMs.")}`);let zi=(await l.question(` ${U}> ${A}${b(`[${Dm}] `)}`)).trim().toLowerCase(),vr;zi===""?vr=t.writeInGroups:vr=zi==="y"||zi==="yes",console.log(vr?` ${P(">")} Write actions ${D("enabled")} in groups`:` ${b("Write actions only in DMs (default).")}`);let Mm=t.rateLimit??30;console.log("");let Om=await H(l," Rate limit (max write actions per hour per user)",String(Mm)),so=Math.max(1,parseInt(Om,10)||30);console.log(` ${P(">")} Rate limit: ${D(String(so))} per hour`),console.log(`
1485
- ${D("Writing configuration files...")}`);let I=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let k=a.envKeyName||"ALFRED_OLLAMA_API_KEY";I.push(`${k}=${c}`)}if(f!==a.defaultModel&&I.push(`ALFRED_LLM_MODEL=${f}`),u&&I.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(R).length>0){I.push("","# === Additional Model Tiers ===");for(let[k,v]of Object.entries(R)){let N=`ALFRED_LLM_${k.toUpperCase()}`;I.push(""),I.push(`${N}_PROVIDER=${v.provider}`),I.push(`${N}_MODEL=${v.model}`),v.apiKey&&I.push(`${N}_API_KEY=${v.apiKey}`),v.baseUrl&&I.push(`${N}_BASE_URL=${v.baseUrl}`)}}I.push("","# === Messaging Platforms ===","");for(let[k,v]of Object.entries(Ue))I.push(`${k}=${v}`);if(I.push("","# === Web Search ===",""),ne?(I.push(`ALFRED_SEARCH_PROVIDER=${ne}`),ae&&I.push(`ALFRED_SEARCH_API_KEY=${ae}`),Q&&I.push(`ALFRED_SEARCH_BASE_URL=${Q}`)):(I.push("# ALFRED_SEARCH_PROVIDER=brave"),I.push("# ALFRED_SEARCH_API_KEY=")),I.push("","# === Email ===",""),K&&z.length>0){let k=z[0];k.provider==="microsoft"?(I.push("ALFRED_EMAIL_PROVIDER=microsoft"),k.msClientId?(I.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${k.msClientId}`),I.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${k.msClientSecret}`),I.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${k.msTenantId}`),I.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${k.msRefreshToken}`)):I.push("# Microsoft email credentials shared from calendar config")):(I.push(`ALFRED_EMAIL_USER=${k.user}`),I.push(`ALFRED_EMAIL_PASS=${k.pass}`)),z.length>1&&I.push("# Additional email accounts configured in config/default.yml")}else I.push("# ALFRED_EMAIL_USER="),I.push("# ALFRED_EMAIL_PASS=");if(I.push("","# === Speech ===",""),Je?(I.push(`ALFRED_SPEECH_PROVIDER=${Je}`),I.push(`ALFRED_SPEECH_API_KEY=${pt}`),cr&&I.push(`ALFRED_SPEECH_BASE_URL=${cr}`),lr&&(I.push("ALFRED_TTS_ENABLED=true"),I.push(`ALFRED_TTS_VOICE=${dr}`))):(I.push("# ALFRED_SPEECH_PROVIDER=groq"),I.push("# ALFRED_SPEECH_API_KEY=")),I.push("","# === Forge (GitHub / GitLab) ===",""),It==="github"?(I.push("ALFRED_FORGE_PROVIDER=github"),I.push(`ALFRED_GITHUB_TOKEN=${ur}`)):It==="gitlab"?(I.push("ALFRED_FORGE_PROVIDER=gitlab"),I.push(`ALFRED_GITLAB_TOKEN=${pr}`)):(I.push("# ALFRED_FORGE_PROVIDER=github"),I.push("# ALFRED_GITHUB_TOKEN=")),I.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),zn?(I.push(`ALFRED_PROXMOX_BASE_URL=${hr}`),I.push(`ALFRED_PROXMOX_TOKEN_ID=${$i}`),I.push(`ALFRED_PROXMOX_TOKEN_SECRET=${fr}`)):(I.push("# ALFRED_PROXMOX_BASE_URL="),I.push("# ALFRED_PROXMOX_TOKEN_ID="),I.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),qn?(I.push(`ALFRED_PBS_BASE_URL=${gr}`),I.push(`ALFRED_PBS_TOKEN_ID=${Ii}`),I.push(`ALFRED_PBS_TOKEN_SECRET=${yr}`),I.push(`ALFRED_PBS_MAX_AGE_HOURS=${wr}`),Gn||I.push("ALFRED_PBS_VERIFY_TLS=false")):(I.push("# ALFRED_PBS_BASE_URL="),I.push("# ALFRED_PBS_TOKEN_ID="),I.push("# ALFRED_PBS_TOKEN_SECRET=")),Tr&&xt?(I.push(`ALFRED_UNIFI_BASE_URL=${es}`),I.push(`ALFRED_UNIFI_API_KEY=${xt}`)):Tr?(I.push(`ALFRED_UNIFI_BASE_URL=${es}`),I.push(`ALFRED_UNIFI_USERNAME=${xi}`),I.push(`ALFRED_UNIFI_PASSWORD=${_r}`)):(I.push("# ALFRED_UNIFI_BASE_URL="),I.push("# ALFRED_UNIFI_API_KEY=")),Xn?(I.push(`ALFRED_HOMEASSISTANT_URL=${kr}`),I.push(`ALFRED_HOMEASSISTANT_TOKEN=${br}`)):(I.push("# ALFRED_HOMEASSISTANT_URL="),I.push("# ALFRED_HOMEASSISTANT_TOKEN=")),I.push("","# === Contacts ===",""),Vn)for(let[k,v]of Object.entries(we))I.push(`${k}=${v}`);else I.push("# ALFRED_CONTACTS_PROVIDER=carddav");I.push("","# === Docker ===",""),Yn?(Ct&&I.push(`ALFRED_DOCKER_SOCKET_PATH=${Ct}`),Nt&&I.push(`ALFRED_DOCKER_HOST=${Nt}`)):(I.push("# ALFRED_DOCKER_SOCKET_PATH="),I.push("# ALFRED_DOCKER_HOST=")),I.push("","# === BMW CarData ===",""),Jn?I.push(`ALFRED_BMW_CLIENT_ID=${Ui}`):I.push("# ALFRED_BMW_CLIENT_ID="),I.push("","# === Routing ===",""),Zn?I.push(`ALFRED_ROUTING_API_KEY=${ji}`):I.push("# ALFRED_ROUTING_API_KEY="),I.push("","# === YouTube ===",""),Qn?(I.push(`ALFRED_YOUTUBE_API_KEY=${Hi}`),Lt&&I.push(`ALFRED_SUPADATA_API_KEY=${Lt}`)):(I.push("# ALFRED_YOUTUBE_API_KEY="),I.push("# ALFRED_SUPADATA_API_KEY=")),I.push("","# === Energy / aWATTar ===",""),eo&&Mt?(Dt&&I.push(`ALFRED_ENERGY_GRID_NAME=${Dt}`),I.push(`ALFRED_ENERGY_GRID_USAGE_CT=${Mt}`),I.push(`ALFRED_ENERGY_GRID_LOSS_CT=${to}`),Er&&I.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Er}`),Sr&&I.push(`ALFRED_ENERGY_GRID_METER_FEE=${Sr}`)):(I.push("# ALFRED_ENERGY_GRID_NAME="),I.push("# ALFRED_ENERGY_GRID_USAGE_CT="),I.push("# ALFRED_ENERGY_GRID_LOSS_CT="),I.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),I.push("# ALFRED_ENERGY_GRID_METER_FEE=")),I.push("","# === Security ===",""),xe?I.push(`ALFRED_OWNER_USER_ID=${xe}`):I.push("# ALFRED_OWNER_USER_ID="),I.push("");let Pm=Re.join(e,".env");Ee.writeFileSync(Pm,I.join(`
1486
- `),"utf-8"),console.log(` ${P("+")} ${b(".env")} written`);let ro=Re.join(e,"config");Ee.existsSync(ro)||Ee.mkdirSync(ro,{recursive:!0});let pl={name:r,telegram:{token:pe.telegram?.token??"",enabled:le.some(k=>k.name==="telegram")},discord:{token:pe.discord?.token??"",enabled:le.some(k=>k.name==="discord")},whatsapp:{enabled:le.some(k=>k.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:pe.matrix?.homeserverUrl??"https://matrix.org",accessToken:pe.matrix?.accessToken??"",userId:pe.matrix?.userId??"",enabled:le.some(k=>k.name==="matrix")},signal:{apiUrl:pe.signal?.apiUrl??"http://localhost:8080",phoneNumber:pe.signal?.phoneNumber??"",enabled:le.some(k=>k.name==="signal")},llm:Object.keys(R).length>0?{default:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...R}:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...ne?{search:{provider:ne,...ae?{apiKey:ae}:{},...Q?{baseUrl:Q}:{}}}:{},...K&&z.length>0?{email:{accounts:z.map(k=>k.provider==="microsoft"?{name:k.name,provider:"microsoft",...k.msClientId?{microsoft:{clientId:k.msClientId,clientSecret:k.msClientSecret,tenantId:k.msTenantId,refreshToken:k.msRefreshToken}}:{}}:{name:k.name,imap:{host:k.imapHost,port:k.imapPort,secure:k.imapPort===993},smtp:{host:k.smtpHost,port:k.smtpPort,secure:k.smtpPort===465},auth:{user:k.user,pass:k.pass}})}}:{},...Je?{speech:{provider:Je,apiKey:pt,...cr?{baseUrl:cr}:{},...lr?{ttsEnabled:!0,ttsVoice:dr}:{}}}:{},...yi?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...At.length>0||It?{codeAgents:{enabled:At.length>0,agents:At,...It==="github"?{forge:{provider:"github",github:{token:ur}}}:It==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:pr}}}:{}}}:{},...zn?{proxmox:{baseUrl:hr,tokenId:$i,tokenSecret:fr,verifyTls:vi}}:{},...qn?{proxmoxBackup:{baseUrl:gr,tokenId:Ii,tokenSecret:yr,maxAgeHours:wr,verifyTls:Gn}}:{},...Tr?{unifi:{baseUrl:es,...xt?{apiKey:xt}:{username:xi,password:_r},site:"default",verifyTls:Ci}}:{},...Xn?{homeassistant:{baseUrl:kr,accessToken:br,verifyTls:Li}}:{},...Vn?{contacts:{provider:je,...je==="carddav"?{carddav:{serverUrl:we.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:we.ALFRED_CARDDAV_CONTACTS_USERNAME}}:je==="google"?{google:{clientId:we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:je==="microsoft"?{microsoft:{clientId:we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Yn?{docker:{...Ct?{socketPath:Ct}:{},...Nt?{host:Nt}:{}}}:{},...Jn?{bmw:{clientId:Ui}}:{},...Zn?{routing:{apiKey:ji}}:{},...Qn?{youtube:{apiKey:Hi,...Lt?{supadata:{enabled:!0,apiKey:Lt}}:{}}}:{},...eo&&Mt?{energy:{...Dt?{gridName:Dt}:{},gridUsageCt:parseFloat(Mt),gridLossCt:parseFloat(to||"0"),...Er?{gridCapacityFee:parseFloat(Er)}:{},...Sr?{gridMeterFee:parseFloat(Sr)}:{}}}:{},api:{enabled:!0,port:3420,host:"127.0.0.1",webUi:Ei,...Wn?{tls:{enabled:!0}}:{}},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};xe&&(pl.security.ownerUserId=xe);let Um="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Gc.dump(pl,{lineWidth:120,noRefs:!0,sortKeys:!1}),Fm=Re.join(ro,"default.yml");Ee.writeFileSync(Fm,Um,"utf-8"),console.log(` ${P("+")} ${b("config/default.yml")} written`);let qi=Re.join(ro,"rules");Ee.existsSync(qi)||Ee.mkdirSync(qi,{recursive:!0});let jm=$r&&xe?`
1472
+ ${D("Web Chat UI (browser-based chat interface)?")}`),console.log(`${b("Serves a web UI at http://host:port/alfred/ \u2014 chat, dashboard, skill health.")}`);let bi=(await l.question(`${U}> ${A}${b(`[${gm}] `)}`)).trim().toLowerCase(),Ei=bi===""?t.webUiEnabled!==!1:bi==="y"||bi==="yes";console.log(Ei?` ${P(">")} Web Chat UI ${D("enabled")} \u2014 accessible at /alfred/`:` ${b("Web Chat UI disabled.")}`);let zn=!1;console.log(`
1473
+ ${D("TLS/HTTPS f\xFCr die HTTP API?")}`),console.log(`${b("Verschl\xFCsselt die Verbindung. Selbstsigniertes Zertifikat wird automatisch generiert.")}`);let Zc=(await l.question(`${U}> ${A}${b("[y/N] ")}`)).trim().toLowerCase();zn=Zc==="y"||Zc==="yes",console.log(zn?` ${P(">")} TLS ${D("enabled")} \u2014 selbstsigniertes Zertifikat in ~/.alfred/tls/`:` ${b("TLS disabled \u2014 API l\xE4uft \xFCber HTTP.")}`),console.log(`
1474
+ ${D("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${b("Control VMs, containers, network devices, and smart home through Alfred.")}`);let mr=t.config.proxmox,Si=t.env.ALFRED_PROXMOX_BASE_URL??mr?.baseUrl??"",ym=Si?"Y/n":"y/N",Qc=(await l.question(` ${V}Enable Proxmox VE?${A} ${b(`[${ym}]`)}: ${U}`)).trim().toLowerCase()||(Si?"y":"n");process.stdout.write(A);let qn=Qc==="y"||Qc==="yes",hr="",$i="",fr="",vi=!0;if(qn){hr=await H(l," Proxmox URL (e.g. https://pve.local:8006)",Si||"https://pve.local:8006");let k=t.env.ALFRED_PROXMOX_TOKEN_ID??mr?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),$i=await H(l," API Token ID (user@realm!name)",k);let v=t.env.ALFRED_PROXMOX_TOKEN_SECRET??mr?.tokenSecret??"";v&&console.log(` ${b(`Current secret: ${be(v)}`)}`),fr=(await l.question(` ${V}API Token Secret${A}: ${U}`)).trim(),process.stdout.write(A),!fr&&v&&(fr=v);let N=mr?.verifyTls===!1?"y/N":"Y/n",Y=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${N}]`)}: ${U}`)).trim().toLowerCase()||(mr?.verifyTls===!1?"n":"y");process.stdout.write(A),vi=Y==="y"||Y==="yes",console.log(` ${P(">")} Proxmox: ${D(hr)} ${b(`(TLS verify: ${vi?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox disabled.")}`);let Qt=t.config.proxmoxBackup,Ai=t.env.ALFRED_PBS_BASE_URL??Qt?.baseUrl??"",wm=Ai?"Y/n":"y/N",el=(await l.question(`
1475
+ ${V}Enable Proxmox Backup Server?${A} ${b(`[${wm}]`)}: ${U}`)).trim().toLowerCase()||(Ai?"y":"n");process.stdout.write(A);let Gn=el==="y"||el==="yes",gr="",Ii="",yr="",wr=24,Kn=!0;if(Gn){gr=await H(l," PBS URL (e.g. https://pbs.local:8007)",Ai||"https://pbs.local:8007");let k=t.env.ALFRED_PBS_TOKEN_ID??Qt?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Configuration \u2192 Access Control \u2192 API Token")}`),Ii=await H(l," API Token ID (user@realm!name)",k);let v=t.env.ALFRED_PBS_TOKEN_SECRET??Qt?.tokenSecret??"";v&&console.log(` ${b(`Current secret: ${be(v)}`)}`),yr=(await l.question(` ${V}API Token Secret${A}: ${U}`)).trim(),process.stdout.write(A),!yr&&v&&(yr=v);let N=t.env.ALFRED_PBS_MAX_AGE_HOURS??Qt?.maxAgeHours?.toString()??"24";wr=parseInt(await H(l," Max backup age (hours, alert if older)",N),10)||24;let Y=Qt?.verifyTls===!1?"y/N":"Y/n",O=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${Y}]`)}: ${U}`)).trim().toLowerCase()||(Qt?.verifyTls===!1?"n":"y");process.stdout.write(A),Kn=O==="y"||O==="yes",console.log(` ${P(">")} PBS: ${D(gr)} ${b(`(max age: ${wr}h, TLS verify: ${Kn?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox Backup Server disabled.")}`);let Rt=t.config.unifi,Ri=t.env.ALFRED_UNIFI_BASE_URL??Rt?.baseUrl??"",Tm=Ri?"Y/n":"y/N",tl=(await l.question(`
1476
+ ${V}Enable UniFi Network?${A} ${b(`[${Tm}]`)}: ${U}`)).trim().toLowerCase()||(Ri?"y":"n");process.stdout.write(A);let Tr=tl==="y"||tl==="yes",es="",xt="",xi="",_r="",Ci=!0;if(Tr){es=await H(l," UniFi URL (e.g. https://unifi.local)",Ri||"https://unifi.local"),console.log(` ${b("Auth: API Key (recommended) or Username/Password")}`);let k=t.env.ALFRED_UNIFI_API_KEY??Rt?.apiKey??"",v=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],N=k?"1":Rt?.username?"2":"1";for(let oe of v)console.log(` ${U}${oe.num}${A}) ${oe.label}`);if(((await l.question(` ${U}> ${A}${b(`[${N}] `)}`)).trim()||N)==="1")k&&console.log(` ${b(`Current key: ${be(k)}`)}`),console.log(` ${b("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),xt=(await l.question(` ${V}API Key${A}: ${U}`)).trim(),process.stdout.write(A),!xt&&k&&(xt=k);else{let oe=t.env.ALFRED_UNIFI_USERNAME??Rt?.username??"";xi=await H(l," Username",oe||"alfred");let ve=t.env.ALFRED_UNIFI_PASSWORD??Rt?.password??"";ve&&console.log(` ${b(`Current password: ${be(ve)}`)}`),_r=(await l.question(` ${V}Password${A}: ${U}`)).trim(),process.stdout.write(A),!_r&&ve&&(_r=ve)}let O=Rt?.verifyTls===!1?"y/N":"Y/n",X=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${O}]`)}: ${U}`)).trim().toLowerCase()||(Rt?.verifyTls===!1?"n":"y");process.stdout.write(A),Ci=X==="y"||X==="yes",console.log(` ${P(">")} UniFi: ${D(es)} ${b(`(TLS verify: ${Ci?"yes":"no"})`)}`)}else console.log(` ${b("UniFi disabled.")}`);let Xn=t.config.homeassistant,Ni=t.env.ALFRED_HOMEASSISTANT_URL??Xn?.baseUrl??"",_m=Ni?"Y/n":"y/N",sl=(await l.question(`
1477
+ ${V}Enable Home Assistant?${A} ${b(`[${_m}]`)}: ${U}`)).trim().toLowerCase()||(Ni?"y":"n");process.stdout.write(A);let Vn=sl==="y"||sl==="yes",kr="",br="",Li=!0;if(Vn){kr=await H(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",Ni||"http://homeassistant.local:8123");let k=t.env.ALFRED_HOMEASSISTANT_TOKEN??Xn?.accessToken??"";k&&console.log(` ${b(`Current token: ${be(k)}`)}`),console.log(` ${b("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),br=(await l.question(` ${V}Long-Lived Access Token${A}: ${U}`)).trim(),process.stdout.write(A),!br&&k&&(br=k);let v=Xn?.verifyTls===!1?"y/N":"Y/n",N=(await l.question(` ${V}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${v}]`)}: ${U}`)).trim().toLowerCase()||(Xn?.verifyTls===!1?"n":"y");process.stdout.write(A),Li=N==="y"||N==="yes",console.log(` ${P(">")} Home Assistant: ${D(kr)} ${b(`(TLS verify: ${Li?"yes":"no"})`)}`)}else console.log(` ${b("Home Assistant disabled.")}`);let Fe=t.config.contacts,Di=t.env.ALFRED_CONTACTS_PROVIDER??Fe?.provider??"",km=Di?"Y/n":"y/N",rl=(await l.question(`
1478
+ ${V}Enable Contacts management?${A} ${b(`[${km}]`)}: ${U}`)).trim().toLowerCase()||(Di?"y":"n");process.stdout.write(A);let Yn=rl==="y"||rl==="yes",je="",we={};if(Yn){let k=["carddav","google","microsoft"],v=k.indexOf(Di),N=v>=0?v+1:1;console.log(` ${ke("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${ke("2)")} Google Contacts`),console.log(` ${ke("3)")} Microsoft 365`);let Y=await Hn(l," > ",1,3,N);if(je=k[Y-1],we.ALFRED_CONTACTS_PROVIDER=je,je==="carddav"){let O=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Fe?.carddav?.serverUrl??"";we.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await H(l," CardDAV Server URL",O||"https://cloud.example.com/remote.php/dav");let X=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Fe?.carddav?.username??"";we.ALFRED_CARDDAV_CONTACTS_USERNAME=await H(l," Username",X);let oe=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Fe?.carddav?.password??"";oe&&console.log(` ${b(`Current password: ${be(oe)}`)}`);let ve=(await l.question(` ${V}Password${A}: ${U}`)).trim();process.stdout.write(A),we.ALFRED_CARDDAV_CONTACTS_PASSWORD=ve||oe}else if(je==="google"){let O=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Fe?.google?.clientId??"";O&&console.log(` ${b(`Current client ID: ${be(O)}`)}`),we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${V}Google Client ID${A}: ${U}`)).trim()||O,process.stdout.write(A);let X=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Fe?.google?.clientSecret??"";we.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${V}Google Client Secret${A}: ${U}`)).trim()||X,process.stdout.write(A);let oe=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Fe?.google?.refreshToken??"";we.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${V}Refresh Token${A}: ${U}`)).trim()||oe,process.stdout.write(A)}else if(je==="microsoft"){let O=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Fe?.microsoft?.clientId??"";O&&console.log(` ${b(`Current client ID: ${be(O)}`)}`),we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${V}Microsoft Client ID${A}: ${U}`)).trim()||O,process.stdout.write(A);let X=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Fe?.microsoft?.clientSecret??"";we.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${V}Microsoft Client Secret${A}: ${U}`)).trim()||X,process.stdout.write(A);let oe=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Fe?.microsoft?.tenantId??"";we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await H(l," Tenant ID",oe||"common");let ve=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Fe?.microsoft?.refreshToken??"";console.log(` ${b("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),we.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${V}Refresh Token${A}: ${U}`)).trim()||ve,process.stdout.write(A)}console.log(` ${P(">")} Contacts: ${D(je)}`)}else console.log(` ${b("Contacts disabled.")}`);let nl=t.config.docker,Mi=t.env.ALFRED_DOCKER_SOCKET_PATH??nl?.socketPath??"",Oi=t.env.ALFRED_DOCKER_HOST??nl?.host??"",bm=Mi||Oi?"Y/n":"y/N",ol=(await l.question(`
1479
+ ${V}Enable Docker management?${A} ${b(`[${bm}]`)}: ${U}`)).trim().toLowerCase()||(Mi||Oi?"y":"n");process.stdout.write(A);let Jn=ol==="y"||ol==="yes",Ct="",Nt="";if(Jn){let k=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${b("Use socket path for local Docker, or host URL for remote.")}`),Ct=await H(l," Docker socket path",Mi||k);let v=(await l.question(` ${V}Docker host URL (optional, for remote)${A}: ${U}`)).trim();process.stdout.write(A),Nt=v||Oi,console.log(` ${P(">")} Docker: ${D(Nt||Ct)}`)}else console.log(` ${b("Docker disabled.")}`);let Em=t.config.bmw,Pi=t.env.ALFRED_BMW_CLIENT_ID??Em?.clientId??"",Sm=Pi?"Y/n":"y/N",il=(await l.question(`
1480
+ ${V}Enable BMW CarData (vehicle status, charging)?${A} ${b(`[${Sm}]`)}: ${U}`)).trim().toLowerCase()||(Pi?"y":"n");process.stdout.write(A);let Zn=il==="y"||il==="yes",Ui="";Zn?(console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${b(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${b(" 3. Client-ID generieren")}`),console.log(` ${b(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),Ui=await H(l," BMW CarData Client ID",Pi),console.log(` ${P(">")} BMW CarData: ${D("enabled")}`)):console.log(` ${b("BMW CarData disabled.")}`);let $m=t.config.routing,Fi=t.env.ALFRED_ROUTING_API_KEY??$m?.apiKey??"",vm=Fi?"Y/n":"y/N",al=(await l.question(`
1481
+ ${V}Enable route planning with live traffic (Google Routes)?${A} ${b(`[${vm}]`)}: ${U}`)).trim().toLowerCase()||(Fi?"y":"n");process.stdout.write(A);let Qn=al==="y"||al==="yes",ji="";Qn?(console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${b(" 2. Routes API aktivieren")}`),console.log(` ${b(" 3. API Key erstellen")}`),ji=await H(l," Google Maps API Key",Fi),console.log(` ${P(">")} Routing: ${D("enabled")}`)):console.log(` ${b("Routing disabled.")}`);let cl=t.config.youtube,Bi=t.env.ALFRED_YOUTUBE_API_KEY??cl?.apiKey??"",Am=t.env.ALFRED_SUPADATA_API_KEY??cl?.supadata?.apiKey??"",Im=Bi?"Y/n":"y/N",ll=(await l.question(`
1482
+ ${V}Enable YouTube (search, video info, transcripts)?${A} ${b(`[${Im}]`)}: ${U}`)).trim().toLowerCase()||(Bi?"y":"n");process.stdout.write(A);let eo=ll==="y"||ll==="yes",Hi="",Lt="";if(eo){console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${b(" 2. YouTube Data API v3 aktivieren")}`),console.log(` ${b(" 3. API Key erstellen (gleicher Key wie f\xFCr Routing m\xF6glich)")}`),Hi=await H(l," YouTube API Key",Bi);let k=(await l.question(` ${V}Supadata API Key (optional, Transkript-Fallback)?${A} ${b("[Enter to skip]")}: ${U}`)).trim();process.stdout.write(A),Lt=k||Am,console.log(` ${P(">")} YouTube: ${D("enabled")}${Lt?" + Supadata Fallback":""}`)}else console.log(` ${b("YouTube disabled.")}`);let st=t.config.energy,Rm=t.env.ALFRED_ENERGY_GRID_NAME??st?.gridName??"",Wi=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(st?.gridUsageCt!=null?String(st.gridUsageCt):""),xm=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(st?.gridLossCt!=null?String(st.gridLossCt):""),Cm=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(st?.gridCapacityFee!=null?String(st.gridCapacityFee):""),Nm=t.env.ALFRED_ENERGY_GRID_METER_FEE??(st?.gridMeterFee!=null?String(st.gridMeterFee):""),Lm=Wi?"Y/n":"y/N",dl=(await l.question(`
1483
+ ${V}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${A} ${b(`[${Lm}]`)}: ${U}`)).trim().toLowerCase()||(Wi?"y":"n");process.stdout.write(A);let to=dl==="y"||dl==="yes",Dt="",Mt="",so="",Er="",Sr="";to?(console.log(` ${b('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${b("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),Dt=await H(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",Rm),Mt=await H(l," Netznutzungsentgelt (ct/kWh netto)",Wi),so=await H(l," Netzverlustentgelt (ct/kWh netto)",xm||"0.38"),Er=await H(l," Leistungspauschale (\u20AC/Monat netto)",Cm),Sr=await H(l," Messentgelt (\u20AC/Monat netto)",Nm||"2.22"),console.log(` ${P(">")} Energy: ${D(Dt||"enabled")} (${Mt} + ${so} ct/kWh)`)):console.log(` ${b("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
1484
+ ${D("Security configuration:")}`);let ul=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",xe;if(ul)xe=await H(l,"Owner user ID (for elevated permissions)",ul);else{let k=(await l.question(`${V}Owner user ID${A} ${b("(optional, for elevated permissions)")}: ${U}`)).trim();process.stdout.write(A),xe=k}let $r=!1;if(xe){let k=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${D("Enable shell access (admin commands) for the owner?")}`),console.log(` ${b("Allows Alfred to execute shell commands. Only for the owner.")}`);let v=(await l.question(` ${U}> ${A}${b(`[${k}] `)}`)).trim().toLowerCase();v===""?$r=t.shellEnabled:$r=v==="y"||v==="yes",console.log($r?` ${P(">")} Shell access ${D("enabled")} for owner ${b(xe)}`:` ${b("Shell access disabled.")}`)}let Dm=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${D("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${b("By default, write actions are only allowed in DMs.")}`);let zi=(await l.question(` ${U}> ${A}${b(`[${Dm}] `)}`)).trim().toLowerCase(),vr;zi===""?vr=t.writeInGroups:vr=zi==="y"||zi==="yes",console.log(vr?` ${P(">")} Write actions ${D("enabled")} in groups`:` ${b("Write actions only in DMs (default).")}`);let Mm=t.rateLimit??30;console.log("");let Om=await H(l," Rate limit (max write actions per hour per user)",String(Mm)),ro=Math.max(1,parseInt(Om,10)||30);console.log(` ${P(">")} Rate limit: ${D(String(ro))} per hour`),console.log(`
1485
+ ${D("Writing configuration files...")}`);let I=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let k=a.envKeyName||"ALFRED_OLLAMA_API_KEY";I.push(`${k}=${c}`)}if(f!==a.defaultModel&&I.push(`ALFRED_LLM_MODEL=${f}`),u&&I.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(R).length>0){I.push("","# === Additional Model Tiers ===");for(let[k,v]of Object.entries(R)){let N=`ALFRED_LLM_${k.toUpperCase()}`;I.push(""),I.push(`${N}_PROVIDER=${v.provider}`),I.push(`${N}_MODEL=${v.model}`),v.apiKey&&I.push(`${N}_API_KEY=${v.apiKey}`),v.baseUrl&&I.push(`${N}_BASE_URL=${v.baseUrl}`)}}I.push("","# === Messaging Platforms ===","");for(let[k,v]of Object.entries(Ue))I.push(`${k}=${v}`);if(I.push("","# === Web Search ===",""),ne?(I.push(`ALFRED_SEARCH_PROVIDER=${ne}`),ae&&I.push(`ALFRED_SEARCH_API_KEY=${ae}`),Q&&I.push(`ALFRED_SEARCH_BASE_URL=${Q}`)):(I.push("# ALFRED_SEARCH_PROVIDER=brave"),I.push("# ALFRED_SEARCH_API_KEY=")),I.push("","# === Email ===",""),K&&z.length>0){let k=z[0];k.provider==="microsoft"?(I.push("ALFRED_EMAIL_PROVIDER=microsoft"),k.msClientId?(I.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${k.msClientId}`),I.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${k.msClientSecret}`),I.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${k.msTenantId}`),I.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${k.msRefreshToken}`)):I.push("# Microsoft email credentials shared from calendar config")):(I.push(`ALFRED_EMAIL_USER=${k.user}`),I.push(`ALFRED_EMAIL_PASS=${k.pass}`)),z.length>1&&I.push("# Additional email accounts configured in config/default.yml")}else I.push("# ALFRED_EMAIL_USER="),I.push("# ALFRED_EMAIL_PASS=");if(I.push("","# === Speech ===",""),Je?(I.push(`ALFRED_SPEECH_PROVIDER=${Je}`),I.push(`ALFRED_SPEECH_API_KEY=${pt}`),cr&&I.push(`ALFRED_SPEECH_BASE_URL=${cr}`),lr&&(I.push("ALFRED_TTS_ENABLED=true"),I.push(`ALFRED_TTS_VOICE=${dr}`))):(I.push("# ALFRED_SPEECH_PROVIDER=groq"),I.push("# ALFRED_SPEECH_API_KEY=")),I.push("","# === Forge (GitHub / GitLab) ===",""),It==="github"?(I.push("ALFRED_FORGE_PROVIDER=github"),I.push(`ALFRED_GITHUB_TOKEN=${ur}`)):It==="gitlab"?(I.push("ALFRED_FORGE_PROVIDER=gitlab"),I.push(`ALFRED_GITLAB_TOKEN=${pr}`)):(I.push("# ALFRED_FORGE_PROVIDER=github"),I.push("# ALFRED_GITHUB_TOKEN=")),I.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),qn?(I.push(`ALFRED_PROXMOX_BASE_URL=${hr}`),I.push(`ALFRED_PROXMOX_TOKEN_ID=${$i}`),I.push(`ALFRED_PROXMOX_TOKEN_SECRET=${fr}`)):(I.push("# ALFRED_PROXMOX_BASE_URL="),I.push("# ALFRED_PROXMOX_TOKEN_ID="),I.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),Gn?(I.push(`ALFRED_PBS_BASE_URL=${gr}`),I.push(`ALFRED_PBS_TOKEN_ID=${Ii}`),I.push(`ALFRED_PBS_TOKEN_SECRET=${yr}`),I.push(`ALFRED_PBS_MAX_AGE_HOURS=${wr}`),Kn||I.push("ALFRED_PBS_VERIFY_TLS=false")):(I.push("# ALFRED_PBS_BASE_URL="),I.push("# ALFRED_PBS_TOKEN_ID="),I.push("# ALFRED_PBS_TOKEN_SECRET=")),Tr&&xt?(I.push(`ALFRED_UNIFI_BASE_URL=${es}`),I.push(`ALFRED_UNIFI_API_KEY=${xt}`)):Tr?(I.push(`ALFRED_UNIFI_BASE_URL=${es}`),I.push(`ALFRED_UNIFI_USERNAME=${xi}`),I.push(`ALFRED_UNIFI_PASSWORD=${_r}`)):(I.push("# ALFRED_UNIFI_BASE_URL="),I.push("# ALFRED_UNIFI_API_KEY=")),Vn?(I.push(`ALFRED_HOMEASSISTANT_URL=${kr}`),I.push(`ALFRED_HOMEASSISTANT_TOKEN=${br}`)):(I.push("# ALFRED_HOMEASSISTANT_URL="),I.push("# ALFRED_HOMEASSISTANT_TOKEN=")),I.push("","# === Contacts ===",""),Yn)for(let[k,v]of Object.entries(we))I.push(`${k}=${v}`);else I.push("# ALFRED_CONTACTS_PROVIDER=carddav");I.push("","# === Docker ===",""),Jn?(Ct&&I.push(`ALFRED_DOCKER_SOCKET_PATH=${Ct}`),Nt&&I.push(`ALFRED_DOCKER_HOST=${Nt}`)):(I.push("# ALFRED_DOCKER_SOCKET_PATH="),I.push("# ALFRED_DOCKER_HOST=")),I.push("","# === BMW CarData ===",""),Zn?I.push(`ALFRED_BMW_CLIENT_ID=${Ui}`):I.push("# ALFRED_BMW_CLIENT_ID="),I.push("","# === Routing ===",""),Qn?I.push(`ALFRED_ROUTING_API_KEY=${ji}`):I.push("# ALFRED_ROUTING_API_KEY="),I.push("","# === YouTube ===",""),eo?(I.push(`ALFRED_YOUTUBE_API_KEY=${Hi}`),Lt&&I.push(`ALFRED_SUPADATA_API_KEY=${Lt}`)):(I.push("# ALFRED_YOUTUBE_API_KEY="),I.push("# ALFRED_SUPADATA_API_KEY=")),I.push("","# === Energy / aWATTar ===",""),to&&Mt?(Dt&&I.push(`ALFRED_ENERGY_GRID_NAME=${Dt}`),I.push(`ALFRED_ENERGY_GRID_USAGE_CT=${Mt}`),I.push(`ALFRED_ENERGY_GRID_LOSS_CT=${so}`),Er&&I.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Er}`),Sr&&I.push(`ALFRED_ENERGY_GRID_METER_FEE=${Sr}`)):(I.push("# ALFRED_ENERGY_GRID_NAME="),I.push("# ALFRED_ENERGY_GRID_USAGE_CT="),I.push("# ALFRED_ENERGY_GRID_LOSS_CT="),I.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),I.push("# ALFRED_ENERGY_GRID_METER_FEE=")),I.push("","# === Security ===",""),xe?I.push(`ALFRED_OWNER_USER_ID=${xe}`):I.push("# ALFRED_OWNER_USER_ID="),I.push("");let Pm=Re.join(e,".env");Ee.writeFileSync(Pm,I.join(`
1486
+ `),"utf-8"),console.log(` ${P("+")} ${b(".env")} written`);let no=Re.join(e,"config");Ee.existsSync(no)||Ee.mkdirSync(no,{recursive:!0});let pl={name:r,telegram:{token:pe.telegram?.token??"",enabled:le.some(k=>k.name==="telegram")},discord:{token:pe.discord?.token??"",enabled:le.some(k=>k.name==="discord")},whatsapp:{enabled:le.some(k=>k.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:pe.matrix?.homeserverUrl??"https://matrix.org",accessToken:pe.matrix?.accessToken??"",userId:pe.matrix?.userId??"",enabled:le.some(k=>k.name==="matrix")},signal:{apiUrl:pe.signal?.apiUrl??"http://localhost:8080",phoneNumber:pe.signal?.phoneNumber??"",enabled:le.some(k=>k.name==="signal")},llm:Object.keys(R).length>0?{default:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...R}:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...ne?{search:{provider:ne,...ae?{apiKey:ae}:{},...Q?{baseUrl:Q}:{}}}:{},...K&&z.length>0?{email:{accounts:z.map(k=>k.provider==="microsoft"?{name:k.name,provider:"microsoft",...k.msClientId?{microsoft:{clientId:k.msClientId,clientSecret:k.msClientSecret,tenantId:k.msTenantId,refreshToken:k.msRefreshToken}}:{}}:{name:k.name,imap:{host:k.imapHost,port:k.imapPort,secure:k.imapPort===993},smtp:{host:k.smtpHost,port:k.smtpPort,secure:k.smtpPort===465},auth:{user:k.user,pass:k.pass}})}}:{},...Je?{speech:{provider:Je,apiKey:pt,...cr?{baseUrl:cr}:{},...lr?{ttsEnabled:!0,ttsVoice:dr}:{}}}:{},...yi?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...At.length>0||It?{codeAgents:{enabled:At.length>0,agents:At,...It==="github"?{forge:{provider:"github",github:{token:ur}}}:It==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:pr}}}:{}}}:{},...qn?{proxmox:{baseUrl:hr,tokenId:$i,tokenSecret:fr,verifyTls:vi}}:{},...Gn?{proxmoxBackup:{baseUrl:gr,tokenId:Ii,tokenSecret:yr,maxAgeHours:wr,verifyTls:Kn}}:{},...Tr?{unifi:{baseUrl:es,...xt?{apiKey:xt}:{username:xi,password:_r},site:"default",verifyTls:Ci}}:{},...Vn?{homeassistant:{baseUrl:kr,accessToken:br,verifyTls:Li}}:{},...Yn?{contacts:{provider:je,...je==="carddav"?{carddav:{serverUrl:we.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:we.ALFRED_CARDDAV_CONTACTS_USERNAME}}:je==="google"?{google:{clientId:we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:je==="microsoft"?{microsoft:{clientId:we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Jn?{docker:{...Ct?{socketPath:Ct}:{},...Nt?{host:Nt}:{}}}:{},...Zn?{bmw:{clientId:Ui}}:{},...Qn?{routing:{apiKey:ji}}:{},...eo?{youtube:{apiKey:Hi,...Lt?{supadata:{enabled:!0,apiKey:Lt}}:{}}}:{},...to&&Mt?{energy:{...Dt?{gridName:Dt}:{},gridUsageCt:parseFloat(Mt),gridLossCt:parseFloat(so||"0"),...Er?{gridCapacityFee:parseFloat(Er)}:{},...Sr?{gridMeterFee:parseFloat(Sr)}:{}}}:{},api:{enabled:!0,port:3420,host:"127.0.0.1",webUi:Ei,...zn?{tls:{enabled:!0}}:{}},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};xe&&(pl.security.ownerUserId=xe);let Um="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Gc.dump(pl,{lineWidth:120,noRefs:!0,sortKeys:!1}),Fm=Re.join(no,"default.yml");Ee.writeFileSync(Fm,Um,"utf-8"),console.log(` ${P("+")} ${b("config/default.yml")} written`);let qi=Re.join(no,"rules");Ee.existsSync(qi)||Ee.mkdirSync(qi,{recursive:!0});let jm=$r&&xe?`
1487
1487
  # Allow admin actions (shell, etc.) for the owner only
1488
1488
  - id: allow-owner-admin
1489
1489
  effect: allow
@@ -1533,7 +1533,7 @@ ${vr?` # Allow write-level skills everywhere (DMs and groups)
1533
1533
  conditions:
1534
1534
  chatType: dm`}
1535
1535
 
1536
- # Rate-limit write actions: max ${so} per hour per user
1536
+ # Rate-limit write actions: max ${ro} per hour per user
1537
1537
  - id: rate-limit-write
1538
1538
  effect: allow
1539
1539
  priority: 250
@@ -1541,7 +1541,7 @@ ${vr?` # Allow write-level skills everywhere (DMs and groups)
1541
1541
  actions: ["*"]
1542
1542
  riskLevels: [write]
1543
1543
  rateLimit:
1544
- maxInvocations: ${so}
1544
+ maxInvocations: ${ro}
1545
1545
  windowSeconds: 3600
1546
1546
  ${jm}
1547
1547
  # Deny destructive and admin actions by default
@@ -1559,14 +1559,14 @@ ${jm}
1559
1559
  scope: global
1560
1560
  actions: ["*"]
1561
1561
  riskLevels: [read, write, destructive, admin]
1562
- `,Hm=Re.join(qi,"default-rules.yml");Ee.writeFileSync(Hm,Bm,"utf-8"),console.log(` ${P("+")} ${b("config/rules/default-rules.yml")} written`);let ml=Re.join(e,"data");Ee.existsSync(ml)||(Ee.mkdirSync(ml,{recursive:!0}),console.log(` ${P("+")} ${b("data/")} directory created`)),console.log(""),console.log(`${pi}${"=".repeat(52)}${A}`),console.log(`${pi}${V} Setup complete!${A}`),console.log(`${pi}${"=".repeat(52)}${A}`),console.log(""),console.log(` ${D("Bot name:")} ${r}`),console.log(` ${D("LLM default:")} ${a.name} (${f})`),c&&console.log(` ${D("API key:")} ${be(c)}`);for(let[k,v]of Object.entries(R)){let N=k.charAt(0).toUpperCase()+k.slice(1);console.log(` ${D(`LLM ${N}:`)}${" ".repeat(Math.max(1,10-N.length))}${v.provider} (${v.model})`)}if(le.length>0?console.log(` ${D("Platforms:")} ${le.map(k=>k.label).join(", ")}`):console.log(` ${D("Platforms:")} none (configure later)`),ne){let k={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${Q})`};console.log(` ${D("Web search:")} ${k[ne]}`)}else console.log(` ${D("Web search:")} ${b("disabled")}`);if(K&&z.length>0){let k=z.map(v=>v.provider==="microsoft"?`${v.name} (Microsoft 365)${v.msClientId?"":" \u2014 shared from Calendar"}`:`${v.name} (${v.imapHost})`);console.log(` ${D("Email:")} ${k.join(", ")}`)}else console.log(` ${D("Email:")} ${b("disabled")}`);if(Je){let k={openai:"OpenAI Whisper",groq:"Groq Whisper"},v=lr?`, TTS: ${dr}`:"";console.log(` ${D("Voice:")} ${k[Je]}${v}`)}else console.log(` ${D("Voice:")} ${b("disabled")}`);console.log(` ${D("Code Sandbox:")} ${yi?P("enabled"):b("disabled")}`),console.log(` ${D("Web Chat UI:")} ${Ei?P("enabled (/alfred/)"):b("disabled")}`),console.log(` ${D("TLS/HTTPS:")} ${Wn?P("enabled (self-signed)"):b("disabled")}`),Qn&&console.log(` ${D("YouTube:")} ${P("enabled")}${Lt?" + Supadata":""}`),zn&&console.log(` ${D("Proxmox:")} ${P(hr)}`),qn&&console.log(` ${D("PBS:")} ${P(gr)} ${b(`(max age: ${wr}h)`)}`),Tr&&console.log(` ${D("UniFi:")} ${P(es)}`),Xn&&console.log(` ${D("Home Assist.:")} ${P(kr)}`),Vn&&console.log(` ${D("Contacts:")} ${P(je)}`),Yn&&console.log(` ${D("Docker:")} ${P(Nt||Ct)}`),Jn&&console.log(` ${D("BMW CarData:")} ${P("enabled")}`),Zn&&console.log(` ${D("Routing:")} ${P("enabled")}`),eo&&console.log(` ${D("Energy:")} ${P(Dt||"enabled")} ${b(`(${Mt} ct/kWh)`)}`),xe&&(console.log(` ${D("Owner ID:")} ${xe}`),console.log(` ${D("Shell access:")} ${$r?P("enabled"):b("disabled")}`)),console.log(` ${D("Write scope:")} ${vr?"DMs + Groups":"DMs only"}`),console.log(` ${D("Rate limit:")} ${so}/hour per user`),console.log(""),console.log(`${mi}Next steps:${A}`),console.log(` ${D("alfred start")} Start Alfred`),console.log(` ${D("alfred status")} Check configuration`),console.log(` ${D("alfred --help")} Show all commands`),console.log(""),console.log(`${St}Edit ${D(".env")}${St} or ${D("config/default.yml")}${St} for manual configuration.${A}`),console.log("")}finally{l.close()}}async function H(l,e,t){let s=(await l.question(`${V}${e}${A} ${b(`[${t}]`)}: ${U}`)).trim();return process.stdout.write(A),s||t}async function De(l,e){for(;;){let t=(await l.question(`${V}${e}${A}: ${U}`)).trim();if(process.stdout.write(A),t)return t;console.log(` ${Yp("!")} This field is required. Please enter a value.`)}}async function Bn(l,e,t,s,r){for(;;){let n=(await l.question(`${U}${e}${A}`)).trim();if(!n)return r;let o=parseInt(n,10);if(!Number.isNaN(o)&&o>=t&&o<=s)return o;console.log(` ${Yp("!")} Please enter a number between ${t} and ${s}.`)}}function gy(){console.log(`
1562
+ `,Hm=Re.join(qi,"default-rules.yml");Ee.writeFileSync(Hm,Bm,"utf-8"),console.log(` ${P("+")} ${b("config/rules/default-rules.yml")} written`);let ml=Re.join(e,"data");Ee.existsSync(ml)||(Ee.mkdirSync(ml,{recursive:!0}),console.log(` ${P("+")} ${b("data/")} directory created`)),console.log(""),console.log(`${pi}${"=".repeat(52)}${A}`),console.log(`${pi}${V} Setup complete!${A}`),console.log(`${pi}${"=".repeat(52)}${A}`),console.log(""),console.log(` ${D("Bot name:")} ${r}`),console.log(` ${D("LLM default:")} ${a.name} (${f})`),c&&console.log(` ${D("API key:")} ${be(c)}`);for(let[k,v]of Object.entries(R)){let N=k.charAt(0).toUpperCase()+k.slice(1);console.log(` ${D(`LLM ${N}:`)}${" ".repeat(Math.max(1,10-N.length))}${v.provider} (${v.model})`)}if(le.length>0?console.log(` ${D("Platforms:")} ${le.map(k=>k.label).join(", ")}`):console.log(` ${D("Platforms:")} none (configure later)`),ne){let k={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${Q})`};console.log(` ${D("Web search:")} ${k[ne]}`)}else console.log(` ${D("Web search:")} ${b("disabled")}`);if(K&&z.length>0){let k=z.map(v=>v.provider==="microsoft"?`${v.name} (Microsoft 365)${v.msClientId?"":" \u2014 shared from Calendar"}`:`${v.name} (${v.imapHost})`);console.log(` ${D("Email:")} ${k.join(", ")}`)}else console.log(` ${D("Email:")} ${b("disabled")}`);if(Je){let k={openai:"OpenAI Whisper",groq:"Groq Whisper"},v=lr?`, TTS: ${dr}`:"";console.log(` ${D("Voice:")} ${k[Je]}${v}`)}else console.log(` ${D("Voice:")} ${b("disabled")}`);console.log(` ${D("Code Sandbox:")} ${yi?P("enabled"):b("disabled")}`),console.log(` ${D("Web Chat UI:")} ${Ei?P("enabled (/alfred/)"):b("disabled")}`),console.log(` ${D("TLS/HTTPS:")} ${zn?P("enabled (self-signed)"):b("disabled")}`),eo&&console.log(` ${D("YouTube:")} ${P("enabled")}${Lt?" + Supadata":""}`),qn&&console.log(` ${D("Proxmox:")} ${P(hr)}`),Gn&&console.log(` ${D("PBS:")} ${P(gr)} ${b(`(max age: ${wr}h)`)}`),Tr&&console.log(` ${D("UniFi:")} ${P(es)}`),Vn&&console.log(` ${D("Home Assist.:")} ${P(kr)}`),Yn&&console.log(` ${D("Contacts:")} ${P(je)}`),Jn&&console.log(` ${D("Docker:")} ${P(Nt||Ct)}`),Zn&&console.log(` ${D("BMW CarData:")} ${P("enabled")}`),Qn&&console.log(` ${D("Routing:")} ${P("enabled")}`),to&&console.log(` ${D("Energy:")} ${P(Dt||"enabled")} ${b(`(${Mt} ct/kWh)`)}`),xe&&(console.log(` ${D("Owner ID:")} ${xe}`),console.log(` ${D("Shell access:")} ${$r?P("enabled"):b("disabled")}`)),console.log(` ${D("Write scope:")} ${vr?"DMs + Groups":"DMs only"}`),console.log(` ${D("Rate limit:")} ${ro}/hour per user`),console.log(""),console.log(`${mi}Next steps:${A}`),console.log(` ${D("alfred start")} Start Alfred`),console.log(` ${D("alfred status")} Check configuration`),console.log(` ${D("alfred --help")} Show all commands`),console.log(""),console.log(`${St}Edit ${D(".env")}${St} or ${D("config/default.yml")}${St} for manual configuration.${A}`),console.log("")}finally{l.close()}}async function H(l,e,t){let s=(await l.question(`${V}${e}${A} ${b(`[${t}]`)}: ${U}`)).trim();return process.stdout.write(A),s||t}async function De(l,e){for(;;){let t=(await l.question(`${V}${e}${A}: ${U}`)).trim();if(process.stdout.write(A),t)return t;console.log(` ${Yp("!")} This field is required. Please enter a value.`)}}async function Hn(l,e,t,s,r){for(;;){let n=(await l.question(`${U}${e}${A}`)).trim();if(!n)return r;let o=parseInt(n,10);if(!Number.isNaN(o)&&o>=t&&o<=s)return o;console.log(` ${Yp("!")} Please enter a number between ${t} and ${s}.`)}}function gy(){console.log(`
1563
1563
  ${uy}${V} _ _ _____ ____ _____ ____
1564
1564
  / \\ | | | ___| _ \\| ____| _ \\
1565
1565
  / _ \\ | | | |_ | |_) | _| | | | |
1566
1566
  / ___ \\| |___| _| | _ <| |___| |_| |
1567
1567
  /_/ \\_\\_____|_| |_| \\_\\_____|____/ ${A}
1568
1568
  ${St} Personal AI Assistant \u2014 Setup Wizard${A}
1569
- `)}var A,V,St,pi,U,mi,dy,uy,ut,or,Vp,Zp=T(()=>{"use strict";qc();A="\x1B[0m",V="\x1B[1m",St="\x1B[2m",pi="\x1B[32m",U="\x1B[33m",mi="\x1B[36m",dy="\x1B[31m",uy="\x1B[35m";p(P,"green");p(py,"yellow");p(ke,"cyan");p(Yp,"red");p(D,"bold");p(b,"dim");p(be,"maskKey");ut=[{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"}]}],or=[{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}]}];p(my,"findCommand");Vp=[{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"}];p(hy,"loadExistingConfig");p(fy,"setupCommand");p(H,"askWithDefault");p(De,"askRequired");p(Bn,"askNumber");p(gy,"printBanner")});var em={};me(em,{configCommand:()=>_y});function wy(l){let e=l.toLowerCase();return yy.some(t=>e.includes(t))}function Ty(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function Qp(l){let e={};for(let[t,s]of Object.entries(l))wy(t)?e[t]=Ty(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Qp(s):e[t]=s;return e}async function _y(){let l=new fe,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Qp(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var yy,tm=T(()=>{"use strict";ot();yy=["token","apikey","api_key","accesstoken","secret","password"];p(wy,"isSensitiveKey");p(Ty,"redactValue");p(Qp,"redactObject");p(_y,"configCommand")});var rm={};me(rm,{rulesCommand:()=>by});import hi from"node:fs";import sm from"node:path";import ky from"js-yaml";async function by(){let l=new fe,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=sm.resolve(e.security.rulesPath);if(!hi.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}hi.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=hi.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 at,o=[],i=[];for(let a of r){let c=sm.join(t,a);try{let d=hi.readFileSync(c,"utf-8"),u=ky.load(d),m=n.loadFromObject(u);o.push(...m)}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 nm=T(()=>{"use strict";ot();go();p(by,"rulesCommand")});var om={};me(om,{statusCommand:()=>Sy});import Hn from"node:fs";import Kc from"node:path";import Ey from"js-yaml";async function Sy(){let l=new fe,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=Kc.resolve(e.storage.path),n=Hn.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=Kc.resolve(e.security.rulesPath),i=0,a=0;if(Hn.existsSync(o)&&Hn.statSync(o).isDirectory()){let c=Hn.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new at;for(let u of c){let m=Kc.join(o,u);try{let h=Hn.readFileSync(m,"utf-8"),f=Ey.load(h),g=d.loadFromObject(f);i+=g.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 im=T(()=>{"use strict";ot();go();p(Sy,"statusCommand")});var lm={};me(lm,{authCommand:()=>jy});import{createServer as $y}from"node:http";import{exec as vy}from"node:child_process";import{readFileSync as Ay,writeFileSync as Iy,existsSync as Ry}from"node:fs";import{createInterface as xy}from"node:readline";import{resolve as Cy}from"node:path";async function Xc(l){let e=xy({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function Ly(){let l={};try{let s=new fe().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 Dy(){let l=Ly(),e=l.clientId||await Xc(" Client ID: "),t=l.clientSecret||await Xc(" Client Secret: "),s=l.tenantId||await Xc(' 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 My(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:am,response_mode:"query",scope:cm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function Oy(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:am,grant_type:"authorization_code",scope:cm}),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 Py(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&vy(t,()=>{})}function Uy(l,e){let t=Cy(process.cwd(),".env"),s=[];Ry(t)&&(s=Ay(t,"utf-8").split(`
1569
+ `)}var A,V,St,pi,U,mi,dy,uy,ut,or,Vp,Zp=T(()=>{"use strict";qc();A="\x1B[0m",V="\x1B[1m",St="\x1B[2m",pi="\x1B[32m",U="\x1B[33m",mi="\x1B[36m",dy="\x1B[31m",uy="\x1B[35m";p(P,"green");p(py,"yellow");p(ke,"cyan");p(Yp,"red");p(D,"bold");p(b,"dim");p(be,"maskKey");ut=[{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"}]}],or=[{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}]}];p(my,"findCommand");Vp=[{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"}];p(hy,"loadExistingConfig");p(fy,"setupCommand");p(H,"askWithDefault");p(De,"askRequired");p(Hn,"askNumber");p(gy,"printBanner")});var em={};me(em,{configCommand:()=>_y});function wy(l){let e=l.toLowerCase();return yy.some(t=>e.includes(t))}function Ty(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function Qp(l){let e={};for(let[t,s]of Object.entries(l))wy(t)?e[t]=Ty(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Qp(s):e[t]=s;return e}async function _y(){let l=new fe,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Qp(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var yy,tm=T(()=>{"use strict";ot();yy=["token","apikey","api_key","accesstoken","secret","password"];p(wy,"isSensitiveKey");p(Ty,"redactValue");p(Qp,"redactObject");p(_y,"configCommand")});var rm={};me(rm,{rulesCommand:()=>by});import hi from"node:fs";import sm from"node:path";import ky from"js-yaml";async function by(){let l=new fe,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=sm.resolve(e.security.rulesPath);if(!hi.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}hi.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=hi.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 at,o=[],i=[];for(let a of r){let c=sm.join(t,a);try{let d=hi.readFileSync(c,"utf-8"),u=ky.load(d),m=n.loadFromObject(u);o.push(...m)}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 nm=T(()=>{"use strict";ot();yo();p(by,"rulesCommand")});var om={};me(om,{statusCommand:()=>Sy});import Wn from"node:fs";import Kc from"node:path";import Ey from"js-yaml";async function Sy(){let l=new fe,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=Kc.resolve(e.storage.path),n=Wn.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=Kc.resolve(e.security.rulesPath),i=0,a=0;if(Wn.existsSync(o)&&Wn.statSync(o).isDirectory()){let c=Wn.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new at;for(let u of c){let m=Kc.join(o,u);try{let h=Wn.readFileSync(m,"utf-8"),f=Ey.load(h),g=d.loadFromObject(f);i+=g.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 im=T(()=>{"use strict";ot();yo();p(Sy,"statusCommand")});var lm={};me(lm,{authCommand:()=>jy});import{createServer as $y}from"node:http";import{exec as vy}from"node:child_process";import{readFileSync as Ay,writeFileSync as Iy,existsSync as Ry}from"node:fs";import{createInterface as xy}from"node:readline";import{resolve as Cy}from"node:path";async function Xc(l){let e=xy({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function Ly(){let l={};try{let s=new fe().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 Dy(){let l=Ly(),e=l.clientId||await Xc(" Client ID: "),t=l.clientSecret||await Xc(" Client Secret: "),s=l.tenantId||await Xc(' 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 My(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:am,response_mode:"query",scope:cm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function Oy(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:am,grant_type:"authorization_code",scope:cm}),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 Py(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&vy(t,()=>{})}function Uy(l,e){let t=Cy(process.cwd(),".env"),s=[];Ry(t)&&(s=Ay(t,"utf-8").split(`
1570
1570
  `));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(`
1571
1571
  `).replace(/\n*$/,`
1572
1572
  `);Iy(t,o)}function Fy(l){return new Promise((e,t)=>{let s=$y(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 Oy(i,l);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(Ny),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 jy(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 Dy(),t=My(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),Py(t);try{let s=await Fy(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),Uy(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(`
@@ -1575,7 +1575,7 @@ ${St} Personal AI Assistant \u2014 Setup Wizard${A}
1575
1575
  <style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0d1117;color:#e6edf3}
1576
1576
  .card{text-align:center;padding:2rem;border:1px solid #30363d;border-radius:12px;background:#161b22}
1577
1577
  h1{color:#3fb950;margin-bottom:.5rem}p{color:#8b949e}</style></head>
1578
- <body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;p(Xc,"askQuestion");p(Ly,"resolveCredentials");p(Dy,"ensureCredentials");p(My,"buildAuthUrl");p(Oy,"exchangeCode");p(Py,"openBrowser");p(Uy,"updateEnvFile");p(Fy,"waitForCallback");p(jy,"authCommand")});var um={};me(um,{logsCommand:()=>Wy});import By from"node:fs";import Hy from"node:path";async function Wy(l,e){let t=new fe,s;try{s=t.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let r=Hy.resolve(s.storage.path);if(!By.existsSync(r)){console.log(`Database not found at: ${r}`),console.log("No log entries. Alfred has not been run yet, or the database path is incorrect.");return}let n;try{n=new ht(r),e?.activity?qy(n,l,e):zy(n,l)}catch(o){console.error("Failed to read log:",o.message),process.exit(1)}finally{n&&n.close()}}function zy(l,e){let t=new ft(l.getDb()),s=t.count({}),r=t.query({limit:e});if(console.log("Alfred \u2014 Audit Log (Security)"),console.log("=============================="),console.log(`Total entries: ${s}`),console.log(`Showing last ${Math.min(e,s)} entries:`),console.log(""),r.length===0){console.log("No audit log entries found.");return}for(let n of r){let o=n.timestamp.toISOString(),i=n.effect==="allow"?"ALLOW":"DENY ";console.log(` ${o} [${i}] ${n.action}`),console.log(` user: ${n.userId} | platform: ${n.platform} | risk: ${n.riskLevel}`),n.ruleId&&console.log(` rule: ${n.ruleId}`),n.chatId&&console.log(` chat: ${n.chatId}`),n.context&&console.log(` context: ${JSON.stringify(n.context)}`),console.log("")}}function qy(l,e,t){let s=new yt(l.getDb());if(t.stats){let o=s.stats(t.since);if(console.log("Alfred \u2014 Activity Stats"),console.log("========================"),t.since&&console.log(`Since: ${t.since}`),console.log(""),o.length===0){console.log("No activity entries found.");return}let i=Math.max(...o.map(c=>c.eventType.length),10),a=Math.max(...o.map(c=>c.outcome.length),7);console.log(` ${"EVENT TYPE".padEnd(i)} ${"OUTCOME".padEnd(a)} COUNT`),console.log(` ${"\u2500".repeat(i)} ${"\u2500".repeat(a)} \u2500\u2500\u2500\u2500\u2500`);for(let c of o)console.log(` ${c.eventType.padEnd(i)} ${c.outcome.padEnd(a)} ${c.count}`);return}let r=s.count({eventType:t.type,source:t.source,outcome:t.outcome}),n=s.query({eventType:t.type,source:t.source,outcome:t.outcome,since:t.since,limit:e});if(console.log("Alfred \u2014 Activity Log"),console.log("======================"),console.log(`Total entries: ${r}`),t.type&&console.log(`Filter: type=${t.type}`),t.source&&console.log(`Filter: source=${t.source}`),t.outcome&&console.log(`Filter: outcome=${t.outcome}`),console.log(`Showing last ${Math.min(e,r)} entries:`),console.log(""),n.length===0){console.log("No activity entries found.");return}for(let o of n){let i=Gy(o.outcome),a=o.durationMs?` (${o.durationMs}ms)`:"";console.log(` ${o.timestamp} [${i}] ${o.eventType}: ${o.action}${a}`),console.log(` source: ${o.source}${o.sourceId?` (${o.sourceId.slice(0,8)})`:""} | platform: ${o.platform??"-"}`),o.userId&&console.log(` user: ${o.userId}`),o.errorMessage&&console.log(` error: ${o.errorMessage.slice(0,200)}`),o.details&&console.log(` details: ${JSON.stringify(o.details)}`),console.log("")}}function Gy(l){switch(l){case"success":return"\x1B[32mSUCCESS\x1B[0m";case"error":return"\x1B[31mERROR \x1B[0m";case"denied":return"\x1B[31mDENIED \x1B[0m";case"approved":return"\x1B[32mAPPROVED\x1B[0m";case"rejected":return"\x1B[33mREJECTED\x1B[0m";case"expired":return"\x1B[33mEXPIRED\x1B[0m";case"skipped":return"\x1B[90mSKIPPED\x1B[0m";default:return l.toUpperCase()}}var pm=T(()=>{"use strict";ot();mo();p(Wy,"logsCommand");p(zy,"showAuditLog");p(qy,"showActivityLog");p(Gy,"formatOutcome")});import{readFileSync as Ky}from"node:fs";import{fileURLToPath as Xy}from"node:url";import{dirname as Vy,join as Yy}from"node:path";function Jy(){try{let l=Vy(Xy(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(Ky(Yy(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}p(Jy,"getVersion");var mm=Jy(),Vc=`
1578
+ <body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;p(Xc,"askQuestion");p(Ly,"resolveCredentials");p(Dy,"ensureCredentials");p(My,"buildAuthUrl");p(Oy,"exchangeCode");p(Py,"openBrowser");p(Uy,"updateEnvFile");p(Fy,"waitForCallback");p(jy,"authCommand")});var um={};me(um,{logsCommand:()=>Wy});import By from"node:fs";import Hy from"node:path";async function Wy(l,e){let t=new fe,s;try{s=t.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let r=Hy.resolve(s.storage.path);if(!By.existsSync(r)){console.log(`Database not found at: ${r}`),console.log("No log entries. Alfred has not been run yet, or the database path is incorrect.");return}let n;try{n=new ht(r),e?.activity?qy(n,l,e):zy(n,l)}catch(o){console.error("Failed to read log:",o.message),process.exit(1)}finally{n&&n.close()}}function zy(l,e){let t=new ft(l.getDb()),s=t.count({}),r=t.query({limit:e});if(console.log("Alfred \u2014 Audit Log (Security)"),console.log("=============================="),console.log(`Total entries: ${s}`),console.log(`Showing last ${Math.min(e,s)} entries:`),console.log(""),r.length===0){console.log("No audit log entries found.");return}for(let n of r){let o=n.timestamp.toISOString(),i=n.effect==="allow"?"ALLOW":"DENY ";console.log(` ${o} [${i}] ${n.action}`),console.log(` user: ${n.userId} | platform: ${n.platform} | risk: ${n.riskLevel}`),n.ruleId&&console.log(` rule: ${n.ruleId}`),n.chatId&&console.log(` chat: ${n.chatId}`),n.context&&console.log(` context: ${JSON.stringify(n.context)}`),console.log("")}}function qy(l,e,t){let s=new yt(l.getDb());if(t.stats){let o=s.stats(t.since);if(console.log("Alfred \u2014 Activity Stats"),console.log("========================"),t.since&&console.log(`Since: ${t.since}`),console.log(""),o.length===0){console.log("No activity entries found.");return}let i=Math.max(...o.map(c=>c.eventType.length),10),a=Math.max(...o.map(c=>c.outcome.length),7);console.log(` ${"EVENT TYPE".padEnd(i)} ${"OUTCOME".padEnd(a)} COUNT`),console.log(` ${"\u2500".repeat(i)} ${"\u2500".repeat(a)} \u2500\u2500\u2500\u2500\u2500`);for(let c of o)console.log(` ${c.eventType.padEnd(i)} ${c.outcome.padEnd(a)} ${c.count}`);return}let r=s.count({eventType:t.type,source:t.source,outcome:t.outcome}),n=s.query({eventType:t.type,source:t.source,outcome:t.outcome,since:t.since,limit:e});if(console.log("Alfred \u2014 Activity Log"),console.log("======================"),console.log(`Total entries: ${r}`),t.type&&console.log(`Filter: type=${t.type}`),t.source&&console.log(`Filter: source=${t.source}`),t.outcome&&console.log(`Filter: outcome=${t.outcome}`),console.log(`Showing last ${Math.min(e,r)} entries:`),console.log(""),n.length===0){console.log("No activity entries found.");return}for(let o of n){let i=Gy(o.outcome),a=o.durationMs?` (${o.durationMs}ms)`:"";console.log(` ${o.timestamp} [${i}] ${o.eventType}: ${o.action}${a}`),console.log(` source: ${o.source}${o.sourceId?` (${o.sourceId.slice(0,8)})`:""} | platform: ${o.platform??"-"}`),o.userId&&console.log(` user: ${o.userId}`),o.errorMessage&&console.log(` error: ${o.errorMessage.slice(0,200)}`),o.details&&console.log(` details: ${JSON.stringify(o.details)}`),console.log("")}}function Gy(l){switch(l){case"success":return"\x1B[32mSUCCESS\x1B[0m";case"error":return"\x1B[31mERROR \x1B[0m";case"denied":return"\x1B[31mDENIED \x1B[0m";case"approved":return"\x1B[32mAPPROVED\x1B[0m";case"rejected":return"\x1B[33mREJECTED\x1B[0m";case"expired":return"\x1B[33mEXPIRED\x1B[0m";case"skipped":return"\x1B[90mSKIPPED\x1B[0m";default:return l.toUpperCase()}}var pm=T(()=>{"use strict";ot();ho();p(Wy,"logsCommand");p(zy,"showAuditLog");p(qy,"showActivityLog");p(Gy,"formatOutcome")});import{readFileSync as Ky}from"node:fs";import{fileURLToPath as Xy}from"node:url";import{dirname as Vy,join as Yy}from"node:path";function Jy(){try{let l=Vy(Xy(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(Ky(Yy(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}p(Jy,"getVersion");var mm=Jy(),Vc=`
1579
1579
  Alfred CLI v${mm}
1580
1580
  Personal AI Assistant
1581
1581