@madh-io/alfred-ai 0.10.74 → 0.10.75

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 +74 -74
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- var Pa=Object.defineProperty;var m=(l,e)=>Pa(l,"name",{value:e,configurable:!0}),Ua=(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 ue=(l,e)=>{for(var t in e)Pa(l,t,{get:e[t],enumerable:!0})};import{z as w}from"zod";var ja,Ba,Ha,za,qa,Wa,Ga,Va,_t,Pu,Uu,Fu,Fa,ju,Bu,Hu,zu,qu,Wu,Gu,Vu,Ku,Xu,Yu,Ju,Zu,Qu,em,tm,sm,rm,nm,om,im,am,cm,lm,dm,um,mm,pm,hm,Oo,Po=T(()=>{"use strict";ja=w.object({token:w.string().optional(),enabled:w.boolean()}),Ba=w.object({token:w.string().optional(),enabled:w.boolean()}),Ha=w.object({enabled:w.boolean(),dataPath:w.string()}),za=w.object({homeserverUrl:w.string(),accessToken:w.string().optional(),userId:w.string().optional(),enabled:w.boolean()}),qa=w.object({apiUrl:w.string(),phoneNumber:w.string().optional(),enabled:w.boolean()}),Wa=w.object({path:w.string()}),Ga=w.object({level:w.enum(["trace","debug","info","warn","error","fatal"]),pretty:w.boolean(),auditLogPath:w.string().optional()}),Va=w.object({rulesPath:w.string(),defaultEffect:w.enum(["allow","deny"]),ownerUserId:w.string().optional()}),_t=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()}),Pu=w.object({default:_t,strong:_t.optional(),fast:_t.optional(),embeddings:_t.optional(),local:_t.optional()}).passthrough(),Uu=w.union([_t,Pu]),Fu=w.object({provider:w.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:w.string().optional(),baseUrl:w.string().optional()}),Fa=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()}),ju=w.union([w.object({accounts:w.array(Fa)}),Fa]),Bu=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()}),Hu=w.object({serverUrl:w.string(),username:w.string(),password:w.string()}),zu=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),qu=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Wu=w.object({provider:w.enum(["caldav","google","microsoft"]),caldav:Hu.optional(),google:zu.optional(),microsoft:qu.optional()}),Gu=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()}),Vu=w.object({servers:w.array(Gu)}),Ku=w.object({enabled:w.boolean(),allowedLanguages:w.array(w.enum(["javascript","python"])).optional(),maxTimeoutMs:w.number().optional(),allowNetwork:w.boolean().optional()}),Xu=w.object({enabled:w.boolean().optional(),minMessageLength:w.number().optional(),minConfidence:w.number().min(0).max(1).optional(),maxExtractionsPerMinute:w.number().optional()}),Yu=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()}),Ju=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()}),Zu=w.object({token:w.string(),baseUrl:w.string().optional()}),Qu=w.object({token:w.string(),baseUrl:w.string().optional()}),em=w.object({provider:w.enum(["github","gitlab"]),baseBranch:w.string().optional(),github:Zu.optional(),gitlab:Qu.optional()}),tm=w.object({enabled:w.boolean(),agents:w.array(Ju),forge:em.optional()}),sm=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),verifyTls:w.boolean().optional(),defaultNode:w.string().optional()}),rm=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()}),nm=w.object({baseUrl:w.string(),accessToken:w.string(),verifyTls:w.boolean().optional()}),om=w.object({serverUrl:w.string(),username:w.string(),password:w.string(),addressBookPath:w.string().optional()}),im=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),am=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),cm=w.object({provider:w.enum(["carddav","google","microsoft"]),carddav:om.optional(),google:im.optional(),microsoft:am.optional()}),lm=w.object({socketPath:w.string().optional(),host:w.string().optional(),verifyTls:w.boolean().optional()}),dm=w.object({clientId:w.string()}),um=w.object({apiKey:w.string(),homeAddress:w.string().optional(),workAddress:w.string().optional()}),mm=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()}),pm=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),hm=w.object({maxHistoryMessages:w.number().min(10).max(500).optional()}).optional(),Oo=w.object({name:w.string(),telegram:ja,discord:Ba.optional(),whatsapp:Ha.optional(),matrix:za.optional(),signal:qa.optional(),llm:Uu,storage:Wa,logger:Ga,security:Va,search:Fu.optional(),email:ju.optional(),speech:Bu.optional(),calendar:Wu.optional(),mcp:Vu.optional(),codeSandbox:Ku.optional(),activeLearning:Xu.optional(),api:Yu.optional(),codeAgents:tm.optional(),proxmox:sm.optional(),unifi:rm.optional(),homeassistant:nm.optional(),contacts:cm.optional(),docker:lm.optional(),bmw:dm.optional(),routing:um.optional(),todo:pm.optional(),energy:mm.optional(),conversation:hm})});var Uo,Fo=T(()=>{"use strict";Uo={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 Ka from"node:fs";import fm from"node:path";import{config as Xa}from"dotenv";import gm from"js-yaml";function Ya(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]=Ya(n,r):t[s]=r}return t}function wm(l){let e={...l};for(let[t,s]of Object.entries(ym)){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]]=r}return e}function jo(){Xa({override:!0})}var ym,le,Ja=T(()=>{"use strict";Po();Fo();m(Ya,"deepMerge");ym={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],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_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_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],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_BMW_CLIENT_ID:["bmw","clientId"],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_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"]};m(wm,"applyEnvOverrides");m(jo,"reloadDotenv");le=class{static{m(this,"ConfigLoader")}loadConfig(e){Xa();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=fm.resolve(t);if(Ka.existsSync(r)){let f=Ka.readFileSync(r,"utf-8"),g=gm.load(f);g&&typeof g=="object"&&(s=g)}let n=Ya(Uo,s),o=wm(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[y,b]of Object.entries(a))!i.includes(y)&&y!=="default"&&(g[y]=b);let h={default:g};for(let y of i)a[y]&&(h[y]=a[y]);o.llm=h}let c=Oo.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 h=u[g];h&&!h.apiKey&&(h.apiKey=f)}}let p=c.email;if(p&&!("accounts"in p))c.email={accounts:[{name:"default",...p}]};else if(p&&"accounts"in p&&"microsoft"in p){let f=p.microsoft;if(f){let h=p.accounts.find(y=>y.provider==="microsoft");if(h){let y=h.microsoft??{};h.microsoft={...y,...f}}delete p.microsoft}}return c}}});var Xe=T(()=>{"use strict";Po();Fo();Ja()});import Bo from"pino";function js(l,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=Bo.transport({target:"pino-pretty",options:{colorize:!0}});return Bo({name:l,level:t,redact:Za},r)}return Bo({name:l,level:t,redact:Za})}var Za,Qa=T(()=>{"use strict";Za={paths:["*.apiKey","*.token","*.password","*.secret","*.accessToken","*.refreshToken","*.clientSecret","*.Authorization","*.authorization"],censor:"[REDACTED]"};m(js,"createLogger")});import Cf from"pino";var ec=T(()=>{"use strict"});var Ho=T(()=>{"use strict";Qa();ec()});var Ut,un=T(()=>{"use strict";Ut=class{static{m(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
2
+ var Pa=Object.defineProperty;var m=(l,e)=>Pa(l,"name",{value:e,configurable:!0}),Ua=(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 ue=(l,e)=>{for(var t in e)Pa(l,t,{get:e[t],enumerable:!0})};import{z as w}from"zod";var ja,Ba,Ha,qa,za,Wa,Ga,Va,_t,Pu,Uu,Fu,Fa,ju,Bu,Hu,qu,zu,Wu,Gu,Vu,Ku,Xu,Yu,Ju,Zu,Qu,em,tm,sm,rm,nm,om,im,am,cm,lm,dm,um,mm,pm,hm,Oo,Po=T(()=>{"use strict";ja=w.object({token:w.string().optional(),enabled:w.boolean()}),Ba=w.object({token:w.string().optional(),enabled:w.boolean()}),Ha=w.object({enabled:w.boolean(),dataPath:w.string()}),qa=w.object({homeserverUrl:w.string(),accessToken:w.string().optional(),userId:w.string().optional(),enabled:w.boolean()}),za=w.object({apiUrl:w.string(),phoneNumber:w.string().optional(),enabled:w.boolean()}),Wa=w.object({path:w.string()}),Ga=w.object({level:w.enum(["trace","debug","info","warn","error","fatal"]),pretty:w.boolean(),auditLogPath:w.string().optional()}),Va=w.object({rulesPath:w.string(),defaultEffect:w.enum(["allow","deny"]),ownerUserId:w.string().optional()}),_t=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()}),Pu=w.object({default:_t,strong:_t.optional(),fast:_t.optional(),embeddings:_t.optional(),local:_t.optional()}).passthrough(),Uu=w.union([_t,Pu]),Fu=w.object({provider:w.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:w.string().optional(),baseUrl:w.string().optional()}),Fa=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()}),ju=w.union([w.object({accounts:w.array(Fa)}),Fa]),Bu=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()}),Hu=w.object({serverUrl:w.string(),username:w.string(),password:w.string()}),qu=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),zu=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Wu=w.object({provider:w.enum(["caldav","google","microsoft"]),caldav:Hu.optional(),google:qu.optional(),microsoft:zu.optional()}),Gu=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()}),Vu=w.object({servers:w.array(Gu)}),Ku=w.object({enabled:w.boolean(),allowedLanguages:w.array(w.enum(["javascript","python"])).optional(),maxTimeoutMs:w.number().optional(),allowNetwork:w.boolean().optional()}),Xu=w.object({enabled:w.boolean().optional(),minMessageLength:w.number().optional(),minConfidence:w.number().min(0).max(1).optional(),maxExtractionsPerMinute:w.number().optional()}),Yu=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()}),Ju=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()}),Zu=w.object({token:w.string(),baseUrl:w.string().optional()}),Qu=w.object({token:w.string(),baseUrl:w.string().optional()}),em=w.object({provider:w.enum(["github","gitlab"]),baseBranch:w.string().optional(),github:Zu.optional(),gitlab:Qu.optional()}),tm=w.object({enabled:w.boolean(),agents:w.array(Ju),forge:em.optional()}),sm=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),verifyTls:w.boolean().optional(),defaultNode:w.string().optional()}),rm=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()}),nm=w.object({baseUrl:w.string(),accessToken:w.string(),verifyTls:w.boolean().optional()}),om=w.object({serverUrl:w.string(),username:w.string(),password:w.string(),addressBookPath:w.string().optional()}),im=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),am=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),cm=w.object({provider:w.enum(["carddav","google","microsoft"]),carddav:om.optional(),google:im.optional(),microsoft:am.optional()}),lm=w.object({socketPath:w.string().optional(),host:w.string().optional(),verifyTls:w.boolean().optional()}),dm=w.object({clientId:w.string()}),um=w.object({apiKey:w.string(),homeAddress:w.string().optional(),workAddress:w.string().optional()}),mm=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()}),pm=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),hm=w.object({maxHistoryMessages:w.number().min(10).max(500).optional()}).optional(),Oo=w.object({name:w.string(),telegram:ja,discord:Ba.optional(),whatsapp:Ha.optional(),matrix:qa.optional(),signal:za.optional(),llm:Uu,storage:Wa,logger:Ga,security:Va,search:Fu.optional(),email:ju.optional(),speech:Bu.optional(),calendar:Wu.optional(),mcp:Vu.optional(),codeSandbox:Ku.optional(),activeLearning:Xu.optional(),api:Yu.optional(),codeAgents:tm.optional(),proxmox:sm.optional(),unifi:rm.optional(),homeassistant:nm.optional(),contacts:cm.optional(),docker:lm.optional(),bmw:dm.optional(),routing:um.optional(),todo:pm.optional(),energy:mm.optional(),conversation:hm})});var Uo,Fo=T(()=>{"use strict";Uo={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 Ka from"node:fs";import fm from"node:path";import{config as Xa}from"dotenv";import gm from"js-yaml";function Ya(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]=Ya(n,r):t[s]=r}return t}function wm(l){let e={...l};for(let[t,s]of Object.entries(ym)){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]]=r}return e}function jo(){Xa({override:!0})}var ym,le,Ja=T(()=>{"use strict";Po();Fo();m(Ya,"deepMerge");ym={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],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_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_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],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_BMW_CLIENT_ID:["bmw","clientId"],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_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"]};m(wm,"applyEnvOverrides");m(jo,"reloadDotenv");le=class{static{m(this,"ConfigLoader")}loadConfig(e){Xa();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=fm.resolve(t);if(Ka.existsSync(r)){let f=Ka.readFileSync(r,"utf-8"),g=gm.load(f);g&&typeof g=="object"&&(s=g)}let n=Ya(Uo,s),o=wm(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[y,b]of Object.entries(a))!i.includes(y)&&y!=="default"&&(g[y]=b);let h={default:g};for(let y of i)a[y]&&(h[y]=a[y]);o.llm=h}let c=Oo.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 h=u[g];h&&!h.apiKey&&(h.apiKey=f)}}let p=c.email;if(p&&!("accounts"in p))c.email={accounts:[{name:"default",...p}]};else if(p&&"accounts"in p&&"microsoft"in p){let f=p.microsoft;if(f){let h=p.accounts.find(y=>y.provider==="microsoft");if(h){let y=h.microsoft??{};h.microsoft={...y,...f}}delete p.microsoft}}return c}}});var Xe=T(()=>{"use strict";Po();Fo();Ja()});import Bo from"pino";function js(l,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=Bo.transport({target:"pino-pretty",options:{colorize:!0}});return Bo({name:l,level:t,redact:Za},r)}return Bo({name:l,level:t,redact:Za})}var Za,Qa=T(()=>{"use strict";Za={paths:["*.apiKey","*.token","*.password","*.secret","*.accessToken","*.refreshToken","*.clientSecret","*.Authorization","*.authorization"],censor:"[REDACTED]"};m(js,"createLogger")});import Cf from"pino";var ec=T(()=>{"use strict"});var Ho=T(()=>{"use strict";Qa();ec()});var Ut,un=T(()=>{"use strict";Ut=class{static{m(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 zo,qo=T(()=>{"use strict";un();zo=[{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 qo,zo=T(()=>{"use strict";un();qo=[{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,
@@ -260,7 +260,7 @@ var Pa=Object.defineProperty;var m=(l,e)=>Pa(l,"name",{value:e,configurable:!0})
260
260
  UNIQUE(date, model)
261
261
  );
262
262
  CREATE INDEX IF NOT EXISTS idx_llm_usage_date ON llm_usage(date);
263
- `)}}]});import tc from"better-sqlite3";import Bs from"node:fs";import mn from"node:path";var Tt,sc=T(()=>{"use strict";un();qo();Tt=class{static{m(this,"Database")}db;constructor(e){let t=mn.dirname(e);Bs.mkdirSync(t,{recursive:!0});let s=Bs.statSync(e,{throwIfNoEntry:!1});if(s&&s.size>1e5){let r=mn.join(mn.dirname(e),"backups");Bs.mkdirSync(r,{recursive:!0});let n=mn.join(r,`alfred-${new Date().toISOString().slice(0,10)}.db`);if(!Bs.existsSync(n))try{let o=new tc(e,{readonly:!0});try{o.pragma("wal_checkpoint(TRUNCATE)")}catch{}o.close(),Bs.copyFileSync(e,n)}catch{}}this.db=new tc(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(`
263
+ `)}}]});import tc from"better-sqlite3";import Bs from"node:fs";import mn from"node:path";var Tt,sc=T(()=>{"use strict";un();zo();Tt=class{static{m(this,"Database")}db;constructor(e){let t=mn.dirname(e);Bs.mkdirSync(t,{recursive:!0});let s=Bs.statSync(e,{throwIfNoEntry:!1});if(s&&s.size>1e5){let r=mn.join(mn.dirname(e),"backups");Bs.mkdirSync(r,{recursive:!0});let n=mn.join(r,`alfred-${new Date().toISOString().slice(0,10)}.db`);if(!Bs.existsSync(n))try{let o=new tc(e,{readonly:!0});try{o.pragma("wal_checkpoint(TRUNCATE)")}catch{}o.close(),Bs.copyFileSync(e,n)}catch{}}this.db=new tc(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(`
264
264
  CREATE TABLE IF NOT EXISTS conversations (
265
265
  id TEXT PRIMARY KEY,
266
266
  platform TEXT NOT NULL,
@@ -310,7 +310,7 @@ var Pa=Object.defineProperty;var m=(l,e)=>Pa(l,"name",{value:e,configurable:!0})
310
310
 
311
311
  CREATE UNIQUE INDEX IF NOT EXISTS idx_users_platform
312
312
  ON users(platform, platform_user_id);
313
- `)}runMigrations(){new Ut(this.db).migrate(zo)}getDb(){return this.db}close(){this.db.close()}}});import rc from"node:crypto";var Hs,nc=T(()=>{"use strict";Hs=class{static{m(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),n={id:rc.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
313
+ `)}runMigrations(){new Ut(this.db).migrate(qo)}getDb(){return this.db}close(){this.db.close()}}});import rc from"node:crypto";var Hs,nc=T(()=>{"use strict";Hs=class{static{m(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),n={id:rc.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
314
314
  INSERT INTO conversations (id, platform, chat_id, user_id, created_at, updated_at)
315
315
  VALUES (?, ?, ?, ?, ?, ?)
316
316
  `).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:rc.randomUUID(),conversationId:e,role:t,content:s,toolCalls:r,createdAt:new Date().toISOString()};return this.db.prepare(`
@@ -320,13 +320,13 @@ var Pa=Object.defineProperty;var m=(l,e)=>Pa(l,"name",{value:e,configurable:!0})
320
320
  DELETE FROM messages WHERE conversation_id = ? AND id NOT IN (
321
321
  SELECT id FROM messages WHERE conversation_id = ? ORDER BY created_at DESC LIMIT ?
322
322
  )
323
- `).run(e,e,t).changes}mapRow(e){return{id:e.id,platform:e.platform,chatId:e.chat_id,userId:e.user_id,createdAt:e.created_at,updatedAt:e.updated_at}}}});import _m from"node:crypto";var zs,oc=T(()=>{"use strict";zs=class{static{m(this,"UserRepository")}db;constructor(e){this.db=e}findOrCreate(e,t,s,r){let n=this.db.prepare("SELECT * FROM users WHERE platform = ? AND platform_user_id = ?").get(e,t);if(n)return this.mapRow(n);let o=new Date().toISOString(),i={id:_m.randomUUID(),platform:e,platformUserId:t,username:s,displayName:r,createdAt:o,updatedAt:o};return this.db.prepare(`
323
+ `).run(e,e,t).changes}mapRow(e){return{id:e.id,platform:e.platform,chatId:e.chat_id,userId:e.user_id,createdAt:e.created_at,updatedAt:e.updated_at}}}});import _m from"node:crypto";var qs,oc=T(()=>{"use strict";qs=class{static{m(this,"UserRepository")}db;constructor(e){this.db=e}findOrCreate(e,t,s,r){let n=this.db.prepare("SELECT * FROM users WHERE platform = ? AND platform_user_id = ?").get(e,t);if(n)return this.mapRow(n);let o=new Date().toISOString(),i={id:_m.randomUUID(),platform:e,platformUserId:t,username:s,displayName:r,createdAt:o,updatedAt:o};return this.db.prepare(`
324
324
  INSERT INTO users (id, platform, platform_user_id, username, display_name, created_at, updated_at)
325
325
  VALUES (?, ?, ?, ?, ?, ?, ?)
326
326
  `).run(i.id,i.platform,i.platformUserId,i.username??null,i.displayName??null,i.createdAt,i.updatedAt),i}findById(e){let t=this.db.prepare("SELECT * FROM users WHERE id = ?").get(e);if(t)return this.mapRow(t)}update(e,t){let s=[],r=[];t.username!==void 0&&(s.push("username = ?"),r.push(t.username??null)),t.displayName!==void 0&&(s.push("display_name = ?"),r.push(t.displayName??null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}updateProfile(e,t){let s=[],r=[];t.timezone!==void 0&&(s.push("timezone = ?"),r.push(t.timezone??null)),t.language!==void 0&&(s.push("language = ?"),r.push(t.language??null)),t.bio!==void 0&&(s.push("bio = ?"),r.push(t.bio??null)),t.preferences!==void 0&&(s.push("preferences = ?"),r.push(t.preferences?JSON.stringify(t.preferences):null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}getProfile(e){let t=this.db.prepare("SELECT display_name, timezone, language, bio, preferences FROM users WHERE id = ?").get(e);if(t)return{displayName:t.display_name??void 0,timezone:t.timezone??void 0,language:t.language??void 0,bio:t.bio??void 0,preferences:t.preferences?JSON.parse(t.preferences):void 0}}setMasterUser(e,t){this.db.prepare("UPDATE users SET master_user_id = ?, updated_at = ? WHERE id = ?").run(t,new Date().toISOString(),e)}getLinkedUsers(e){return this.db.prepare("SELECT DISTINCT * FROM users WHERE master_user_id = ? OR id = ?").all(e,e).map(s=>this.mapRow(s))}findFirstByPlatformNotIn(e){let t=e.map(()=>"?").join(", "),s=this.db.prepare(`SELECT * FROM users WHERE platform NOT IN (${t}) LIMIT 1`).get(...e);if(s)return this.mapRow(s)}getMasterUserId(e){return this.db.prepare("SELECT master_user_id FROM users WHERE id = ?").get(e)?.master_user_id??e}mapRow(e){return{id:e.id,platform:e.platform,platformUserId:e.platform_user_id,username:e.username??void 0,displayName:e.display_name??void 0,timezone:e.timezone??void 0,language:e.language??void 0,bio:e.bio??void 0,preferences:e.preferences?JSON.parse(e.preferences):void 0,masterUserId:e.master_user_id??void 0,createdAt:e.created_at,updatedAt:e.updated_at}}}});var Et,ic=T(()=>{"use strict";Et=class{static{m(this,"AuditRepository")}db;constructor(e){this.db=e}log(e){this.db.prepare(`
327
327
  INSERT INTO audit_log (id, timestamp, user_id, action, risk_level, rule_id, effect, platform, chat_id, context)
328
328
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
329
- `).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return s.push(n),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}mapRow(e){return{id:e.id,timestamp:new Date(e.timestamp),userId:e.user_id,action:e.action,riskLevel:e.risk_level,ruleId:e.rule_id??void 0,effect:e.effect,platform:e.platform,chatId:e.chat_id??void 0,context:e.context?JSON.parse(e.context):void 0}}}});import{randomUUID as Tm}from"node:crypto";var qs,ac=T(()=>{"use strict";qs=class{static{m(this,"MemoryRepository")}db;constructor(e){this.db=e}save(e,t,s,r="general"){return this.saveWithMetadata(e,t,s,r,"general",1,"manual")}saveWithMetadata(e,t,s,r,n,o,i){let a=new Date().toISOString(),c=Tm();this.db.prepare(`INSERT INTO memories (id, user_id, key, value, category, type, confidence, source, created_at, updated_at)
329
+ `).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return s.push(n),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}mapRow(e){return{id:e.id,timestamp:new Date(e.timestamp),userId:e.user_id,action:e.action,riskLevel:e.risk_level,ruleId:e.rule_id??void 0,effect:e.effect,platform:e.platform,chatId:e.chat_id??void 0,context:e.context?JSON.parse(e.context):void 0}}}});import{randomUUID as Tm}from"node:crypto";var zs,ac=T(()=>{"use strict";zs=class{static{m(this,"MemoryRepository")}db;constructor(e){this.db=e}save(e,t,s,r="general"){return this.saveWithMetadata(e,t,s,r,"general",1,"manual")}saveWithMetadata(e,t,s,r,n,o,i){let a=new Date().toISOString(),c=Tm();this.db.prepare(`INSERT INTO memories (id, user_id, key, value, category, type, confidence, source, created_at, updated_at)
330
330
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
331
331
  ON CONFLICT(user_id, key) DO UPDATE SET
332
332
  value = excluded.value,
@@ -425,9 +425,9 @@ var Pa=Object.defineProperty;var m=(l,e)=>Pa(l,"name",{value:e,configurable:!0})
425
425
  SUM(cache_write_tokens) as cache_write_tokens,
426
426
  SUM(cost_usd) as cost_usd
427
427
  FROM llm_usage GROUP BY model
428
- `)}record(e,t,s,r,n,o){let i=new Date().toISOString().slice(0,10);this.stmtUpsert.run(i,e,1,t,s,r,n,o)}getDaily(e){let t=this.stmtDaily.all(e);return this.buildSummary(e,t)}getRange(e,t){let s=this.stmtRange.all(e,t),r=new Map;for(let n of s){let o=n.date;r.has(o)||r.set(o,[]),r.get(o).push(n)}return[...r.entries()].map(([n,o])=>this.buildSummary(n,o))}getTotal(){return this.stmtTotal.all().map(t=>this.mapRow(t))}buildSummary(e,t){let s=t.map(r=>this.mapRow(r));return{date:e,models:s,totalCalls:s.reduce((r,n)=>r+n.calls,0),totalInputTokens:s.reduce((r,n)=>r+n.inputTokens,0),totalOutputTokens:s.reduce((r,n)=>r+n.outputTokens,0),totalCostUsd:Math.round(s.reduce((r,n)=>r+n.costUsd,0)*1e6)/1e6}}mapRow(e){return{model:e.model,calls:e.calls,inputTokens:e.input_tokens,outputTokens:e.output_tokens,cacheReadTokens:e.cache_read_tokens,cacheWriteTokens:e.cache_write_tokens,costUsd:e.cost_usd}}}});var Wo=T(()=>{"use strict";sc();nc();oc();ic();ac();un();qo();cc();lc();dc();uc();mc();pc();fc();gc();yc();wc();_c()});function Ye(l){if(Go[l])return Go[l];let e=Object.entries(Go).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Go,Rm,ve,bt=T(()=>{"use strict";Go={"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}},Rm={maxInputTokens:128e3,maxOutputTokens:8192};m(Ye,"lookupContextWindow");ve=class{static{m(this,"LLMProvider")}config;contextWindow=Rm;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import xm from"@anthropic-ai/sdk";var sr,Vo=T(()=>{"use strict";bt();sr=class extends ve{static{m(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new xm({apiKey:this.config.apiKey,maxRetries:5});let e=Ye(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 Cm from"openai";var Ne,Ft=T(()=>{"use strict";bt();Ne=class extends ve{static{m(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Cm({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=Ye(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,p=0;for await(let f of r){let g=f.choices[0];if(!g)continue;let h=g.delta;if(h?.content&&(a+=h.content,yield{type:"text_delta",text:h.content}),h?.tool_calls)for(let y of h.tool_calls)if(y.id){if(n){let b;try{b=JSON.parse(i||"{}")}catch{b={}}c.push({id:n,name:o,input:b})}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}});g.finish_reason&&(d=g.finish_reason),f.usage&&(u=f.usage.prompt_tokens,p=f.usage.completion_tokens)}if(n){let f;try{f=JSON.parse(i||"{}")}catch{f={}}c.push({id:n,name:o,input:f})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:p},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{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 rr,Ko=T(()=>{"use strict";Ft();rr=class extends Ne{static{m(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var nr,Xo=T(()=>{"use strict";bt();nr=class extends ve{static{m(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=Ye(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 f=await n.text();throw new Error(`Ollama API error (${n.status}): ${f}`)}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,p=[];try{for(;;){let{done:f,value:g}=await o.read();if(f)break;a+=i.decode(g,{stream:!0});let h=a.split(`
428
+ `)}record(e,t,s,r,n,o){let i=new Date().toISOString().slice(0,10);this.stmtUpsert.run(i,e,1,t,s,r,n,o)}getDaily(e){let t=this.stmtDaily.all(e);return this.buildSummary(e,t)}getRange(e,t){let s=this.stmtRange.all(e,t),r=new Map;for(let n of s){let o=n.date;r.has(o)||r.set(o,[]),r.get(o).push(n)}return[...r.entries()].map(([n,o])=>this.buildSummary(n,o))}getTotal(){return this.stmtTotal.all().map(t=>this.mapRow(t))}buildSummary(e,t){let s=t.map(r=>this.mapRow(r));return{date:e,models:s,totalCalls:s.reduce((r,n)=>r+n.calls,0),totalInputTokens:s.reduce((r,n)=>r+n.inputTokens,0),totalOutputTokens:s.reduce((r,n)=>r+n.outputTokens,0),totalCostUsd:Math.round(s.reduce((r,n)=>r+n.costUsd,0)*1e6)/1e6}}mapRow(e){return{model:e.model,calls:e.calls,inputTokens:e.input_tokens,outputTokens:e.output_tokens,cacheReadTokens:e.cache_read_tokens,cacheWriteTokens:e.cache_write_tokens,costUsd:e.cost_usd}}}});var Wo=T(()=>{"use strict";sc();nc();oc();ic();ac();un();zo();cc();lc();dc();uc();mc();pc();fc();gc();yc();wc();_c()});function Ye(l){if(Go[l])return Go[l];let e=Object.entries(Go).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Go,Rm,ve,bt=T(()=>{"use strict";Go={"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}},Rm={maxInputTokens:128e3,maxOutputTokens:8192};m(Ye,"lookupContextWindow");ve=class{static{m(this,"LLMProvider")}config;contextWindow=Rm;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import xm from"@anthropic-ai/sdk";var sr,Vo=T(()=>{"use strict";bt();sr=class extends ve{static{m(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new xm({apiKey:this.config.apiKey,maxRetries:5});let e=Ye(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 Cm from"openai";var Ne,Ft=T(()=>{"use strict";bt();Ne=class extends ve{static{m(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Cm({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=Ye(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,p=0;for await(let f of r){let g=f.choices[0];if(!g)continue;let h=g.delta;if(h?.content&&(a+=h.content,yield{type:"text_delta",text:h.content}),h?.tool_calls)for(let y of h.tool_calls)if(y.id){if(n){let b;try{b=JSON.parse(i||"{}")}catch{b={}}c.push({id:n,name:o,input:b})}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}});g.finish_reason&&(d=g.finish_reason),f.usage&&(u=f.usage.prompt_tokens,p=f.usage.completion_tokens)}if(n){let f;try{f=JSON.parse(i||"{}")}catch{f={}}c.push({id:n,name:o,input:f})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:p},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{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 rr,Ko=T(()=>{"use strict";Ft();rr=class extends Ne{static{m(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var nr,Xo=T(()=>{"use strict";bt();nr=class extends ve{static{m(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=Ye(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 f=await n.text();throw new Error(`Ollama API error (${n.status}): ${f}`)}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,p=[];try{for(;;){let{done:f,value:g}=await o.read();if(f)break;a+=i.decode(g,{stream:!0});let h=a.split(`
429
429
  `);a=h.pop()??"";for(let y of h){let b=y.trim();if(!b)continue;let k;try{k=JSON.parse(b)}catch{continue}if(k.message?.content&&(c+=k.message.content,yield{type:"text_delta",text:k.message.content}),k.message?.tool_calls)for(let S of k.message.tool_calls){let j={id:`ollama_tool_${p.length}`,name:S.function.name,input:S.function.arguments};p.push(j),yield{type:"tool_use_start",toolCall:{id:j.id,name:j.name}},yield{type:"tool_use_delta",toolCall:{input:j.input}}}k.done&&(d=k.prompt_eval_count??0,u=k.eval_count??0,yield{type:"message_complete",response:{content:c,model:this.config.model,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:p.length>0?"tool_use":"end_turn"}})}}if(a.trim()){let f;try{f=JSON.parse(a.trim())}catch{return}if(f.message?.content&&(c+=f.message.content,yield{type:"text_delta",text:f.message.content}),f.message?.tool_calls)for(let g of f.message.tool_calls){let h={id:`ollama_tool_${p.length}`,name:g.function.name,input:g.function.arguments};p.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}},yield{type:"tool_use_delta",toolCall:{input:h.input}}}f.done&&(d=f.prompt_eval_count??0,u=f.eval_count??0,yield{type:"message_complete",response:{content:c,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:p.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(`
430
- `)};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 or,Yo=T(()=>{"use strict";Ft();or=class extends Ne{static{m(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 Dm}from"@google/genai";var ir,Jo=T(()=>{"use strict";bt();ir=class extends ve{static{m(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Dm({apiKey:this.config.apiKey});let e=Ye(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 p of d.functionCalls){let f={id:p.id??`google_tool_${o.length}`,name:p.name,input:p.args??{}};o.push(f),yield{type:"tool_use_start",toolCall:{id:f.id,name:f.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 p=JSON.parse(c.content);u=typeof p=="object"&&p!==null?p:{result:p}}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)s.push(d);else{let u=[...i];for(let p=0;p<o.length;p++){let f=o[p];u.push({functionCall:{id:f.id,name:f.name,args:f.input},...p===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 ar,Zo=T(()=>{"use strict";Ft();ar=class extends Ne{static{m(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function Qo(l){switch(l.provider){case"anthropic":return new sr(l);case"openai":return new Ne(l);case"openrouter":return new rr(l);case"ollama":return new nr(l);case"openwebui":return new or(l);case"google":return new ir(l);case"mistral":return new ar(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var ei=T(()=>{"use strict";Vo();Ft();Ko();Xo();Yo();Jo();Zo();m(Qo,"createLLMProvider")});function Tc(l){let e=l.toLowerCase();for(let[t,s]of Lm)if(e.startsWith(t.toLowerCase()))return s}function pn(l,e){let t=Tc(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=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 Lm,cr,ti=T(()=>{"use strict";Lm=[["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}]];m(Tc,"getModelPricing");m(pn,"calculateCost");cr=class{static{m(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=pn(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 si(l,e){return new hn(l,e)}var Nm,hn,Ec=T(()=>{"use strict";bt();ei();ti();Nm=["default","strong","fast","embeddings","local"],hn=class extends ve{static{m(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new cr;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of Nm){let t=this.multiConfig[e];if(t){let s=Qo(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}}resolve(e){return e&&this.providers.has(e)?{provider:this.providers.get(e),resolvedTier:e}:{provider:this.providers.get("default"),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");let n=await t.complete(e),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:s,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}async*stream(e){let{provider:t}=this.resolve(e.tier);yield*t.stream(e)}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()}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};m(si,"createModelRouter")});function Me(l){return Math.ceil(l.length/3.5)}function kt(l){if(typeof l.content=="string")return Me(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=Me(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=Me(t.name)+Me(JSON.stringify(t.input));break;case"tool_result":e+=Me(t.content);break}return e}function ri(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(p=>{if(p.type!=="tool_result")return p;let f=p.content;if(typeof f!="string"||f.length<r)return p;d=!0;let g=n.get(p.tool_use_id)||"unknown",h=f.split(`
430
+ `)};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 or,Yo=T(()=>{"use strict";Ft();or=class extends Ne{static{m(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 Lm}from"@google/genai";var ir,Jo=T(()=>{"use strict";bt();ir=class extends ve{static{m(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Lm({apiKey:this.config.apiKey});let e=Ye(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 p of d.functionCalls){let f={id:p.id??`google_tool_${o.length}`,name:p.name,input:p.args??{}};o.push(f),yield{type:"tool_use_start",toolCall:{id:f.id,name:f.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 p=JSON.parse(c.content);u=typeof p=="object"&&p!==null?p:{result:p}}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)s.push(d);else{let u=[...i];for(let p=0;p<o.length;p++){let f=o[p];u.push({functionCall:{id:f.id,name:f.name,args:f.input},...p===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 ar,Zo=T(()=>{"use strict";Ft();ar=class extends Ne{static{m(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function Qo(l){switch(l.provider){case"anthropic":return new sr(l);case"openai":return new Ne(l);case"openrouter":return new rr(l);case"ollama":return new nr(l);case"openwebui":return new or(l);case"google":return new ir(l);case"mistral":return new ar(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var ei=T(()=>{"use strict";Vo();Ft();Ko();Xo();Yo();Jo();Zo();m(Qo,"createLLMProvider")});function Tc(l){let e=l.toLowerCase();for(let[t,s]of Dm)if(e.startsWith(t.toLowerCase()))return s}function pn(l,e){let t=Tc(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=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 Dm,cr,ti=T(()=>{"use strict";Dm=[["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}]];m(Tc,"getModelPricing");m(pn,"calculateCost");cr=class{static{m(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=pn(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 si(l,e){return new hn(l,e)}var Nm,hn,Ec=T(()=>{"use strict";bt();ei();ti();Nm=["default","strong","fast","embeddings","local"],hn=class extends ve{static{m(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new cr;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of Nm){let t=this.multiConfig[e];if(t){let s=Qo(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}}resolve(e){return e&&this.providers.has(e)?{provider:this.providers.get(e),resolvedTier:e}:{provider:this.providers.get("default"),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");let n=await t.complete(e),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:s,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}async*stream(e){let{provider:t}=this.resolve(e.tier);yield*t.stream(e)}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()}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};m(si,"createModelRouter")});function Me(l){return Math.ceil(l.length/3.5)}function kt(l){if(typeof l.content=="string")return Me(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=Me(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=Me(t.name)+Me(JSON.stringify(t.input));break;case"tool_result":e+=Me(t.content);break}return e}function ri(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(p=>{if(p.type!=="tool_result")return p;let f=p.content;if(typeof f!="string"||f.length<r)return p;d=!0;let g=n.get(p.tool_use_id)||"unknown",h=f.split(`
431
431
  `)[0].slice(0,s),y=p.is_error?"Fehler":"Ergebnis";return{...p,content:`[${y}: ${g} \u2014 ${h}]`}});return d?{...a,content:u}:a})}var lr,bc=T(()=>{"use strict";m(Me,"estimateTokens");m(kt,"estimateMessageTokens");m(ri,"trimOldToolResults");lr=class{static{m(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}).
432
432
 
433
433
  ## Core principles
@@ -494,13 +494,13 @@ This summarizes the earlier conversation. Use it to maintain continuity. The mos
494
494
  `;c+=`
495
495
  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+=`
496
496
 
497
- 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 ni=T(()=>{"use strict";bt();Vo();Ft();Ko();Xo();Yo();Jo();Zo();ei();Ec();bc();ti()});var dr,oi=T(()=>{"use strict";dr=class{static{m(this,"RateLimiter")}buckets=new Map;checkCount=0;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+r)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+r?this.buckets.set(e,{count:1,windowStart:s}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+36e5&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var ur,kc=T(()=>{"use strict";oi();ur=class{static{m(this,"RuleEngine")}rules=[];rateLimiter=new dr;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.check(r,e.rateLimit).allowed?(this.rateLimiter.increment(r,e.rateLimit),!0):!1}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&&t.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 $c,Sc,vc,$t,Ac=T(()=>{"use strict";$c=["allow","deny"],Sc=["global","user","conversation","platform"],vc=["read","write","destructive","admin"],$t=class{static{m(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"||!$c.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${$c.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"||!Sc.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Sc.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(!vc.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${vc.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`);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 Mm from"node:crypto";var mr,Ic=T(()=>{"use strict";mr=class{static{m(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:Mm.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 fn=T(()=>{"use strict";kc();oi();Ac();Ic()});var R,U=T(()=>{"use strict";R=class{static{m(this,"Skill")}}});function ae(l){return l.masterUserId??l.userId}function V(l){let e=new Set;if(e.add(ae(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Oe=T(()=>{"use strict";m(ae,"effectiveUserId");m(V,"allUserIds")});var jt,Rc=T(()=>{"use strict";jt=class{static{m(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 Bt,xc=T(()=>{"use strict";Bt=class{static{m(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,p=m(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),f=m(g=>{a||(a=!0,p(),i(g))},"finish");e.execute(t,s).then(g=>{this.logger.info({skill:r,success:g.success,...g.success?{}:{error:g.error}},"Skill execution completed"),f(g)},g=>{let h=g instanceof Error?g.message:String(g);this.logger.error({skill:r,error:h},"Skill execution failed"),f({success:!1,error:h})}),u=setTimeout(()=>{if(a)return;let g=o.getIdleMs();if(g>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:g,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),f({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(g/1e3)}s (last state: ${y.state})`});return}let h=o.getSnapshot();this.logger.info({skill:r,idleMs:g,state:h.state,iteration:h.iteration,totalMs:h.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){p();return}let y=o.getIdleMs(),b=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:b.state,iteration:b.iteration,totalMs:b.totalElapsedMs},"Agent went inactive \u2014 aborting"),f({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${b.state})`})):this.logger.debug({skill:r,idleMs:y,state:b.state,iteration:b.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let g=o.getSnapshot();this.logger.error({skill:r,totalMs:g.totalElapsedMs,state:g.state,iteration:g.iteration},"Absolute time limit reached \u2014 force killing agent"),f({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=await Promise.race([e.execute(t,s),new Promise((i,a)=>{setTimeout(()=>a(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]);return this.logger.info({skill:r,success:o.success,...o.success?{}:{error:o.error}},"Skill execution completed"),o}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 St,ii=T(()=>{"use strict";St=class{static{m(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 Om from"node:fs";import ai from"node:path";var gn,Cc=T(()=>{"use strict";U();gn=class{static{m(this,"PluginLoader")}async loadFromDirectory(e){let t=ai.resolve(e),s;try{s=await Om.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=ai.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=ai.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 R))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`)}}});var Pm,Um,Ht,Dc=T(()=>{"use strict";U();Pm=/Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)/g,Um=/^[\d+\-*/().,\s%]*(Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)[\d+\-*/().,\s(%)]*)*$/,Ht=class extends R{static{m(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();if(!Um.test(r))return{success:!1,error:`Invalid expression: "${r}" contains disallowed constructs`};let n=r.replace(Pm,"");if(/[a-zA-Z]/.test(n))return{success:!1,error:`Invalid expression: "${r}" contains disallowed identifiers`};try{let i=new Function("Math",`"use strict"; return (${r});`)(Math);return typeof i!="number"||!isFinite(i)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:i,display:`${r} = ${i}`}}catch{return{success:!1,error:`Invalid expression: "${r}"`}}}}});var zt,Lc=T(()=>{"use strict";U();zt=class extends R{static{m(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=m(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 qt,Nc=T(()=>{"use strict";U();qt=class extends R{static{m(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}**
497
+ 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 ni=T(()=>{"use strict";bt();Vo();Ft();Ko();Xo();Yo();Jo();Zo();ei();Ec();bc();ti()});var dr,oi=T(()=>{"use strict";dr=class{static{m(this,"RateLimiter")}buckets=new Map;checkCount=0;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+r)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+r?this.buckets.set(e,{count:1,windowStart:s}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+36e5&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var ur,kc=T(()=>{"use strict";oi();ur=class{static{m(this,"RuleEngine")}rules=[];rateLimiter=new dr;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.check(r,e.rateLimit).allowed?(this.rateLimiter.increment(r,e.rateLimit),!0):!1}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&&t.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 $c,Sc,vc,$t,Ac=T(()=>{"use strict";$c=["allow","deny"],Sc=["global","user","conversation","platform"],vc=["read","write","destructive","admin"],$t=class{static{m(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"||!$c.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${$c.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"||!Sc.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Sc.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(!vc.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${vc.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`);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 Mm from"node:crypto";var mr,Ic=T(()=>{"use strict";mr=class{static{m(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:Mm.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 fn=T(()=>{"use strict";kc();oi();Ac();Ic()});var R,U=T(()=>{"use strict";R=class{static{m(this,"Skill")}}});function ae(l){return l.masterUserId??l.userId}function V(l){let e=new Set;if(e.add(ae(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Oe=T(()=>{"use strict";m(ae,"effectiveUserId");m(V,"allUserIds")});var jt,Rc=T(()=>{"use strict";jt=class{static{m(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 Bt,xc=T(()=>{"use strict";Bt=class{static{m(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,p=m(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),f=m(g=>{a||(a=!0,p(),i(g))},"finish");e.execute(t,s).then(g=>{this.logger.info({skill:r,success:g.success,...g.success?{}:{error:g.error}},"Skill execution completed"),f(g)},g=>{let h=g instanceof Error?g.message:String(g);this.logger.error({skill:r,error:h},"Skill execution failed"),f({success:!1,error:h})}),u=setTimeout(()=>{if(a)return;let g=o.getIdleMs();if(g>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:g,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),f({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(g/1e3)}s (last state: ${y.state})`});return}let h=o.getSnapshot();this.logger.info({skill:r,idleMs:g,state:h.state,iteration:h.iteration,totalMs:h.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){p();return}let y=o.getIdleMs(),b=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:b.state,iteration:b.iteration,totalMs:b.totalElapsedMs},"Agent went inactive \u2014 aborting"),f({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${b.state})`})):this.logger.debug({skill:r,idleMs:y,state:b.state,iteration:b.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let g=o.getSnapshot();this.logger.error({skill:r,totalMs:g.totalElapsedMs,state:g.state,iteration:g.iteration},"Absolute time limit reached \u2014 force killing agent"),f({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=await Promise.race([e.execute(t,s),new Promise((i,a)=>{setTimeout(()=>a(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]);return this.logger.info({skill:r,success:o.success,...o.success?{}:{error:o.error}},"Skill execution completed"),o}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 St,ii=T(()=>{"use strict";St=class{static{m(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 Om from"node:fs";import ai from"node:path";var gn,Cc=T(()=>{"use strict";U();gn=class{static{m(this,"PluginLoader")}async loadFromDirectory(e){let t=ai.resolve(e),s;try{s=await Om.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=ai.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=ai.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 R))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`)}}});var Pm,Um,Ht,Lc=T(()=>{"use strict";U();Pm=/Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)/g,Um=/^[\d+\-*/().,\s%]*(Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)[\d+\-*/().,\s(%)]*)*$/,Ht=class extends R{static{m(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();if(!Um.test(r))return{success:!1,error:`Invalid expression: "${r}" contains disallowed constructs`};let n=r.replace(Pm,"");if(/[a-zA-Z]/.test(n))return{success:!1,error:`Invalid expression: "${r}" contains disallowed identifiers`};try{let i=new Function("Math",`"use strict"; return (${r});`)(Math);return typeof i!="number"||!isFinite(i)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:i,display:`${r} = ${i}`}}catch{return{success:!1,error:`Invalid expression: "${r}"`}}}}});var qt,Dc=T(()=>{"use strict";U();qt=class extends R{static{m(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=m(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 zt,Nc=T(()=>{"use strict";U();zt=class extends R{static{m(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}**
498
498
  ${a.url}
499
499
  ${a.snippet}`).join(`
500
500
 
501
501
  `);return{success:!0,data:{query:s,results:o},display:`Search results for "${s}":
502
502
 
503
- ${i}`}}catch(o){return{success:!1,error:`Search failed: ${o instanceof Error?o.message:String(o)}`}}}async searchBrave(e,t){let s=new URL("https://api.search.brave.com/res/v1/web/search");s.searchParams.set("q",e),s.searchParams.set("count",String(t));let r=await fetch(s.toString(),{headers:{Accept:"application/json","Accept-Encoding":"gzip","X-Subscription-Token":this.config.apiKey}});if(!r.ok)throw new Error(`Brave Search API returned ${r.status}: ${r.statusText}`);return((await r.json()).web?.results??[]).slice(0,t).map(o=>({title:o.title,url:o.url,snippet:o.description}))}async searchSearXNG(e,t){let s=(this.config.baseUrl??"http://localhost:8080").replace(/\/+$/,""),r=new URL(`${s}/search`);r.searchParams.set("q",e),r.searchParams.set("format","json"),r.searchParams.set("pageno","1");let n=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`SearXNG returned ${n.status}: ${n.statusText}`);return((await n.json()).results??[]).slice(0,t).map(i=>({title:i.title,url:i.url,snippet:i.content}))}async searchTavily(e,t){let s=await fetch("https://api.tavily.com/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:this.config.apiKey,query:e,max_results:t,include_answer:!1})});if(!s.ok)throw new Error(`Tavily API returned ${s.status}: ${s.statusText}`);return((await s.json()).results??[]).slice(0,t).map(n=>({title:n.title,url:n.url,snippet:n.content}))}async searchDuckDuckGo(e,t){let s=new URL("https://html.duckduckgo.com/html/");s.searchParams.set("q",e);let r=await fetch(s.toString(),{headers:{"User-Agent":"Mozilla/5.0 (compatible; Alfred/1.0)"}});if(!r.ok)throw new Error(`DuckDuckGo returned ${r.status}: ${r.statusText}`);let n=await r.text();return this.parseDuckDuckGoHtml(n,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,n=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,o=[],i;for(;(i=r.exec(e))!==null;){let c=i[1],d=this.stripHtml(i[2]).trim(),u=this.extractDdgUrl(c);d&&u&&o.push({url:u,title:d})}let a=[];for(;(i=n.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let c=0;c<Math.min(o.length,t);c++)s.push({title:o[c].title,url:o[c].url,snippet:a[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ")}}});var Wt,Mc=T(()=>{"use strict";U();Oe();Wt=class extends R{static{m(this,"ReminderSkill")}reminderRepo;metadata={name:"reminder",category:"productivity",description:'Set timed reminders that notify the user later. Use when the user says "remind me", "erinnere mich", or asks to be notified about something at a specific time. Prefer triggerAt (absolute time like "14:30" or "2026-02-28 09:00") over delayMinutes \u2014 it is more precise and avoids calculation errors.',riskLevel:"write",version:"3.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["set","list","cancel"],description:"The reminder action to perform"},message:{type:"string",description:"The reminder message (required for set)"},triggerAt:{type:"string",description:'Absolute time for the reminder. Accepts "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date. Preferred over delayMinutes for time-specific reminders.'},delayMinutes:{type:"number",description:"Minutes until the reminder triggers. Use triggerAt instead when the user specifies a clock time."},reminderId:{type:"string",description:"The ID of the reminder to cancel (required for cancel)"}},required:["action"]}};constructor(e){super(),this.reminderRepo=e}getAllReminders(e){let t=new Set,s=[];for(let r of V(e))for(let n of this.reminderRepo.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"set":return this.setReminder(e,t);case"list":return this.listReminders(t);case"cancel":return this.cancelReminder(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: set, list, cancel`}}}setReminder(e,t){let s=e.message,r=e.triggerAt,n=e.delayMinutes;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "message" for set action'};let o;if(r&&typeof r=="string"){let u=this.parseTriggerAt(r,t.timezone);if(!u)return{success:!1,error:`Could not parse triggerAt "${r}". Use "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date.`};if(u.getTime()<=Date.now())return{success:!1,error:`The time "${r}" is in the past. Please specify a future time.`};o=u}else if(n!==void 0&&typeof n=="number"&&n>0)o=new Date(Date.now()+n*60*1e3);else return{success:!1,error:'Provide either "triggerAt" (e.g. "14:30") or "delayMinutes" (positive number) for set action.'};let i=this.reminderRepo.create(ae(t),t.platform,t.chatId,s,o),a=o.getTime()-Date.now(),c=Math.round(a/6e4),d=o.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...t.timezone?{timeZone:t.timezone}:{}});return{success:!0,data:{reminderId:i.id,message:s,triggerAt:i.triggerAt},display:`Reminder set (${i.id}): "${s}" at ${d} (in ${c} min)`}}parseTriggerAt(e,t){let s=e.trim(),r=/^(\d{1,2}):(\d{2})$/.exec(s);if(r){let o=parseInt(r[1],10),i=parseInt(r[2],10);return o>23||i>59?void 0:this.buildDateInTimezone(o,i,void 0,t)}let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(n){let o=parseInt(n[1],10),i=parseInt(n[2],10)-1,a=parseInt(n[3],10),c=parseInt(n[4],10),d=parseInt(n[5],10);return c>23||d>59||i>11||a>31?void 0:this.buildDateInTimezone(c,d,{year:o,month:i,day:a},t)}}buildDateInTimezone(e,t,s,r){if(!r){let f=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||f.setHours(e,t,0,0),f}let n=new Date,o=s?new Date(Date.UTC(s.year,s.month,s.day,e,t,0)):new Date(Date.UTC(n.getFullYear(),n.getMonth(),n.getDate(),e,t,0)),i=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});if(!s){let f=i.formatToParts(n),g=parseInt(f.find(q=>q.type==="year").value,10),h=parseInt(f.find(q=>q.type==="month").value,10)-1,y=parseInt(f.find(q=>q.type==="day").value,10),b=new Date(Date.UTC(g,h,y,e,t,0)),k=i.formatToParts(b),S=parseInt(k.find(q=>q.type==="hour").value,10),j=parseInt(k.find(q=>q.type==="minute").value,10),N=(e-S)*60+(t-j);return b=new Date(b.getTime()+N*6e4),b}let a=o,c=i.formatToParts(a),d=parseInt(c.find(f=>f.type==="hour").value,10),u=parseInt(c.find(f=>f.type==="minute").value,10),p=(e-d)*60+(t-u);return a=new Date(a.getTime()+p*6e4),a}listReminders(e){let s=this.getAllReminders(e).map(r=>({reminderId:r.id,message:r.message,triggerAt:r.triggerAt}));return{success:!0,data:s,display:s.length===0?"No active reminders.":`Active reminders:
503
+ ${i}`}}catch(o){return{success:!1,error:`Search failed: ${o instanceof Error?o.message:String(o)}`}}}async searchBrave(e,t){let s=new URL("https://api.search.brave.com/res/v1/web/search");s.searchParams.set("q",e),s.searchParams.set("count",String(t));let r=await fetch(s.toString(),{headers:{Accept:"application/json","Accept-Encoding":"gzip","X-Subscription-Token":this.config.apiKey}});if(!r.ok)throw new Error(`Brave Search API returned ${r.status}: ${r.statusText}`);return((await r.json()).web?.results??[]).slice(0,t).map(o=>({title:o.title,url:o.url,snippet:o.description}))}async searchSearXNG(e,t){let s=(this.config.baseUrl??"http://localhost:8080").replace(/\/+$/,""),r=new URL(`${s}/search`);r.searchParams.set("q",e),r.searchParams.set("format","json"),r.searchParams.set("pageno","1");let n=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`SearXNG returned ${n.status}: ${n.statusText}`);return((await n.json()).results??[]).slice(0,t).map(i=>({title:i.title,url:i.url,snippet:i.content}))}async searchTavily(e,t){let s=await fetch("https://api.tavily.com/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:this.config.apiKey,query:e,max_results:t,include_answer:!1})});if(!s.ok)throw new Error(`Tavily API returned ${s.status}: ${s.statusText}`);return((await s.json()).results??[]).slice(0,t).map(n=>({title:n.title,url:n.url,snippet:n.content}))}async searchDuckDuckGo(e,t){let s=new URL("https://html.duckduckgo.com/html/");s.searchParams.set("q",e);let r=await fetch(s.toString(),{headers:{"User-Agent":"Mozilla/5.0 (compatible; Alfred/1.0)"}});if(!r.ok)throw new Error(`DuckDuckGo returned ${r.status}: ${r.statusText}`);let n=await r.text();return this.parseDuckDuckGoHtml(n,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,n=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,o=[],i;for(;(i=r.exec(e))!==null;){let c=i[1],d=this.stripHtml(i[2]).trim(),u=this.extractDdgUrl(c);d&&u&&o.push({url:u,title:d})}let a=[];for(;(i=n.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let c=0;c<Math.min(o.length,t);c++)s.push({title:o[c].title,url:o[c].url,snippet:a[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ")}}});var Wt,Mc=T(()=>{"use strict";U();Oe();Wt=class extends R{static{m(this,"ReminderSkill")}reminderRepo;metadata={name:"reminder",category:"productivity",description:'Set timed reminders that notify the user later. Use when the user says "remind me", "erinnere mich", or asks to be notified about something at a specific time. Prefer triggerAt (absolute time like "14:30" or "2026-02-28 09:00") over delayMinutes \u2014 it is more precise and avoids calculation errors.',riskLevel:"write",version:"3.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["set","list","cancel"],description:"The reminder action to perform"},message:{type:"string",description:"The reminder message (required for set)"},triggerAt:{type:"string",description:'Absolute time for the reminder. Accepts "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date. Preferred over delayMinutes for time-specific reminders.'},delayMinutes:{type:"number",description:"Minutes until the reminder triggers. Use triggerAt instead when the user specifies a clock time."},reminderId:{type:"string",description:"The ID of the reminder to cancel (required for cancel)"}},required:["action"]}};constructor(e){super(),this.reminderRepo=e}getAllReminders(e){let t=new Set,s=[];for(let r of V(e))for(let n of this.reminderRepo.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"set":return this.setReminder(e,t);case"list":return this.listReminders(t);case"cancel":return this.cancelReminder(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: set, list, cancel`}}}setReminder(e,t){let s=e.message,r=e.triggerAt,n=e.delayMinutes;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "message" for set action'};let o;if(r&&typeof r=="string"){let u=this.parseTriggerAt(r,t.timezone);if(!u)return{success:!1,error:`Could not parse triggerAt "${r}". Use "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date.`};if(u.getTime()<=Date.now())return{success:!1,error:`The time "${r}" is in the past. Please specify a future time.`};o=u}else if(n!==void 0&&typeof n=="number"&&n>0)o=new Date(Date.now()+n*60*1e3);else return{success:!1,error:'Provide either "triggerAt" (e.g. "14:30") or "delayMinutes" (positive number) for set action.'};let i=this.reminderRepo.create(ae(t),t.platform,t.chatId,s,o),a=o.getTime()-Date.now(),c=Math.round(a/6e4),d=o.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...t.timezone?{timeZone:t.timezone}:{}});return{success:!0,data:{reminderId:i.id,message:s,triggerAt:i.triggerAt},display:`Reminder set (${i.id}): "${s}" at ${d} (in ${c} min)`}}parseTriggerAt(e,t){let s=e.trim(),r=/^(\d{1,2}):(\d{2})$/.exec(s);if(r){let o=parseInt(r[1],10),i=parseInt(r[2],10);return o>23||i>59?void 0:this.buildDateInTimezone(o,i,void 0,t)}let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(n){let o=parseInt(n[1],10),i=parseInt(n[2],10)-1,a=parseInt(n[3],10),c=parseInt(n[4],10),d=parseInt(n[5],10);return c>23||d>59||i>11||a>31?void 0:this.buildDateInTimezone(c,d,{year:o,month:i,day:a},t)}}buildDateInTimezone(e,t,s,r){if(!r){let f=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||f.setHours(e,t,0,0),f}let n=new Date,o=s?new Date(Date.UTC(s.year,s.month,s.day,e,t,0)):new Date(Date.UTC(n.getFullYear(),n.getMonth(),n.getDate(),e,t,0)),i=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});if(!s){let f=i.formatToParts(n),g=parseInt(f.find(z=>z.type==="year").value,10),h=parseInt(f.find(z=>z.type==="month").value,10)-1,y=parseInt(f.find(z=>z.type==="day").value,10),b=new Date(Date.UTC(g,h,y,e,t,0)),k=i.formatToParts(b),S=parseInt(k.find(z=>z.type==="hour").value,10),j=parseInt(k.find(z=>z.type==="minute").value,10),N=(e-S)*60+(t-j);return b=new Date(b.getTime()+N*6e4),b}let a=o,c=i.formatToParts(a),d=parseInt(c.find(f=>f.type==="hour").value,10),u=parseInt(c.find(f=>f.type==="minute").value,10),p=(e-d)*60+(t-u);return a=new Date(a.getTime()+p*6e4),a}listReminders(e){let s=this.getAllReminders(e).map(r=>({reminderId:r.id,message:r.message,triggerAt:r.triggerAt}));return{success:!0,data:s,display:s.length===0?"No active reminders.":`Active reminders:
504
504
  ${s.map(r=>`- ${r.reminderId}: "${r.message}" (triggers at ${r.triggerAt})`).join(`
505
505
  `)}`}}cancelReminder(e,t){let s=e.reminderId;return!s||typeof s!="string"?{success:!1,error:'Missing required field "reminderId" for cancel action'}:this.getAllReminders(t).some(i=>i.id===s)?this.reminderRepo.cancel(s)?{success:!0,data:{reminderId:s},display:`Reminder "${s}" cancelled.`}:{success:!1,error:`Reminder "${s}" not found`}:{success:!1,error:`Reminder "${s}" not found`}}}});var Gt,Oc=T(()=>{"use strict";U();Oe();Gt=class extends R{static{m(this,"NoteSkill")}noteRepo;metadata={name:"note",category:"productivity",description:"Save, list, search, or delete persistent notes (stored in SQLite). Use when the user wants to write down or retrieve text notes, lists, or ideas.",riskLevel:"write",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","list","search","delete"],description:"The note action to perform"},title:{type:"string",description:"The note title (required for save)"},content:{type:"string",description:"The note content (required for save)"},noteId:{type:"string",description:"The ID of the note to delete (required for delete)"},query:{type:"string",description:"Search query to filter notes (required for search)"}},required:["action"]}};constructor(e){super(),this.noteRepo=e}async execute(e,t){let s=e.action;switch(s){case"save":return this.saveNote(e,t);case"list":return this.listNotes(t);case"search":return this.searchNotes(e,t);case"delete":return this.deleteNote(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: save, list, search, delete`}}}saveNote(e,t){let s=e.title,r=e.content;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "title" for save action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "content" for save action'};let n=this.noteRepo.save(ae(t),s,r);return{success:!0,data:{noteId:n.id,title:n.title},display:`Note saved: "${s}"`}}listNotes(e){let t=new Set,s=[];for(let n of V(e))for(let o of this.noteRepo.list(n))t.has(o.id)||(t.add(o.id),s.push(o));if(s.length===0)return{success:!0,data:[],display:"No notes found."};let r=s.map(n=>`- **${n.title}** (${n.id.slice(0,8)}\u2026)
506
506
  ${n.content.slice(0,100)}${n.content.length>100?"\u2026":""}`).join(`
@@ -520,19 +520,19 @@ ${n.map(o=>`- ${o.key}: "${o.value}"`).join(`
520
520
  ${n.map(i=>`- [${i.category}] ${i.key}: "${i.value}"`).join(`
521
521
  `)}`}}deleteMemory(e,t){let s=e.key;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for delete action'};let r=!1;for(let n of V(t))if(this.memoryRepo.delete(n,s)){r=!0;break}return{success:!0,data:{key:s,deleted:r},display:r?`Memory "${s}" deleted.`:`No memory found for key "${s}".`}}async semanticSearchMemories(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for semantic_search action'};if(!this.embeddingService)return this.searchMemories(e,t);let r=new Set,n=[];for(let o of V(t))for(let i of await this.embeddingService.semanticSearch(o,s,10))r.has(i.key)||(r.add(i.key),n.push(i));return n.length===0?this.searchMemories(e,t):{success:!0,data:n,display:`Found ${n.length} semantically related memory(ies):
522
522
  ${n.map(o=>`- ${o.key}: "${o.value}" (score: ${o.score.toFixed(2)})`).join(`
523
- `)}`}}}});var Hm,zm,qm,Yt,Hc=T(()=>{"use strict";U();ii();Hm=15,zm=25,qm=12e4,Yt=class extends R{static{m(this,"DelegateSkill")}llm;skillRegistry;skillSandbox;securityManager;metadata={name:"delegate",category:"core",description:'Delegate a complex sub-task to an autonomous sub-agent that has full tool access. The sub-agent can use shell, web search, calculator, memory, email, and all other tools. Use when a task is independent enough to run in parallel or when it requires a focused, multi-step workflow (e.g. "research X and summarize", "find all TODO files and list them", "check the weather and draft a packing list"). Control depth with max_iterations (default 15, max 25).',riskLevel:"write",version:"3.0.0",timeoutMs:qm,inputSchema:{type:"object",properties:{task:{type:"string",description:"The task to delegate to the sub-agent. Be specific about what you want."},context:{type:"string",description:"Additional context the sub-agent needs (optional)"},max_iterations:{type:"number",description:"Max tool iterations (1-25). Default: 15."}},required:["task"]}};onProgress;constructor(e,t,s,r){super(),this.llm=e,this.skillRegistry=t,this.skillSandbox=s,this.securityManager=r}setProgressCallback(e){this.onProgress=e}createTracker(){return new St(this.onProgress)}async execute(e,t){let s=e.task,r=e.context;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task"'};let n=e.max_iterations,o=n?Math.max(1,Math.min(zm,Math.round(n))):Hm,i=t.onProgress??this.onProgress,a=t.tracker?t.tracker:new St(i);a.ping("starting",{maxIterations:o});let c=this.buildSubAgentTools(),d=new Map,u=0,p=`You are a sub-agent of Alfred, a personal AI assistant. Complete the assigned task using the tools available to you. Work step by step: use tools to gather information, then synthesize a clear result. Be concise and return only the final answer when done.
523
+ `)}`}}}});var Hm,qm,zm,Yt,Hc=T(()=>{"use strict";U();ii();Hm=15,qm=25,zm=12e4,Yt=class extends R{static{m(this,"DelegateSkill")}llm;skillRegistry;skillSandbox;securityManager;metadata={name:"delegate",category:"core",description:'Delegate a complex sub-task to an autonomous sub-agent that has full tool access. The sub-agent can use shell, web search, calculator, memory, email, and all other tools. Use when a task is independent enough to run in parallel or when it requires a focused, multi-step workflow (e.g. "research X and summarize", "find all TODO files and list them", "check the weather and draft a packing list"). Control depth with max_iterations (default 15, max 25).',riskLevel:"write",version:"3.0.0",timeoutMs:zm,inputSchema:{type:"object",properties:{task:{type:"string",description:"The task to delegate to the sub-agent. Be specific about what you want."},context:{type:"string",description:"Additional context the sub-agent needs (optional)"},max_iterations:{type:"number",description:"Max tool iterations (1-25). Default: 15."}},required:["task"]}};onProgress;constructor(e,t,s,r){super(),this.llm=e,this.skillRegistry=t,this.skillSandbox=s,this.securityManager=r}setProgressCallback(e){this.onProgress=e}createTracker(){return new St(this.onProgress)}async execute(e,t){let s=e.task,r=e.context;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task"'};let n=e.max_iterations,o=n?Math.max(1,Math.min(qm,Math.round(n))):Hm,i=t.onProgress??this.onProgress,a=t.tracker?t.tracker:new St(i);a.ping("starting",{maxIterations:o});let c=this.buildSubAgentTools(),d=new Map,u=0,p=`You are a sub-agent of Alfred, a personal AI assistant. Complete the assigned task using the tools available to you. Work step by step: use tools to gather information, then synthesize a clear result. Be concise and return only the final answer when done.
524
524
 
525
525
  When tool results contain "[Data stored as result_N]", use code_sandbox with action "run_with_data" and data="result_N" to process the data. The data will be injected as INPUT_DATA (parsed array/object). Never hardcode data in code.
526
526
  Available JS libraries in code_sandbox (no install needed): exceljs, pdfkit, pdf-parse.`,f=s;r&&typeof r=="string"&&(f=`${s}
527
527
 
528
- Additional context: ${r}`);let g=[{role:"user",content:f}];try{let h=0,y=0,b=0;for(;;){a.ping("llm_call",{iteration:h,maxIterations:o});let k=await this.llm.complete({messages:g,system:p,tools:c.length>0?c:void 0,maxTokens:8192,tier:"strong"});if(y+=k.usage.inputTokens,b+=k.usage.outputTokens,a.ping("processing",{iteration:h,maxIterations:o}),!k.toolCalls||k.toolCalls.length===0||h>=o)return a.ping("done",{iteration:h,maxIterations:o}),{success:!0,data:{response:k.content,iterations:h,usage:{inputTokens:y,outputTokens:b}},display:k.content};h++;let S=[];k.content&&S.push({type:"text",text:k.content});for(let N of k.toolCalls)S.push({type:"tool_use",id:N.id,name:N.name,input:N.input});g.push({role:"assistant",content:S});let j=[];for(let N of k.toolCalls){a.ping("tool_call",{iteration:h,maxIterations:o,tool:N.name});let q=N.input;if(N.name==="code_sandbox"&&N.input.data){let O=String(N.input.data);d.has(O)&&(q={...N.input,data:d.get(O)},q.action==="run"&&(q.action="run_with_data"))}let ee=await this.executeSubAgentTool({...N,input:q},t),D=ee.content;if(!ee.isError&&D.length>500){let O=`result_${++u}`,ie=ee.rawData!=null?JSON.stringify(ee.rawData):D;d.set(O,ie),D+=`
528
+ Additional context: ${r}`);let g=[{role:"user",content:f}];try{let h=0,y=0,b=0;for(;;){a.ping("llm_call",{iteration:h,maxIterations:o});let k=await this.llm.complete({messages:g,system:p,tools:c.length>0?c:void 0,maxTokens:8192,tier:"strong"});if(y+=k.usage.inputTokens,b+=k.usage.outputTokens,a.ping("processing",{iteration:h,maxIterations:o}),!k.toolCalls||k.toolCalls.length===0||h>=o)return a.ping("done",{iteration:h,maxIterations:o}),{success:!0,data:{response:k.content,iterations:h,usage:{inputTokens:y,outputTokens:b}},display:k.content};h++;let S=[];k.content&&S.push({type:"text",text:k.content});for(let N of k.toolCalls)S.push({type:"tool_use",id:N.id,name:N.name,input:N.input});g.push({role:"assistant",content:S});let j=[];for(let N of k.toolCalls){a.ping("tool_call",{iteration:h,maxIterations:o,tool:N.name});let z=N.input;if(N.name==="code_sandbox"&&N.input.data){let O=String(N.input.data);d.has(O)&&(z={...N.input,data:d.get(O)},z.action==="run"&&(z.action="run_with_data"))}let ee=await this.executeSubAgentTool({...N,input:z},t),L=ee.content;if(!ee.isError&&L.length>500){let O=`result_${++u}`,ie=ee.rawData!=null?JSON.stringify(ee.rawData):L;d.set(O,ie),L+=`
529
529
 
530
- [Data stored as "${O}" \u2014 use code_sandbox action "run_with_data" with data="${O}" to process this data. Do NOT copy data into code.]`}j.push({type:"tool_result",tool_use_id:N.id,content:D,is_error:ee.isError})}g.push({role:"user",content:j})}}catch(h){return{success:!1,error:`Sub-agent failed: ${h instanceof Error?h.message:String(h)}`}}}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 Je,yn=T(()=>{"use strict";Je=class{static{m(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 zc={};ue(zc,{MicrosoftGraphEmailProvider:()=>wn});var wn,ci=T(()=>{"use strict";yn();wn=class extends Je{static{m(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=m(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=m(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),p=await Promise.allSettled(u.map(async f=>{let g={id:f.id,from:f.from,subject:f.subject,date:f.date.toISOString().split("T")[0],preview:(f.preview??"").slice(0,200)};try{let h=await this.readMessage(f.id),y=this.extractAmount(h.body);y&&(g.amount=y.amount,g.currency=y.currency)}catch{}return g}));for(let f of p)f.status==="fulfilled"&&a.push(f.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 p=s?this.toKqlDate(s):"01/01/2000",f=r?this.toKqlDate(r):"12/31/2099";o.push(`received:${p}..${f}`)}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(p=>this.mapMessage(p)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let p=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),f=(p.value??[]).map(g=>this.mapMessage(g));d.push(...f),u=p["@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,`
530
+ [Data stored as "${O}" \u2014 use code_sandbox action "run_with_data" with data="${O}" to process this data. Do NOT copy data into code.]`}j.push({type:"tool_result",tool_use_id:N.id,content:L,is_error:ee.isError})}g.push({role:"user",content:j})}}catch(h){return{success:!1,error:`Sub-agent failed: ${h instanceof Error?h.message:String(h)}`}}}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 Je,yn=T(()=>{"use strict";Je=class{static{m(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 qc={};ue(qc,{MicrosoftGraphEmailProvider:()=>wn});var wn,ci=T(()=>{"use strict";yn();wn=class extends Je{static{m(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=m(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=m(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),p=await Promise.allSettled(u.map(async f=>{let g={id:f.id,from:f.from,subject:f.subject,date:f.date.toISOString().split("T")[0],preview:(f.preview??"").slice(0,200)};try{let h=await this.readMessage(f.id),y=this.extractAmount(h.body);y&&(g.amount=y.amount,g.currency=y.currency)}catch{}return g}));for(let f of p)f.status==="fulfilled"&&a.push(f.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 p=s?this.toKqlDate(s):"01/01/2000",f=r?this.toKqlDate(r):"12/31/2099";o.push(`received:${p}..${f}`)}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(p=>this.mapMessage(p)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let p=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),f=(p.value??[]).map(g=>this.mapMessage(g));d.push(...f),u=p["@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,`
531
531
  `).replace(/<\/p>/gi,`
532
532
 
533
533
  `).replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\n{3,}/g,`
534
534
 
535
- `).trim()}}});var qc={};ue(qc,{StandardEmailProvider:()=>_n});var _n,li=T(()=>{"use strict";yn();_n=class extends Je{static{m(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(p=>p.name?`${p.name} <${p.address}>`:p.address??"")??[],a=n.envelope?.cc?.map(p=>p.name?`${p.name} <${p.address}>`:p.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 p=this.formatAddress(u.envelope?.from?.[0]);o.push({id:String(u.seq),from:p,to:u.envelope?.to?.map(f=>f.name?`${f.name} <${f.address}>`:f.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=m((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(`
535
+ `).trim()}}});var zc={};ue(zc,{StandardEmailProvider:()=>_n});var _n,li=T(()=>{"use strict";yn();_n=class extends Je{static{m(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(p=>p.name?`${p.name} <${p.address}>`:p.address??"")??[],a=n.envelope?.cc?.map(p=>p.name?`${p.name} <${p.address}>`:p.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 p=this.formatAddress(u.envelope?.from?.[0]);o.push({id:String(u.seq),from:p,to:u.envelope?.to?.map(f=>f.name?`${f.name} <${f.address}>`:f.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=m((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(`
536
536
 
537
537
  `));let r=s.match(/boundary="?([^"\s;]+)"?/i)??e.match(/boundary="?([^"\s;]+)"?/i);if(!r)return t.slice(1).join(`
538
538
 
@@ -542,7 +542,7 @@ Additional context: ${r}`);let g=[{role:"user",content:f}];try{let h=0,y=0,b=0;f
542
542
  \r
543
543
  `);if(d>=0)return this.decodeBody(i.slice(d+4))}}return this.decodeBody(t.slice(1).join(`
544
544
 
545
- `).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 pr(l){if(l.provider==="microsoft"){if(!l.microsoft)throw new Error("Microsoft email config missing");let{MicrosoftGraphEmailProvider:s}=await Promise.resolve().then(()=>(ci(),zc)),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(()=>(li(),qc)),t=new e(l);return await t.initialize(),t}var Wc=T(()=>{"use strict";m(pr,"createEmailProvider")});var nt,Gc=T(()=>{"use strict";yn();Wc();li();ci();U();nt=class extends R{static{m(this,"EmailSkill")}metadata;providers;accountNames;defaultAccount;multiAccount;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(", ")})`}}:{},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"],description:'The email action to perform. Use "extract" for bulk invoice/receipt extraction from large mailboxes \u2014 it searches with pagination, reads bodies server-side, and returns structured data with amounts.'},...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"]}}}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);default:return{success:!1,error:`Unknown action: ${s}. Use: inbox, read, search, send, draft, folders, folder, reply, forward, attachment`}}}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]",p=c.hasAttachments?" [ATT]":"";return`${d+1}. [${this.encodeId(r,c.id)}]${u}${p} ${c.subject}
545
+ `).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 pr(l){if(l.provider==="microsoft"){if(!l.microsoft)throw new Error("Microsoft email config missing");let{MicrosoftGraphEmailProvider:s}=await Promise.resolve().then(()=>(ci(),qc)),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(()=>(li(),zc)),t=new e(l);return await t.initialize(),t}var Wc=T(()=>{"use strict";m(pr,"createEmailProvider")});var nt,Gc=T(()=>{"use strict";yn();Wc();li();ci();U();nt=class extends R{static{m(this,"EmailSkill")}metadata;providers;accountNames;defaultAccount;multiAccount;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(", ")})`}}:{},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"],description:'The email action to perform. Use "extract" for bulk invoice/receipt extraction from large mailboxes \u2014 it searches with pagination, reads bodies server-side, and returns structured data with amounts.'},...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"]}}}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);default:return{success:!1,error:`Unknown action: ${s}. Use: inbox, read, search, send, draft, folders, folder, reply, forward, attachment`}}}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]",p=c.hasAttachments?" [ATT]":"";return`${d+1}. [${this.encodeId(r,c.id)}]${u}${p} ${c.subject}
546
546
  From: ${c.from}
547
547
  Date: ${c.date.toISOString()}`}).join(`
548
548
 
@@ -645,7 +645,7 @@ ${r.join(`
645
645
  `)}`}}cancelTask(e,t){let s=e.task_id;return!s||typeof s!="string"?{success:!1,error:'Missing required field "task_id" for cancel action'}:this.getAllTasks(t).some(i=>i.id===s)?this.taskRepo.cancel(s)?{success:!0,data:{taskId:s},display:`Background task "${s}" cancelled.`}:{success:!1,error:`Task "${s}" not found or already completed`}:{success:!1,error:`Task "${s}" not found or already completed`}}}});var is,ul=T(()=>{"use strict";U();Oe();is=class extends R{static{m(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 V(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 p=parseInt(o,10);if(isNaN(p)||p<=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 p=new Date(o);if(isNaN(p.getTime()))return{success:!1,error:"For once schedule, value must be a valid ISO date string"};if(p.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:ae(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:
646
646
  ${s.join(`
647
647
  `)}`}}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=V(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=V(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 At,hi=T(()=>{"use strict";At=class{static{m(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(`
648
- `),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 Xm,It,fi=T(()=>{"use strict";U();Xm=["read","write","destructive","admin"],It=class extends R{static{m(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&&Xm.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 yr,ml=T(()=>{"use strict";hi();fi();yr=class{static{m(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new At(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 It(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 pl=T(()=>{"use strict";hi();fi();ml()});import{spawn as Ym}from"node:child_process";import Ue from"node:fs";import Fe from"node:path";import Jm from"node:os";import Zm from"node:crypto";var Rt,gi=T(()=>{"use strict";Rt=class{static{m(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=Ua.resolve(`${s}/package.json`);e.add(Fe.dirname(Fe.dirname(r)))}catch{}try{let s=Ue.realpathSync(process.argv[1]??""),r=Fe.dirname(s),n=Fe.join(r,"node_modules");Ue.existsSync(n)&&e.add(n);let o=Fe.join(r,"..","node_modules");Ue.existsSync(o)&&e.add(Ue.realpathSync(o))}catch{}let t=Fe.join(process.cwd(),"node_modules");if(Ue.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(Fe.delimiter))s&&e.add(s);return[...e].join(Fe.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=Fe.join(Jm.tmpdir(),`alfred-sandbox-${Zm.randomUUID()}`);Ue.mkdirSync(n,{recursive:!0});try{let o=t==="javascript"?"js":"py",i=Fe.join(n,`script.${o}`);Ue.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[i],d=Date.now();return await new Promise(u=>{let p=Ym(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"]}),f="",g="";p.stdout.on("data",h=>{f+=h.toString()}),p.stderr.on("data",h=>{g+=h.toString()}),p.on("close",h=>{let y=Date.now()-d,b=[];try{let k=Ue.readdirSync(n).filter(S=>!S.startsWith("script."));for(let S of k){let j=Fe.join(n,S),N=Ue.statSync(j);if(N.isFile()&&N.size<1e7){let q=Ue.readFileSync(j),ee=S.endsWith(".png")?"image/png":S.endsWith(".jpg")||S.endsWith(".jpeg")?"image/jpeg":S.endsWith(".svg")?"image/svg+xml":S.endsWith(".csv")?"text/csv":S.endsWith(".json")?"application/json":S.endsWith(".html")||S.endsWith(".htm")?"text/html":S.endsWith(".txt")?"text/plain":S.endsWith(".md")?"text/markdown":S.endsWith(".xml")?"application/xml":S.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":S.endsWith(".xls")?"application/vnd.ms-excel":S.endsWith(".pdf")?"application/pdf":"application/octet-stream";b.push({name:S,data:q,mimeType:ee})}}}catch{}u({stdout:f.slice(0,5e4),stderr:g.slice(0,1e4),exitCode:h??1,files:b.length>0?b:void 0,durationMs:y})}),p.on("error",h=>{u({stdout:"",stderr:h.message,exitCode:1,durationMs:Date.now()-d})}),p.stdin.end()})}finally{try{Ue.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var wr,hl=T(()=>{"use strict";U();gi();wr=class extends R{static{m(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 Rt;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 p=!1;try{JSON.parse(o),p=!0}catch{}n==="javascript"?a=p?`const INPUT_DATA = ${o};
648
+ `),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 Xm,It,fi=T(()=>{"use strict";U();Xm=["read","write","destructive","admin"],It=class extends R{static{m(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&&Xm.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 yr,ml=T(()=>{"use strict";hi();fi();yr=class{static{m(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new At(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 It(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 pl=T(()=>{"use strict";hi();fi();ml()});import{spawn as Ym}from"node:child_process";import Ue from"node:fs";import Fe from"node:path";import Jm from"node:os";import Zm from"node:crypto";var Rt,gi=T(()=>{"use strict";Rt=class{static{m(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=Ua.resolve(`${s}/package.json`);e.add(Fe.dirname(Fe.dirname(r)))}catch{}try{let s=Ue.realpathSync(process.argv[1]??""),r=Fe.dirname(s),n=Fe.join(r,"node_modules");Ue.existsSync(n)&&e.add(n);let o=Fe.join(r,"..","node_modules");Ue.existsSync(o)&&e.add(Ue.realpathSync(o))}catch{}let t=Fe.join(process.cwd(),"node_modules");if(Ue.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(Fe.delimiter))s&&e.add(s);return[...e].join(Fe.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=Fe.join(Jm.tmpdir(),`alfred-sandbox-${Zm.randomUUID()}`);Ue.mkdirSync(n,{recursive:!0});try{let o=t==="javascript"?"js":"py",i=Fe.join(n,`script.${o}`);Ue.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[i],d=Date.now();return await new Promise(u=>{let p=Ym(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"]}),f="",g="";p.stdout.on("data",h=>{f+=h.toString()}),p.stderr.on("data",h=>{g+=h.toString()}),p.on("close",h=>{let y=Date.now()-d,b=[];try{let k=Ue.readdirSync(n).filter(S=>!S.startsWith("script."));for(let S of k){let j=Fe.join(n,S),N=Ue.statSync(j);if(N.isFile()&&N.size<1e7){let z=Ue.readFileSync(j),ee=S.endsWith(".png")?"image/png":S.endsWith(".jpg")||S.endsWith(".jpeg")?"image/jpeg":S.endsWith(".svg")?"image/svg+xml":S.endsWith(".csv")?"text/csv":S.endsWith(".json")?"application/json":S.endsWith(".html")||S.endsWith(".htm")?"text/html":S.endsWith(".txt")?"text/plain":S.endsWith(".md")?"text/markdown":S.endsWith(".xml")?"application/xml":S.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":S.endsWith(".xls")?"application/vnd.ms-excel":S.endsWith(".pdf")?"application/pdf":"application/octet-stream";b.push({name:S,data:z,mimeType:ee})}}}catch{}u({stdout:f.slice(0,5e4),stderr:g.slice(0,1e4),exitCode:h??1,files:b.length>0?b:void 0,durationMs:y})}),p.on("error",h=>{u({stdout:"",stderr:h.message,exitCode:1,durationMs:Date.now()-d})}),p.stdin.end()})}finally{try{Ue.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var wr,hl=T(()=>{"use strict";U();gi();wr=class extends R{static{m(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 Rt;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 p=!1;try{JSON.parse(o),p=!0}catch{}n==="javascript"?a=p?`const INPUT_DATA = ${o};
649
649
  ${r}`:`const INPUT_DATA = ${JSON.stringify(o)};
650
650
  ${r}`:a=p?`import json as _json
651
651
  INPUT_DATA = _json.loads(${JSON.stringify(o)})
@@ -723,7 +723,7 @@ Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this
723
723
  `)}}let r=t??new Date().toISOString(),n=s??new Date(Date.now()+864e5).toISOString(),o=await this.api("GET",`/api/calendars/${e}?start=${encodeURIComponent(r)}&end=${encodeURIComponent(n)}`),i=[`## Calendar Events: ${e}`,"","| Start | End | Summary | Location |","|-------|-----|---------|----------|"];for(let a of o){let c=a.start?.dateTime?new Date(a.start.dateTime).toLocaleString():a.start?.date??"-",d=a.end?.dateTime?new Date(a.end.dateTime).toLocaleString():a.end?.date??"-";i.push(`| ${c} | ${d} | ${a.summary??"-"} | ${a.location??"-"} |`)}return o.length===0&&i.push("| - | - | No events in range | - |"),{success:!0,data:o,display:i.join(`
724
724
  `)}}async getErrorLog(){let e=await this.apiText("GET","/api/error_log"),t=e.length>3e3?`\u2026${e.slice(-3e3)}`:e;return{success:!0,data:t,display:["## Error Log","","```",t,"```"].join(`
725
725
  `)}}async getBriefingSummary(e,t){let s=await this.api("GET","/api/states");if(e?.length){let d=new Set(e.map(p=>p.toLowerCase())),u=s.filter(p=>d.has(p.entity_id.toLowerCase()));return this.formatBriefingSummary(u)}if(t?.length){let d=new Set(t.map(p=>p.toLowerCase())),u=s.filter(p=>{let f=p.entity_id.split(".")[0];return d.has(f)});return this.formatBriefingSummary(u)}let r=[],n=[],o=[];for(let d of s){let u=d.entity_id,p=u.split(".")[0],f=d.state,g=d.attributes??{},h=g.device_class??"";if(p==="binary_sensor"){["door","window","opening","garage_door","lock","motion","occupancy","smoke","gas","moisture"].includes(h)&&f==="on"&&r.push(d);continue}if(p==="light"){if(f==="on"){let y=g.friendly_name??u;if(/^0x[a-f0-9]+$/i.test(y)||/\bLED\b/i.test(y))continue;r.push(d)}continue}if(p==="sensor"){if(f==="unavailable"||f==="unknown")continue;let b=`${u.toLowerCase()} ${(g.friendly_name??"").toLowerCase()}`;if(h==="battery"){n.push(d);continue}if(h==="power"||/power_consumption|stromverbrauch|leistung/.test(b)){o.push(d);continue}continue}if(p==="climate"){r.push(d);continue}if(p==="person"){r.push(d);continue}}n.sort((d,u)=>{let p=parseFloat(d.state)||999,f=parseFloat(u.state)||999;return p-f});let i=n.slice(0,5),a=o.filter(d=>!isNaN(parseFloat(d.state)));a.sort((d,u)=>{let p=Math.abs(parseFloat(d.state)||0);return Math.abs(parseFloat(u.state)||0)-p});let c=a.slice(0,5);return this.formatBriefingSummary(r,i,c)}formatBriefingSummary(e,t,s){let r=[...e,...t??[],...s??[]];if(r.length===0)return{success:!0,data:[],display:"Keine relevanten Smart-Home-Daten gefunden."};let n=new Map;for(let c of e){let d=c.entity_id.split(".")[0];n.has(d)||n.set(d,[]),n.get(d).push(c)}let o={binary_sensor:"Kontakte & Melder",light:"Lichter (an)",climate:"Klima",person:"Anwesenheit"},i=[];for(let[c,d]of n){let u=o[c]??c;i.push(`**${u}:**`);for(let p of d){let f=p.attributes?.friendly_name??p.entity_id,g=p.attributes?.unit_of_measurement??"",h=p.state;i.push(`- ${f}: ${h}${g?` ${g}`:""}`)}i.push("")}if(t&&t.length>0){let c=t.map(d=>`${(d.attributes?.friendly_name??d.entity_id).replace(/\s*(battery|akku|soc|ladezustand)\s*/gi," ").trim()}: ${d.state}%`);i.push(`**\u{1F50B} Akkus:** ${c.join(" | ")}`),i.push("")}if(s&&s.length>0){let c=s.map(d=>{let u=(d.attributes?.friendly_name??d.entity_id).replace(/\s*(power|leistung|stromverbrauch)\s*/gi," ").trim(),p=d.attributes?.unit_of_measurement??"W";return`${u}: ${d.state} ${p}`});i.push(`**\u26A1 Leistung:** ${c.join(" | ")}`),i.push("")}return{success:!0,data:r.map(c=>({entity_id:c.entity_id,state:c.state,friendly_name:c.attributes?.friendly_name,unit:c.attributes?.unit_of_measurement,device_class:c.attributes?.device_class})),display:i.join(`
726
- `).trim()}}async getEnergyStats(e,t){let{start:s,end:r,label:n}=this.parseEnergyPeriod(e??"today"),o;if(t?o=[t]:o=(await this.api("GET","/api/states")).filter(h=>{let y=h.attributes??{},b=y.state_class,k=y.device_class,S=(y.unit_of_measurement??"").toLowerCase();return h.entity_id.startsWith("sensor.")&&(b==="total_increasing"||b==="total")&&(k==="energy"||S==="kwh"||S==="wh"||S==="mwh")}).map(h=>h.entity_id),o.length===0)return{success:!0,data:[],display:"Keine Energie-Sensoren gefunden (ben\xF6tigt state_class: total_increasing und device_class: energy)."};let i=[],a=[],c=o.join(","),d=`/api/history/period/${s}?end=${encodeURIComponent(r)}&filter_entity_id=${encodeURIComponent(c)}&minimal_response&no_attributes`,u;try{u=await this.api("GET",d)}catch{return this.getEnergyStatsViaTemplate(o,s,r,n)}for(let g of u){if(!g||g.length<2)continue;let h=g[0]?.entity_id;if(!h)continue;let y=null,b=null;for(let k of g){let S=parseFloat(k.state);isNaN(S)||(y===null&&(y=S),b=S)}if(y!==null&&b!==null){let k=b-y;k<0&&(k=0);let S=await this.api("GET",`/api/states/${h}`).catch(()=>null),j=S?.attributes?.friendly_name??h,N=S?.attributes?.unit_of_measurement??"kWh",q=k,ee=N;N.toLowerCase()==="wh"?(q=k/1e3,ee="kWh"):N.toLowerCase()==="mwh"&&(q=k*1e3,ee="kWh"),i.push({entityId:h,name:j,consumption:Math.round(q*100)/100,unit:ee})}}if(i.length===0&&a.length===0)return{success:!0,data:[],display:`Keine Verbrauchsdaten f\xFCr Zeitraum "${n}" gefunden. M\xF6glicherweise liegt der Zeitraum au\xDFerhalb der History-Retention.`};let p=i.reduce((g,h)=>g+(h.unit==="kWh"?h.consumption:0),0),f=[`## Energieverbrauch: ${n}`,"","| Sensor | Verbrauch |","|--------|-----------|"];for(let g of i.sort((h,y)=>y.consumption-h.consumption))f.push(`| ${g.name} | ${g.consumption} ${g.unit} |`);return i.length>1&&f.push(`| **Gesamt** | **${Math.round(p*100)/100} kWh** |`),a.length>0&&f.push("",`Fehler bei: ${a.join(", ")}`),{success:!0,data:i,display:f.join(`
726
+ `).trim()}}async getEnergyStats(e,t){let{start:s,end:r,label:n}=this.parseEnergyPeriod(e??"today"),o;if(t?o=[t]:o=(await this.api("GET","/api/states")).filter(h=>{let y=h.attributes??{},b=y.state_class,k=y.device_class,S=(y.unit_of_measurement??"").toLowerCase();return h.entity_id.startsWith("sensor.")&&(b==="total_increasing"||b==="total")&&(k==="energy"||S==="kwh"||S==="wh"||S==="mwh")}).map(h=>h.entity_id),o.length===0)return{success:!0,data:[],display:"Keine Energie-Sensoren gefunden (ben\xF6tigt state_class: total_increasing und device_class: energy)."};let i=[],a=[],c=o.join(","),d=`/api/history/period/${s}?end=${encodeURIComponent(r)}&filter_entity_id=${encodeURIComponent(c)}&minimal_response&no_attributes`,u;try{u=await this.api("GET",d)}catch{return this.getEnergyStatsViaTemplate(o,s,r,n)}for(let g of u){if(!g||g.length<2)continue;let h=g[0]?.entity_id;if(!h)continue;let y=null,b=null;for(let k of g){let S=parseFloat(k.state);isNaN(S)||(y===null&&(y=S),b=S)}if(y!==null&&b!==null){let k=b-y;k<0&&(k=0);let S=await this.api("GET",`/api/states/${h}`).catch(()=>null),j=S?.attributes?.friendly_name??h,N=S?.attributes?.unit_of_measurement??"kWh",z=k,ee=N;N.toLowerCase()==="wh"?(z=k/1e3,ee="kWh"):N.toLowerCase()==="mwh"&&(z=k*1e3,ee="kWh"),i.push({entityId:h,name:j,consumption:Math.round(z*100)/100,unit:ee})}}if(i.length===0&&a.length===0)return{success:!0,data:[],display:`Keine Verbrauchsdaten f\xFCr Zeitraum "${n}" gefunden. M\xF6glicherweise liegt der Zeitraum au\xDFerhalb der History-Retention.`};let p=i.reduce((g,h)=>g+(h.unit==="kWh"?h.consumption:0),0),f=[`## Energieverbrauch: ${n}`,"","| Sensor | Verbrauch |","|--------|-----------|"];for(let g of i.sort((h,y)=>y.consumption-h.consumption))f.push(`| ${g.name} | ${g.consumption} ${g.unit} |`);return i.length>1&&f.push(`| **Gesamt** | **${Math.round(p*100)/100} kWh** |`),a.length>0&&f.push("",`Fehler bei: ${a.join(", ")}`),{success:!0,data:i,display:f.join(`
727
727
  `)}}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(`
728
728
  `)}}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:yi(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}\`
729
729
 
@@ -753,7 +753,7 @@ ${a}`}}completeTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success
753
753
  |---|---|---|---|`,n=s.map(o=>`| ${o.list} | ${o.open} | ${o.completed} | ${o.total} |`).join(`
754
754
  `);return{success:!0,data:s,display:`${s.length} list(s):
755
755
  ${r}
756
- ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(ae(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import Rl from"node:http";import xl from"node:https";import{execFile as ep}from"node:child_process";import{promisify as tp}from"node:util";function bi(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 Dl(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 ki(l){return!l||l.length===0?"-":l.map(e=>e.replace(/^\//,"")).join(", ")}function sp(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 rp(l){return l?new Date(l*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var Cl,Cn,Ll=T(()=>{"use strict";U();Cl=tp(ep);m(bi,"formatBytes");m(Dl,"formatPorts");m(ki,"containerName");m(sp,"stripDockerStreamHeaders");m(rp,"relativeTime");Cn=class extends R{static{m(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")?xl:Rl).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")?xl:Rl).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(`| ${ki(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${Dl(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
756
+ ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(ae(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import Rl from"node:http";import xl from"node:https";import{execFile as ep}from"node:child_process";import{promisify as tp}from"node:util";function bi(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 Ll(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 ki(l){return!l||l.length===0?"-":l.map(e=>e.replace(/^\//,"")).join(", ")}function sp(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 rp(l){return l?new Date(l*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var Cl,Cn,Dl=T(()=>{"use strict";U();Cl=tp(ep);m(bi,"formatBytes");m(Ll,"formatPorts");m(ki,"containerName");m(sp,"stripDockerStreamHeaders");m(rp,"relativeTime");Cn=class extends R{static{m(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")?xl:Rl).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")?xl:Rl).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(`| ${ki(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${Ll(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
757
757
  `)}}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(([,p])=>p&&p.length>0).map(([p,f])=>`${f.map(h=>`${h.HostIp??"0.0.0.0"}:${h.HostPort}`).join(", ")} -> ${p}`),c=o.map(p=>`- ${p.Source??"-"} -> ${p.Destination??"-"} (${p.Type??"-"}, ${p.RW?"rw":"ro"})`),d=n.IPAddress||Object.values(n.Networks??{}).map(p=>p.IPAddress).filter(Boolean).join(", ")||"-",u=[`## Container: ${ki(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(p=>`- ${p}`).join(`
758
758
  `):"- No port bindings","","### Mounts",c.length>0?c.join(`
759
759
  `):"- No mounts"];return{success:!0,data:t,display:u.join(`
@@ -765,26 +765,26 @@ ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(ae(t),s);
765
765
  `)}}async getSystemInfo(){let e=await this.api("GET","/info"),t=["## Docker System Info","",`**Docker Version:** ${e.ServerVersion??"-"}`,`**OS:** ${e.OperatingSystem??"-"} (${e.Architecture??"-"})`,`**Kernel:** ${e.KernelVersion??"-"}`,`**CPUs:** ${e.NCPU??"-"}`,`**Memory:** ${bi(e.MemTotal)}`,`**Containers:** ${e.Containers??"-"} (running: ${e.ContainersRunning??"-"}, paused: ${e.ContainersPaused??"-"}, stopped: ${e.ContainersStopped??"-"})`,`**Images:** ${e.Images??"-"}`,`**Storage Driver:** ${e.Driver??"-"}`,`**Docker Root Dir:** ${e.DockerRootDir??"-"}`];return{success:!0,data:e,display:t.join(`
766
766
  `)}}async pruneAll(){let[e,t,s,r]=await Promise.all([this.api("POST","/containers/prune"),this.api("POST","/images/prune"),this.api("POST","/volumes/prune"),this.api("POST","/networks/prune")]),n=e.ContainersDeleted?.length??0,o=t.ImagesDeleted?.length??0,i=s.VolumesDeleted?.length??0,a=r.NetworksDeleted?.length??0,c=(e.SpaceReclaimed??0)+(t.SpaceReclaimed??0)+(s.SpaceReclaimed??0),d=["## Docker Prune Results","",`**Containers removed:** ${n}`,`**Images removed:** ${o}`,`**Volumes removed:** ${i}`,`**Networks removed:** ${a}`,"",`**Total space reclaimed:** ${bi(c)}`];return{success:!0,data:{containers:e,images:t,volumes:s,networks:r},display:d.join(`
767
767
  `)}}async composePs(e){let s=(await this.api("GET","/containers/json?all=true")).filter(o=>o.Labels?.["com.docker.compose.project"]),r=new Map;for(let o of s){let i=o.Labels["com.docker.compose.project"];e&&i!==e||(r.has(i)||r.set(i,[]),r.get(i).push(o))}let n=["## Docker Compose Projects",""];if(r.size===0)return n.push(e?`No containers found for project "${e}".`:"No Compose-managed containers found."),{success:!0,data:[],display:n.join(`
768
- `)};for(let[o,i]of r){n.push(`### ${o}`),n.push(""),n.push("| Service | Name | Status | Ports |"),n.push("|---------|------|--------|-------|");for(let a of i){let c=a.Labels?.["com.docker.compose.service"]??"-";n.push(`| ${c} | ${ki(a.Names)} | ${a.Status??a.State??"-"} | ${Dl(a.Ports)} |`)}n.push("")}return{success:!0,data:[...r.entries()],display:n.join(`
768
+ `)};for(let[o,i]of r){n.push(`### ${o}`),n.push(""),n.push("| Service | Name | Status | Ports |"),n.push("|---------|------|--------|-------|");for(let a of i){let c=a.Labels?.["com.docker.compose.service"]??"-";n.push(`| ${c} | ${ki(a.Names)} | ${a.Status??a.State??"-"} | ${Ll(a.Ports)} |`)}n.push("")}return{success:!0,data:[...r.entries()],display:n.join(`
769
769
  `)}}async composeUp(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await Cl("docker",["compose","-p",e,"up","-d"],{timeout:12e4}),r=(t+`
770
770
  `+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose up:** \`${e}\``,"","```",r,"```"].join(`
771
771
  `)}}async composeDown(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await Cl("docker",["compose","-p",e,"down"],{timeout:12e4}),r=(t+`
772
772
  `+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose down:** \`${e}\``,"","```",r,"```"].join(`
773
- `)}}}});import{readFile as Nl,writeFile as Ml,mkdir as Ol}from"node:fs/promises";import{homedir as $i}from"node:os";import{join as Si}from"node:path";import Fl from"node:crypto";function cp(){let l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Fl.randomBytes(86);return Array.from(e).map(t=>l[t%l.length]).join("")}function lp(l){return Fl.createHash("sha256").update(l).digest("base64url")}function fe(l,e){return l[e]?.value??"?"}var np,Pl,Dn,op,ip,ap,Ul,Ln,dp,Nn,jl=T(()=>{"use strict";U();np="https://customer.bmwgroup.com/gcdm/oauth/device/code",Pl="https://customer.bmwgroup.com/gcdm/oauth/token",Dn="https://api-cardata.bmwgroup.com",op="v1",ip="authenticate_user openid cardata:api:read cardata:streaming:read",ap=5*6e4,Ul="Alfred",Ln=Si($i(),".alfred","bmw-tokens.json");m(cp,"generateCodeVerifier");m(lp,"generateCodeChallenge");dp=["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"];m(fe,"tv");Nn=class extends R{static{m(this,"BMWSkill")}metadata={name:"bmw",category:"infrastructure",description:'BMW CarData \u2014 Fahrzeugdaten abrufen. "authorize" startet den Device-Auth-Flow (einmalig). "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.1.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 (for polling token in step 2)"},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=cp(),s=lp(t),r=await fetch(np,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,response_type:"device_code",code_challenge:s,code_challenge_method:"S256",scope:ip}),signal:AbortSignal.timeout(15e3)});if(!r.ok){let i=await r.text().catch(()=>"");throw new Error(`Device code request failed: HTTP ${r.status} \u2014 ${i.slice(0,300)}`)}let n=await r.json(),o={codeVerifier:t,deviceCode:n.device_code};return await this.savePartialTokens(o),this.tokens=null,{success:!0,data:n,display:["## BMW Autorisierung","",`1. \xD6ffne: **${n.verification_uri_complete??n.verification_uri}**`,`2. Gib diesen Code ein: **${n.user_code}**`,"",`Danach ruf diese Action erneut auf mit \`device_code: "${n.device_code}"\` um den Token abzuholen.`].join(`
773
+ `)}}}});import{readFile as Nl,writeFile as Ml,mkdir as Ol}from"node:fs/promises";import{homedir as $i}from"node:os";import{join as Si}from"node:path";import Fl from"node:crypto";function cp(){let l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Fl.randomBytes(86);return Array.from(e).map(t=>l[t%l.length]).join("")}function lp(l){return Fl.createHash("sha256").update(l).digest("base64url")}function fe(l,e){return l[e]?.value??"?"}var np,Pl,Ln,op,ip,ap,Ul,Dn,dp,Nn,jl=T(()=>{"use strict";U();np="https://customer.bmwgroup.com/gcdm/oauth/device/code",Pl="https://customer.bmwgroup.com/gcdm/oauth/token",Ln="https://api-cardata.bmwgroup.com",op="v1",ip="authenticate_user openid cardata:api:read cardata:streaming:read",ap=5*6e4,Ul="Alfred",Dn=Si($i(),".alfred","bmw-tokens.json");m(cp,"generateCodeVerifier");m(lp,"generateCodeChallenge");dp=["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"];m(fe,"tv");Nn=class extends R{static{m(this,"BMWSkill")}metadata={name:"bmw",category:"infrastructure",description:'BMW CarData \u2014 Fahrzeugdaten abrufen. "authorize" startet den Device-Auth-Flow (einmalig). "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.1.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 (for polling token in step 2)"},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=cp(),s=lp(t),r=await fetch(np,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,response_type:"device_code",code_challenge:s,code_challenge_method:"S256",scope:ip}),signal:AbortSignal.timeout(15e3)});if(!r.ok){let i=await r.text().catch(()=>"");throw new Error(`Device code request failed: HTTP ${r.status} \u2014 ${i.slice(0,300)}`)}let n=await r.json(),o={codeVerifier:t,deviceCode:n.device_code};return await this.savePartialTokens(o),this.tokens=null,{success:!0,data:n,display:["## BMW Autorisierung","",`1. \xD6ffne: **${n.verification_uri_complete??n.verification_uri}**`,`2. Gib diesen Code ein: **${n.user_code}**`,"",`Danach ruf diese Action erneut auf mit \`device_code: "${n.device_code}"\` um den Token abzuholen.`].join(`
774
774
  `)}}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(Pl,{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 p=await r.text().catch(()=>"");if(p.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 ${p.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(p){d=p instanceof Error?p.message:String(p)}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(`
775
- `)}}async fetchVin(e){let t=await fetch(`${Dn}/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(`${Dn}/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===Ul);if(i)return i.containerId}let s=await fetch(`${Dn}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:Ul,purpose:"Alfred AI Assistant",technicalDescriptors:dp}),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":op,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<ap)return s.data;let r=await this.ensureToken(),n=`${Dn}${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(){if(this.tokens)return this.tokens;try{let e=await Nl(Ln,"utf-8");return this.tokens=JSON.parse(e),this.tokens}catch{return null}}async saveTokens(e){await Ol(Si($i(),".alfred"),{recursive:!0}),await Ml(Ln,JSON.stringify(e,null,2),"utf-8")}async savePartialTokens(e){await Ol(Si($i(),".alfred"),{recursive:!0});let t={};try{let s=await Nl(Ln,"utf-8");t=JSON.parse(s)}catch{}await Ml(Ln,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(Pl,{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=fe(o,"vehicle.drivetrain.batteryManagement.header"),a=fe(o,"vehicle.drivetrain.electricEngine.remainingElectricRange"),c=fe(o,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=fe(o,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),p=["## 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:p.join(`
775
+ `)}}async fetchVin(e){let t=await fetch(`${Ln}/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(`${Ln}/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===Ul);if(i)return i.containerId}let s=await fetch(`${Ln}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:Ul,purpose:"Alfred AI Assistant",technicalDescriptors:dp}),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":op,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<ap)return s.data;let r=await this.ensureToken(),n=`${Ln}${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(){if(this.tokens)return this.tokens;try{let e=await Nl(Dn,"utf-8");return this.tokens=JSON.parse(e),this.tokens}catch{return null}}async saveTokens(e){await Ol(Si($i(),".alfred"),{recursive:!0}),await Ml(Dn,JSON.stringify(e,null,2),"utf-8")}async savePartialTokens(e){await Ol(Si($i(),".alfred"),{recursive:!0});let t={};try{let s=await Nl(Dn,"utf-8");t=JSON.parse(s)}catch{}await Ml(Dn,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(Pl,{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=fe(o,"vehicle.drivetrain.batteryManagement.header"),a=fe(o,"vehicle.drivetrain.electricEngine.remainingElectricRange"),c=fe(o,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=fe(o,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),p=["## 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:p.join(`
776
776
  `)}}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=fe(n,"vehicle.drivetrain.electricEngine.charging.status"),i=fe(n,"vehicle.drivetrain.batteryManagement.header"),a=fe(n,"vehicle.drivetrain.electricEngine.charging.level"),c=fe(n,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=fe(n,"vehicle.powertrain.electric.battery.charging.power"),u=fe(n,"vehicle.drivetrain.electricEngine.charging.hvStatus"),p=fe(n,"vehicle.powertrain.electric.battery.stateOfCharge.target"),f=fe(n,"vehicle.drivetrain.electricEngine.charging.acVoltage"),g=fe(n,"vehicle.drivetrain.electricEngine.charging.acAmpere"),h=fe(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"),y=fe(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen"),b=fe(n,"vehicle.body.chargingPort.lockedStatus"),k=["## BMW Ladestatus","",`**Status:** ${o}`,`**Ladestand:** ${i} %`,`**Ladelevel:** ${a}`,`**Ladeleistung:** ${d} kW`,`**Restzeit:** ${c} min`,`**Ziel-SoC:** ${p} %`,`**HV-Batterie:** ${u}`,`**AC Spannung:** ${f} V`,`**AC Strom:** ${g} A`,`**Stecker eingesteckt:** ${h}`,`**Ladeklappe offen:** ${y}`,`**Ladeport-Schloss:** ${b}`];return{success:!0,data:n,display:k.join(`
777
- `)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),n=new Date,o=s??n.toISOString(),i=t??new Date(n.getTime()-30*24*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 p=u.startTime,f=u.endTime,g=m(O=>new Date(O*1e3).toLocaleString("de-AT",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"}),"fmtDateTime"),h=p?g(p):"-",y=f?g(f):"-",b=u.totalChargingDurationSec,k=b!=null?Math.round(b/60):"-",S=u.energyConsumedFromPowerGridKwh??"-",j=u.displayedStartSoc??"-",N=u.displayedSoc??"-",q=u.mileage!=null?`${u.mileage}`:"-",ee=u.chargingLocation,D=ee?.formattedAddress??ee?.streetAddress??"-";d.push(`| ${h} | ${y} | ${k} min | ${S} kWh | ${j}% | ${N}% | ${q} | ${D} |`)}return c.length===0&&d.push("| - | - | Keine Sessions gefunden | - | - | - | - | - |"),{success:!0,data:a,display:d.join(`
778
- `)}}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}`)]),p=d.data??d.chargingSessions??[],f=parseFloat(fe(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(p.length<2)return{success:!0,data:{sessions:p.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let g=p.filter(O=>typeof O.mileage=="number"&&typeof O.displayedStartSoc=="number"&&typeof O.displayedSoc=="number").sort((O,ie)=>O.mileage-ie.mileage);if(g.length<2)return{success:!0,data:{sessions:g.length},display:"Nicht gen\xFCgend Lade-Sessions mit vollst\xE4ndigen Daten."};let h=[];for(let O=1;O<g.length;O++){let ie=g[O-1],He=g[O],ke=ie.mileage,oe=He.mileage,J=oe-ke;if(J<=0)continue;let B=ie.displayedSoc,de=He.displayedStartSoc,Re=B-de;if(Re<=0)continue;let Ie=Re/100*f,x=Ie/J*100,z=He.startTime,re=z?new Date(z*1e3).toLocaleDateString("de-AT"):"-";h.push({fromKm:ke,toKm:oe,distance:J,socUsed:Re,kWhUsed:Ie,consumption:x,date:re})}if(h.length===0)return{success:!0,data:{},display:"Keine auswertbaren Fahrtabschnitte gefunden."};if(t==="last"){let O=h[h.length-1];return{success:!0,data:O,display:["## Letzte Fahrt (gesch\xE4tzt)","",`**Datum:** ${O.date}`,`**Strecke:** ${O.distance} km`,`**Verbrauch:** ${O.consumption.toFixed(1)} kWh/100km`,`**Energie:** ${O.kWhUsed.toFixed(1)} kWh (${O.socUsed}% SoC)`,`**km-Stand:** ${O.fromKm} \u2192 ${O.toKm}`].join(`
779
- `)}}let y=h.reduce((O,ie)=>O+ie.distance,0),b=h.reduce((O,ie)=>O+ie.kWhUsed,0),k=b/y*100,S=h.map(O=>O.consumption).sort((O,ie)=>O-ie),j=S[0],N=S[S.length-1],q=S[Math.floor(S.length/2)],D=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${f} kWh`,`**Ausgewertete Fahrten:** ${h.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${b.toFixed(1)} kWh`,"",`**Durchschnitt:** ${k.toFixed(1)} kWh/100km`,`**Min:** ${j.toFixed(1)} kWh/100km`,`**Max:** ${N.toFixed(1)} kWh/100km`,`**Median:** ${q.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let O of h)D.push(`| ${O.date} | ${O.distance} km | ${O.consumption.toFixed(1)} kWh/100km | ${O.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:k,totalDistance:y,totalKwh:b,segments:h},display:D.join(`
777
+ `)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),n=new Date,o=s??n.toISOString(),i=t??new Date(n.getTime()-30*24*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 p=u.startTime,f=u.endTime,g=m(O=>new Date(O*1e3).toLocaleString("de-AT",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"}),"fmtDateTime"),h=p?g(p):"-",y=f?g(f):"-",b=u.totalChargingDurationSec,k=b!=null?Math.round(b/60):"-",S=u.energyConsumedFromPowerGridKwh??"-",j=u.displayedStartSoc??"-",N=u.displayedSoc??"-",z=u.mileage!=null?`${u.mileage}`:"-",ee=u.chargingLocation,L=ee?.formattedAddress??ee?.streetAddress??"-";d.push(`| ${h} | ${y} | ${k} min | ${S} kWh | ${j}% | ${N}% | ${z} | ${L} |`)}return c.length===0&&d.push("| - | - | Keine Sessions gefunden | - | - | - | - | - |"),{success:!0,data:a,display:d.join(`
778
+ `)}}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}`)]),p=d.data??d.chargingSessions??[],f=parseFloat(fe(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(p.length<2)return{success:!0,data:{sessions:p.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let g=p.filter(O=>typeof O.mileage=="number"&&typeof O.displayedStartSoc=="number"&&typeof O.displayedSoc=="number").sort((O,ie)=>O.mileage-ie.mileage);if(g.length<2)return{success:!0,data:{sessions:g.length},display:"Nicht gen\xFCgend Lade-Sessions mit vollst\xE4ndigen Daten."};let h=[];for(let O=1;O<g.length;O++){let ie=g[O-1],He=g[O],ke=ie.mileage,oe=He.mileage,J=oe-ke;if(J<=0)continue;let B=ie.displayedSoc,de=He.displayedStartSoc,Re=B-de;if(Re<=0)continue;let Ie=Re/100*f,x=Ie/J*100,q=He.startTime,re=q?new Date(q*1e3).toLocaleDateString("de-AT"):"-";h.push({fromKm:ke,toKm:oe,distance:J,socUsed:Re,kWhUsed:Ie,consumption:x,date:re})}if(h.length===0)return{success:!0,data:{},display:"Keine auswertbaren Fahrtabschnitte gefunden."};if(t==="last"){let O=h[h.length-1];return{success:!0,data:O,display:["## Letzte Fahrt (gesch\xE4tzt)","",`**Datum:** ${O.date}`,`**Strecke:** ${O.distance} km`,`**Verbrauch:** ${O.consumption.toFixed(1)} kWh/100km`,`**Energie:** ${O.kWhUsed.toFixed(1)} kWh (${O.socUsed}% SoC)`,`**km-Stand:** ${O.fromKm} \u2192 ${O.toKm}`].join(`
779
+ `)}}let y=h.reduce((O,ie)=>O+ie.distance,0),b=h.reduce((O,ie)=>O+ie.kWhUsed,0),k=b/y*100,S=h.map(O=>O.consumption).sort((O,ie)=>O-ie),j=S[0],N=S[S.length-1],z=S[Math.floor(S.length/2)],L=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${f} kWh`,`**Ausgewertete Fahrten:** ${h.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${b.toFixed(1)} kWh`,"",`**Durchschnitt:** ${k.toFixed(1)} kWh/100km`,`**Min:** ${j.toFixed(1)} kWh/100km`,`**Max:** ${N.toFixed(1)} kWh/100km`,`**Median:** ${z.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let O of h)L.push(`| ${O.date} | ${O.distance} km | ${O.consumption.toFixed(1)} kWh/100km | ${O.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:k,totalDistance:y,totalKwh:b,segments:h},display:L.join(`
780
780
  `)}}}});var up,Mn,Bl=T(()=>{"use strict";U();up="https://routes.googleapis.com/directions/v2:computeRoutes",Mn=class extends R{static{m(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. Orte als Adresse, "lat,lng", oder Alias ("home"/"zuhause", "work"/"b\xFCro") angeben.',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, "lat,lng", oder Alias wie "home"/"zuhause"/"work"/"b\xFCro"'},destination:{type:"string",description:'Ziel-Adresse, "lat,lng", oder Alias wie "home"/"zuhause"/"work"/"b\xFCro"'},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,p=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(c)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(u>1&&p.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(u)}`),s){let f=new Date(new Date(s).getTime()+c*6e4);p.push(`**Gesch\xE4tzte Ankunft:** ${f.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:c,staticDurationMinutes:d},display:p.join(`
781
781
  `)}}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),p=["## 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:p.join(`
782
- `)}}resolveAddressAlias(e){let t=e.toLowerCase().trim(),s=["home","zuhause","von zuhause","nach hause","daheim"],r=["work","arbeit","b\xFCro","office","firma"];return this.config.homeAddress&&s.some(n=>t===n||t.startsWith(n+" "))?this.config.homeAddress:this.config.workAddress&&r.some(n=>t===n||t.startsWith(n+" "))?this.config.workAddress:e}buildWaypoint(e){let t=this.resolveAddressAlias(e),s=t.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return s?{location:{latLng:{latitude:parseFloat(s[1]),longitude:parseFloat(s[2])}}}:{address:t}}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=m(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(up,{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 Hl,zl,mp,pp,hp,us,ql,Wl,Gl,vi,Ai,Vl,On,Kl=T(()=>{"use strict";U();Hl=1.5,zl=4.79,mp=5.75,pp=1.03,hp=new Date("2026-04-01T00:00:00+02:00"),us=1.2,ql=.1,Wl=.58,Gl=.04,vi=.32,Ai=1.62,Vl="https://api.awattar.at/v1/marketdata",On=class extends R{static{m(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(`
782
+ `)}}resolveAddressAlias(e){let t=e.toLowerCase().trim(),s=["home","zuhause","von zuhause","nach hause","daheim"],r=["work","arbeit","b\xFCro","office","firma"];return this.config.homeAddress&&s.some(n=>t===n||t.startsWith(n+" "))?this.config.homeAddress:this.config.workAddress&&r.some(n=>t===n||t.startsWith(n+" "))?this.config.workAddress:e}buildWaypoint(e){let t=this.resolveAddressAlias(e),s=t.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return s?{location:{latLng:{latitude:parseFloat(s[1]),longitude:parseFloat(s[2])}}}:{address:t}}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=m(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(up,{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 Hl,ql,mp,pp,hp,us,zl,Wl,Gl,vi,Ai,Vl,On,Kl=T(()=>{"use strict";U();Hl=1.5,ql=4.79,mp=5.75,pp=1.03,hp=new Date("2026-04-01T00:00:00+02:00"),us=1.2,zl=.1,Wl=.58,Gl=.04,vi=.32,Ai=1.62,Vl="https://api.awattar.at/v1/marketdata",On=class extends R{static{m(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(`
783
783
  `)}}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,p=0;for(let g of o){let h=this.calculatePrice(g.marketprice),y=this.formatHourRange(g.start_timestamp,g.end_timestamp),b=this.spotCtKwh(g.marketprice);c.push(`| ${y} | ${b.toFixed(2)} | ${h.bruttoCt.toFixed(2)} |`),d=Math.min(d,h.bruttoCt),u=Math.max(u,h.bruttoCt),p+=h.bruttoCt}let f=p/o.length;return c.push(""),c.push(`**Min:** ${d.toFixed(2)} ct/kWh | **Max:** ${u.toFixed(2)} ct/kWh | **\xD8:** ${f.toFixed(2)} ct/kWh`),{success:!0,data:{entries:o.length,min:d,max:u,avg:f},display:c.join(`
784
784
  `)}}async cheapest(e){let t=e??3,s=Date.now(),r=s+24*60*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),p=new Date(c.start_timestamp).toLocaleDateString("de-AT",{weekday:"short"});a.push(`- **${p} ${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(`
785
785
  `)}}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(`
786
786
  `)}}async briefingSummary(){let e=Date.now(),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 heute verf\xFCgbar."};let n=r.map(y=>({time:this.formatHourRange(y.start_timestamp,y.end_timestamp),bruttoCt:this.calculatePrice(y.marketprice).bruttoCt,start:y.start_timestamp,isCurrent:y.start_timestamp<=e&&y.end_timestamp>e,isPast:y.end_timestamp<=e})),o=n.find(y=>y.isCurrent),i=n.filter(y=>!y.isPast),a=n.map(y=>y.bruttoCt),c=a.reduce((y,b)=>y+b,0)/a.length,d=Math.min(...a),u=Math.max(...a),p=[...i].sort((y,b)=>y.bruttoCt-b.bruttoCt),f=p.slice(0,3),g=p.slice(-3).reverse(),h=[];o&&h.push(`**Aktuell (${o.time}):** ${o.bruttoCt.toFixed(2)} ct/kWh brutto`),h.push(`**Tagesdurchschnitt:** ${c.toFixed(2)} ct/kWh | **Min:** ${d.toFixed(2)} | **Max:** ${u.toFixed(2)}`),h.push(""),h.push("**G\xFCnstigste 3 Stunden (Rest des Tages):**");for(let y of f)h.push(`- ${y.time}: ${y.bruttoCt.toFixed(2)} ct/kWh`);h.push(""),h.push("**Teuerste 3 Stunden (Rest des Tages):**");for(let y of g)h.push(`- ${y.time}: ${y.bruttoCt.toFixed(2)} ct/kWh`);return{success:!0,data:{currentCt:o?.bruttoCt,avgCt:c,minCt:d,maxCt:u,cheapest:f.map(y=>({time:y.time,bruttoCt:y.bruttoCt})),expensive:g.map(y=>({time:y.time,bruttoCt:y.bruttoCt}))},display:h.join(`
787
- `)}}spotCtKwh(e){return e/10}calculatePrice(e){let t=this.spotCtKwh(e),s=new Date<hp,n=(s?t*pp:t)+Hl,o=this.getGridCosts(),i=o.usageCt+o.lossCt,a=ql+Wl+Gl,c=n+i+a,d=c*us;return{spotCt:t,ausgleichCt:s?t*.03:0,aufschlagCt:Hl,energieNettoCt:n,netznutzungCt:o.usageCt,netzverlustCt:o.lossCt,eAbgabeCt:ql,oekoArbeitCt:Wl,oekoVerlustCt:Gl,gesamtNettoCt:c,ustCt:c*.2,bruttoCt:d,gridName:o.name,hasGrid:o.usageCt>0}}getGridCosts(){let e=this.config?.gridUsageCt??0,t=this.config?.gridLossCt??0,s=this.config?.gridName??"";return e>0?{name:s,usageCt:e,lossCt:t}:{name:"",usageCt:0,lossCt:0}}formatBreakdown(e){let t=["| Komponente | ct/kWh |","|---|---:|",`| EPEX Spot Marktpreis | ${e.spotCt.toFixed(2)} |`];e.ausgleichCt>0&&t.push(`| Ausgleichsenergie (3%) | ${e.ausgleichCt.toFixed(2)} |`),t.push(`| aWATTar Aufschlag | ${e.aufschlagCt.toFixed(2)} |`),t.push(`| **Energie netto** | **${e.energieNettoCt.toFixed(2)}** |`),e.hasGrid&&(t.push(`| Netznutzung (${e.gridName}) | ${e.netznutzungCt.toFixed(2)} |`),t.push(`| Netzverlust | ${e.netzverlustCt.toFixed(2)} |`)),t.push(`| Elektrizit\xE4tsabgabe | ${e.eAbgabeCt.toFixed(2)} |`),t.push(`| \xD6kostrom-F\xF6rderbeitrag | ${e.oekoArbeitCt.toFixed(2)} |`),t.push(`| \xD6kostrom-Verlust | ${e.oekoVerlustCt.toFixed(2)} |`),t.push(`| **Gesamt netto** | **${e.gesamtNettoCt.toFixed(2)}** |`),t.push(`| USt (20%) | ${e.ustCt.toFixed(2)} |`),t.push(`| **Gesamt brutto** | **${e.bruttoCt.toFixed(2)}** |`),e.hasGrid||(t.push(""),t.push("*Netzentgelte nicht inkludiert \u2014 Netzkosten via `alfred setup` oder ENV konfigurieren*"));let s=this.config?.gridCapacityFee??0,r=this.config?.gridMeterFee??0;if(t.push(""),t.push("**Fixe Monatskosten (netto \u2192 brutto):**"),t.push(`- aWATTar Grundgeb\xFChr: ${zl.toFixed(2)} \u20AC \u2192 ${mp.toFixed(2)} \u20AC`),s>0){let i=this.config?.gridName?` (${this.config.gridName})`:"";t.push(`- Leistungspauschale${i}: ${s.toFixed(2)} \u20AC \u2192 ${(s*us).toFixed(2)} \u20AC`)}r>0&&t.push(`- Messentgelt: ${r.toFixed(2)} \u20AC \u2192 ${(r*us).toFixed(2)} \u20AC`),t.push(`- \xD6kostrom-F\xF6rderpauschale: ${vi.toFixed(2)} \u20AC \u2192 ${(vi*us).toFixed(2)} \u20AC`),t.push(`- Erneuerbaren-F\xF6rderpauschale: ${Ai.toFixed(2)} \u20AC \u2192 ${(Ai*us).toFixed(2)} \u20AC`);let n=zl+vi+Ai+s+r,o=n*us;return t.push(`- **Summe:** ${n.toFixed(2)} \u20AC \u2192 **${o.toFixed(2)} \u20AC brutto/Monat**`),t.join(`
787
+ `)}}spotCtKwh(e){return e/10}calculatePrice(e){let t=this.spotCtKwh(e),s=new Date<hp,n=(s?t*pp:t)+Hl,o=this.getGridCosts(),i=o.usageCt+o.lossCt,a=zl+Wl+Gl,c=n+i+a,d=c*us;return{spotCt:t,ausgleichCt:s?t*.03:0,aufschlagCt:Hl,energieNettoCt:n,netznutzungCt:o.usageCt,netzverlustCt:o.lossCt,eAbgabeCt:zl,oekoArbeitCt:Wl,oekoVerlustCt:Gl,gesamtNettoCt:c,ustCt:c*.2,bruttoCt:d,gridName:o.name,hasGrid:o.usageCt>0}}getGridCosts(){let e=this.config?.gridUsageCt??0,t=this.config?.gridLossCt??0,s=this.config?.gridName??"";return e>0?{name:s,usageCt:e,lossCt:t}:{name:"",usageCt:0,lossCt:0}}formatBreakdown(e){let t=["| Komponente | ct/kWh |","|---|---:|",`| EPEX Spot Marktpreis | ${e.spotCt.toFixed(2)} |`];e.ausgleichCt>0&&t.push(`| Ausgleichsenergie (3%) | ${e.ausgleichCt.toFixed(2)} |`),t.push(`| aWATTar Aufschlag | ${e.aufschlagCt.toFixed(2)} |`),t.push(`| **Energie netto** | **${e.energieNettoCt.toFixed(2)}** |`),e.hasGrid&&(t.push(`| Netznutzung (${e.gridName}) | ${e.netznutzungCt.toFixed(2)} |`),t.push(`| Netzverlust | ${e.netzverlustCt.toFixed(2)} |`)),t.push(`| Elektrizit\xE4tsabgabe | ${e.eAbgabeCt.toFixed(2)} |`),t.push(`| \xD6kostrom-F\xF6rderbeitrag | ${e.oekoArbeitCt.toFixed(2)} |`),t.push(`| \xD6kostrom-Verlust | ${e.oekoVerlustCt.toFixed(2)} |`),t.push(`| **Gesamt netto** | **${e.gesamtNettoCt.toFixed(2)}** |`),t.push(`| USt (20%) | ${e.ustCt.toFixed(2)} |`),t.push(`| **Gesamt brutto** | **${e.bruttoCt.toFixed(2)}** |`),e.hasGrid||(t.push(""),t.push("*Netzentgelte nicht inkludiert \u2014 Netzkosten via `alfred setup` oder ENV konfigurieren*"));let s=this.config?.gridCapacityFee??0,r=this.config?.gridMeterFee??0;if(t.push(""),t.push("**Fixe Monatskosten (netto \u2192 brutto):**"),t.push(`- aWATTar Grundgeb\xFChr: ${ql.toFixed(2)} \u20AC \u2192 ${mp.toFixed(2)} \u20AC`),s>0){let i=this.config?.gridName?` (${this.config.gridName})`:"";t.push(`- Leistungspauschale${i}: ${s.toFixed(2)} \u20AC \u2192 ${(s*us).toFixed(2)} \u20AC`)}r>0&&t.push(`- Messentgelt: ${r.toFixed(2)} \u20AC \u2192 ${(r*us).toFixed(2)} \u20AC`),t.push(`- \xD6kostrom-F\xF6rderpauschale: ${vi.toFixed(2)} \u20AC \u2192 ${(vi*us).toFixed(2)} \u20AC`),t.push(`- Erneuerbaren-F\xF6rderpauschale: ${Ai.toFixed(2)} \u20AC \u2192 ${(Ai*us).toFixed(2)} \u20AC`);let n=ql+vi+Ai+s+r,o=n*us;return t.push(`- **Summe:** ${n.toFixed(2)} \u20AC \u2192 **${o.toFixed(2)} \u20AC brutto/Monat**`),t.join(`
788
788
  `)}async fetchMarketData(e,t){let s=new URLSearchParams;e!=null&&s.set("start",e.toString()),t!=null&&s.set("end",t.toString());let r=s.toString()?`${Vl}?${s}`:Vl,n=await fetch(r,{signal:AbortSignal.timeout(1e4)});if(!n.ok){let i=await n.text().catch(()=>"");throw new Error(`HTTP ${n.status} \u2014 ${i.slice(0,300)}`)}return(await n.json()).data||[]}formatHourRange(e,t){let s=new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}),r=new Date(t).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"});return`${s}\u2013${r}`}}});var ms,Xl=T(()=>{"use strict";U();ms=class extends R{static{m(this,"TransitSkill")}metadata={name:"transit_search",category:"information",description:'\xD6ffentlicher Nahverkehr in \xD6sterreich (\xD6BB, Wiener Linien, etc.). "search_stop" sucht Haltestellen nach Name. "journeys" berechnet Verbindungen zwischen zwei Orten (Name oder Stop-ID). "departures" zeigt Abfahrten an einer Haltestelle (Stop-ID erforderlich, zuerst search_stop verwenden). Deckt Busse, Stra\xDFenbahnen, U-Bahn, S-Bahn, Regionalz\xFCge und Fernz\xFCge ab.',riskLevel:"read",version:"1.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["journeys","departures","search_stop"],description:"Transit action"},query:{type:"string",description:"Haltestellenname f\xFCr search_stop"},from:{type:"string",description:"Start-Haltestelle (Name oder ID) f\xFCr journeys"},to:{type:"string",description:"Ziel-Haltestelle (Name oder ID) f\xFCr journeys"},stop_id:{type:"string",description:"Stop-ID f\xFCr departures (von search_stop erhalten)"},departure:{type:"string",description:"ISO-Zeitpunkt f\xFCr gew\xFCnschte Abfahrt (optional)"},arrival:{type:"string",description:"ISO-Zeitpunkt f\xFCr gew\xFCnschte Ankunft (optional, nur f\xFCr journeys)"},results:{type:"number",description:"Anzahl Ergebnisse (Standard: 3)"},duration:{type:"number",description:"Zeitfenster in Minuten f\xFCr departures (Standard: 30)"}},required:["action"]}};client;constructor(e){super(),this.client=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"search_stop":return await this.searchStop(e);case"journeys":return await this.findJourneys(e);case"departures":return await this.findDepartures(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Transit API error: ${r instanceof Error?r.message:String(r)}`}}}async searchStop(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query" for search_stop'};let s=await this.client.searchStops(t);if(s.length===0)return{success:!0,data:[],display:`Keine Haltestellen gefunden f\xFCr "${t}".`};let r=["## Haltestellen",""];for(let n of s.slice(0,10))r.push(`- **${n.name}** (ID: \`${n.id}\`)`);return{success:!0,data:s,display:r.join(`
789
789
  `)}}async findJourneys(e){let t=e.from,s=e.to;if(!t)return{success:!1,error:'Missing required field "from" for journeys'};if(!s)return{success:!1,error:'Missing required field "to" for journeys'};let r={};e.departure&&(r.departure=new Date(e.departure)),e.arrival&&(r.arrival=new Date(e.arrival)),e.results&&(r.results=e.results);let n=await this.client.journeys(t,s,r);if(n.length===0)return{success:!0,data:[],display:`Keine Verbindungen gefunden von ${t} nach ${s}.`};let o=[`## Verbindungen: ${t} \u2192 ${s}`,""];for(let i=0;i<n.length;i++){let a=n[i],c=this.formatTime(a.departure),d=this.formatTime(a.arrival);o.push(`### Verbindung ${i+1}: ${c} \u2192 ${d} (${a.duration} min, ${a.transfers} Umstieg${a.transfers!==1?"e":""})`);for(let u of a.legs)u.walking?o.push(` - \u{1F6B6} Fu\xDFweg \u2192 ${u.destination} (${this.formatTime(u.departure)}\u2013${this.formatTime(u.arrival)})`):o.push(` - ${u.line||u.mode} Ri. ${u.direction||u.destination}: ${u.origin} ${this.formatTime(u.departure)} \u2192 ${u.destination} ${this.formatTime(u.arrival)}`);o.push("")}return{success:!0,data:n,display:o.join(`
790
790
  `)}}async findDepartures(e){let t=e.stop_id;if(!t)return{success:!1,error:'Missing required field "stop_id" for departures. Use search_stop first to find the stop ID.'};let s={};e.departure&&(s.when=new Date(e.departure)),e.duration&&(s.duration=e.duration);let r=await this.client.departures(t,s);if(r.length===0)return{success:!0,data:[],display:"Keine Abfahrten gefunden."};let n=["## Abfahrten",""];for(let o of r){let i=this.formatTime(o.when),a=o.delay?` (+${o.delay} min)`:"",c=o.platform?` [Steig ${o.platform}]`:"";n.push(`- **${i}${a}** ${o.line} \u2192 ${o.direction}${c}`)}return{success:!0,data:r,display:n.join(`
@@ -807,7 +807,7 @@ ${d}=${p}
807
807
  `)}}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 p=u/d*100;p>95&&t.push({source:"proxmox",message:`${o} RAM usage ${p.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),p;if(u.status===200)p="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(f=>f.split(";")[0]),o=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let f=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!f.ok)throw new Error(`UniFi login failed: HTTP ${f.status}`);p="classic",n=(f.headers.getSetCookie?.()??[]).map(g=>g.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=m(c=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${c}`,"apiUrl"),a=m(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 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 Un,ed=T(()=>{"use strict";U();Un=class extends R{static{m(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=m(()=>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(`
808
808
  `);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}
809
809
  ${i.join(`
810
- `)}`:"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 td,fs,sd=T(()=>{"use strict";U();td=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],fs=class extends R{static{m(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. Common condition_field paths by skill: 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:"Parameters to pass to the skill (for create)"},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)"},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};constructor(e){super(),this.watchRepo=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;if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};if(!o)return{success:!1,error:'Missing required field "condition_field"'};if(!i||!td.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${td.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"};let p=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:o,operator:i,value:a},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u});return{success:!0,data:{watchId:p.id,name:s,skillName:r,conditionField:o,conditionOperator:i,conditionValue:a,intervalMinutes:c},display:`Watch erstellt (${p.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${o} ${i}${a!=null?" "+a:""}`}}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}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${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:
810
+ `)}`:"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 td,fs,sd=T(()=>{"use strict";U();td=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],fs=class extends R{static{m(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)"},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;if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};if(!o)return{success:!1,error:'Missing required field "condition_field"'};if(!i||!td.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${td.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(this.skillRegistry){let f=this.skillRegistry.get(r);if(!f)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let g=f.metadata.inputSchema;if(g&&Array.isArray(g.required)){let h=g.required.filter(y=>!(y in n));if(h.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${h.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(g.required)}`}}}let p=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:o,operator:i,value:a},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u});return{success:!0,data:{watchId:p.id,name:s,skillName:r,conditionField:o,conditionOperator:i,conditionValue:a,intervalMinutes:c},display:`Watch erstellt (${p.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${o} ${i}${a!=null?" "+a:""}`}}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}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${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:
811
811
  ${s.join(`
812
812
  `)}`}}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 Ct,Fn=T(()=>{"use strict";Ct=class{static{m(this,"MarketplaceProvider")}async getDetail(e){throw new Error("Detail not supported")}}});var rd,br,Ri=T(()=>{"use strict";Fn();rd="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",br=class extends Ct{static{m(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 a={date_desc:"1",price_asc:"2",price_desc:"3"};s.searchParams.set("sfId",a[e.sort])}e.postcode&&s.searchParams.set("postcode",e.postcode);let r=await fetch(s.toString(),{headers:{"User-Agent":rd,Accept:"text/html"}});if(!r.ok)throw new Error(`willhaben HTTP ${r.status}`);let n=await r.text(),i=this.parseNextData(n).map(a=>this.mapAdvert(a));return{listings: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":rd,Accept:"text/html"}});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=JSON.parse(n[1]),i=o?.props?.pageProps?.advertDetail??o?.props?.pageProps?.ad??o?.props?.pageProps,a=i?.attributes?.attribute??[],c=m(f=>a.find(h=>h.name===f)?.values?.[0]??void 0,"attr"),d={};for(let f of a)f.name&&f.values?.[0]&&(d[f.name]=f.values[0]);let u=(i?.advertImageList?.advertImage??[]).map(f=>f.mainImageUrl??f.referenceImageUrl).filter(Boolean),p=c("PRICE");return{id:e,title:c("HEADING")??i?.description??"Kein Titel",price:p?parseFloat(p):null,currency:"EUR",condition:c("CONDITION"),location:[c("LOCATION"),c("POSTCODE")].filter(Boolean).join(" "),url:t,imageUrls:u,seller:c("ORGANIZER")??void 0,sellerSince:c("ORGANIZER_SINCE")??void 0,publishedAt:c("PUBLISHED_String")??void 0,description:c("BODY")??c("DESCRIPTION")??i?.body??"",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");return JSON.parse(t[1])?.props?.pageProps?.searchResult?.advertSummaryList?.advertSummary??[]}extractTotalCount(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);return t?JSON.parse(t[1])?.props?.pageProps?.searchResult?.rowsFound:void 0}mapAdvert(e){let t=e.attributes?.attribute??[],s=m(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 kr,xi=T(()=>{"use strict";Fn();kr=class extends Ct{static{m(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 jn(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 Ci(l,e){return l==null?"k.A.":`${l.toFixed(2)} ${e}`}var $r,nd=T(()=>{"use strict";U();Ri();xi();m(jn,"median");m(Ci,"formatPrice");$r=class extends R{static{m(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. 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 br),e?.ebay?.appId&&e?.ebay?.certId&&this.providers.push(new kr(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 g=e.listing_id;return g?this.handleDetail(r,g):{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 p=this.getProviders(r);if(p.length===0)return{success:!1,error:"Keine Marketplace-Provider verf\xFCgbar f\xFCr diese Plattform"};let f={query:n,priceMin:o,priceMax:i,rows:a,sort:c,condition:d,postcode:u};switch(s){case"search":return this.handleSearch(p,f);case"compare":return this.handleCompare(p,{...f,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(", ")})`:""}
813
813
  `),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} | ${Ci(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:** ${jn(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?jn(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(`
@@ -816,7 +816,7 @@ ${s.join(`
816
816
  `),c.push("| # | Titel | Preis | Standort | Plattform | Link |"),c.push("|---|-------|-------|----------|-----------|------|");for(let d=0;d<i.length;d++){let u=i[d],p=u.title.length>60?u.title.slice(0,57)+"...":u.title;c.push(`| ${d+1} | ${p} | ${Ci(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:jn(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(`
817
817
  `)}}async handleDetail(e,t){let r=(e==="all"?this.providers:this.providers.filter(o=>o.platform===e))[0];if(!r)return{success:!1,error:"Kein Provider verf\xFCgbar f\xFCr diese Plattform"};let n=await r.getDetail(t);return{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:`**${n.title}** \u2014 ${Ci(n.price,n.currency)}
818
818
  \u{1F4CD} ${n.location??"k.A."}
819
- ${n.description.slice(0,500)}`}}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 od=T(()=>{"use strict";nd();Fn();Ri();xi()});function gp(){let l=new Date,e=new Date(l.getFullYear(),l.getMonth(),l.getDate()),t=new Date(e.getTime()+24*60*60*1e3);return{start:e.toISOString(),end:t.toISOString()}}function yp(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 wp(){let l=new Date().getDay();return l>=1&&l<=5}var Di,Bn,id=T(()=>{"use strict";U();Oe();m(gp,"todayRange");Di=[{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"}];m(yp,"extractCity");m(wp,"isWeekday");Bn=class extends R{static{m(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 Di.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=Di.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:Di.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
819
+ ${n.description.slice(0,500)}`}}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 od=T(()=>{"use strict";nd();Fn();Ri();xi()});function gp(){let l=new Date,e=new Date(l.getFullYear(),l.getMonth(),l.getDate()),t=new Date(e.getTime()+24*60*60*1e3);return{start:e.toISOString(),end:t.toISOString()}}function yp(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 wp(){let l=new Date().getDay();return l>=1&&l<=5}var Li,Bn,id=T(()=>{"use strict";U();Oe();m(gp,"todayRange");Li=[{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"}];m(yp,"extractCity");m(wp,"isWeekday");Bn=class extends R{static{m(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 Li.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=Li.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:Li.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
820
820
  ${t.join(`
821
821
  `)}
822
822
 
@@ -837,14 +837,14 @@ ${a.display}`):a.error&&d.push(`**Route:** \u26A0\uFE0F ${a.error}`),c?.success&
837
837
  `),s.trim()}buildHighlights(e){let t=[],s=e.find(i=>i.module==="bmw")?.data;if(s){let i=this.extractBatteryLevel(s);i!=null&&i<30&&t.push(`\u{1F697} BMW Akku bei ${i}% \u2014 laden empfohlen`)}let r=e.find(i=>i.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(i=>i.module==="energy")?.data;if(n){let i=n.currentCt,a=n.avgCt;i!=null&&a!=null&&i<a&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${i} ct/kWh)`)}let o=e.find(i=>i.module==="calendar")?.data;return Array.isArray(o)&&o.length>0&&t.push(`\u{1F4C5} ${o.length} Termin(e) heute`),t}extractBatteryLevel(e){if(!e||typeof e!="object")return null;let t=e,s=t.chargingLevelPercent??t.batterySoc??t.soc??t.chargingState?.chargingLevelPercent;if(typeof s=="number")return s;if(typeof s=="string"){let r=parseFloat(s);return isNaN(r)?null:r}return null}}});import{spawn as _p}from"node:child_process";import ad from"node:fs";import dd from"node:path";function kp(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 $p(l,e){return l.map(t=>t.replace(/\{\{prompt\}\}/g,e))}function Hn(l){return l.length<=cd?l:`[...truncated...]
838
838
  `+l.slice(-cd)}function ld(l){let e=new Map;function t(s){let r;try{r=ad.readdirSync(s,{withFileTypes:!0})}catch{return}for(let n of r){if(bp.has(n.name))continue;let o=dd.join(s,n.name);if(n.isDirectory())t(o);else if(n.isFile())try{let i=ad.statSync(o);e.set(o,i.mtimeMs)}catch{}}}return m(t,"walk"),t(l),e}function Sp(l,e,t){let s=[];for(let[r,n]of e){let o=l.get(r);(o===void 0||n>o)&&s.push(dd.relative(t,r))}return s.sort()}async function Sr(l,e,t={}){let s=t.cwd??l.cwd??process.cwd(),r=t.timeoutMs??l.timeoutMs??Tp,n=Math.min(r,Ep),o=$p(l.argsTemplate,e),i={...process.env,...l.env?kp(l.env):{}},a=process.platform==="win32",c=ld(s),d=Date.now();return new Promise(u=>{let p=_p(l.command,o,{cwd:s,env:i,shell:a,stdio:l.promptVia==="stdin"?["pipe","pipe","pipe"]:["ignore","pipe","pipe"]}),f="",g="",h=!1,y=setTimeout(()=>{h=!0,p.kill("SIGTERM"),setTimeout(()=>p.kill("SIGKILL"),5e3)},n);p.stdout?.on("data",b=>{f+=b.toString()}),p.stderr?.on("data",b=>{let k=b.toString();if(g+=k,t.onProgress){let S=k.trim().split(`
839
839
  `).pop();S&&t.onProgress(`[${l.name}] ${S}`)}}),l.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",b=>{clearTimeout(y);let k=Date.now()-d,S=ld(s),j=Sp(c,S,s);u({stdout:Hn(f),stderr:Hn(g),exitCode:h?124:b??1,durationMs:k,modifiedFiles:j})}),p.on("error",b=>{clearTimeout(y);let k=Date.now()-d;u({stdout:Hn(f),stderr:Hn(g+`
840
- `+b.message),exitCode:127,durationMs:k,modifiedFiles:[]})})})}var Tp,Ep,cd,bp,zn=T(()=>{"use strict";Tp=3e5,Ep=9e5,cd=1e5,bp=new Set([".git","node_modules",".next","dist",".cache"]);m(kp,"resolveEnv");m($p,"buildArgs");m(Hn,"truncateOutput");m(ld,"snapshotMtimes");m(Sp,"detectModifiedFiles");m(Sr,"executeAgent")});import{execFile as vp}from"node:child_process";function Be(l,e){return new Promise((t,s)=>{vp("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 qn(l){try{let e=await Be(["rev-parse","--abbrev-ref","HEAD"],l),t=await Be(["status","--porcelain"],l);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function Li(l,e){await Be(["checkout","-b",l],e)}async function Ni(l){await Be(["add","-A"],l)}async function Mi(l,e){await Be(["commit","-m",l],e);let t=await Be(["rev-parse","--short","HEAD"],e),r=(await Be(["diff","--stat","HEAD~1","HEAD"],e)).split(`
841
- `).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function Oi(l,e,t){await Be(["push","-u",l,e],t)}function Pi(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function gs(l,e){try{return await Be(["remote","get-url",l],e)}catch{return null}}function ys(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 vr(l){await Be(["init"],l)}async function Ar(l,e,t){await Be(["remote","add",l,e],t)}var Ui=T(()=>{"use strict";m(Be,"git");m(qn,"gitStatus");m(Li,"gitCreateBranch");m(Ni,"gitStageAll");m(Mi,"gitCommit");m(Oi,"gitPush");m(Pi,"slugifyBranch");m(gs,"gitGetRemoteUrl");m(ys,"parseRemoteUrl");m(vr,"gitInitRepo");m(Ar,"gitAddRemote")});function ws(l){switch(l.provider){case"github":{if(!l.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Fi(l.github)}case"gitlab":{if(!l.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new ji(l.gitlab)}default:throw new Error(`Unknown forge provider: ${l.provider}`)}}var Dt,Fi,ji,Bi=T(()=>{"use strict";Dt=class{static{m(this,"ForgeClient")}},Fi=class extends Dt{static{m(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}}},ji=class extends Dt{static{m(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}}};m(ws,"createForgeClient")});function ud(l,e){return l.length<=e?l:l.slice(0,e)+`
840
+ `+b.message),exitCode:127,durationMs:k,modifiedFiles:[]})})})}var Tp,Ep,cd,bp,qn=T(()=>{"use strict";Tp=3e5,Ep=9e5,cd=1e5,bp=new Set([".git","node_modules",".next","dist",".cache"]);m(kp,"resolveEnv");m($p,"buildArgs");m(Hn,"truncateOutput");m(ld,"snapshotMtimes");m(Sp,"detectModifiedFiles");m(Sr,"executeAgent")});import{execFile as vp}from"node:child_process";function Be(l,e){return new Promise((t,s)=>{vp("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 zn(l){try{let e=await Be(["rev-parse","--abbrev-ref","HEAD"],l),t=await Be(["status","--porcelain"],l);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function Di(l,e){await Be(["checkout","-b",l],e)}async function Ni(l){await Be(["add","-A"],l)}async function Mi(l,e){await Be(["commit","-m",l],e);let t=await Be(["rev-parse","--short","HEAD"],e),r=(await Be(["diff","--stat","HEAD~1","HEAD"],e)).split(`
841
+ `).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function Oi(l,e,t){await Be(["push","-u",l,e],t)}function Pi(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function gs(l,e){try{return await Be(["remote","get-url",l],e)}catch{return null}}function ys(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 vr(l){await Be(["init"],l)}async function Ar(l,e,t){await Be(["remote","add",l,e],t)}var Ui=T(()=>{"use strict";m(Be,"git");m(zn,"gitStatus");m(Di,"gitCreateBranch");m(Ni,"gitStageAll");m(Mi,"gitCommit");m(Oi,"gitPush");m(Pi,"slugifyBranch");m(gs,"gitGetRemoteUrl");m(ys,"parseRemoteUrl");m(vr,"gitInitRepo");m(Ar,"gitAddRemote")});function ws(l){switch(l.provider){case"github":{if(!l.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Fi(l.github)}case"gitlab":{if(!l.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new ji(l.gitlab)}default:throw new Error(`Unknown forge provider: ${l.provider}`)}}var Lt,Fi,ji,Bi=T(()=>{"use strict";Lt=class{static{m(this,"ForgeClient")}},Fi=class extends Lt{static{m(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}}},ji=class extends Lt{static{m(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}}};m(ws,"createForgeClient")});function ud(l,e){return l.length<=e?l:l.slice(0,e)+`
842
842
  [...truncated]`}function md(l){let e=l.replace(/^```(?:json)?\s*\n?/m,"").replace(/\n?```\s*$/m,"");return JSON.parse(e)}async function Np(l,e,t){let r=`Available agents:
843
843
  ${e.map(a=>`- ${a.name}: command="${a.command}"`).join(`
844
844
  `)}
845
845
 
846
846
  Task:
847
- ${l}`,n=await t.complete({system:Dp,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"}),o=md(n.content);if(!Array.isArray(o.subtasks)||o.subtasks.length===0)throw new Error("LLM returned an empty plan with no subtasks");let i=new Set(e.map(a=>a.name));for(let a of o.subtasks)if(!i.has(a.agent))throw new Error(`Plan references unknown agent "${a.agent}". Available: ${[...i].join(", ")}`);return o}async function Mp(l,e,t,s){let r=new Hi(t),n=[],o=l.map(async i=>{await r.acquire();try{s?.(`Running ${i.id}: ${i.description}`);let a=e.get(i.agent),c=await Sr(a,i.prompt,{onProgress:s?u=>s(`[${i.id}] ${u}`):void 0}),d={subtask:i,execution:c};return n.push(d),s?.(`Completed ${i.id}: exit=${c.exitCode}, ${c.modifiedFiles.length} files modified`),d}finally{r.release()}});return await Promise.all(o),n}async function Op(l,e,t){let s=e.map(o=>{let i=ud(o.execution.stdout,xp),a=ud(o.execution.stderr,Cp);return[`### ${o.subtask.id} (${o.subtask.description})`,`Agent: ${o.subtask.agent}`,`Exit code: ${o.execution.exitCode}`,`Modified files: ${o.execution.modifiedFiles.join(", ")||"none"}`,i?`stdout:
847
+ ${l}`,n=await t.complete({system:Lp,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"}),o=md(n.content);if(!Array.isArray(o.subtasks)||o.subtasks.length===0)throw new Error("LLM returned an empty plan with no subtasks");let i=new Set(e.map(a=>a.name));for(let a of o.subtasks)if(!i.has(a.agent))throw new Error(`Plan references unknown agent "${a.agent}". Available: ${[...i].join(", ")}`);return o}async function Mp(l,e,t,s){let r=new Hi(t),n=[],o=l.map(async i=>{await r.acquire();try{s?.(`Running ${i.id}: ${i.description}`);let a=e.get(i.agent),c=await Sr(a,i.prompt,{onProgress:s?u=>s(`[${i.id}] ${u}`):void 0}),d={subtask:i,execution:c};return n.push(d),s?.(`Completed ${i.id}: exit=${c.exitCode}, ${c.modifiedFiles.length} files modified`),d}finally{r.release()}});return await Promise.all(o),n}async function Op(l,e,t){let s=e.map(o=>{let i=ud(o.execution.stdout,xp),a=ud(o.execution.stderr,Cp);return[`### ${o.subtask.id} (${o.subtask.description})`,`Agent: ${o.subtask.agent}`,`Exit code: ${o.execution.exitCode}`,`Modified files: ${o.execution.modifiedFiles.join(", ")||"none"}`,i?`stdout:
848
848
  ${i}`:"",a?`stderr:
849
849
  ${a}`:""].filter(Boolean).join(`
850
850
  `)}).join(`
@@ -853,11 +853,11 @@ ${a}`:""].filter(Boolean).join(`
853
853
  ${l}
854
854
 
855
855
  Results:
856
- ${s}`,n=await t.complete({system:Lp,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=md(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 Lt(l,e,t,s={}){let r=Math.min(s.maxIterations??Ap,Ip),n=s.maxConcurrent??Rp,o=s.onProgress,i=Date.now(),a=new Map(e.map(h=>[h.name,h]));o?.("Planning subtasks...");let c=await Np(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,p=0,f="";for(;p<r;){p++,o?.(`Iteration ${p}: executing ${u.length} subtask(s)...`);let h=await Mp(u,a,n,o);d=d.concat(h),o?.(`Iteration ${p}: validating results...`);let y=await Op(l,d,t);if(f=y.summary,y.approved||y.fixTasks.length===0)break;let b=y.fixTasks.filter(k=>a.has(k.agent)?!0:(o?.(`Warning: fix task "${k.id}" references unknown agent "${k.agent}", skipping`),!1));if(b.length===0)break;u=b,o?.(`Validation requested ${b.length} fix task(s), iterating...`)}let g=[...new Set(d.flatMap(h=>h.execution.modifiedFiles))].sort();return{plan:c,iterations:p,subtaskResults:d,allModifiedFiles:g,summary:f,totalDurationMs:Date.now()-i}}async function Ir(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await qn({cwd:n});if(!i.isRepo)try{await vr({cwd:n}),i=await qn({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 Lt(l,e,t,s),git:o}}let a=null,c=await gs("origin",{cwd:n});if(c){let g=ys(c);g?(a={owner:g.owner,repo:g.repo},r?.(`Detected remote: ${g.owner}/${g.repo} (${g.baseUrl})`)):o.warnings.push(`Could not parse remote URL: ${c}`)}let d=s.forge;if(!c&&d)try{let g=ws(d),h=n.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${h}" on forge...`);let y=await g.createProject({name:h,visibility:"private"});await Ar("origin",y.cloneUrl,{cwd:n});let b=ys(y.cloneUrl);b&&(a={owner:b.owner,repo:b.repo}),r?.(`Project created: ${y.url} \u2014 remote "origin" set`)}catch(g){let h=g instanceof Error?g.message:String(g);o.warnings.push(`Project creation failed: ${h}`),r?.(`Warning: project creation failed \u2014 ${h}`)}let u=Pi(l);try{await Li(u,{cwd:n}),o.branch=u,r?.(`Created branch: ${u}`)}catch(g){throw new Error(`Failed to create branch "${u}": ${g instanceof Error?g.message:String(g)}`)}let p=await Lt(l,e,t,s);try{await Ni({cwd:n});let g=`feat: ${l.slice(0,72)}
856
+ ${s}`,n=await t.complete({system:Dp,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=md(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 Dt(l,e,t,s={}){let r=Math.min(s.maxIterations??Ap,Ip),n=s.maxConcurrent??Rp,o=s.onProgress,i=Date.now(),a=new Map(e.map(h=>[h.name,h]));o?.("Planning subtasks...");let c=await Np(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,p=0,f="";for(;p<r;){p++,o?.(`Iteration ${p}: executing ${u.length} subtask(s)...`);let h=await Mp(u,a,n,o);d=d.concat(h),o?.(`Iteration ${p}: validating results...`);let y=await Op(l,d,t);if(f=y.summary,y.approved||y.fixTasks.length===0)break;let b=y.fixTasks.filter(k=>a.has(k.agent)?!0:(o?.(`Warning: fix task "${k.id}" references unknown agent "${k.agent}", skipping`),!1));if(b.length===0)break;u=b,o?.(`Validation requested ${b.length} fix task(s), iterating...`)}let g=[...new Set(d.flatMap(h=>h.execution.modifiedFiles))].sort();return{plan:c,iterations:p,subtaskResults:d,allModifiedFiles:g,summary:f,totalDurationMs:Date.now()-i}}async function Ir(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await zn({cwd:n});if(!i.isRepo)try{await vr({cwd:n}),i=await zn({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 Dt(l,e,t,s),git:o}}let a=null,c=await gs("origin",{cwd:n});if(c){let g=ys(c);g?(a={owner:g.owner,repo:g.repo},r?.(`Detected remote: ${g.owner}/${g.repo} (${g.baseUrl})`)):o.warnings.push(`Could not parse remote URL: ${c}`)}let d=s.forge;if(!c&&d)try{let g=ws(d),h=n.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${h}" on forge...`);let y=await g.createProject({name:h,visibility:"private"});await Ar("origin",y.cloneUrl,{cwd:n});let b=ys(y.cloneUrl);b&&(a={owner:b.owner,repo:b.repo}),r?.(`Project created: ${y.url} \u2014 remote "origin" set`)}catch(g){let h=g instanceof Error?g.message:String(g);o.warnings.push(`Project creation failed: ${h}`),r?.(`Warning: project creation failed \u2014 ${h}`)}let u=Pi(l);try{await Di(u,{cwd:n}),o.branch=u,r?.(`Created branch: ${u}`)}catch(g){throw new Error(`Failed to create branch "${u}": ${g instanceof Error?g.message:String(g)}`)}let p=await Dt(l,e,t,s);try{await Ni({cwd:n});let g=`feat: ${l.slice(0,72)}
857
857
 
858
858
  Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,h=await Mi(g,{cwd:n});o.commit=h,r?.(`Committed: ${h.sha} (${h.filesChanged} files changed)`)}catch(g){let h=g instanceof Error?g.message:String(g);return o.warnings.push(`Commit failed: ${h}`),r?.(`Warning: commit failed \u2014 ${h}`),{...p,git:o}}if(!await gs("origin",{cwd:n}))return o.warnings.push("No remote configured \u2014 skipping push and PR creation"),r?.("No remote configured, skipping push and PR"),{...p,git:o};try{await Oi("origin",u,{cwd:n}),r?.(`Pushed branch: ${u}`)}catch(g){let h=g instanceof Error?g.message:String(g);return o.warnings.push(`Push failed: ${h}`),r?.(`Warning: push failed \u2014 ${h}`),{...p,git:o}}if(d&&a)try{let g=ws(d),h=s.baseBranch??d.baseBranch??"main",y=s.prTitle??`feat: ${l.slice(0,72)}`,b=["## Summary",p.summary,"",`**Iterations:** ${p.iterations}`,`**Modified files:** ${p.allModifiedFiles.length}`,p.allModifiedFiles.map(S=>`- \`${S}\``).join(`
859
859
  `),"","_Automated by Alfred_"].join(`
860
- `),k=await g.createPullRequest(a,{title:y,body:b,head:u,base:h});o.pullRequest=k,r?.(`PR created: ${k.url}`)}catch(g){let h=g instanceof Error?g.message:String(g);o.warnings.push(`PR creation failed: ${h}`),r?.(`Warning: PR creation failed \u2014 ${h}`)}else d||(o.warnings.push("No forge configured \u2014 skipping PR creation"),r?.("No forge configured, skipping PR creation"));return{...p,git:o}}var Ap,Ip,Rp,xp,Cp,Dp,Lp,Hi,zi=T(()=>{"use strict";zn();Ui();Bi();Ap=3,Ip=5,Rp=3,xp=2048,Cp=1024,Dp=`You are a task planner for a multi-agent coding system.
860
+ `),k=await g.createPullRequest(a,{title:y,body:b,head:u,base:h});o.pullRequest=k,r?.(`PR created: ${k.url}`)}catch(g){let h=g instanceof Error?g.message:String(g);o.warnings.push(`PR creation failed: ${h}`),r?.(`Warning: PR creation failed \u2014 ${h}`)}else d||(o.warnings.push("No forge configured \u2014 skipping PR creation"),r?.("No forge configured, skipping PR creation"));return{...p,git:o}}var Ap,Ip,Rp,xp,Cp,Lp,Dp,Hi,qi=T(()=>{"use strict";qn();Ui();Bi();Ap=3,Ip=5,Rp=3,xp=2048,Cp=1024,Lp=`You are a task planner for a multi-agent coding system.
861
861
  You receive a high-level task and a list of available coding agents.
862
862
  Your job is to decompose the task into concrete subtasks, each assigned to an agent.
863
863
 
@@ -873,7 +873,7 @@ Respond with ONLY valid JSON (no markdown fences):
873
873
  "subtasks": [
874
874
  { "id": "task-1", "agent": "<agent-name>", "prompt": "<detailed prompt>", "description": "<short description>" }
875
875
  ]
876
- }`,Lp=`You are a code review validator for a multi-agent coding system.
876
+ }`,Dp=`You are a code review validator for a multi-agent coding system.
877
877
  You receive the original task and the results from each subtask execution.
878
878
  Your job is to determine if the task was completed successfully.
879
879
 
@@ -887,7 +887,7 @@ Respond with ONLY valid JSON (no markdown fences):
887
887
  "fixTasks": [
888
888
  { "id": "fix-1", "agent": "<agent-name>", "prompt": "<detailed fix prompt>", "description": "<short description>" }
889
889
  ]
890
- }`;m(ud,"truncate");m(md,"parseJSON");Hi=class{static{m(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()}};m(Np,"planSubtasks");m(Mp,"executeSubtasksParallel");m(Op,"validateResults");m(Lt,"orchestrate");m(Ir,"orchestrateWithGit")});var Rr,pd=T(()=>{"use strict";U();zn();zi();Rr=class extends R{static{m(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(`
890
+ }`;m(ud,"truncate");m(md,"parseJSON");Hi=class{static{m(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()}};m(Np,"planSubtasks");m(Mp,"executeSubtasksParallel");m(Op,"validateResults");m(Dt,"orchestrate");m(Ir,"orchestrateWithGit")});var Rr,pd=T(()=>{"use strict";U();qn();qi();Rr=class extends R{static{m(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(`
891
891
  `);return{success:!0,data:{agents:e},display:`Available code agents:
892
892
  ${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 Sr(n,r,{cwd:o,timeoutMs:i,onProgress:t.onProgress}),c=[];return a.stdout&&c.push(`**stdout:**
893
893
  \`\`\`
@@ -899,7 +899,7 @@ ${a.stderr}
899
899
  ${a.modifiedFiles.map(d=>`- ${d}`).join(`
900
900
  `)}`),{success:a.exitCode===0,data:{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,durationMs:a.durationMs,modifiedFiles:a.modifiedFiles},display:c.join(`
901
901
 
902
- `),...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 Ir(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress,forge:this.forgeConfig,prTitle:a,baseBranch:c});return this.formatGitOrchestrationResult(u)}let d=await Lt(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(`
902
+ `),...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 Ir(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress,forge:this.forgeConfig,prTitle:a,baseBranch:c});return this.formatGitOrchestrationResult(u)}let d=await Dt(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(`
903
903
  **Modified files:**
904
904
  ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
905
905
  `)}`),e.summary&&t.push(`
@@ -908,9 +908,9 @@ ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
908
908
 
909
909
  **Git:**
910
910
  ${s.join(`
911
- `)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+n}}}});var hd=T(()=>{"use strict";pd();zn();zi();Ui();Bi()});var ne={};ue(ne,{ActivityTracker:()=>St,BMWSkill:()=>Nn,BackgroundTaskSkill:()=>os,BriefingSkill:()=>Bn,BrowserSkill:()=>ss,CalculatorSkill:()=>Ht,CalendarProvider:()=>Pe,CalendarSkill:()=>vt,ClipboardSkill:()=>es,CodeAgentSkill:()=>Rr,CodeExecutionSkill:()=>wr,CodeExecutor:()=>Rt,ConfigureSkill:()=>hs,ContactsProvider:()=>je,ContactsSkill:()=>Er,CrossPlatformSkill:()=>ns,DelegateSkill:()=>Yt,DockerSkill:()=>Cn,DocumentSkill:()=>as,EmailProvider:()=>Je,EmailSkill:()=>nt,EnergyPriceSkill:()=>On,FileSkill:()=>Zt,ForgeClient:()=>Dt,HomeAssistantSkill:()=>vn,HttpSkill:()=>Jt,ImageGenerateSkill:()=>ls,MCPClient:()=>At,MCPManager:()=>yr,MCPSkillAdapter:()=>It,MarketplaceSkill:()=>$r,MemorySkill:()=>Xt,MicrosoftTodoSkill:()=>Un,MonitorSkill:()=>Pn,NoteSkill:()=>Gt,PluginLoader:()=>gn,ProfileSkill:()=>rs,ProxmoxSkill:()=>$n,ReminderSkill:()=>Wt,RoutingSkill:()=>Mn,ScheduledTaskSkill:()=>is,ScreenshotSkill:()=>ts,ShellSkill:()=>Kt,Skill:()=>R,SkillRegistry:()=>jt,SkillSandbox:()=>Bt,SystemInfoSkill:()=>zt,TTSSkill:()=>cs,TodoSkill:()=>ds,TransitSkill:()=>ms,UniFiSkill:()=>Sn,WatchSkill:()=>fs,WeatherSkill:()=>Vt,WebSearchSkill:()=>qt,allUserIds:()=>V,createCalendarProvider:()=>gr,createContactsProvider:()=>Ei,createEmailProvider:()=>pr,createForgeClient:()=>ws,effectiveUserId:()=>ae,gitAddRemote:()=>Ar,gitGetRemoteUrl:()=>gs,gitInitRepo:()=>vr,orchestrate:()=>Lt,orchestrateWithGit:()=>Ir,parseRemoteUrl:()=>ys});var se=T(()=>{"use strict";U();Oe();Rc();xc();ii();Cc();Dc();Lc();Nc();Mc();Oc();Pc();jc();Bc();Hc();Gc();Kc();Yc();Jc();Qc();tl();sl();cl();ll();dl();ul();pl();fl();gl();yl();wl();_l();Tl();El();Al();Il();Ll();jl();Bl();Kl();Xl();Zl();Ql();ed();sd();od();id();hd()});var xr,qi=T(()=>{"use strict";xr=class{static{m(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 Ze(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 _s=T(()=>{"use strict";m(Ze,"buildSkillContext")});function fd(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(Pp))e.has(r)&&n.test(l)&&(t.add(r),s=!0);if(!s){let r=["productivity","information","media","automation"];for(let n of r)e.has(n)&&t.add(n)}return t}function gd(l,e){return l.filter(t=>e.has(t.category??"core"))}var Pp,yd=T(()=>{"use strict";Pp={productivity:/\b(todo|note|remind|calendar|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)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|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)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|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)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};m(fd,"selectCategories");m(gd,"filterSkills")});import Wi from"node:fs";import wd from"node:path";var Up,_d,Fp,Td,jp,Bp,Hp,Ed,zp,Cr,Gi=T(()=>{"use strict";ni();_s();yd();Up=15*60*1e3,_d=50,Fp=2,Td=.85,jp=1e5,Bp=2e3,Hp=.1,Ed=3,zp=10,Cr=class{static{m(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;activeAgents=new Map;agentIdCounter=0;metrics={requestsTotal:0,requestsSuccess:0,requestsFailed:0,avgDurationMs:0,totalInputTokens:0,totalOutputTokens:0,totalCostUsd:0};getMetrics(){return{...this.metrics}}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 lr}async process(e,t){let s=Date.now();this.logger.info({platform:e.platform,userId:e.userId,chatId:e.chatId},"Processing message");try{let{user:r,masterUserId:n,linkedPlatformUserIds:o,context:i}=Ze(this.users,{platformUserId:e.userId,platform:e.platform,chatId:e.chatId,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),a=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,r.id),c=!e.metadata?.skipHistory&&this.conversationSummarizer?this.conversationSummarizer.getSummary(a.id):void 0,d=c?zp:this.maxHistoryMessages,u=e.metadata?.skipHistory?[]:this.conversationManager.getHistory(a.id,d);this.conversationManager.addMessage(a.id,"user",e.text);let p,f=this.isSyntheticLabel(e.text),g=e.attachments?.some(G=>G.type==="audio")??!1,h=f&&!g;if(this.memoryRetriever&&e.text&&!h)try{p=await this.memoryRetriever.retrieve(n,e.text,15,o)}catch(G){this.logger.debug({err:G},"Hybrid memory retrieval failed")}if(!p&&this.memoryRepo&&!h)try{let G=[n,...(o??[]).filter(K=>K!==n)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let K=new Set;p=[];for(let Z of G)for(let ce of await this.embeddingService.semanticSearch(Z,e.text,10))K.has(ce.key)||(K.add(ce.key),p.push(ce));for(let Z of G)for(let ce of this.memoryRepo.getRecentForPrompt(Z,5))K.has(ce.key)||(K.add(ce.key),p.push(ce))}else{let K=new Set;p=[];for(let Z of G)for(let ce of this.memoryRepo.getRecentForPrompt(Z,20))K.has(ce.key)||(K.add(ce.key),p.push(ce))}}catch(G){this.logger.debug({err:G},"Memory loading failed")}p&&p.length>0&&(p=this.applyMemoryBudget(p));let y;try{"getProfile"in this.users&&(y=this.users.getProfile(n),y&&!y.displayName&&(y.displayName=r.displayName??r.username))}catch(G){this.logger.debug({err:G},"Profile loading failed")}let b=i.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,k=this.skillRegistry?this.skillRegistry.getAll().map(G=>G.metadata):void 0,S=k;if(k&&e.text){let G=new Set(k.map(Z=>Z.category??"core")),K=fd(e.text,G);S=gd(k,K)}let j=S?this.promptBuilder.buildTools(S):void 0,N=this.promptBuilder.buildSystemPrompt({memories:p,skills:S,userProfile:y,conversationSummary:c?.summary}),q=this.buildActiveAgentStatus();q&&(N+=`
911
+ `)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+n}}}});var hd=T(()=>{"use strict";pd();qn();qi();Ui();Bi()});var ne={};ue(ne,{ActivityTracker:()=>St,BMWSkill:()=>Nn,BackgroundTaskSkill:()=>os,BriefingSkill:()=>Bn,BrowserSkill:()=>ss,CalculatorSkill:()=>Ht,CalendarProvider:()=>Pe,CalendarSkill:()=>vt,ClipboardSkill:()=>es,CodeAgentSkill:()=>Rr,CodeExecutionSkill:()=>wr,CodeExecutor:()=>Rt,ConfigureSkill:()=>hs,ContactsProvider:()=>je,ContactsSkill:()=>Er,CrossPlatformSkill:()=>ns,DelegateSkill:()=>Yt,DockerSkill:()=>Cn,DocumentSkill:()=>as,EmailProvider:()=>Je,EmailSkill:()=>nt,EnergyPriceSkill:()=>On,FileSkill:()=>Zt,ForgeClient:()=>Lt,HomeAssistantSkill:()=>vn,HttpSkill:()=>Jt,ImageGenerateSkill:()=>ls,MCPClient:()=>At,MCPManager:()=>yr,MCPSkillAdapter:()=>It,MarketplaceSkill:()=>$r,MemorySkill:()=>Xt,MicrosoftTodoSkill:()=>Un,MonitorSkill:()=>Pn,NoteSkill:()=>Gt,PluginLoader:()=>gn,ProfileSkill:()=>rs,ProxmoxSkill:()=>$n,ReminderSkill:()=>Wt,RoutingSkill:()=>Mn,ScheduledTaskSkill:()=>is,ScreenshotSkill:()=>ts,ShellSkill:()=>Kt,Skill:()=>R,SkillRegistry:()=>jt,SkillSandbox:()=>Bt,SystemInfoSkill:()=>qt,TTSSkill:()=>cs,TodoSkill:()=>ds,TransitSkill:()=>ms,UniFiSkill:()=>Sn,WatchSkill:()=>fs,WeatherSkill:()=>Vt,WebSearchSkill:()=>zt,allUserIds:()=>V,createCalendarProvider:()=>gr,createContactsProvider:()=>Ei,createEmailProvider:()=>pr,createForgeClient:()=>ws,effectiveUserId:()=>ae,gitAddRemote:()=>Ar,gitGetRemoteUrl:()=>gs,gitInitRepo:()=>vr,orchestrate:()=>Dt,orchestrateWithGit:()=>Ir,parseRemoteUrl:()=>ys});var se=T(()=>{"use strict";U();Oe();Rc();xc();ii();Cc();Lc();Dc();Nc();Mc();Oc();Pc();jc();Bc();Hc();Gc();Kc();Yc();Jc();Qc();tl();sl();cl();ll();dl();ul();pl();fl();gl();yl();wl();_l();Tl();El();Al();Il();Dl();jl();Bl();Kl();Xl();Zl();Ql();ed();sd();od();id();hd()});var xr,zi=T(()=>{"use strict";xr=class{static{m(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 Ze(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 _s=T(()=>{"use strict";m(Ze,"buildSkillContext")});function fd(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(Pp))e.has(r)&&n.test(l)&&(t.add(r),s=!0);if(!s){let r=["productivity","information","media","automation"];for(let n of r)e.has(n)&&t.add(n)}return t}function gd(l,e){return l.filter(t=>e.has(t.category??"core"))}var Pp,yd=T(()=>{"use strict";Pp={productivity:/\b(todo|note|remind|calendar|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)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|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)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|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)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};m(fd,"selectCategories");m(gd,"filterSkills")});import Wi from"node:fs";import wd from"node:path";var Up,_d,Fp,Td,jp,Bp,Hp,Ed,qp,Cr,Gi=T(()=>{"use strict";ni();_s();yd();Up=15*60*1e3,_d=50,Fp=2,Td=.85,jp=1e5,Bp=2e3,Hp=.1,Ed=3,qp=10,Cr=class{static{m(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;activeAgents=new Map;agentIdCounter=0;metrics={requestsTotal:0,requestsSuccess:0,requestsFailed:0,avgDurationMs:0,totalInputTokens:0,totalOutputTokens:0,totalCostUsd:0};getMetrics(){return{...this.metrics}}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 lr}async process(e,t){let s=Date.now();this.logger.info({platform:e.platform,userId:e.userId,chatId:e.chatId},"Processing message");try{let{user:r,masterUserId:n,linkedPlatformUserIds:o,context:i}=Ze(this.users,{platformUserId:e.userId,platform:e.platform,chatId:e.chatId,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),a=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,r.id),c=!e.metadata?.skipHistory&&this.conversationSummarizer?this.conversationSummarizer.getSummary(a.id):void 0,d=c?qp:this.maxHistoryMessages,u=e.metadata?.skipHistory?[]:this.conversationManager.getHistory(a.id,d);this.conversationManager.addMessage(a.id,"user",e.text);let p,f=this.isSyntheticLabel(e.text),g=e.attachments?.some(G=>G.type==="audio")??!1,h=f&&!g;if(this.memoryRetriever&&e.text&&!h)try{p=await this.memoryRetriever.retrieve(n,e.text,15,o)}catch(G){this.logger.debug({err:G},"Hybrid memory retrieval failed")}if(!p&&this.memoryRepo&&!h)try{let G=[n,...(o??[]).filter(K=>K!==n)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let K=new Set;p=[];for(let Z of G)for(let ce of await this.embeddingService.semanticSearch(Z,e.text,10))K.has(ce.key)||(K.add(ce.key),p.push(ce));for(let Z of G)for(let ce of this.memoryRepo.getRecentForPrompt(Z,5))K.has(ce.key)||(K.add(ce.key),p.push(ce))}else{let K=new Set;p=[];for(let Z of G)for(let ce of this.memoryRepo.getRecentForPrompt(Z,20))K.has(ce.key)||(K.add(ce.key),p.push(ce))}}catch(G){this.logger.debug({err:G},"Memory loading failed")}p&&p.length>0&&(p=this.applyMemoryBudget(p));let y;try{"getProfile"in this.users&&(y=this.users.getProfile(n),y&&!y.displayName&&(y.displayName=r.displayName??r.username))}catch(G){this.logger.debug({err:G},"Profile loading failed")}let b=i.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,k=this.skillRegistry?this.skillRegistry.getAll().map(G=>G.metadata):void 0,S=k;if(k&&e.text){let G=new Set(k.map(Z=>Z.category??"core")),K=fd(e.text,G);S=gd(k,K)}let j=S?this.promptBuilder.buildTools(S):void 0,N=this.promptBuilder.buildSystemPrompt({memories:p,skills:S,userProfile:y,conversationSummary:c?.summary}),z=this.buildActiveAgentStatus();z&&(N+=`
912
912
 
913
- `+q);let ee=this.promptBuilder.buildMessages(u),D=this.collapseRepeatedToolErrors(ee),O=ri(D),ie=D.reduce((G,K)=>G+kt(K),0)-O.reduce((G,K)=>G+kt(K),0);ie>100&&this.logger.debug(`Tool result trimming saved ~${ie} tokens`);let He=await this.buildUserContent(e,t);O.push({role:"user",content:He});let ke=j?Me(JSON.stringify(j)):0,oe=1,J=this.trimToContextWindow(N,O,ke,oe),B,de=0,Re=Date.now(),Ie="",x=0,z=0,re=0,xe=[],We=[],tt=[];for(t?.("Thinking...");;){de>0&&this.compressToolLoop(J,N,ke);try{B=await this.llm.complete({messages:J,system:N,tools:j&&j.length>0?j:void 0,tier:e.metadata?.tier}),z+=B.usage?.inputTokens??0,re+=B.usage?.outputTokens??0}catch(we){if((we instanceof Error?we.message:String(we)).includes("prompt is too long")&&oe>.3){oe*=.5,this.logger.warn({budgetMultiplier:oe},"Prompt too long, retrimming with reduced budget"),J=this.trimToContextWindow(N,O,ke,oe);continue}throw we}if(!B.toolCalls||B.toolCalls.length===0)break;let G=Date.now()-Re;if(G>=Up){let we=Math.round(G/6e4);this.logger.warn({iteration:de,elapsedMin:we,pendingToolCalls:B.toolCalls.length},"Tool loop timeout reached"),B=await this.abortToolLoop(J,B,a.id,N,`Das Zeitlimit von ${we} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(de>=_d){this.logger.warn({iteration:de,pendingToolCalls:B.toolCalls.length},"Tool loop iteration cap reached"),B=await this.abortToolLoop(J,B,a.id,N,`Das Iterationslimit von ${_d} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}de++,this.logger.info({iteration:de,toolCalls:B.toolCalls.length},"Processing tool calls");let K=[];B.content&&K.push({type:"text",text:B.content});for(let we of B.toolCalls)K.push({type:"tool_use",id:we.id,name:we.name,input:we.input});J.push({role:"assistant",content:K});let Z=await this.executeToolCallsParallel(B.toolCalls,{...i,conversationId:a.id,timezone:b},t),ce=Z.blocks;Z.attachments.length>0&&xe.push(...Z.attachments),We.push(...B.toolCalls),tt.push(...ce);let lt=this.buildErrorSignature(ce);if(lt){if(lt===Ie?x++:(x=1,Ie=lt),x>=Fp){this.logger.warn({iteration:de,consecutiveErrors:x,errorSignature:lt},"Tool loop aborted: same error repeated consecutively"),B=await this.abortToolLoop(J,B,a.id,N,`Der gleiche Tool-Fehler ist ${x}x hintereinander aufgetreten: "${Ie.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else x=0,Ie="";J.push({role:"user",content:ce}),t?.("Thinking...")}let ze=B.content;if(!ze)for(let G=J.length-1;G>=0;G--){let K=J[G];if(K.role==="assistant"&&Array.isArray(K.content)){let Z=K.content.find(ce=>ce.type==="text");if(Z&&"text"in Z&&Z.text){ze=Z.text;break}}}if(ze||(ze="(no response)"),We.length>0&&(this.conversationManager.addMessage(a.id,"assistant","",JSON.stringify(We)),this.conversationManager.addMessage(a.id,"user","",JSON.stringify(tt))),this.conversationManager.addMessage(a.id,"assistant",ze),this.activeLearning&&this.activeLearning.onMessageProcessed(n,e.text,ze),this.conversationSummarizer&&!e.metadata?.skipHistory){let G=u.slice(-8).map(K=>({role:K.role,content:K.content}));this.conversationSummarizer.onMessageProcessed(a.id,u.length+2,e.text,ze,G)}let ao=Date.now()-s,bs=B.model??"unknown",Xr=pn(bs,{inputTokens:z,outputTokens:re});return this.logger.info({duration:ao,model:bs,tokens:B.usage,totalTokens:{inputTokens:z,outputTokens:re},costUsd:Math.round(Xr*1e6)/1e6,stopReason:B.stopReason,toolIterations:de},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:z,output:re,costUsd:Xr}),{text:ze,attachments:xe.length>0?xe: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=m((u,p)=>{let f=p.content;if(p.attachments&&p.attachments.length>0){r.push(...p.attachments);let g=p.attachments.map(h=>h.fileName).join(", ");f+=`
913
+ `+z);let ee=this.promptBuilder.buildMessages(u),L=this.collapseRepeatedToolErrors(ee),O=ri(L),ie=L.reduce((G,K)=>G+kt(K),0)-O.reduce((G,K)=>G+kt(K),0);ie>100&&this.logger.debug(`Tool result trimming saved ~${ie} tokens`);let He=await this.buildUserContent(e,t);O.push({role:"user",content:He});let ke=j?Me(JSON.stringify(j)):0,oe=1,J=this.trimToContextWindow(N,O,ke,oe),B,de=0,Re=Date.now(),Ie="",x=0,q=0,re=0,xe=[],We=[],tt=[];for(t?.("Thinking...");;){de>0&&this.compressToolLoop(J,N,ke);try{B=await this.llm.complete({messages:J,system:N,tools:j&&j.length>0?j:void 0,tier:e.metadata?.tier}),q+=B.usage?.inputTokens??0,re+=B.usage?.outputTokens??0}catch(we){if((we instanceof Error?we.message:String(we)).includes("prompt is too long")&&oe>.3){oe*=.5,this.logger.warn({budgetMultiplier:oe},"Prompt too long, retrimming with reduced budget"),J=this.trimToContextWindow(N,O,ke,oe);continue}throw we}if(!B.toolCalls||B.toolCalls.length===0)break;let G=Date.now()-Re;if(G>=Up){let we=Math.round(G/6e4);this.logger.warn({iteration:de,elapsedMin:we,pendingToolCalls:B.toolCalls.length},"Tool loop timeout reached"),B=await this.abortToolLoop(J,B,a.id,N,`Das Zeitlimit von ${we} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(de>=_d){this.logger.warn({iteration:de,pendingToolCalls:B.toolCalls.length},"Tool loop iteration cap reached"),B=await this.abortToolLoop(J,B,a.id,N,`Das Iterationslimit von ${_d} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}de++,this.logger.info({iteration:de,toolCalls:B.toolCalls.length},"Processing tool calls");let K=[];B.content&&K.push({type:"text",text:B.content});for(let we of B.toolCalls)K.push({type:"tool_use",id:we.id,name:we.name,input:we.input});J.push({role:"assistant",content:K});let Z=await this.executeToolCallsParallel(B.toolCalls,{...i,conversationId:a.id,timezone:b},t),ce=Z.blocks;Z.attachments.length>0&&xe.push(...Z.attachments),We.push(...B.toolCalls),tt.push(...ce);let lt=this.buildErrorSignature(ce);if(lt){if(lt===Ie?x++:(x=1,Ie=lt),x>=Fp){this.logger.warn({iteration:de,consecutiveErrors:x,errorSignature:lt},"Tool loop aborted: same error repeated consecutively"),B=await this.abortToolLoop(J,B,a.id,N,`Der gleiche Tool-Fehler ist ${x}x hintereinander aufgetreten: "${Ie.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else x=0,Ie="";J.push({role:"user",content:ce}),t?.("Thinking...")}let qe=B.content;if(!qe)for(let G=J.length-1;G>=0;G--){let K=J[G];if(K.role==="assistant"&&Array.isArray(K.content)){let Z=K.content.find(ce=>ce.type==="text");if(Z&&"text"in Z&&Z.text){qe=Z.text;break}}}if(qe||(qe="(no response)"),We.length>0&&(this.conversationManager.addMessage(a.id,"assistant","",JSON.stringify(We)),this.conversationManager.addMessage(a.id,"user","",JSON.stringify(tt))),this.conversationManager.addMessage(a.id,"assistant",qe),this.activeLearning&&this.activeLearning.onMessageProcessed(n,e.text,qe),this.conversationSummarizer&&!e.metadata?.skipHistory){let G=u.slice(-8).map(K=>({role:K.role,content:K.content}));this.conversationSummarizer.onMessageProcessed(a.id,u.length+2,e.text,qe,G)}let ao=Date.now()-s,bs=B.model??"unknown",Xr=pn(bs,{inputTokens:q,outputTokens:re});return this.logger.info({duration:ao,model:bs,tokens:B.usage,totalTokens:{inputTokens:q,outputTokens:re},costUsd:Math.round(Xr*1e6)/1e6,stopReason:B.stopReason,toolIterations:de},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:q,output:re,costUsd:Xr}),{text:qe,attachments:xe.length>0?xe: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=m((u,p)=>{let f=p.content;if(p.attachments&&p.attachments.length>0){r.push(...p.attachments);let g=p.attachments.map(h=>h.fileName).join(", ");f+=`
914
914
 
915
915
  [${p.attachments.length} Datei(en) werden dem User gesendet: ${g}]`}return{type:"tool_result",tool_use_id:u.id,content:f,is_error:p.isError}},"buildBlock");if(e.length===1){let u=e[0],p=this.getToolLabel(u.name,u.input);s?.(p);let f=await this.executeToolCall(u,t,s);return{blocks:[n(u,f)],attachments:r}}let o=3;s?.(`Running ${e.length} tools...`);let i=new Map;for(let u=0;u<e.length;u++){let p=e[u].name,f=i.get(p);f||(f=[],i.set(p,f)),f.push(u)}let a=[...i.values()].some(u=>u.length>o),c;if(a){c=new Map;let u=[...i.entries()].map(async([p,f])=>{for(let g=0;g<f.length;g+=o){let h=f.slice(g,g+o),y=await Promise.allSettled(h.map(b=>this.executeToolCall(e[b],t,s)));for(let b=0;b<h.length;b++)c.set(h[b],y[b])}});await Promise.all(u)}else{let u=await Promise.allSettled(e.map(p=>this.executeToolCall(p,t,s)));c=new Map(u.map((p,f)=>[f,p]))}return{blocks:e.map((u,p)=>{let f=c.get(p);return f.status==="fulfilled"?n(u,f.value):{type:"tool_result",tool_use_id:u.id,content:`Tool execution failed: ${f.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.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"),{content:`Access denied: ${n.reason}`,isError:!0}}if(this.skillSandbox){let n,o;if(e.name==="delegate"){let{ActivityTracker:a}=await Promise.resolve().then(()=>(se(),ne));n=new a(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;try{let a=await this.skillSandbox.execute(r,e.input,i,void 0,n);return{content:a.display??(a.success?JSON.stringify(a.data):a.error??"Unknown error"),isError:!a.success,attachments:a.attachments}}finally{o&&this.activeAgents.delete(o)}}try{let n=await r.execute(e.input,t);return{content:n.display??(n.success?JSON.stringify(n.data):n.error??"Unknown error"),isError:!n.success,attachments:n.attachments}}catch(n){return{content:`Skill execution failed: ${n instanceof Error?n.message:String(n)}`,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(`
916
916
  `)}applyMemoryBudget(e){let t=e.some(o=>o.score!=null&&o.score>0),s=e;t&&(s=e.filter(o=>(o.score??1)>=Hp));let r=0,n=[];for(let o of s){let i=Me(`[${o.category}] ${o.key}: ${o.value}`);if(r+i>Bp)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*Td);if(Me(t)+s+e.reduce((h,y)=>h+kt(y),0)<=n)return;let a=[];for(let h=0;h<e.length-1;h++){let y=e[h],b=e[h+1];y.role==="assistant"&&Array.isArray(y.content)&&y.content.some(k=>k.type==="tool_use")&&b.role==="user"&&Array.isArray(b.content)&&b.content.some(k=>k.type==="tool_result")&&a.push({start:h,end:h+1})}if(a.length<=Ed)return;let c=a.length-Ed,d=a.slice(0,c),u=[];for(let h of d){let y=e[h.start],b=[];if(Array.isArray(y.content))for(let j of y.content)j.type==="tool_use"&&b.push(j.name);let k=e[h.end],S="ok";Array.isArray(k.content)&&k.content.some(N=>N.type==="tool_result"&&N.is_error)&&(S="error"),u.push(`- ${b.join(", ")}: ${S}`)}let p=d[0].start,g=d[d.length-1].end-p+1;e.splice(p,g,{role:"assistant",content:`[Earlier tool interactions compressed (${d.length} pairs):
@@ -928,9 +928,9 @@ The conversation continues below with the most recent messages.]`})}return y.pus
928
928
  [File content]:
929
929
  ${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{Wi.unlinkSync(a)}catch{}d=`[File received: "${i.fileName??"unknown"}" (duplicate, not saved again)]
930
930
  [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+=`
931
- [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??wd.resolve("./data/inbox");try{Wi.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=wd.join(t,o);try{return Wi.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 Dr,Vi=T(()=>{"use strict";Dr=class{static{m(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;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.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}`;if(await this.sendMessage(t.platform,t.chatId,s),this.linkedUsers)try{let r=this.linkedUsers.getMasterUserId(t.userId),n=this.linkedUsers.getLinkedUsers(r);for(let o of n){if(o.platform===t.platform)continue;let i=this.linkedUsers.findConversation(o.platform,o.id);i&&await this.sendMessage(o.platform,i.chatId,s)}}catch(r){this.logger.debug({err:r,reminderId:t.id},"Cross-platform reminder delivery failed")}this.reminderRepo.markFired(t.id),this.logger.info({reminderId:t.id},"Reminder fired")}catch(s){this.logger.error({err:s,reminderId:t.id},"Failed to send reminder")}}catch(e){this.logger.error({err:e},"Error checking due reminders")}}}});var Lr,Ki=T(()=>{"use strict";Lr=class{static{m(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 Nr,Xi=T(()=>{"use strict";Nr=class{static{m(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 Mr,Yi=T(()=>{"use strict";Mr=class{static{m(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 Or,Ji=T(()=>{"use strict";Or=class{static{m(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(g=>({origin:g.origin?.name||g.origin?.id||"Unknown",destination:g.destination?.name||g.destination?.id||"Unknown",departure:g.departure||g.plannedDeparture||"",arrival:g.arrival||g.plannedArrival||"",line:g.line?.name,direction:g.direction,mode:g.line?.mode||(g.walking?"walking":"unknown"),walking:g.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,p=a.filter(g=>!g.walking),f=Math.max(0,p.length-1);return{legs:a,departure:c,arrival:d,duration:u,transfers:f}})}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 Pr,Zi=T(()=>{"use strict";Pr=class{static{m(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,`
931
+ [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??wd.resolve("./data/inbox");try{Wi.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=wd.join(t,o);try{return Wi.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 Lr,Vi=T(()=>{"use strict";Lr=class{static{m(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;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.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}`;if(await this.sendMessage(t.platform,t.chatId,s),this.linkedUsers)try{let r=this.linkedUsers.getMasterUserId(t.userId),n=this.linkedUsers.getLinkedUsers(r);for(let o of n){if(o.platform===t.platform)continue;let i=this.linkedUsers.findConversation(o.platform,o.id);i&&await this.sendMessage(o.platform,i.chatId,s)}}catch(r){this.logger.debug({err:r,reminderId:t.id},"Cross-platform reminder delivery failed")}this.reminderRepo.markFired(t.id),this.logger.info({reminderId:t.id},"Reminder fired")}catch(s){this.logger.error({err:s,reminderId:t.id},"Failed to send reminder")}}catch(e){this.logger.error({err:e},"Error checking due reminders")}}}});var Dr,Ki=T(()=>{"use strict";Dr=class{static{m(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 Nr,Xi=T(()=>{"use strict";Nr=class{static{m(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 Mr,Yi=T(()=>{"use strict";Mr=class{static{m(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 Or,Ji=T(()=>{"use strict";Or=class{static{m(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(g=>({origin:g.origin?.name||g.origin?.id||"Unknown",destination:g.destination?.name||g.destination?.id||"Unknown",departure:g.departure||g.plannedDeparture||"",arrival:g.arrival||g.plannedArrival||"",line:g.line?.name,direction:g.direction,mode:g.line?.mode||(g.walking?"walking":"unknown"),walking:g.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,p=a.filter(g=>!g.walking),f=Math.max(0,p.length-1);return{legs:a,departure:c,arrival:d,duration:u,transfers:f}})}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 Pr,Zi=T(()=>{"use strict";Pr=class{static{m(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,`
932
932
 
933
- `),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 Ur,Qi=T(()=>{"use strict";Ur=class{static{m(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 qp}from"node:crypto";var Fr,ea=T(()=>{"use strict";Fr=class{static{m(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=qp("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),p=this.chunkText(c,500,50);for(let f=0;f<p.length;f++){let g;try{g=await this.embeddingService.embedAndStore(e,p[f],"document",`${u.id}:${f}`)}catch(h){this.logger.warn({documentId:u.id,chunkIndex:f,err:h},"Embedding failed for chunk, continuing")}this.docRepo.addChunk(u.id,f,p[f],g)}return this.docRepo.updateChunkCount(u.id,p.length),this.logger.info({documentId:u.id,filename:s,chunkCount:p.length},"Document ingested"),{documentId:u.id,chunkCount:p.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),p=u.lastIndexOf(`
933
+ `),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 Ur,Qi=T(()=>{"use strict";Ur=class{static{m(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 zp}from"node:crypto";var Fr,ea=T(()=>{"use strict";Fr=class{static{m(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=zp("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),p=this.chunkText(c,500,50);for(let f=0;f<p.length;f++){let g;try{g=await this.embeddingService.embedAndStore(e,p[f],"document",`${u.id}:${f}`)}catch(h){this.logger.warn({documentId:u.id,chunkIndex:f,err:h},"Embedding failed for chunk, continuing")}this.docRepo.addChunk(u.id,f,p[f],g)}return this.docRepo.updateChunkCount(u.id,p.length),this.logger.info({documentId:u.id,filename:s,chunkCount:p.length},"Document ingested"),{documentId:u.id,chunkCount:p.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),p=u.lastIndexOf(`
934
934
 
935
935
  `);if(p>0)c=d+p;else{let g=u.lastIndexOf(". ");g>0&&(c=d+g+1)}let f=e.slice(a,c).trim();f&&i.push(f),a=c-o}return i.filter(c=>c.length>0)}}});var jr,ta=T(()=>{"use strict";_s();jr=class{static{m(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;pollTimer;running=0;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;constructor(e,t,s,r,n,o){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o}start(){this.pollTimer=setInterval(()=>this.poll(),this.pollIntervalMs),this.logger.info("Background task runner started")}stop(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0),this.logger.info("Background task runner stopped")}async poll(){if(!(this.running>=this.maxConcurrent))try{let e=this.maxConcurrent-this.running,t=this.taskRepo.getPending(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")}}async runTask(e){this.taskRepo.updateStatus(e.id,"running");try{let t=this.skillRegistry.get(e.skillName);if(!t){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}let s;try{s=JSON.parse(e.skillInput)}catch(c){this.logger.warn({taskId:e.id,err:c},"Malformed skill input JSON"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:r}=Ze(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),n=new Promise((c,d)=>setTimeout(()=>d(new Error("Background task timed out")),this.taskTimeoutMs)),o=await Promise.race([this.skillSandbox.execute(t,s,r),n]),i=JSON.stringify(o.data??o.display??o.error);this.taskRepo.updateStatus(e.id,o.success?"completed":"failed",i,o.error);let a=this.adapters.get(e.platform);if(a){let c=o.success?`\u2705 Background task completed: ${e.description}
936
936
 
@@ -961,7 +961,7 @@ Extract memories from this conversation:
961
961
  User: {USER_MESSAGE}
962
962
  Assistant: {ASSISTANT_RESPONSE}
963
963
 
964
- Return ONLY a valid JSON array, no explanation:`,Hr=class{static{m(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=Jp.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 Yp.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});var zr,ia=T(()=>{"use strict";na();oa();zr=class{static{m(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new Hr(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;let r=ra(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 Zp,Qp,eh,th,qr,aa=T(()=>{"use strict";Zp=Math.LN2,Qp=.3,eh=.7,th=3,qr=class{static{m(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 h of n)for(let y of this.memoryRepo.keywordSearch(h,t,30))o.has(y.id)||(o.add(y.id),i.push(y));let a=[],c=!1;if(this.embeddingService)try{let h=new Set;for(let y of n)for(let b of await this.embeddingService.semanticSearch(y,t,30))h.has(b.key)||(h.add(b.key),a.push(b));c=a.length>0}catch(h){this.logger.debug({err:h},"Semantic search failed, falling back to keyword-only")}let d=new Map,u=i.length;for(let h=0;h<i.length;h++){let y=i[h],b=u>0?1-h/u:0,k=c?Qp:1,S=this.applyBoosts(b*k,y);d.set(y.key,{memory:{key:y.key,value:y.value,category:y.category,type:y.type,score:S},score:S}),this.memoryRepo.recordAccess(y.id)}if(c)for(let h of a){let y=h.score*eh,b=d.get(h.key);if(b)b.score+=y,b.memory.score=b.score;else{let k=this.memoryRepo.recall(e,h.key),S=this.applyBoosts(y,k||void 0);d.set(h.key,{memory:{key:h.key,value:h.value,category:h.category,type:k?.type||"general",score:S},score:S}),k&&this.memoryRepo.recordAccess(k.id)}}let p=Array.from(d.values()).sort((h,y)=>y.score-h.score),f=new Map,g=[];for(let{memory:h}of p){let y=f.get(h.type)||0;if(!(y>=th)&&(f.set(h.type,y+1),g.push(h),g.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:g.length,hasSemanticSearch:c},"Hybrid memory retrieval complete"),g}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(-Zp*n/2592e6);s*=o}return s}}});var Wr,ca=T(()=>{"use strict";Wr=class{static{m(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.
964
+ Return ONLY a valid JSON array, no explanation:`,Hr=class{static{m(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=Jp.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 Yp.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});var qr,ia=T(()=>{"use strict";na();oa();qr=class{static{m(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new Hr(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;let r=ra(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 Zp,Qp,eh,th,zr,aa=T(()=>{"use strict";Zp=Math.LN2,Qp=.3,eh=.7,th=3,zr=class{static{m(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 h of n)for(let y of this.memoryRepo.keywordSearch(h,t,30))o.has(y.id)||(o.add(y.id),i.push(y));let a=[],c=!1;if(this.embeddingService)try{let h=new Set;for(let y of n)for(let b of await this.embeddingService.semanticSearch(y,t,30))h.has(b.key)||(h.add(b.key),a.push(b));c=a.length>0}catch(h){this.logger.debug({err:h},"Semantic search failed, falling back to keyword-only")}let d=new Map,u=i.length;for(let h=0;h<i.length;h++){let y=i[h],b=u>0?1-h/u:0,k=c?Qp:1,S=this.applyBoosts(b*k,y);d.set(y.key,{memory:{key:y.key,value:y.value,category:y.category,type:y.type,score:S},score:S}),this.memoryRepo.recordAccess(y.id)}if(c)for(let h of a){let y=h.score*eh,b=d.get(h.key);if(b)b.score+=y,b.memory.score=b.score;else{let k=this.memoryRepo.recall(e,h.key),S=this.applyBoosts(y,k||void 0);d.set(h.key,{memory:{key:h.key,value:h.value,category:h.category,type:k?.type||"general",score:S},score:S}),k&&this.memoryRepo.recordAccess(k.id)}}let p=Array.from(d.values()).sort((h,y)=>y.score-h.score),f=new Map,g=[];for(let{memory:h}of p){let y=f.get(h.type)||0;if(!(y>=th)&&(f.set(h.type,y+1),g.push(h),g.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:g.length,hasSemanticSearch:c},"Hybrid memory retrieval complete"),g}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(-Zp*n/2592e6);s*=o}return s}}});var Wr,ca=T(()=>{"use strict";Wr=class{static{m(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.
965
965
  `;if(e&&(n+=`
966
966
  ## Bisherige Zusammenfassung
967
967
  ${e}
@@ -989,17 +989,17 @@ Regeln:
989
989
  - Leere Punkte: "\u2014"
990
990
  - Sprache: Deutsch (oder Sprache des Gespr\xE4chs)`,n}}});import{EventEmitter as sh}from"node:events";var pe,Qe=T(()=>{"use strict";pe=class extends sh{static{m(this,"MessagingAdapter")}status="disconnected";async sendPhoto(e,t,s){}async sendFile(e,t,s,r){}async sendVoice(e,t,s){}endStream(e){}getStatus(){return this.status}splitText(e,t){if(e.length<=t)return[e];let s=[],r=e;for(;r.length>0;){if(r.length<=t){s.push(r);break}let n=-1,i=r.slice(0,t).lastIndexOf(`
991
991
 
992
- `);if(i>0&&(n=i),n<0){let c=r.slice(0,t).match(/.*[.!?]\s/s);c&&(n=c[0].length)}n<0&&(n=t),s.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return s}}});import{Bot as rh,InputFile as la}from"grammy";function vd(l){if(l==="markdown")return"MarkdownV2";if(l==="html")return"HTML"}var Gn,Ad=T(()=>{"use strict";Qe();m(vd,"mapParseMode");Gn=class extends pe{static{m(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new rh(e)}async connect(){this.status="connecting",this.bot.on("message:text",e=>{this.emit("message",this.normalizeMessage(e.message,e.message.text))}),this.bot.on("message:photo",async e=>{let t=e.message,r=(t.caption??"")||"[Photo]",n=t.photo[t.photo.length-1],o=await this.downloadAttachment(n.file_id,"image","image/jpeg"),i=this.normalizeMessage(t,r);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:voice",async e=>{let t=e.message,s=await this.downloadAttachment(t.voice.file_id,"audio",t.voice.mime_type??"audio/ogg"),r=this.normalizeMessage(t,"[Voice message]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:audio",async e=>{let t=e.message,r=(t.caption??"")||`[Audio: ${t.audio.file_name??"audio"}]`,n=await this.downloadAttachment(t.audio.file_id,"audio",t.audio.mime_type??"audio/mpeg"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:video",async e=>{let t=e.message,r=(t.caption??"")||"[Video]",n=await this.downloadAttachment(t.video.file_id,"video",t.video.mime_type??"video/mp4"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,n=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,o=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),i=this.normalizeMessage(t,n);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:video_note",async e=>{let t=e.message,s=await this.downloadAttachment(t.video_note.file_id,"video","video/mp4"),r=this.normalizeMessage(t,"[Video note]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:sticker",e=>{let t=e.message,s=t.sticker.emoji??"\u{1F3F7}\uFE0F";this.emit("message",this.normalizeMessage(t,`[Sticker: ${s}]`))}),this.bot.catch(e=>{this.emit("error",e.error)}),this.bot.start({onStart:m(()=>{this.status="connected",this.emit("connected")},"onStart")})}async disconnect(){await this.bot.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,4096),n="";for(let o of r){let i=await this.bot.api.sendMessage(Number(e),o,{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:vd(s?.parseMode)});n=String(i.message_id)}return n}async editMessage(e,t,s,r){await this.bot.api.editMessageText(Number(e),Number(t),s,{parse_mode:vd(r?.parseMode)})}async deleteMessage(e,t){await this.bot.api.deleteMessage(Number(e),Number(t))}async sendPhoto(e,t,s){let r=await this.bot.api.sendPhoto(Number(e),new la(t,"image.png"),{caption:s});return String(r.message_id)}async sendFile(e,t,s,r){let n=await this.bot.api.sendDocument(Number(e),new la(t,s),{caption:r});return String(n.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new la(t,"voice.ogg"),{caption:s});return String(r.message_id)}normalizeMessage(e,t){return{id:String(e.message_id),platform:"telegram",chatId:String(e.chat.id),chatType:e.chat.type==="private"?"dm":"group",userId:String(e.from.id),userName:e.from.username??String(e.from.id),displayName:[e.from.first_name,e.from.last_name].filter(Boolean).join(" "),text:t,timestamp:new Date(e.date*1e3),replyToMessageId:e.reply_to_message?String(e.reply_to_message.message_id):void 0}}async downloadAttachment(e,t,s,r){try{let o=(await this.bot.api.getFile(e)).file_path;if(!o)return;let i=`https://api.telegram.org/file/bot${this.bot.token}/${o}`,a=await fetch(i);if(!a.ok)return;let c=Buffer.from(await a.arrayBuffer());return{type:t,mimeType:s,fileName:r??o.split("/").pop(),size:c.length,data:c}}catch(n){console.error("[telegram] Failed to download file",e,n);return}}}});import{Client as nh,GatewayIntentBits as Vn,Events as da}from"discord.js";var Kn,Id=T(()=>{"use strict";Qe();Kn=class extends pe{static{m(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new nh({intents:[Vn.Guilds,Vn.GuildMessages,Vn.MessageContent,Vn.DirectMessages]}),this.client.on(da.MessageCreate,async e=>{if(!e.author.bot)try{let t=await this.downloadAttachments(e),s=e.content||this.inferTextFromAttachments(t),r={id:e.id,platform:"discord",chatId:e.channelId,chatType:e.channel.isDMBased()?"dm":"group",userId:e.author.id,userName:e.author.username,displayName:e.author.displayName,text:s,timestamp:e.createdAt,replyToMessageId:e.reference?.messageId??void 0,attachments:t.length>0?t:void 0};this.emit("message",r)}catch(t){this.emit("error",t instanceof Error?t:new Error(String(t)))}}),this.client.on(da.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(da.Error,e=>{this.emit("error",e)}),await this.client.login(this.token)}async disconnect(){this.client?.destroy(),this.client=null,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){if(!this.client)throw new Error("Client is not connected");let r=await this.client.channels.fetch(e);if(!r?.isTextBased()||!("send"in r))throw new Error(`Channel ${e} is not a text channel`);let n=this.splitText(t,2e3),o="";for(let i=0;i<n.length;i++)i===0&&s?.replyToMessageId?o=(await(await r.messages.fetch(s.replyToMessageId)).reply(n[i])).id:o=(await r.send(n[i])).id;return o}async editMessage(e,t,s,r){if(!this.client)throw new Error("Client is not connected");let n=await this.client.channels.fetch(e);if(!n?.isTextBased()||!("messages"in n))throw new Error(`Channel ${e} is not a text channel`);await(await n.messages.fetch(t)).edit(s)}async deleteMessage(e,t){if(!this.client)throw new Error("Client is not connected");let s=await this.client.channels.fetch(e);if(!s?.isTextBased()||!("messages"in s))throw new Error(`Channel ${e} is not a text channel`);await(await s.messages.fetch(t)).delete()}async sendPhoto(e,t,s){if(!this.client)return;let r=await this.client.channels.fetch(e);return!r?.isTextBased()||!("send"in r)?void 0:(await r.send({content:s,files:[{attachment:t,name:"image.png"}]})).id}async sendFile(e,t,s,r){if(!this.client)return;let n=await this.client.channels.fetch(e);return!n?.isTextBased()||!("send"in n)?void 0:(await n.send({content:r,files:[{attachment:t,name:s}]})).id}async sendVoice(e,t,s){return this.sendFile(e,t,"voice.ogg",s)}async downloadAttachments(e){let t=[],s=e.attachments;if(!s||s.size===0)return t;for(let[,r]of s)try{let n=await fetch(r.url);if(!n.ok)continue;let o=await n.arrayBuffer(),i=Buffer.from(o),a=this.classifyContentType(r.contentType);t.push({type:a,url:r.url,mimeType:r.contentType??void 0,fileName:r.name??void 0,size:r.size??i.length,data:i})}catch(n){console.error("[discord] Failed to download attachment",r.url,n)}return t}classifyContentType(e){return e?e.startsWith("image/")?"image":e.startsWith("audio/")?"audio":e.startsWith("video/")?"video":"document":"other"}inferTextFromAttachments(e){if(e.length===0)return"";let t=e.map(s=>s.type);return t.includes("image")?"[Photo]":t.includes("audio")?"[Voice message]":t.includes("video")?"[Video]":t.includes("document")?"[Document]":"[File]"}}});var Xn,Rd=T(()=>{"use strict";Qe();Xn=class extends pe{static{m(this,"MatrixAdapter")}platform="matrix";client;homeserverUrl;accessToken;botUserId;constructor(e,t,s){super(),this.homeserverUrl=e.replace(/\/+$/,""),this.accessToken=t,this.botUserId=s}async connect(){this.status="connecting";let{MatrixClient:e,SimpleFsStorageProvider:t,AutojoinRoomsMixin:s}=await import("matrix-bot-sdk"),r=new t("./data/matrix-storage");this.client=new e(this.homeserverUrl,this.accessToken,r),s.setupOnClient(this.client),this.client.on("room.message",async(n,o)=>{if(o.sender===this.botUserId)return;let i=o.content?.msgtype;if(i)try{let a=await this.normalizeEvent(n,o,i);a&&this.emit("message",a)}catch(a){this.emit("error",a instanceof Error?a:new Error(String(a)))}}),await this.client.start(),this.status="connected",this.emit("connected")}async disconnect(){this.client.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,32e3),n="";for(let o of r)s?.parseMode==="html"?n=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:o.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:o}):n=await this.client.sendText(e,o);return n}async editMessage(e,t,s,r){let n=r?.parseMode==="html",o={msgtype:"m.text",body:"* "+(n?s.replace(/<[^>]*>/g,""):s),"m.new_content":{msgtype:"m.text",body:n?s.replace(/<[^>]*>/g,""):s,...n?{format:"org.matrix.custom.html",formatted_body:s}:{}},"m.relates_to":{rel_type:"m.replace",event_id:t}};await this.client.sendEvent(e,"m.room.message",o)}async deleteMessage(e,t){await this.client.redactEvent(e,t)}async sendPhoto(e,t,s){let r=await this.client.uploadContent(t,"image/png","image.png"),n={msgtype:"m.image",body:s??"image.png",url:r,info:{mimetype:"image/png",size:t.length}};return await this.client.sendEvent(e,"m.room.message",n)}async sendFile(e,t,s,r){let n=this.guessMimeType(s),o=await this.client.uploadContent(t,n,s),i={msgtype:"m.file",body:r??s,filename:s,url:o,info:{mimetype:n,size:t.length}};return await this.client.sendEvent(e,"m.room.message",i)}async normalizeEvent(e,t,s){let r;try{r=(await this.client.getUserProfile(t.sender))?.displayname??void 0}catch{}let n={id:t.event_id,platform:"matrix",chatId:e,chatType:"group",userId:t.sender,userName:t.sender.split(":")[0].slice(1),displayName:r,timestamp:new Date(t.origin_server_ts),replyToMessageId:t.content["m.relates_to"]?.["m.in_reply_to"]?.event_id};switch(s){case"m.text":return{...n,text:t.content.body};case"m.image":{let o=await this.downloadAttachment(t.content,"image");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Photo]",attachments:o?[o]:void 0}}case"m.audio":{let o=await this.downloadAttachment(t.content,"audio");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Voice message]",attachments:o?[o]:void 0}}case"m.video":{let o=await this.downloadAttachment(t.content,"video");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Video]",attachments:o?[o]:void 0}}case"m.file":{let o=await this.downloadAttachment(t.content,"document");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Document]",attachments:o?[o]:void 0}}default:return t.content.body?{...n,text:t.content.body}:void 0}}async downloadAttachment(e,t){let s=e.url;if(!s||!s.startsWith("mxc://"))return;let r=e.info??{},n=r.mimetype,o=r.size,i=e.filename??e.body??"file",a=s.slice(6),c=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${a}`,`${this.homeserverUrl}/_matrix/media/v3/download/${a}`];for(let d of c)try{let u=await fetch(d,{headers:{Authorization:`Bearer ${this.accessToken}`}});if(u.status===404)continue;if(!u.ok){console.error(`[matrix] Download failed (${u.status})`,s,d);continue}let p=await u.arrayBuffer(),f=Buffer.from(p);return{type:t,mimeType:n,fileName:i,size:o??f.length,data:f}}catch(u){console.error("[matrix] Download error",s,d,u);continue}console.error("[matrix] All download endpoints failed for",s)}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Yn,xd=T(()=>{"use strict";Qe();Yn=class extends pe{static{m(this,"WhatsAppAdapter")}platform="whatsapp";socket;downloadMedia;dataPath;reconnectAttempts=0;reconnectTimer;constructor(e){super(),this.dataPath=e}async connect(){this.status="connecting";let{makeWASocket:e,useMultiFileAuthState:t,DisconnectReason:s,downloadMediaMessage:r}=await import("@whiskeysockets/baileys");this.downloadMedia=r;let{state:n,saveCreds:o}=await t(this.dataPath);this.socket=e({auth:n,printQRInTerminal:!0}),this.socket.ev.on("creds.update",o),this.socket.ev.on("connection.update",i=>{if(i.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),i.connection==="close"){let c=i.lastDisconnect?.error?.output?.statusCode!==s.loggedOut;if(this.status="disconnected",this.emit("disconnected"),c){let d=Math.min(1e3*Math.pow(2,this.reconnectAttempts),6e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>this.connect(),d)}}}),this.socket.ev.on("messages.upsert",({messages:i,type:a})=>{if(a==="notify")for(let c of i)c.message&&(c.key.fromMe||this.processMessage(c).catch(d=>{this.emit("error",d instanceof Error?d:new Error(String(d)))}))})}async disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.reconnectAttempts=0,this.socket?.end(void 0),this.socket=void 0,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,65e3),n="";for(let o=0;o<r.length;o++)n=(await this.socket.sendMessage(e,{text:r[o]},o===0&&s?.replyToMessageId?{quoted:{key:{remoteJid:e,id:s.replyToMessageId},message:{}}}:void 0))?.key?.id??"";return n}async editMessage(e,t,s,r){await this.socket.sendMessage(e,{text:s,edit:{remoteJid:e,id:t,fromMe:!0}})}async deleteMessage(e,t){await this.socket.sendMessage(e,{delete:{remoteJid:e,id:t,fromMe:!0}})}async sendPhoto(e,t,s){return(await this.socket.sendMessage(e,{image:t,caption:s}))?.key?.id}async sendFile(e,t,s,r){return(await this.socket.sendMessage(e,{document:t,fileName:s,caption:r,mimetype:this.guessMimeType(s)}))?.key?.id}async processMessage(e){let t=e.message,s=t.conversation??t.extendedTextMessage?.text??t.imageMessage?.caption??t.videoMessage?.caption??t.documentMessage?.caption??"",r=[],n=s;if(t.imageMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.imageMessage.mimetype??"image/jpeg";r.push({type:"image",mimeType:a,fileName:t.imageMessage.fileName??`image.${a.split("/")[1]??"jpeg"}`,size:t.imageMessage.fileLength??i.length,data:i})}n||(n="[Photo]")}else if(t.audioMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.audioMessage.mimetype??"audio/ogg";r.push({type:"audio",mimeType:a,fileName:t.audioMessage.fileName??`audio.${a.split("/")[1]??"ogg"}`,size:t.audioMessage.fileLength??i.length,data:i})}n||(n="[Voice message]")}else if(t.videoMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"video",mimeType:t.videoMessage.mimetype??"video/mp4",size:t.videoMessage.fileLength??i.length,data:i}),n||(n="[Video]")}else if(t.documentMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"document",mimeType:t.documentMessage.mimetype??"application/octet-stream",fileName:t.documentMessage.fileName??"document",size:t.documentMessage.fileLength??i.length,data:i}),n||(n="[Document]")}else if(t.stickerMessage&&!s)return;if(!n&&r.length===0)return;let o={id:e.key.id??"",platform:"whatsapp",chatId:e.key.remoteJid??"",chatType:e.key.remoteJid?.endsWith("@g.us")?"group":"dm",userId:e.key.participant??e.key.remoteJid??"",userName:e.pushName??e.key.participant??e.key.remoteJid??"",displayName:e.pushName??void 0,text:n,timestamp:new Date(e.messageTimestamp*1e3),replyToMessageId:t.extendedTextMessage?.contextInfo?.stanzaId??void 0,attachments:r.length>0?r:void 0};this.emit("message",o)}async downloadMediaSafe(e){try{if(!this.downloadMedia)return;let t=await this.downloadMedia(e,"buffer",{});return Buffer.isBuffer(t)?t:Buffer.from(t)}catch(t){console.error("[whatsapp] Failed to download media",t);return}}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Jn,Cd=T(()=>{"use strict";Qe();Jn=class extends pe{static{m(this,"SignalAdapter")}apiUrl;phoneNumber;platform="signal";pollingInterval;constructor(e,t){super(),this.apiUrl=e,this.phoneNumber=t}async connect(){this.status="connecting";let e=3,t;for(let s=0;s<=e;s++)try{let r=await fetch(`${this.apiUrl}/v1/about`);if(!r.ok)throw new Error(`Signal API not reachable: ${r.status}`);this.pollingInterval=setInterval(()=>{this.pollMessages().catch(n=>{this.emit("error",n instanceof Error?n:new Error(String(n)))})},2e3),this.status="connected",this.emit("connected");return}catch(r){if(t=r instanceof Error?r:new Error(String(r)),s<e){let n=1e3*Math.pow(2,s);await new Promise(o=>setTimeout(o,n))}}this.status="error",this.emit("error",t)}async disconnect(){this.pollingInterval&&(clearInterval(this.pollingInterval),this.pollingInterval=void 0),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,6e3),n="";for(let o of r){let i=e.startsWith("group."),a={message:o,number:this.phoneNumber};i?a.recipients=[e.replace("group.","")]:a.recipients=[e];let c=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!c.ok)throw new Error(`Signal send failed: ${c.status} ${await c.text()}`);let d=await c.json();n=String(d.timestamp??Date.now())}return n}async editMessage(e,t,s,r){throw new Error("Signal does not support message editing")}async deleteMessage(e,t){let s={number:this.phoneNumber,recipients:[e],timestamp:Number(t)},r=await fetch(`${this.apiUrl}/v1/deleteMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!r.ok)throw new Error(`Signal delete failed: ${r.status} ${await r.text()}`)}async pollMessages(){let e=await fetch(`${this.apiUrl}/v1/receive/${this.phoneNumber}`);if(!e.ok)return;let t=await e.json();for(let s of t){let r=s.envelope?.dataMessage;if(!r||!r.message&&(!r.attachments||r.attachments.length===0))continue;let n=s.envelope,o=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:n.sourceNumber??n.source??"",i=[];if(r.attachments)for(let d of r.attachments){let u=await this.downloadAttachment(d);u&&i.push(u)}let a=r.message||this.inferTextFromAttachments(i)||"";if(!a&&i.length===0)continue;let c={id:String(r.timestamp??Date.now()),platform:"signal",chatId:o,chatType:r.groupInfo?"group":"dm",userId:n.sourceNumber??n.source??"",userName:n.sourceName??n.sourceNumber??n.source??"",displayName:n.sourceName,text:a,timestamp:new Date(r.timestamp??Date.now()),attachments:i.length>0?i:void 0};this.emit("message",c)}}async downloadAttachment(e){if(e.id)try{let t=await fetch(`${this.apiUrl}/v1/attachments/${e.id}`);if(!t.ok)return;let s=await t.arrayBuffer(),r=Buffer.from(s);return{type:this.classifyContentType(e.contentType),mimeType:e.contentType??void 0,fileName:e.filename??void 0,size:e.size??r.length,data:r}}catch(t){console.error("[signal] Failed to download attachment",e.id,t);return}}classifyContentType(e){return e?e.startsWith("image/")?"image":e.startsWith("audio/")?"audio":e.startsWith("video/")?"video":"document":"other"}inferTextFromAttachments(e){if(e.length===0)return"";let t=e.map(s=>s.type);return t.includes("image")?"[Photo]":t.includes("audio")?"[Voice message]":t.includes("video")?"[Video]":t.includes("document")?"[Document]":"[File]"}}});import ua from"node:readline";var Zn,Dd=T(()=>{"use strict";Qe();Zn=class extends pe{static{m(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=ua.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
992
+ `);if(i>0&&(n=i),n<0){let c=r.slice(0,t).match(/.*[.!?]\s/s);c&&(n=c[0].length)}n<0&&(n=t),s.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return s}}});import{Bot as rh,InputFile as la}from"grammy";function vd(l){if(l==="markdown")return"MarkdownV2";if(l==="html")return"HTML"}var Gn,Ad=T(()=>{"use strict";Qe();m(vd,"mapParseMode");Gn=class extends pe{static{m(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new rh(e)}async connect(){this.status="connecting",this.bot.on("message:text",e=>{this.emit("message",this.normalizeMessage(e.message,e.message.text))}),this.bot.on("message:photo",async e=>{let t=e.message,r=(t.caption??"")||"[Photo]",n=t.photo[t.photo.length-1],o=await this.downloadAttachment(n.file_id,"image","image/jpeg"),i=this.normalizeMessage(t,r);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:voice",async e=>{let t=e.message,s=await this.downloadAttachment(t.voice.file_id,"audio",t.voice.mime_type??"audio/ogg"),r=this.normalizeMessage(t,"[Voice message]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:audio",async e=>{let t=e.message,r=(t.caption??"")||`[Audio: ${t.audio.file_name??"audio"}]`,n=await this.downloadAttachment(t.audio.file_id,"audio",t.audio.mime_type??"audio/mpeg"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:video",async e=>{let t=e.message,r=(t.caption??"")||"[Video]",n=await this.downloadAttachment(t.video.file_id,"video",t.video.mime_type??"video/mp4"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,n=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,o=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),i=this.normalizeMessage(t,n);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:video_note",async e=>{let t=e.message,s=await this.downloadAttachment(t.video_note.file_id,"video","video/mp4"),r=this.normalizeMessage(t,"[Video note]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:sticker",e=>{let t=e.message,s=t.sticker.emoji??"\u{1F3F7}\uFE0F";this.emit("message",this.normalizeMessage(t,`[Sticker: ${s}]`))}),this.bot.catch(e=>{this.emit("error",e.error)}),this.bot.start({onStart:m(()=>{this.status="connected",this.emit("connected")},"onStart")})}async disconnect(){await this.bot.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,4096),n="";for(let o of r){let i=await this.bot.api.sendMessage(Number(e),o,{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:vd(s?.parseMode)});n=String(i.message_id)}return n}async editMessage(e,t,s,r){await this.bot.api.editMessageText(Number(e),Number(t),s,{parse_mode:vd(r?.parseMode)})}async deleteMessage(e,t){await this.bot.api.deleteMessage(Number(e),Number(t))}async sendPhoto(e,t,s){let r=await this.bot.api.sendPhoto(Number(e),new la(t,"image.png"),{caption:s});return String(r.message_id)}async sendFile(e,t,s,r){let n=await this.bot.api.sendDocument(Number(e),new la(t,s),{caption:r});return String(n.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new la(t,"voice.ogg"),{caption:s});return String(r.message_id)}normalizeMessage(e,t){return{id:String(e.message_id),platform:"telegram",chatId:String(e.chat.id),chatType:e.chat.type==="private"?"dm":"group",userId:String(e.from.id),userName:e.from.username??String(e.from.id),displayName:[e.from.first_name,e.from.last_name].filter(Boolean).join(" "),text:t,timestamp:new Date(e.date*1e3),replyToMessageId:e.reply_to_message?String(e.reply_to_message.message_id):void 0}}async downloadAttachment(e,t,s,r){try{let o=(await this.bot.api.getFile(e)).file_path;if(!o)return;let i=`https://api.telegram.org/file/bot${this.bot.token}/${o}`,a=await fetch(i);if(!a.ok)return;let c=Buffer.from(await a.arrayBuffer());return{type:t,mimeType:s,fileName:r??o.split("/").pop(),size:c.length,data:c}}catch(n){console.error("[telegram] Failed to download file",e,n);return}}}});import{Client as nh,GatewayIntentBits as Vn,Events as da}from"discord.js";var Kn,Id=T(()=>{"use strict";Qe();Kn=class extends pe{static{m(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new nh({intents:[Vn.Guilds,Vn.GuildMessages,Vn.MessageContent,Vn.DirectMessages]}),this.client.on(da.MessageCreate,async e=>{if(!e.author.bot)try{let t=await this.downloadAttachments(e),s=e.content||this.inferTextFromAttachments(t),r={id:e.id,platform:"discord",chatId:e.channelId,chatType:e.channel.isDMBased()?"dm":"group",userId:e.author.id,userName:e.author.username,displayName:e.author.displayName,text:s,timestamp:e.createdAt,replyToMessageId:e.reference?.messageId??void 0,attachments:t.length>0?t:void 0};this.emit("message",r)}catch(t){this.emit("error",t instanceof Error?t:new Error(String(t)))}}),this.client.on(da.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(da.Error,e=>{this.emit("error",e)}),await this.client.login(this.token)}async disconnect(){this.client?.destroy(),this.client=null,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){if(!this.client)throw new Error("Client is not connected");let r=await this.client.channels.fetch(e);if(!r?.isTextBased()||!("send"in r))throw new Error(`Channel ${e} is not a text channel`);let n=this.splitText(t,2e3),o="";for(let i=0;i<n.length;i++)i===0&&s?.replyToMessageId?o=(await(await r.messages.fetch(s.replyToMessageId)).reply(n[i])).id:o=(await r.send(n[i])).id;return o}async editMessage(e,t,s,r){if(!this.client)throw new Error("Client is not connected");let n=await this.client.channels.fetch(e);if(!n?.isTextBased()||!("messages"in n))throw new Error(`Channel ${e} is not a text channel`);await(await n.messages.fetch(t)).edit(s)}async deleteMessage(e,t){if(!this.client)throw new Error("Client is not connected");let s=await this.client.channels.fetch(e);if(!s?.isTextBased()||!("messages"in s))throw new Error(`Channel ${e} is not a text channel`);await(await s.messages.fetch(t)).delete()}async sendPhoto(e,t,s){if(!this.client)return;let r=await this.client.channels.fetch(e);return!r?.isTextBased()||!("send"in r)?void 0:(await r.send({content:s,files:[{attachment:t,name:"image.png"}]})).id}async sendFile(e,t,s,r){if(!this.client)return;let n=await this.client.channels.fetch(e);return!n?.isTextBased()||!("send"in n)?void 0:(await n.send({content:r,files:[{attachment:t,name:s}]})).id}async sendVoice(e,t,s){return this.sendFile(e,t,"voice.ogg",s)}async downloadAttachments(e){let t=[],s=e.attachments;if(!s||s.size===0)return t;for(let[,r]of s)try{let n=await fetch(r.url);if(!n.ok)continue;let o=await n.arrayBuffer(),i=Buffer.from(o),a=this.classifyContentType(r.contentType);t.push({type:a,url:r.url,mimeType:r.contentType??void 0,fileName:r.name??void 0,size:r.size??i.length,data:i})}catch(n){console.error("[discord] Failed to download attachment",r.url,n)}return t}classifyContentType(e){return e?e.startsWith("image/")?"image":e.startsWith("audio/")?"audio":e.startsWith("video/")?"video":"document":"other"}inferTextFromAttachments(e){if(e.length===0)return"";let t=e.map(s=>s.type);return t.includes("image")?"[Photo]":t.includes("audio")?"[Voice message]":t.includes("video")?"[Video]":t.includes("document")?"[Document]":"[File]"}}});var Xn,Rd=T(()=>{"use strict";Qe();Xn=class extends pe{static{m(this,"MatrixAdapter")}platform="matrix";client;homeserverUrl;accessToken;botUserId;constructor(e,t,s){super(),this.homeserverUrl=e.replace(/\/+$/,""),this.accessToken=t,this.botUserId=s}async connect(){this.status="connecting";let{MatrixClient:e,SimpleFsStorageProvider:t,AutojoinRoomsMixin:s}=await import("matrix-bot-sdk"),r=new t("./data/matrix-storage");this.client=new e(this.homeserverUrl,this.accessToken,r),s.setupOnClient(this.client),this.client.on("room.message",async(n,o)=>{if(o.sender===this.botUserId)return;let i=o.content?.msgtype;if(i)try{let a=await this.normalizeEvent(n,o,i);a&&this.emit("message",a)}catch(a){this.emit("error",a instanceof Error?a:new Error(String(a)))}}),await this.client.start(),this.status="connected",this.emit("connected")}async disconnect(){this.client.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,32e3),n="";for(let o of r)s?.parseMode==="html"?n=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:o.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:o}):n=await this.client.sendText(e,o);return n}async editMessage(e,t,s,r){let n=r?.parseMode==="html",o={msgtype:"m.text",body:"* "+(n?s.replace(/<[^>]*>/g,""):s),"m.new_content":{msgtype:"m.text",body:n?s.replace(/<[^>]*>/g,""):s,...n?{format:"org.matrix.custom.html",formatted_body:s}:{}},"m.relates_to":{rel_type:"m.replace",event_id:t}};await this.client.sendEvent(e,"m.room.message",o)}async deleteMessage(e,t){await this.client.redactEvent(e,t)}async sendPhoto(e,t,s){let r=await this.client.uploadContent(t,"image/png","image.png"),n={msgtype:"m.image",body:s??"image.png",url:r,info:{mimetype:"image/png",size:t.length}};return await this.client.sendEvent(e,"m.room.message",n)}async sendFile(e,t,s,r){let n=this.guessMimeType(s),o=await this.client.uploadContent(t,n,s),i={msgtype:"m.file",body:r??s,filename:s,url:o,info:{mimetype:n,size:t.length}};return await this.client.sendEvent(e,"m.room.message",i)}async normalizeEvent(e,t,s){let r;try{r=(await this.client.getUserProfile(t.sender))?.displayname??void 0}catch{}let n={id:t.event_id,platform:"matrix",chatId:e,chatType:"group",userId:t.sender,userName:t.sender.split(":")[0].slice(1),displayName:r,timestamp:new Date(t.origin_server_ts),replyToMessageId:t.content["m.relates_to"]?.["m.in_reply_to"]?.event_id};switch(s){case"m.text":return{...n,text:t.content.body};case"m.image":{let o=await this.downloadAttachment(t.content,"image");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Photo]",attachments:o?[o]:void 0}}case"m.audio":{let o=await this.downloadAttachment(t.content,"audio");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Voice message]",attachments:o?[o]:void 0}}case"m.video":{let o=await this.downloadAttachment(t.content,"video");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Video]",attachments:o?[o]:void 0}}case"m.file":{let o=await this.downloadAttachment(t.content,"document");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Document]",attachments:o?[o]:void 0}}default:return t.content.body?{...n,text:t.content.body}:void 0}}async downloadAttachment(e,t){let s=e.url;if(!s||!s.startsWith("mxc://"))return;let r=e.info??{},n=r.mimetype,o=r.size,i=e.filename??e.body??"file",a=s.slice(6),c=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${a}`,`${this.homeserverUrl}/_matrix/media/v3/download/${a}`];for(let d of c)try{let u=await fetch(d,{headers:{Authorization:`Bearer ${this.accessToken}`}});if(u.status===404)continue;if(!u.ok){console.error(`[matrix] Download failed (${u.status})`,s,d);continue}let p=await u.arrayBuffer(),f=Buffer.from(p);return{type:t,mimeType:n,fileName:i,size:o??f.length,data:f}}catch(u){console.error("[matrix] Download error",s,d,u);continue}console.error("[matrix] All download endpoints failed for",s)}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Yn,xd=T(()=>{"use strict";Qe();Yn=class extends pe{static{m(this,"WhatsAppAdapter")}platform="whatsapp";socket;downloadMedia;dataPath;reconnectAttempts=0;reconnectTimer;constructor(e){super(),this.dataPath=e}async connect(){this.status="connecting";let{makeWASocket:e,useMultiFileAuthState:t,DisconnectReason:s,downloadMediaMessage:r}=await import("@whiskeysockets/baileys");this.downloadMedia=r;let{state:n,saveCreds:o}=await t(this.dataPath);this.socket=e({auth:n,printQRInTerminal:!0}),this.socket.ev.on("creds.update",o),this.socket.ev.on("connection.update",i=>{if(i.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),i.connection==="close"){let c=i.lastDisconnect?.error?.output?.statusCode!==s.loggedOut;if(this.status="disconnected",this.emit("disconnected"),c){let d=Math.min(1e3*Math.pow(2,this.reconnectAttempts),6e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>this.connect(),d)}}}),this.socket.ev.on("messages.upsert",({messages:i,type:a})=>{if(a==="notify")for(let c of i)c.message&&(c.key.fromMe||this.processMessage(c).catch(d=>{this.emit("error",d instanceof Error?d:new Error(String(d)))}))})}async disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.reconnectAttempts=0,this.socket?.end(void 0),this.socket=void 0,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,65e3),n="";for(let o=0;o<r.length;o++)n=(await this.socket.sendMessage(e,{text:r[o]},o===0&&s?.replyToMessageId?{quoted:{key:{remoteJid:e,id:s.replyToMessageId},message:{}}}:void 0))?.key?.id??"";return n}async editMessage(e,t,s,r){await this.socket.sendMessage(e,{text:s,edit:{remoteJid:e,id:t,fromMe:!0}})}async deleteMessage(e,t){await this.socket.sendMessage(e,{delete:{remoteJid:e,id:t,fromMe:!0}})}async sendPhoto(e,t,s){return(await this.socket.sendMessage(e,{image:t,caption:s}))?.key?.id}async sendFile(e,t,s,r){return(await this.socket.sendMessage(e,{document:t,fileName:s,caption:r,mimetype:this.guessMimeType(s)}))?.key?.id}async processMessage(e){let t=e.message,s=t.conversation??t.extendedTextMessage?.text??t.imageMessage?.caption??t.videoMessage?.caption??t.documentMessage?.caption??"",r=[],n=s;if(t.imageMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.imageMessage.mimetype??"image/jpeg";r.push({type:"image",mimeType:a,fileName:t.imageMessage.fileName??`image.${a.split("/")[1]??"jpeg"}`,size:t.imageMessage.fileLength??i.length,data:i})}n||(n="[Photo]")}else if(t.audioMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.audioMessage.mimetype??"audio/ogg";r.push({type:"audio",mimeType:a,fileName:t.audioMessage.fileName??`audio.${a.split("/")[1]??"ogg"}`,size:t.audioMessage.fileLength??i.length,data:i})}n||(n="[Voice message]")}else if(t.videoMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"video",mimeType:t.videoMessage.mimetype??"video/mp4",size:t.videoMessage.fileLength??i.length,data:i}),n||(n="[Video]")}else if(t.documentMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"document",mimeType:t.documentMessage.mimetype??"application/octet-stream",fileName:t.documentMessage.fileName??"document",size:t.documentMessage.fileLength??i.length,data:i}),n||(n="[Document]")}else if(t.stickerMessage&&!s)return;if(!n&&r.length===0)return;let o={id:e.key.id??"",platform:"whatsapp",chatId:e.key.remoteJid??"",chatType:e.key.remoteJid?.endsWith("@g.us")?"group":"dm",userId:e.key.participant??e.key.remoteJid??"",userName:e.pushName??e.key.participant??e.key.remoteJid??"",displayName:e.pushName??void 0,text:n,timestamp:new Date(e.messageTimestamp*1e3),replyToMessageId:t.extendedTextMessage?.contextInfo?.stanzaId??void 0,attachments:r.length>0?r:void 0};this.emit("message",o)}async downloadMediaSafe(e){try{if(!this.downloadMedia)return;let t=await this.downloadMedia(e,"buffer",{});return Buffer.isBuffer(t)?t:Buffer.from(t)}catch(t){console.error("[whatsapp] Failed to download media",t);return}}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Jn,Cd=T(()=>{"use strict";Qe();Jn=class extends pe{static{m(this,"SignalAdapter")}apiUrl;phoneNumber;platform="signal";pollingInterval;constructor(e,t){super(),this.apiUrl=e,this.phoneNumber=t}async connect(){this.status="connecting";let e=3,t;for(let s=0;s<=e;s++)try{let r=await fetch(`${this.apiUrl}/v1/about`);if(!r.ok)throw new Error(`Signal API not reachable: ${r.status}`);this.pollingInterval=setInterval(()=>{this.pollMessages().catch(n=>{this.emit("error",n instanceof Error?n:new Error(String(n)))})},2e3),this.status="connected",this.emit("connected");return}catch(r){if(t=r instanceof Error?r:new Error(String(r)),s<e){let n=1e3*Math.pow(2,s);await new Promise(o=>setTimeout(o,n))}}this.status="error",this.emit("error",t)}async disconnect(){this.pollingInterval&&(clearInterval(this.pollingInterval),this.pollingInterval=void 0),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,6e3),n="";for(let o of r){let i=e.startsWith("group."),a={message:o,number:this.phoneNumber};i?a.recipients=[e.replace("group.","")]:a.recipients=[e];let c=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!c.ok)throw new Error(`Signal send failed: ${c.status} ${await c.text()}`);let d=await c.json();n=String(d.timestamp??Date.now())}return n}async editMessage(e,t,s,r){throw new Error("Signal does not support message editing")}async deleteMessage(e,t){let s={number:this.phoneNumber,recipients:[e],timestamp:Number(t)},r=await fetch(`${this.apiUrl}/v1/deleteMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!r.ok)throw new Error(`Signal delete failed: ${r.status} ${await r.text()}`)}async pollMessages(){let e=await fetch(`${this.apiUrl}/v1/receive/${this.phoneNumber}`);if(!e.ok)return;let t=await e.json();for(let s of t){let r=s.envelope?.dataMessage;if(!r||!r.message&&(!r.attachments||r.attachments.length===0))continue;let n=s.envelope,o=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:n.sourceNumber??n.source??"",i=[];if(r.attachments)for(let d of r.attachments){let u=await this.downloadAttachment(d);u&&i.push(u)}let a=r.message||this.inferTextFromAttachments(i)||"";if(!a&&i.length===0)continue;let c={id:String(r.timestamp??Date.now()),platform:"signal",chatId:o,chatType:r.groupInfo?"group":"dm",userId:n.sourceNumber??n.source??"",userName:n.sourceName??n.sourceNumber??n.source??"",displayName:n.sourceName,text:a,timestamp:new Date(r.timestamp??Date.now()),attachments:i.length>0?i:void 0};this.emit("message",c)}}async downloadAttachment(e){if(e.id)try{let t=await fetch(`${this.apiUrl}/v1/attachments/${e.id}`);if(!t.ok)return;let s=await t.arrayBuffer(),r=Buffer.from(s);return{type:this.classifyContentType(e.contentType),mimeType:e.contentType??void 0,fileName:e.filename??void 0,size:e.size??r.length,data:r}}catch(t){console.error("[signal] Failed to download attachment",e.id,t);return}}classifyContentType(e){return e?e.startsWith("image/")?"image":e.startsWith("audio/")?"audio":e.startsWith("video/")?"video":"document":"other"}inferTextFromAttachments(e){if(e.length===0)return"";let t=e.map(s=>s.type);return t.includes("image")?"[Photo]":t.includes("audio")?"[Voice message]":t.includes("video")?"[Video]":t.includes("document")?"[Document]":"[File]"}}});import ua from"node:readline";var Zn,Ld=T(()=>{"use strict";Qe();Zn=class extends pe{static{m(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=ua.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
993
993
  Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leave.
994
994
  `),this.rl.on("line",e=>{let t=e.trim();if(!t){this.prompt();return}if(t==="/quit"||t==="/exit"){console.log(`
995
995
  Goodbye!
996
996
  `),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(`
997
997
  Alfred: ${t}
998
- `),this.prompt(),r}async editMessage(e,t,s,r){ua.clearLine(process.stdout,0),ua.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import oh from"node:http";import ih from"node:crypto";var ah,Qn,Ld=T(()=>{"use strict";Qe();ah=1048576,Qn=class extends pe{static{m(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;constructor(e,t,s){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}async connect(){this.status="connecting",this.server=oh.createServer((e,t)=>{this.handleRequest(e,t)}),await new Promise((e,t)=>{this.server.listen(this.port,this.host,()=>{e()}),this.server.once("error",t)}),this.status="connected",this.emit("connected")}async disconnect(){for(let[e,t]of this.streams)this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e);this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),r}async editMessage(e,t,s,r){let n=this.streams.get(e);n&&this.writeSseEvent(n,"status",{type:"status",text:s})}async deleteMessage(e,t){}async sendPhoto(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,r){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:r}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"voice",data:t.toString("base64"),caption:s}),`api-voice-${++this.messageCounter}`}endStream(e){let t=this.streams.get(e);t&&(this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e))}handleRequest(e,t){if(t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Access-Control-Allow-Origin",this.corsOrigin),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.method==="OPTIONS"){t.writeHead(204),t.end();return}let s=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`);s.pathname==="/api/health"&&e.method==="GET"?this.handleHealth(t):s.pathname==="/api/metrics"&&e.method==="GET"?this.handleMetrics(t):s.pathname==="/api/message"&&e.method==="POST"?this.handleMessage(e,t):(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;return!s||s!==`Bearer ${this.apiToken}`?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleHealth(e){let t=this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",r=s==="ok"?200:503;e.writeHead(r,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(this.metricsFn())):this.handleHealth(e)}handleMessage(e,t){if(!this.checkAuth(e,t))return;let s="",r=0,n=!1;e.on("data",o=>{if(!n){if(r+=o.length,r>ah){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-${ih.randomUUID()}`,c=o.userId??"api-user",d=this.streams.get(a);d&&(this.writeSseEvent(d,"done",{type:"done"}),d.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this.streams.set(a,t),e.on("close",()=>{this.streams.delete(a)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:a,chatType:"dm",userId:c,userName:c,displayName:"API User",text:i,timestamp:new Date};this.emit("message",u)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON body"}))}})}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
998
+ `),this.prompt(),r}async editMessage(e,t,s,r){ua.clearLine(process.stdout,0),ua.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import oh from"node:http";import ih from"node:crypto";var ah,Qn,Dd=T(()=>{"use strict";Qe();ah=1048576,Qn=class extends pe{static{m(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;constructor(e,t,s){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}async connect(){this.status="connecting",this.server=oh.createServer((e,t)=>{this.handleRequest(e,t)}),await new Promise((e,t)=>{this.server.listen(this.port,this.host,()=>{e()}),this.server.once("error",t)}),this.status="connected",this.emit("connected")}async disconnect(){for(let[e,t]of this.streams)this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e);this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),r}async editMessage(e,t,s,r){let n=this.streams.get(e);n&&this.writeSseEvent(n,"status",{type:"status",text:s})}async deleteMessage(e,t){}async sendPhoto(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,r){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:r}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"voice",data:t.toString("base64"),caption:s}),`api-voice-${++this.messageCounter}`}endStream(e){let t=this.streams.get(e);t&&(this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e))}handleRequest(e,t){if(t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Access-Control-Allow-Origin",this.corsOrigin),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.method==="OPTIONS"){t.writeHead(204),t.end();return}let s=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`);s.pathname==="/api/health"&&e.method==="GET"?this.handleHealth(t):s.pathname==="/api/metrics"&&e.method==="GET"?this.handleMetrics(t):s.pathname==="/api/message"&&e.method==="POST"?this.handleMessage(e,t):(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;return!s||s!==`Bearer ${this.apiToken}`?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleHealth(e){let t=this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",r=s==="ok"?200:503;e.writeHead(r,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(this.metricsFn())):this.handleHealth(e)}handleMessage(e,t){if(!this.checkAuth(e,t))return;let s="",r=0,n=!1;e.on("data",o=>{if(!n){if(r+=o.length,r>ah){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-${ih.randomUUID()}`,c=o.userId??"api-user",d=this.streams.get(a);d&&(this.writeSseEvent(d,"done",{type:"done"}),d.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this.streams.set(a,t),e.on("close",()=>{this.streams.delete(a)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:a,chatType:"dm",userId:c,userName:c,displayName:"API User",text:i,timestamp:new Date};this.emit("message",u)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON body"}))}})}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
999
999
  data: ${JSON.stringify(s)}
1000
1000
 
1001
- `)}}});var it={};ue(it,{CLIAdapter:()=>Zn,DiscordAdapter:()=>Kn,HttpAdapter:()=>Qn,MatrixAdapter:()=>Xn,MessagingAdapter:()=>pe,SignalAdapter:()=>Jn,TelegramAdapter:()=>Gn,WhatsAppAdapter:()=>Yn});var at=T(()=>{"use strict";Qe();Ad();Id();Rd();xd();Cd();Dd();Ld()});import eo from"node:fs";import to from"node:path";import ch from"js-yaml";var Nt,Nd=T(()=>{"use strict";Ho();Wo();Xe();ni();fn();se();qi();Gi();Vi();Ki();Xi();Yi();Ji();Zi();Qi();ea();ta();sa();Sd();ia();aa();ca();Nt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;adapters=new Map;formatter=new Pr;userRepo;skillRegistry;mcpManager;calendarSkill;usageRepo;constructor(e){this.config=e,this.logger=js("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new Tt(this.config.storage.path);let e=this.database.getDb(),t=new Hs(e),s=new zs(e);this.userRepo=s;let r=new Et(e),n=new qs(e),o=new Ws(e),i=new Gs(e),a=new Vs(e),c=new Ks(e),d=new Xs(e),u=new Ys(e);this.logger.info("Storage initialized");let p=new ur,f=this.loadSecurityRules();p.loadRules(f);let g=new mr(p,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:f.length},"Security engine initialized");let h=si(this.config.llm,this.logger.child({component:"llm"}));await h.initialize(),this.llmProvider=h;let y=new tr(e);this.usageRepo=y,h.setPersist((x,z,re,xe,We,tt)=>{y.record(x,z,re,xe,We,tt)});let b=new Ur(h,a,this.logger.child({component:"embeddings"})),k=this.config.activeLearning?.enabled!==!1,S,j;k&&(S=new zr({llm:h,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:b,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),j=new qr(n,this.logger.child({component:"memory-retriever"}),b),this.logger.info("Active learning & memory retriever initialized"));let N=new er(e),q=new Wr(h,N,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ee=new Bt(this.logger.child({component:"sandbox"})),D=this.skillRegistry=new jt;D.register(new Ht),D.register(new zt),D.register(new qt(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),D.register(new Wt(o)),D.register(new Gt(i));let O=new Zs(e);if(D.register(new ds(O)),D.register(new Vt),D.register(new Kt),D.register(new Xt(n,b)),D.register(new Yt(h,D,ee,g)),this.config.email?.accounts?.length){let x=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 re=await pr(z);x.set(z.name,re),this.logger.info({account:z.name,provider:z.provider??"imap-smtp"},"Email account initialized")}catch(re){this.logger.warn({err:re,account:z.name},"Email account initialization failed, skipping")}D.register(x.size>0?new nt(x):new nt)}else D.register(new nt);D.register(new Jt),D.register(new Zt);let ie=new hs;ie.setReloadCallback(x=>this.reloadService(x)),D.register(ie),D.register(new es),D.register(new ts),D.register(new ss),D.register(new rs(s)),D.register(new ns(s,c,this.adapters,(x,z)=>t.findByPlatformAndUser(x,z))),D.register(new os(d)),D.register(new is(u));let He=new Js(e),ke=new Fr(He,b,this.logger.child({component:"documents"}));D.register(new as(He,ke,b));let oe;if(this.config.calendar)try{let x=await gr(this.config.calendar);oe=new vt(x),D.register(oe),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(x){this.logger.warn({err:x},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=oe,this.config.mcp?.servers?.length){let{MCPManager:x}=await Promise.resolve().then(()=>(se(),ne));this.mcpManager=new x(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let z of this.mcpManager.getSkills())D.register(z);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},h)),this.logger.info({agents:this.config.codeAgents.agents.map(z=>z.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:x,createContactsProvider:z}=await Promise.resolve().then(()=>(se(),ne)),re=await z(this.config.contacts);D.register(new x(re)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(x){this.logger.warn({err:x},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant){let{MonitorSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:x}=await Promise.resolve().then(()=>(se(),ne));D.register(new x(D,this.config,n)),this.logger.info("Briefing skill registered")}this.logger.info({skills:D.getAll().map(x=>x.metadata.name)},"Skills registered");let J;if(this.config.speech?.apiKey&&(J=new Lr(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 x=new Nr(this.config.speech,this.logger.child({component:"tts"}));D.register(new cs(x)),this.logger.info("Text-to-speech skill registered")}let B=this.detectImageGenProvider();if(B){let x=new Mr(B,this.logger.child({component:"image-gen"}));D.register(new ls(x)),this.logger.info({provider:B.provider},"Image generation skill registered")}try{let x=new Or(this.logger.child({component:"transit"}));D.register(new ms(x)),this.logger.info("Public transit skill registered")}catch(x){this.logger.warn({err:x},"Failed to register transit skill")}let de=new xr(t),Re=to.resolve(to.dirname(this.config.storage.path),"inbox");this.pipeline=new Cr({llm:h,conversationManager:de,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:D,skillSandbox:ee,securityManager:g,memoryRepo:n,speechTranscriber:J,inboxPath:Re,embeddingService:b,activeLearning:S,memoryRetriever:j,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:ke,conversationSummarizer:q}),this.reminderScheduler=new Dr(o,async(x,z,re)=>{let xe=this.adapters.get(x);xe?await xe.sendMessage(z,re):this.logger.warn({platform:x,chatId:z},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(x=>s.getMasterUserId(x),"getMasterUserId"),getLinkedUsers:m(x=>s.getLinkedUsers(x),"getLinkedUsers"),findConversation:m((x,z)=>t.findByPlatformAndUser(x,z),"findConversation")}),this.backgroundTaskRunner=new jr(D,ee,d,this.adapters,s,this.logger.child({component:"background-tasks"})),this.proactiveScheduler=new Br(u,D,ee,h,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,de);let Ie=new Qs(e);D.register(new fs(Ie)),this.watchEngine=new Wn(Ie,D,ee,this.adapters,s,this.logger.child({component:"watch-engine"})),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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>({db:!!this.database,uptime:Math.floor(process.uptime()),adapters:Object.fromEntries([...this.adapters].map(([n,o])=>[n,o.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10))}),"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback")})),this.logger.info({port:s,host:r},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters)this.setupAdapterHandlers(e,t),await t.connect(),this.logger.info({platform:e},"Adapter connected");this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),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(()=>(at(),it)),t=new e;this.adapters.set("cli",t),this.setupAdapterHandlers("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.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.getDb().pragma("wal_checkpoint(TRUNCATE)")}catch{}this.database.close(),this.logger.info("Alfred stopped")}async reloadService(e){try{jo();let t=new le().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(se(),ne)),n=await r(t.contacts);this.skillRegistry.register(new s(n)),this.config.contacts=t.contacts,this.logger.info({provider:t.contacts.provider},"Contacts skill hot-reloaded")}if(e==="docker"&&t.docker){let{DockerSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.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(`
1002
- `)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async d=>{if(d!==n){n=d;try{r?await t.editMessage(s.chatId,r,d):r=await t.sendMessage(s.chatId,d)}catch(u){this.logger.debug({err:u,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o),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 d of i.attachments)try{let u=d.mimeType.startsWith("image/"),p=d.mimeType==="audio/ogg"||d.mimeType==="audio/opus";u?await t.sendPhoto(s.chatId,d.data,d.fileName):p?await t.sendVoice(s.chatId,d.data):await t.sendFile(s.chatId,d.data,d.fileName)}catch(u){this.logger.warn({err:u,fileName:d.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=to.resolve(this.config.security.rulesPath),t=[];if(!eo.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!eo.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=eo.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=to.join(e,n),i=eo.readFileSync(o,"utf-8"),a=ch.load(i);a?.rules&&Array.isArray(a.rules)&&(t.push(...a.rules),this.logger.info({file:n,count:a.rules.length},"Loaded security rules"))}catch(o){this.logger.error({err:o,file:n},"Failed to load security rules file")}return t}}});var Md=T(()=>{"use strict"});var ma=T(()=>{"use strict";Nd();Gi();qi();Vi();Ki();Xi();Zi();Qi();ta();sa();_s();ea();Yi();Ji();ia();aa();oa();Md();na();ca()});import so from"node:fs";import Od from"node:path";import lh from"node:os";function Pd(){try{let l=so.readFileSync(pa,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Ud(l){try{let e=Od.dirname(pa);so.existsSync(e)||so.mkdirSync(e,{recursive:!0}),so.writeFileSync(pa,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Mt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),uh);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function Fd(l,e,t){switch(l){case"anthropic":{let s=await Mt("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 Mt(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 Mt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await Mt("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 Mt("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 Mt(`${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 Mt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function ha(l,e,t){let s=Pd(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<dh)return r.models;try{let n=await Fd(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Ud(s),n}catch{}return r?r.models:[]}function ro(l,e,t){Fd(l,e,t).then(s=>{if(s.length>0){let r=Pd();r.providers[l]={fetchedAt:Date.now(),models:s},Ud(r)}}).catch(()=>{})}function fa(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 dh,uh,pa,ga=T(()=>{"use strict";dh=24*60*60*1e3,uh=5e3,pa=Od.join(lh.homedir(),".alfred","model-cache.json");m(Pd,"readCache");m(Ud,"writeCache");m(Mt,"fetchWithTimeout");m(Fd,"fetchModelsFromAPI");m(ha,"getModels");m(ro,"refreshCacheInBackground");m(fa,"mergeModels")});var jd={};ue(jd,{startCommand:()=>mh});async function mh(){let l=new le,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=js("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new Nt(e),r=!1,n=m(async o=>{if(!r){r=!0,t.info({signal:o},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(i){t.error({error:i},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",o=>{t.fatal({error:o},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",o=>{t.fatal({reason:o},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let o=e.llm;o?.default?.provider?ro(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&ro(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&ro(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 Bd=T(()=>{"use strict";Xe();Ho();ma();ga();m(mh,"startCommand")});var zd={};ue(zd,{chatCommand:()=>fh});import Hd from"node:http";import Gr from"node:readline";function ph(l,e){return new Promise(t=>{let s=Hd.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 hh(l,e){let t=Gr.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
1001
+ `)}}});var it={};ue(it,{CLIAdapter:()=>Zn,DiscordAdapter:()=>Kn,HttpAdapter:()=>Qn,MatrixAdapter:()=>Xn,MessagingAdapter:()=>pe,SignalAdapter:()=>Jn,TelegramAdapter:()=>Gn,WhatsAppAdapter:()=>Yn});var at=T(()=>{"use strict";Qe();Ad();Id();Rd();xd();Cd();Ld();Dd()});import eo from"node:fs";import to from"node:path";import ch from"js-yaml";var Nt,Nd=T(()=>{"use strict";Ho();Wo();Xe();ni();fn();se();zi();Gi();Vi();Ki();Xi();Yi();Ji();Zi();Qi();ea();ta();sa();Sd();ia();aa();ca();Nt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;adapters=new Map;formatter=new Pr;userRepo;skillRegistry;mcpManager;calendarSkill;usageRepo;constructor(e){this.config=e,this.logger=js("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new Tt(this.config.storage.path);let e=this.database.getDb(),t=new Hs(e),s=new qs(e);this.userRepo=s;let r=new Et(e),n=new zs(e),o=new Ws(e),i=new Gs(e),a=new Vs(e),c=new Ks(e),d=new Xs(e),u=new Ys(e);this.logger.info("Storage initialized");let p=new ur,f=this.loadSecurityRules();p.loadRules(f);let g=new mr(p,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:f.length},"Security engine initialized");let h=si(this.config.llm,this.logger.child({component:"llm"}));await h.initialize(),this.llmProvider=h;let y=new tr(e);this.usageRepo=y,h.setPersist((x,q,re,xe,We,tt)=>{y.record(x,q,re,xe,We,tt)});let b=new Ur(h,a,this.logger.child({component:"embeddings"})),k=this.config.activeLearning?.enabled!==!1,S,j;k&&(S=new qr({llm:h,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:b,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),j=new zr(n,this.logger.child({component:"memory-retriever"}),b),this.logger.info("Active learning & memory retriever initialized"));let N=new er(e),z=new Wr(h,N,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ee=new Bt(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new jt;L.register(new Ht),L.register(new qt),L.register(new zt(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new Wt(o)),L.register(new Gt(i));let O=new Zs(e);if(L.register(new ds(O)),L.register(new Vt),L.register(new Kt),L.register(new Xt(n,b)),L.register(new Yt(h,L,ee,g)),this.config.email?.accounts?.length){let x=new Map;for(let q of this.config.email.accounts)try{q.provider==="microsoft"&&!q.microsoft?.clientId&&this.config.calendar?.microsoft&&(q.microsoft={...this.config.calendar.microsoft});let re=await pr(q);x.set(q.name,re),this.logger.info({account:q.name,provider:q.provider??"imap-smtp"},"Email account initialized")}catch(re){this.logger.warn({err:re,account:q.name},"Email account initialization failed, skipping")}L.register(x.size>0?new nt(x):new nt)}else L.register(new nt);L.register(new Jt),L.register(new Zt);let ie=new hs;ie.setReloadCallback(x=>this.reloadService(x)),L.register(ie),L.register(new es),L.register(new ts),L.register(new ss),L.register(new rs(s)),L.register(new ns(s,c,this.adapters,(x,q)=>t.findByPlatformAndUser(x,q))),L.register(new os(d)),L.register(new is(u));let He=new Js(e),ke=new Fr(He,b,this.logger.child({component:"documents"}));L.register(new as(He,ke,b));let oe;if(this.config.calendar)try{let x=await gr(this.config.calendar);oe=new vt(x),L.register(oe),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(x){this.logger.warn({err:x},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=oe,this.config.mcp?.servers?.length){let{MCPManager:x}=await Promise.resolve().then(()=>(se(),ne));this.mcpManager=new x(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let q of this.mcpManager.getSkills())L.register(q);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},h)),this.logger.info({agents:this.config.codeAgents.agents.map(q=>q.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:x,createContactsProvider:q}=await Promise.resolve().then(()=>(se(),ne)),re=await q(this.config.contacts);L.register(new x(re)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(x){this.logger.warn({err:x},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant){let{MonitorSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:x}=await Promise.resolve().then(()=>(se(),ne));L.register(new x(L,this.config,n)),this.logger.info("Briefing skill registered")}this.logger.info({skills:L.getAll().map(x=>x.metadata.name)},"Skills registered");let J;if(this.config.speech?.apiKey&&(J=new Dr(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 x=new Nr(this.config.speech,this.logger.child({component:"tts"}));L.register(new cs(x)),this.logger.info("Text-to-speech skill registered")}let B=this.detectImageGenProvider();if(B){let x=new Mr(B,this.logger.child({component:"image-gen"}));L.register(new ls(x)),this.logger.info({provider:B.provider},"Image generation skill registered")}try{let x=new Or(this.logger.child({component:"transit"}));L.register(new ms(x)),this.logger.info("Public transit skill registered")}catch(x){this.logger.warn({err:x},"Failed to register transit skill")}let de=new xr(t),Re=to.resolve(to.dirname(this.config.storage.path),"inbox");this.pipeline=new Cr({llm:h,conversationManager:de,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:ee,securityManager:g,memoryRepo:n,speechTranscriber:J,inboxPath:Re,embeddingService:b,activeLearning:S,memoryRetriever:j,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:ke,conversationSummarizer:z}),this.reminderScheduler=new Lr(o,async(x,q,re)=>{let xe=this.adapters.get(x);xe?await xe.sendMessage(q,re):this.logger.warn({platform:x,chatId:q},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(x=>s.getMasterUserId(x),"getMasterUserId"),getLinkedUsers:m(x=>s.getLinkedUsers(x),"getLinkedUsers"),findConversation:m((x,q)=>t.findByPlatformAndUser(x,q),"findConversation")}),this.backgroundTaskRunner=new jr(L,ee,d,this.adapters,s,this.logger.child({component:"background-tasks"})),this.proactiveScheduler=new Br(u,L,ee,h,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,de);let Ie=new Qs(e);L.register(new fs(Ie,L)),this.watchEngine=new Wn(Ie,L,ee,this.adapters,s,this.logger.child({component:"watch-engine"})),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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it));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(()=>(at(),it)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>({db:!!this.database,uptime:Math.floor(process.uptime()),adapters:Object.fromEntries([...this.adapters].map(([n,o])=>[n,o.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10))}),"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback")})),this.logger.info({port:s,host:r},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters)this.setupAdapterHandlers(e,t),await t.connect(),this.logger.info({platform:e},"Adapter connected");this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),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(()=>(at(),it)),t=new e;this.adapters.set("cli",t),this.setupAdapterHandlers("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.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.getDb().pragma("wal_checkpoint(TRUNCATE)")}catch{}this.database.close(),this.logger.info("Alfred stopped")}async reloadService(e){try{jo();let t=new le().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(se(),ne)),n=await r(t.contacts);this.skillRegistry.register(new s(n)),this.config.contacts=t.contacts,this.logger.info({provider:t.contacts.provider},"Contacts skill hot-reloaded")}if(e==="docker"&&t.docker){let{DockerSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(se(),ne));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.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(`
1002
+ `)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async d=>{if(d!==n){n=d;try{r?await t.editMessage(s.chatId,r,d):r=await t.sendMessage(s.chatId,d)}catch(u){this.logger.debug({err:u,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o),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 d of i.attachments)try{let u=d.mimeType.startsWith("image/"),p=d.mimeType==="audio/ogg"||d.mimeType==="audio/opus";u?await t.sendPhoto(s.chatId,d.data,d.fileName):p?await t.sendVoice(s.chatId,d.data):await t.sendFile(s.chatId,d.data,d.fileName)}catch(u){this.logger.warn({err:u,fileName:d.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=to.resolve(this.config.security.rulesPath),t=[];if(!eo.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!eo.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=eo.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=to.join(e,n),i=eo.readFileSync(o,"utf-8"),a=ch.load(i);a?.rules&&Array.isArray(a.rules)&&(t.push(...a.rules),this.logger.info({file:n,count:a.rules.length},"Loaded security rules"))}catch(o){this.logger.error({err:o,file:n},"Failed to load security rules file")}return t}}});var Md=T(()=>{"use strict"});var ma=T(()=>{"use strict";Nd();Gi();zi();Vi();Ki();Xi();Zi();Qi();ta();sa();_s();ea();Yi();Ji();ia();aa();oa();Md();na();ca()});import so from"node:fs";import Od from"node:path";import lh from"node:os";function Pd(){try{let l=so.readFileSync(pa,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Ud(l){try{let e=Od.dirname(pa);so.existsSync(e)||so.mkdirSync(e,{recursive:!0}),so.writeFileSync(pa,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Mt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),uh);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function Fd(l,e,t){switch(l){case"anthropic":{let s=await Mt("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 Mt(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 Mt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await Mt("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 Mt("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 Mt(`${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 Mt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function ha(l,e,t){let s=Pd(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<dh)return r.models;try{let n=await Fd(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Ud(s),n}catch{}return r?r.models:[]}function ro(l,e,t){Fd(l,e,t).then(s=>{if(s.length>0){let r=Pd();r.providers[l]={fetchedAt:Date.now(),models:s},Ud(r)}}).catch(()=>{})}function fa(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 dh,uh,pa,ga=T(()=>{"use strict";dh=24*60*60*1e3,uh=5e3,pa=Od.join(lh.homedir(),".alfred","model-cache.json");m(Pd,"readCache");m(Ud,"writeCache");m(Mt,"fetchWithTimeout");m(Fd,"fetchModelsFromAPI");m(ha,"getModels");m(ro,"refreshCacheInBackground");m(fa,"mergeModels")});var jd={};ue(jd,{startCommand:()=>mh});async function mh(){let l=new le,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=js("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new Nt(e),r=!1,n=m(async o=>{if(!r){r=!0,t.info({signal:o},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(i){t.error({error:i},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",o=>{t.fatal({error:o},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",o=>{t.fatal({reason:o},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let o=e.llm;o?.default?.provider?ro(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&ro(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&ro(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 Bd=T(()=>{"use strict";Xe();Ho();ma();ga();m(mh,"startCommand")});var qd={};ue(qd,{chatCommand:()=>fh});import Hd from"node:http";import Gr from"node:readline";function ph(l,e){return new Promise(t=>{let s=Hd.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 hh(l,e){let t=Gr.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
1003
1003
  Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
1004
1004
  `),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
1005
1005
  Goodbye!
@@ -1014,42 +1014,42 @@ Error: ${f.text??"Unknown error"}
1014
1014
  `),t.prompt();break}}catch{}}}),i.on("end",()=>{if(a.length>0){let c=a.split(`
1015
1015
  `).find(d=>d.startsWith("data: "));if(c)try{let d=JSON.parse(c.slice(6));(d.type==="done"||d.type==="error")&&t.prompt()}catch{}}}),i.on("error",c=>{console.error(`
1016
1016
  Connection error: ${c.message}`),t.prompt()})});o.on("error",i=>{console.error(`
1017
- Failed to send message: ${i.message}`),t.prompt()}),o.write(n),o.end()}),t.on("close",()=>{process.exit(0)})}async function fh(l){let e=new le,t;try{t=e.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let s=t.api?.host??"127.0.0.1",r=t.api?.port??3420;if(await ph(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),hh(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let i=t.llm[l.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let o=new Nt(t);try{await o.initialize(),await o.startWithCLI()}catch(i){console.error("Failed to start chat:",i.message),process.exit(1)}}var qd=T(()=>{"use strict";Xe();ma();m(ph,"checkHealth");m(hh,"startClientMode");m(fh,"chatCommand")});var Vd={};ue(Vd,{setupCommand:()=>vh});import{createInterface as gh}from"node:readline/promises";import{stdin as yh,stdout as wh}from"node:process";import{execFileSync as _h}from"node:child_process";import ye from"node:fs";import Th from"node:os";import be from"node:path";import ya from"js-yaml";function M(l){return`${no}${l}${v}`}function kh(l){return`${P}${l}${v}`}function ge(l){return`${oo}${l}${v}`}function Gd(l){return`${Eh}${l}${v}`}function C(l){return`${X}${l}${v}`}function E(l){return`${ct}${l}${v}`}function _e(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function $h(l){let e=process.platform==="win32",t=e?"where":"which";try{let n=_h(t,[l],{stdio:"pipe"}).toString().trim();if(n)return n.split(/\r?\n/)[0]}catch{}let s=Th.homedir(),r=e?[be.join(s,".local","bin",`${l}.exe`),be.join(s,"AppData","Roaming","npm",`${l}.cmd`),be.join(s,"AppData","Roaming","npm",`${l}`)]:[be.join(s,".local","bin",l),"/usr/local/bin/"+l,"/opt/homebrew/bin/"+l,be.join(s,".npm-global","bin",l)];for(let n of r)try{return ye.accessSync(n,ye.constants.X_OK),n}catch{}return null}function Sh(l){let e={},t={},s=!1,r=!1,n=30,o=be.join(l,"config","default.yml");if(ye.existsSync(o))try{let p=ya.load(ye.readFileSync(o,"utf-8"));p&&typeof p=="object"&&Object.assign(e,p)}catch{}let i=be.join(l,".env");if(ye.existsSync(i))try{let p=ye.readFileSync(i,"utf-8").split(`
1017
+ Failed to send message: ${i.message}`),t.prompt()}),o.write(n),o.end()}),t.on("close",()=>{process.exit(0)})}async function fh(l){let e=new le,t;try{t=e.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let s=t.api?.host??"127.0.0.1",r=t.api?.port??3420;if(await ph(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),hh(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let i=t.llm[l.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let o=new Nt(t);try{await o.initialize(),await o.startWithCLI()}catch(i){console.error("Failed to start chat:",i.message),process.exit(1)}}var zd=T(()=>{"use strict";Xe();ma();m(ph,"checkHealth");m(hh,"startClientMode");m(fh,"chatCommand")});var Vd={};ue(Vd,{setupCommand:()=>vh});import{createInterface as gh}from"node:readline/promises";import{stdin as yh,stdout as wh}from"node:process";import{execFileSync as _h}from"node:child_process";import ye from"node:fs";import Th from"node:os";import be from"node:path";import ya from"js-yaml";function M(l){return`${no}${l}${v}`}function kh(l){return`${P}${l}${v}`}function ge(l){return`${oo}${l}${v}`}function Gd(l){return`${Eh}${l}${v}`}function C(l){return`${X}${l}${v}`}function E(l){return`${ct}${l}${v}`}function _e(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function $h(l){let e=process.platform==="win32",t=e?"where":"which";try{let n=_h(t,[l],{stdio:"pipe"}).toString().trim();if(n)return n.split(/\r?\n/)[0]}catch{}let s=Th.homedir(),r=e?[be.join(s,".local","bin",`${l}.exe`),be.join(s,"AppData","Roaming","npm",`${l}.cmd`),be.join(s,"AppData","Roaming","npm",`${l}`)]:[be.join(s,".local","bin",l),"/usr/local/bin/"+l,"/opt/homebrew/bin/"+l,be.join(s,".npm-global","bin",l)];for(let n of r)try{return ye.accessSync(n,ye.constants.X_OK),n}catch{}return null}function Sh(l){let e={},t={},s=!1,r=!1,n=30,o=be.join(l,"config","default.yml");if(ye.existsSync(o))try{let p=ya.load(ye.readFileSync(o,"utf-8"));p&&typeof p=="object"&&Object.assign(e,p)}catch{}let i=be.join(l,".env");if(ye.existsSync(i))try{let p=ye.readFileSync(i,"utf-8").split(`
1018
1018
  `);for(let f of p){let g=f.trim();if(!g||g.startsWith("#"))continue;let h=g.indexOf("=");h>0&&(t[g.slice(0,h)]=g.slice(h+1))}}catch{}let a=be.join(l,"config","rules","default-rules.yml");if(ye.existsSync(a))try{let p=ya.load(ye.readFileSync(a,"utf-8"));if(p?.rules){s=p.rules.some(h=>h.id==="allow-owner-admin"&&h.effect==="allow"),p.rules.find(h=>h.id==="allow-write-for-dm"||h.id==="allow-write-all")?.id==="allow-write-all"&&(r=!0);let g=p.rules.find(h=>h.id==="rate-limit-write");g?.rateLimit?.maxInvocations&&(n=g.rateLimit.maxInvocations)}}catch{}let c=!!e.codeSandbox?.enabled,d=e.llm,u={};if(d){for(let p of["strong","fast","embeddings","local"])d[p]?.provider&&d[p]?.model&&(u[p]=d[p]);d.default?.provider&&(e.llm={...e.llm,provider:d.default.provider,model:d.default.model,baseUrl:d.default.baseUrl})}return{config:e,env:t,shellEnabled:s,writeInGroups:r,rateLimit:n,codeSandboxEnabled:c,multiModelTiers:u}}async function vh(){let l=gh({input:yh,output:wh}),e=process.cwd(),t=Sh(e),s=Object.keys(t.config).length>0;try{Ah(),console.log(s?`${oo}Existing configuration found \u2014 press Enter to keep current values.${v}
1019
1019
  ${ct}Only change what you need to update.${v}
1020
1020
  `:`${oo}Welcome to the Alfred setup wizard!${v}
1021
1021
  ${ct}This will walk you through configuring your AI assistant.${v}
1022
1022
  ${ct}Press Enter to accept defaults shown in [brackets].${v}
1023
1023
  `);let r=await F(l,"What should your bot be called?",t.config.name??"Alfred"),n=t.config.llm?.provider?et.findIndex(_=>_.name===t.config.llm?.provider):-1,o=n>=0?n+1:1;console.log(`
1024
- ${C("Which LLM provider would you like to use?")}`);for(let _=0;_<et.length;_++){let $=_===n?` ${E("(current)")}`:"";console.log(` ${ge(String(_+1)+")")} ${et[_].label}${$}`)}let i=await Vr(l,"> ",1,et.length,o),a=et[i-1];console.log(` ${M(">")} Selected: ${C(a.label)}`);let c="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?c=await F(l,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):c=await Ae(l,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${M(">")} API key set: ${E(_e(c))}`));let u=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let $=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if($){let I={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 F(l,I[a.name]??"API Base URL",$.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${M(">")} URL: ${E(u)}`)}}let f=t.config.llm?.model??a.defaultModel;console.log("");let g,h=await ha(a.name,c,u),y=fa(h,a.models??[]);if(y.length>0){console.log(`${C("Available models:")}`);for(let I=0;I<y.length;I++){let W=y[I],L=W.desc??W.name??"",H=W.id===f?` ${M("(current)")}`:"";console.log(` ${ge(`${I+1})`)} ${W.id}${L?` ${E(`\u2014 ${L}`)}`:""}${H}`)}console.log(` ${ge(`${y.length+1})`)} ${E("Other (enter manually)")}`);let _=await F(l,"Choose model","1"),$=parseInt(_,10)-1;$>=0&&$<y.length?g=y[$].id:g=await F(l,"Model ID",f)}else g=await F(l,"Which model?",f);let b=Object.keys(t.multiModelTiers).length>0,k=b?"Y/n":"y/N";console.log(`
1024
+ ${C("Which LLM provider would you like to use?")}`);for(let _=0;_<et.length;_++){let $=_===n?` ${E("(current)")}`:"";console.log(` ${ge(String(_+1)+")")} ${et[_].label}${$}`)}let i=await Vr(l,"> ",1,et.length,o),a=et[i-1];console.log(` ${M(">")} Selected: ${C(a.label)}`);let c="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?c=await F(l,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):c=await Ae(l,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${M(">")} API key set: ${E(_e(c))}`));let u=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let $=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if($){let I={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 F(l,I[a.name]??"API Base URL",$.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${M(">")} URL: ${E(u)}`)}}let f=t.config.llm?.model??a.defaultModel;console.log("");let g,h=await ha(a.name,c,u),y=fa(h,a.models??[]);if(y.length>0){console.log(`${C("Available models:")}`);for(let I=0;I<y.length;I++){let W=y[I],D=W.desc??W.name??"",H=W.id===f?` ${M("(current)")}`:"";console.log(` ${ge(`${I+1})`)} ${W.id}${D?` ${E(`\u2014 ${D}`)}`:""}${H}`)}console.log(` ${ge(`${y.length+1})`)} ${E("Other (enter manually)")}`);let _=await F(l,"Choose model","1"),$=parseInt(_,10)-1;$>=0&&$<y.length?g=y[$].id:g=await F(l,"Model ID",f)}else g=await F(l,"Which model?",f);let b=Object.keys(t.multiModelTiers).length>0,k=b?"Y/n":"y/N";console.log(`
1025
1025
  ${C("Configure additional model tiers for specialized tasks?")}`),console.log(`${E("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let S=(await l.question(`${P}> ${v}${E(`[${k}] `)}`)).trim().toLowerCase(),j=S===""?b:S==="y"||S==="yes",N={};if(j){let _=[{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 $ of _){let I=t.multiModelTiers[$.key],W=!!I?.model;console.log(`
1026
- ${C(`${$.label} model`)} ${E(`(${$.hint})`)}`),W&&console.log(` ${E(`Current: ${I.provider}/${I.model}`)}`);let L=I?.provider??a.name,H=et.map(Se=>Se.name).join(", ");console.log(` ${E(`Providers: ${H}`)}`);let Te=(await l.question(` ${P}Provider: ${v}${E(`[${L}] `)}`)).trim()||L;if(!Te&&!W){console.log(` ${E("Skipped.")}`);continue}let Y=Te,Ee,Le;if(Y!==a.name){let Se=I?.apiKey??t.env[`ALFRED_LLM_${$.key.toUpperCase()}_API_KEY`]??"";if(Se?Ee=await F(l,` API key for ${Y}`,Se):(et.find(Ke=>Ke.name===Y)?.needsApiKey??!0)&&(Ee=await Ae(l,` API key for ${Y}`)),["ollama","openwebui"].includes(Y)){let Ke=(I?.baseUrl??"")||et.find(dn=>dn.name===Y)?.baseUrl||"";Ke&&(Le=await F(l,` ${Y} URL`,Ke))}}let wt=Ee??(Y===a.name?c:void 0),Fs=Le??(Y===a.name?u:void 0),No=et.find(Se=>Se.name===Y),Mo=await ha(Y,wt,Fs),rt=fa(Mo,No?.models??[]),Ve;if(rt.length>0){console.log(` ${C("Available models:")}`);for(let Pt=0;Pt<rt.length;Pt++){let Ke=rt[Pt],dn=Ke.desc??Ke.name??"",Ou=Ke.id===I?.model?` ${M("(current)")}`:"";console.log(` ${ge(`${Pt+1})`)} ${Ke.id}${dn?` ${E(`\u2014 ${dn}`)}`:""}${Ou}`)}console.log(` ${ge(`${rt.length+1})`)} ${E("Other (enter manually)")}`),console.log(` ${ge("0)")} ${E("Skip this tier")}`);let Se=(await l.question(` ${P}> ${v}${W?E(`[${I.model}] `):""}`)).trim();if(Se==="0"){console.log(` ${E("Skipped.")}`);continue}let ln=parseInt(Se,10)-1;ln>=0&&ln<rt.length?Ve=rt[ln].id:!Se&&W?Ve=I.model:Ve=await F(l," Model ID",W?I.model:$.defaultModel)}else if(console.log(` ${E("Press Enter to skip.")}`),Ve=(await l.question(` ${P}Model: ${v}${W?E(`[${I.model}] `):""}`)).trim()||(W?I.model:""),!Ve){console.log(` ${E("Skipped.")}`);continue}N[$.key]={provider:Y,model:Ve,...Ee?{apiKey:Ee}:{},...Le?{baseUrl:Le}:{}},console.log(` ${M(">")} ${$.label}: ${C(Y)}/${C(Ve)}`)}Object.keys(N).length===0&&console.log(`
1027
- ${E("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${E("Using single model for all tasks.")}`);let q=["brave","tavily","duckduckgo","searxng"],ee=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",D=q.indexOf(ee),O=D>=0?D+1:0;console.log(`
1028
- ${C("Web Search provider (for searching the internet):")}`);let ie=["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"],He=m(_=>D===_?` ${E("(current)")}`:"","mark");console.log(` ${ge("0)")} None (disable web search)${D===-1&&ee===""?` ${E("(current)")}`:""}`);for(let _=0;_<ie.length;_++)console.log(` ${ge(String(_+1)+")")} ${ie[_]}${He(_)}`);let ke=await Vr(l,"> ",0,q.length,O),oe,J="",B="";if(ke>=1&&ke<=q.length&&(oe=q[ke-1]),oe==="brave"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?J=await F(l," Brave Search API key",_):(console.log(` ${E("Get your free API key at: https://brave.com/search/api/")}`),J=await Ae(l," Brave Search API key")),console.log(` ${M(">")} Brave Search: ${E(_e(J))}`)}else if(oe==="tavily"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?J=await F(l," Tavily API key",_):(console.log(` ${E("Get your free API key at: https://tavily.com/")}`),J=await Ae(l," Tavily API key")),console.log(` ${M(">")} Tavily: ${E(_e(J))}`)}else if(oe==="duckduckgo")console.log(` ${M(">")} DuckDuckGo: ${E("no API key needed")}`);else if(oe==="searxng"){let _=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";B=await F(l," SearXNG URL",_),B=B.replace(/\/+$/,""),console.log(` ${M(">")} SearXNG: ${E(B)}`)}else console.log(` ${E("Web search disabled \u2014 you can configure it later.")}`);let de=[];for(let _=0;_<Es.length;_++){let $=Es[_];t.config[$.configKey]?.enabled&&de.push(_+1)}let Re=de.length>0?de.join(","):"";console.log(`
1029
- ${C("Which messaging platforms do you want to enable?")}`),console.log(`${E("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let _=0;_<Es.length;_++){let $=de.includes(_+1)?` ${E("(enabled)")}`:"";console.log(` ${ge(String(_+1)+")")} ${Es[_].label}${$}`)}console.log(` ${ge("0)")} None (configure later)`);let Ie=(await l.question(`${P}> ${v}${Re?E(`[${Re}] `):""}`)).trim(),x=[],z=Ie||Re;if(z&&z!=="0"){let _=z.split(",").map($=>parseInt($.trim(),10));for(let $ of _)if($>=1&&$<=Es.length){let I=Es[$-1];x.includes(I)||x.push(I)}}x.length>0?console.log(` ${M(">")} Enabling: ${x.map(_=>C(_.label)).join(", ")}`):console.log(` ${E("No platforms selected \u2014 you can configure them later.")}`);let re={},xe={};for(let _ of x){if(_.credentials.length===0){_.name==="whatsapp"&&console.log(`
1026
+ ${C(`${$.label} model`)} ${E(`(${$.hint})`)}`),W&&console.log(` ${E(`Current: ${I.provider}/${I.model}`)}`);let D=I?.provider??a.name,H=et.map(Se=>Se.name).join(", ");console.log(` ${E(`Providers: ${H}`)}`);let Te=(await l.question(` ${P}Provider: ${v}${E(`[${D}] `)}`)).trim()||D;if(!Te&&!W){console.log(` ${E("Skipped.")}`);continue}let Y=Te,Ee,De;if(Y!==a.name){let Se=I?.apiKey??t.env[`ALFRED_LLM_${$.key.toUpperCase()}_API_KEY`]??"";if(Se?Ee=await F(l,` API key for ${Y}`,Se):(et.find(Ke=>Ke.name===Y)?.needsApiKey??!0)&&(Ee=await Ae(l,` API key for ${Y}`)),["ollama","openwebui"].includes(Y)){let Ke=(I?.baseUrl??"")||et.find(dn=>dn.name===Y)?.baseUrl||"";Ke&&(De=await F(l,` ${Y} URL`,Ke))}}let wt=Ee??(Y===a.name?c:void 0),Fs=De??(Y===a.name?u:void 0),No=et.find(Se=>Se.name===Y),Mo=await ha(Y,wt,Fs),rt=fa(Mo,No?.models??[]),Ve;if(rt.length>0){console.log(` ${C("Available models:")}`);for(let Pt=0;Pt<rt.length;Pt++){let Ke=rt[Pt],dn=Ke.desc??Ke.name??"",Ou=Ke.id===I?.model?` ${M("(current)")}`:"";console.log(` ${ge(`${Pt+1})`)} ${Ke.id}${dn?` ${E(`\u2014 ${dn}`)}`:""}${Ou}`)}console.log(` ${ge(`${rt.length+1})`)} ${E("Other (enter manually)")}`),console.log(` ${ge("0)")} ${E("Skip this tier")}`);let Se=(await l.question(` ${P}> ${v}${W?E(`[${I.model}] `):""}`)).trim();if(Se==="0"){console.log(` ${E("Skipped.")}`);continue}let ln=parseInt(Se,10)-1;ln>=0&&ln<rt.length?Ve=rt[ln].id:!Se&&W?Ve=I.model:Ve=await F(l," Model ID",W?I.model:$.defaultModel)}else if(console.log(` ${E("Press Enter to skip.")}`),Ve=(await l.question(` ${P}Model: ${v}${W?E(`[${I.model}] `):""}`)).trim()||(W?I.model:""),!Ve){console.log(` ${E("Skipped.")}`);continue}N[$.key]={provider:Y,model:Ve,...Ee?{apiKey:Ee}:{},...De?{baseUrl:De}:{}},console.log(` ${M(">")} ${$.label}: ${C(Y)}/${C(Ve)}`)}Object.keys(N).length===0&&console.log(`
1027
+ ${E("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${E("Using single model for all tasks.")}`);let z=["brave","tavily","duckduckgo","searxng"],ee=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",L=z.indexOf(ee),O=L>=0?L+1:0;console.log(`
1028
+ ${C("Web Search provider (for searching the internet):")}`);let ie=["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"],He=m(_=>L===_?` ${E("(current)")}`:"","mark");console.log(` ${ge("0)")} None (disable web search)${L===-1&&ee===""?` ${E("(current)")}`:""}`);for(let _=0;_<ie.length;_++)console.log(` ${ge(String(_+1)+")")} ${ie[_]}${He(_)}`);let ke=await Vr(l,"> ",0,z.length,O),oe,J="",B="";if(ke>=1&&ke<=z.length&&(oe=z[ke-1]),oe==="brave"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?J=await F(l," Brave Search API key",_):(console.log(` ${E("Get your free API key at: https://brave.com/search/api/")}`),J=await Ae(l," Brave Search API key")),console.log(` ${M(">")} Brave Search: ${E(_e(J))}`)}else if(oe==="tavily"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?J=await F(l," Tavily API key",_):(console.log(` ${E("Get your free API key at: https://tavily.com/")}`),J=await Ae(l," Tavily API key")),console.log(` ${M(">")} Tavily: ${E(_e(J))}`)}else if(oe==="duckduckgo")console.log(` ${M(">")} DuckDuckGo: ${E("no API key needed")}`);else if(oe==="searxng"){let _=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";B=await F(l," SearXNG URL",_),B=B.replace(/\/+$/,""),console.log(` ${M(">")} SearXNG: ${E(B)}`)}else console.log(` ${E("Web search disabled \u2014 you can configure it later.")}`);let de=[];for(let _=0;_<Es.length;_++){let $=Es[_];t.config[$.configKey]?.enabled&&de.push(_+1)}let Re=de.length>0?de.join(","):"";console.log(`
1029
+ ${C("Which messaging platforms do you want to enable?")}`),console.log(`${E("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let _=0;_<Es.length;_++){let $=de.includes(_+1)?` ${E("(enabled)")}`:"";console.log(` ${ge(String(_+1)+")")} ${Es[_].label}${$}`)}console.log(` ${ge("0)")} None (configure later)`);let Ie=(await l.question(`${P}> ${v}${Re?E(`[${Re}] `):""}`)).trim(),x=[],q=Ie||Re;if(q&&q!=="0"){let _=q.split(",").map($=>parseInt($.trim(),10));for(let $ of _)if($>=1&&$<=Es.length){let I=Es[$-1];x.includes(I)||x.push(I)}}x.length>0?console.log(` ${M(">")} Enabling: ${x.map(_=>C(_.label)).join(", ")}`):console.log(` ${E("No platforms selected \u2014 you can configure them later.")}`);let re={},xe={};for(let _ of x){if(_.credentials.length===0){_.name==="whatsapp"&&console.log(`
1030
1030
  ${kh("i")} WhatsApp: a QR code will be displayed on first start.`);continue}console.log(`
1031
- ${C(_.label+" configuration:")}`);let $={};for(let I of _.credentials){let W=t.env[I.envKey]??"",L;W?L=await F(l,` ${I.prompt}`,W):I.defaultValue?L=await F(l,` ${I.prompt}`,I.defaultValue):I.required?L=await Ae(l,` ${I.prompt}`):(L=(await l.question(` ${I.prompt}: ${P}`)).trim(),process.stdout.write(v)),$[I.configField]=L,xe[I.envKey]=L,I.configField==="token"||I.configField==="accessToken"?console.log(` ${M(">")} Set: ${E(_e(L))}`):console.log(` ${M(">")} Set: ${E(L)}`)}re[_.configKey]=$}let We=t.config.email?.accounts??[],tt=We[0],ze=tt?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",ao=tt?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",bs=We.length>0||!!ze||ao==="microsoft",Xr=bs?"Y/n":"y/N";console.log(`
1032
- ${C("Email access (read & send emails)?")}`),console.log(`${E("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let G=(await l.question(`${P}> ${v}${E(`[${Xr}] `)}`)).trim().toLowerCase(),K=G===""?bs:G==="y"||G==="yes",Z=[],ce={"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"}},lt=m(async(_,$)=>{let I={name:_,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},W=$?.provider??"",L=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],H=W==="microsoft"?1:0;console.log("");for(let Y=0;Y<L.length;Y++){let Ee=Y===H?` ${E("(current)")}`:"";console.log(` ${ge(`${Y+1})`)} ${L[Y]}${Ee}`)}let Q=(await l.question(`${P}> ${v}${E(`[${H+1}] `)}`)).trim(),Te=Q===""?H:parseInt(Q,10)-1;if(I.provider=Te===1?"microsoft":"imap-smtp",I.provider==="microsoft"){let Y=t.config.calendar?.microsoft,Ee=$?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Le=$?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",wt=$?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(Y&&!Ee)console.log(` ${M(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${E("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${E("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${E("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),I.msClientId=await F(l," Client ID",Ee),I.msClientId||(I.msClientId=await Ae(l," Client ID"));let Fs=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";I.msClientSecret=await F(l," Client Secret",Fs),I.msClientSecret||(I.msClientSecret=await Ae(l," Client Secret")),I.msTenantId=await F(l," Tenant ID",Le),I.msTenantId||(I.msTenantId=await Ae(l," Tenant ID")),console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),I.msRefreshToken=await F(l," Refresh Token",wt),I.msRefreshToken||(I.msRefreshToken=await Ae(l," Refresh Token"))}console.log(` ${M(">")} Email [${_}]: Microsoft 365 (Graph API)`)}else{let Y=$?.auth?.user??"";console.log(""),I.user=await F(l," Email address",Y||""),I.user||(I.user=await Ae(l," Email address"));let Ee=$?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";Ee?I.pass=await F(l," Password / App password",Ee):(console.log(` ${E("For Gmail: use an App Password (not your regular password)")}`),console.log(` ${E(" \u2192 Google Account \u2192 Security \u2192 2-Step \u2192 App passwords")}`),I.pass=await Ae(l," Password / App password"));let Le=I.user.split("@")[1]?.toLowerCase()??"",wt=ce[Le],Fs=$?.imap?.host??wt?.imap??`imap.${Le}`,No=$?.smtp?.host??wt?.smtp??`smtp.${Le}`,Mo=$?.imap?.port??993,rt=$?.smtp?.port??587;wt&&console.log(` ${M(">")} Detected ${Le} \u2014 using preset server settings`),I.imapHost=await F(l," IMAP server",Fs);let Ve=await F(l," IMAP port",String(Mo));I.imapPort=parseInt(Ve,10)||993,I.smtpHost=await F(l," SMTP server",No);let Se=await F(l," SMTP port",String(rt));I.smtpPort=parseInt(Se,10)||587,console.log(` ${M(">")} Email [${_}]: ${E(I.user)} via ${E(I.imapHost)}`)}return I},"configureEmailAccount");if(K){let _=tt??(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 lt("default",_));let $=!0;for(;$;){let I=(await l.question(`
1033
- ${C("Add another email account?")} ${E("[y/N]")} `)).trim().toLowerCase();if(I==="y"||I==="yes"){let L=(await l.question(` ${C("Account name:")} `)).trim()||`account${Z.length+1}`,H=We.find(Q=>Q.name===L);Z.push(await lt(L,H))}else $=!1}}else console.log(` ${E("Email disabled \u2014 you can configure it later.")}`);let we=["openai","groq"],Ea=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",Yr=we.indexOf(Ea),du=Yr>=0?Yr+1:0;console.log(`
1034
- ${C("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${E("Transcribes voice messages from Telegram, Discord, etc.")}`);let ba=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${ge("0)")} None (disable voice transcription)${Yr===-1?` ${E("(current)")}`:""}`);for(let _=0;_<ba.length;_++){let $=Yr===_?` ${E("(current)")}`:"";console.log(` ${ge(String(_+1)+")")} ${ba[_]}${$}`)}let co=await Vr(l,"> ",0,we.length,du),qe,st="",ks="";if(co>=1&&co<=we.length&&(qe=we[co-1]),qe==="openai"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?st=await F(l," OpenAI API key (for Whisper)",_):(console.log(` ${E("Uses your OpenAI API key for Whisper transcription.")}`),st=await Ae(l," OpenAI API key")),console.log(` ${M(">")} OpenAI Whisper: ${E(_e(st))}`)}else if(qe==="groq"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?st=await F(l," Groq API key",_):(console.log(` ${E("Get your free API key at: https://console.groq.com/")}`),st=await Ae(l," Groq API key"));let $=t.env.ALFRED_SPEECH_BASE_URL??"";$&&(ks=await F(l," Groq API URL",$)),console.log(` ${M(">")} Groq Whisper: ${E(_e(st))}`)}else console.log(` ${E("Voice transcription disabled \u2014 you can configure it later.")}`);let $s=!1,Ss="alloy";if(qe){let _=t.config.speech?.ttsEnabled??!1,$=_?"Y/n":"y/N";console.log(`
1035
- ${C("Voice responses (Text-to-Speech)?")}`),console.log(`${E("Alfred can reply as a voice message when the user asks for it.")}`);let I=(await l.question(`${P}> ${v}${E(`[${$}] `)}`)).trim().toLowerCase();if($s=I===""?_:I==="y"||I==="yes",$s){let W=["alloy","echo","fable","onyx","nova","shimmer"],L=t.config.speech?.ttsVoice??"alloy",H=W.indexOf(L),Q=H>=0?H+1:1;console.log(`
1031
+ ${C(_.label+" configuration:")}`);let $={};for(let I of _.credentials){let W=t.env[I.envKey]??"",D;W?D=await F(l,` ${I.prompt}`,W):I.defaultValue?D=await F(l,` ${I.prompt}`,I.defaultValue):I.required?D=await Ae(l,` ${I.prompt}`):(D=(await l.question(` ${I.prompt}: ${P}`)).trim(),process.stdout.write(v)),$[I.configField]=D,xe[I.envKey]=D,I.configField==="token"||I.configField==="accessToken"?console.log(` ${M(">")} Set: ${E(_e(D))}`):console.log(` ${M(">")} Set: ${E(D)}`)}re[_.configKey]=$}let We=t.config.email?.accounts??[],tt=We[0],qe=tt?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",ao=tt?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",bs=We.length>0||!!qe||ao==="microsoft",Xr=bs?"Y/n":"y/N";console.log(`
1032
+ ${C("Email access (read & send emails)?")}`),console.log(`${E("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let G=(await l.question(`${P}> ${v}${E(`[${Xr}] `)}`)).trim().toLowerCase(),K=G===""?bs:G==="y"||G==="yes",Z=[],ce={"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"}},lt=m(async(_,$)=>{let I={name:_,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},W=$?.provider??"",D=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],H=W==="microsoft"?1:0;console.log("");for(let Y=0;Y<D.length;Y++){let Ee=Y===H?` ${E("(current)")}`:"";console.log(` ${ge(`${Y+1})`)} ${D[Y]}${Ee}`)}let Q=(await l.question(`${P}> ${v}${E(`[${H+1}] `)}`)).trim(),Te=Q===""?H:parseInt(Q,10)-1;if(I.provider=Te===1?"microsoft":"imap-smtp",I.provider==="microsoft"){let Y=t.config.calendar?.microsoft,Ee=$?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",De=$?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",wt=$?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(Y&&!Ee)console.log(` ${M(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${E("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${E("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${E("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),I.msClientId=await F(l," Client ID",Ee),I.msClientId||(I.msClientId=await Ae(l," Client ID"));let Fs=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";I.msClientSecret=await F(l," Client Secret",Fs),I.msClientSecret||(I.msClientSecret=await Ae(l," Client Secret")),I.msTenantId=await F(l," Tenant ID",De),I.msTenantId||(I.msTenantId=await Ae(l," Tenant ID")),console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),I.msRefreshToken=await F(l," Refresh Token",wt),I.msRefreshToken||(I.msRefreshToken=await Ae(l," Refresh Token"))}console.log(` ${M(">")} Email [${_}]: Microsoft 365 (Graph API)`)}else{let Y=$?.auth?.user??"";console.log(""),I.user=await F(l," Email address",Y||""),I.user||(I.user=await Ae(l," Email address"));let Ee=$?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";Ee?I.pass=await F(l," Password / App password",Ee):(console.log(` ${E("For Gmail: use an App Password (not your regular password)")}`),console.log(` ${E(" \u2192 Google Account \u2192 Security \u2192 2-Step \u2192 App passwords")}`),I.pass=await Ae(l," Password / App password"));let De=I.user.split("@")[1]?.toLowerCase()??"",wt=ce[De],Fs=$?.imap?.host??wt?.imap??`imap.${De}`,No=$?.smtp?.host??wt?.smtp??`smtp.${De}`,Mo=$?.imap?.port??993,rt=$?.smtp?.port??587;wt&&console.log(` ${M(">")} Detected ${De} \u2014 using preset server settings`),I.imapHost=await F(l," IMAP server",Fs);let Ve=await F(l," IMAP port",String(Mo));I.imapPort=parseInt(Ve,10)||993,I.smtpHost=await F(l," SMTP server",No);let Se=await F(l," SMTP port",String(rt));I.smtpPort=parseInt(Se,10)||587,console.log(` ${M(">")} Email [${_}]: ${E(I.user)} via ${E(I.imapHost)}`)}return I},"configureEmailAccount");if(K){let _=tt??(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 lt("default",_));let $=!0;for(;$;){let I=(await l.question(`
1033
+ ${C("Add another email account?")} ${E("[y/N]")} `)).trim().toLowerCase();if(I==="y"||I==="yes"){let D=(await l.question(` ${C("Account name:")} `)).trim()||`account${Z.length+1}`,H=We.find(Q=>Q.name===D);Z.push(await lt(D,H))}else $=!1}}else console.log(` ${E("Email disabled \u2014 you can configure it later.")}`);let we=["openai","groq"],Ea=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",Yr=we.indexOf(Ea),du=Yr>=0?Yr+1:0;console.log(`
1034
+ ${C("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${E("Transcribes voice messages from Telegram, Discord, etc.")}`);let ba=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${ge("0)")} None (disable voice transcription)${Yr===-1?` ${E("(current)")}`:""}`);for(let _=0;_<ba.length;_++){let $=Yr===_?` ${E("(current)")}`:"";console.log(` ${ge(String(_+1)+")")} ${ba[_]}${$}`)}let co=await Vr(l,"> ",0,we.length,du),ze,st="",ks="";if(co>=1&&co<=we.length&&(ze=we[co-1]),ze==="openai"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?st=await F(l," OpenAI API key (for Whisper)",_):(console.log(` ${E("Uses your OpenAI API key for Whisper transcription.")}`),st=await Ae(l," OpenAI API key")),console.log(` ${M(">")} OpenAI Whisper: ${E(_e(st))}`)}else if(ze==="groq"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?st=await F(l," Groq API key",_):(console.log(` ${E("Get your free API key at: https://console.groq.com/")}`),st=await Ae(l," Groq API key"));let $=t.env.ALFRED_SPEECH_BASE_URL??"";$&&(ks=await F(l," Groq API URL",$)),console.log(` ${M(">")} Groq Whisper: ${E(_e(st))}`)}else console.log(` ${E("Voice transcription disabled \u2014 you can configure it later.")}`);let $s=!1,Ss="alloy";if(ze){let _=t.config.speech?.ttsEnabled??!1,$=_?"Y/n":"y/N";console.log(`
1035
+ ${C("Voice responses (Text-to-Speech)?")}`),console.log(`${E("Alfred can reply as a voice message when the user asks for it.")}`);let I=(await l.question(`${P}> ${v}${E(`[${$}] `)}`)).trim().toLowerCase();if($s=I===""?_:I==="y"||I==="yes",$s){let W=["alloy","echo","fable","onyx","nova","shimmer"],D=t.config.speech?.ttsVoice??"alloy",H=W.indexOf(D),Q=H>=0?H+1:1;console.log(`
1036
1036
  ${C("Which voice?")}`);for(let Y=0;Y<W.length;Y++){let Ee=H===Y?` ${E("(current)")}`:"";console.log(` ${ge(String(Y+1)+")")} ${W[Y]}${Ee}`)}let Te=await Vr(l," > ",1,W.length,Q);Ss=W[Te-1],console.log(` ${M(">")} TTS voice: ${C(Ss)}`)}else console.log(` ${E("Voice responses disabled.")}`)}let uu=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
1037
1037
  ${C("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${E("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let lo=(await l.question(`${P}> ${v}${E(`[${uu}] `)}`)).trim().toLowerCase(),uo=lo===""?t.codeSandboxEnabled:lo==="y"||lo==="yes";console.log(uo?` ${M(">")} Code Sandbox ${C("enabled")} (JavaScript + Python)`:` ${E("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
1038
1038
  ${C("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${E("Scanning for known coding agents on this system...")}`);let mo=[];for(let _ of Wd){let $=$h(_.whichCmd);$?(mo.push({..._,resolvedPath:$}),console.log(` ${M("\u2713")} ${C(_.label)} ${E(`(${$})`)}`)):console.log(` ${E("\xB7")} ${E(_.label)} ${E("\u2014 not found")}`)}let po=(t.config.codeAgents?.agents??[]).filter(_=>!Wd.some($=>$.name===_.name));for(let _ of po)console.log(` ${M("\u2713")} ${C(_.name)} ${E(`(${_.command}) \u2014 from existing config`)}`);let dt=[];if(mo.length===0&&po.length===0)console.log(`
1039
- ${E("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let _=[...mo.map(L=>({name:L.name,command:L.resolvedPath??L.command,argsTemplate:L.argsTemplate,promptVia:L.promptVia,label:L.label,detected:!0})),...po.map(L=>({name:L.name,command:L.command,argsTemplate:L.argsTemplate,promptVia:L.promptVia??"arg",label:L.name,detected:!1}))];console.log(`
1040
- ${C("Which agents should Alfred use?")} ${E("(comma-separated, e.g. 1,2)")}`);let $=new Set((t.config.codeAgents?.agents??[]).map(L=>L.name));for(let L=0;L<_.length;L++){let H=_[L],Q=$.has(H.name)?` ${E("(current)")}`:"";console.log(` ${P}${L+1}${v}) ${H.label}${Q}`)}console.log(` ${P}0${v}) None`);let I=_.map((L,H)=>$.size>0?$.has(L.name)?String(H+1):null:L.detected?String(H+1):null).filter(Boolean).join(",")||"0",W=(await l.question(` ${P}> ${v}${E(`[${I}] `)}`)).trim()||I;W!=="0"&&(dt=W.split(",").map(H=>parseInt(H.trim(),10)).filter(H=>!isNaN(H)&&H>=1&&H<=_.length).map(H=>{let Q=_[H-1];return{name:Q.name,command:Q.command,argsTemplate:Q.argsTemplate,promptVia:Q.promptVia}})),dt.length>0?console.log(` ${M(">")} ${C(String(dt.length))} agent(s) selected: ${dt.map(L=>L.name).join(", ")}`):console.log(` ${E("No agents selected.")}`)}let ho=t.config.codeAgents?.forge,fo=ho?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
1039
+ ${E("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let _=[...mo.map(D=>({name:D.name,command:D.resolvedPath??D.command,argsTemplate:D.argsTemplate,promptVia:D.promptVia,label:D.label,detected:!0})),...po.map(D=>({name:D.name,command:D.command,argsTemplate:D.argsTemplate,promptVia:D.promptVia??"arg",label:D.name,detected:!1}))];console.log(`
1040
+ ${C("Which agents should Alfred use?")} ${E("(comma-separated, e.g. 1,2)")}`);let $=new Set((t.config.codeAgents?.agents??[]).map(D=>D.name));for(let D=0;D<_.length;D++){let H=_[D],Q=$.has(H.name)?` ${E("(current)")}`:"";console.log(` ${P}${D+1}${v}) ${H.label}${Q}`)}console.log(` ${P}0${v}) None`);let I=_.map((D,H)=>$.size>0?$.has(D.name)?String(H+1):null:D.detected?String(H+1):null).filter(Boolean).join(",")||"0",W=(await l.question(` ${P}> ${v}${E(`[${I}] `)}`)).trim()||I;W!=="0"&&(dt=W.split(",").map(H=>parseInt(H.trim(),10)).filter(H=>!isNaN(H)&&H>=1&&H<=_.length).map(H=>{let Q=_[H-1];return{name:Q.name,command:Q.command,argsTemplate:Q.argsTemplate,promptVia:Q.promptVia}})),dt.length>0?console.log(` ${M(">")} ${C(String(dt.length))} agent(s) selected: ${dt.map(D=>D.name).join(", ")}`):console.log(` ${E("No agents selected.")}`)}let ho=t.config.codeAgents?.forge,fo=ho?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
1041
1041
  ${C("Forge Integration (auto-create PRs/MRs after code agent orchestration)?")}`),console.log(`${E("Connects to GitHub or GitLab to push branches and create pull/merge requests.")}`),console.log(`${E("Owner/repo are detected automatically from the git remote at runtime.")}`);let ka=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let _ of ka){let $=_.name===fo?` ${E("(current)")}`:"";console.log(` ${P}${_.num}${v}) ${_.label}${$}`)}let $a=fo==="github"?"2":fo==="gitlab"?"3":"1",mu=(await l.question(`${P}> ${v}${E(`[${$a}] `)}`)).trim()||$a,ut=ka.find(_=>_.num===mu)?.name??"",vs="",As="";if(ut==="github"){console.log(` ${M(">")} Forge: ${C("GitHub")}`);let _=t.env.ALFRED_GITHUB_TOKEN??ho?.github?.token??"";_&&console.log(` ${E(`Current token: ${_e(_)}`)}`),console.log(` ${E("Create a token at https://github.com/settings/tokens (scope: repo)")}`),vs=(await l.question(` ${X}GitHub Token${v}: ${P}`)).trim(),process.stdout.write(v),!vs&&_&&(vs=_)}else if(ut==="gitlab"){console.log(` ${M(">")} Forge: ${C("GitLab")}`);let _=t.env.ALFRED_GITLAB_TOKEN??ho?.gitlab?.token??"";_&&console.log(` ${E(`Current token: ${_e(_)}`)}`),console.log(` ${E("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),As=(await l.question(` ${X}GitLab Token${v}: ${P}`)).trim(),process.stdout.write(v),!As&&_&&(As=_)}else console.log(` ${E("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);console.log(`
1042
1042
  ${C("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${E("Control VMs, containers, network devices, and smart home through Alfred.")}`);let Is=t.config.proxmox,go=t.env.ALFRED_PROXMOX_BASE_URL??Is?.baseUrl??"",pu=go?"Y/n":"y/N",Sa=(await l.question(` ${X}Enable Proxmox VE?${v} ${E(`[${pu}]`)}: ${P}`)).trim().toLowerCase()||(go?"y":"n");process.stdout.write(v);let Jr=Sa==="y"||Sa==="yes",Rs="",yo="",xs="",wo=!0;if(Jr){Rs=await F(l," Proxmox URL (e.g. https://pve.local:8006)",go||"https://pve.local:8006");let _=t.env.ALFRED_PROXMOX_TOKEN_ID??Is?.tokenId??"";_&&console.log(` ${E(`Current token ID: ${_}`)}`),console.log(` ${E("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),yo=await F(l," API Token ID (user@realm!name)",_);let $=t.env.ALFRED_PROXMOX_TOKEN_SECRET??Is?.tokenSecret??"";$&&console.log(` ${E(`Current secret: ${_e($)}`)}`),xs=(await l.question(` ${X}API Token Secret${v}: ${P}`)).trim(),process.stdout.write(v),!xs&&$&&(xs=$);let I=Is?.verifyTls===!1?"y/N":"Y/n",W=(await l.question(` ${X}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${I}]`)}: ${P}`)).trim().toLowerCase()||(Is?.verifyTls===!1?"n":"y");process.stdout.write(v),wo=W==="y"||W==="yes",console.log(` ${M(">")} Proxmox: ${C(Rs)} ${E(`(TLS verify: ${wo?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox disabled.")}`);let mt=t.config.unifi,_o=t.env.ALFRED_UNIFI_BASE_URL??mt?.baseUrl??"",hu=_o?"Y/n":"y/N",va=(await l.question(`
1043
- ${X}Enable UniFi Network?${v} ${E(`[${hu}]`)}: ${P}`)).trim().toLowerCase()||(_o?"y":"n");process.stdout.write(v);let Cs=va==="y"||va==="yes",Ot="",pt="",To="",Ds="",Eo=!0;if(Cs){Ot=await F(l," UniFi URL (e.g. https://unifi.local)",_o||"https://unifi.local"),console.log(` ${E("Auth: API Key (recommended) or Username/Password")}`);let _=t.env.ALFRED_UNIFI_API_KEY??mt?.apiKey??"",$=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],I=_?"1":mt?.username?"2":"1";for(let Q of $)console.log(` ${P}${Q.num}${v}) ${Q.label}`);if(((await l.question(` ${P}> ${v}${E(`[${I}] `)}`)).trim()||I)==="1")_&&console.log(` ${E(`Current key: ${_e(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),pt=(await l.question(` ${X}API Key${v}: ${P}`)).trim(),process.stdout.write(v),!pt&&_&&(pt=_);else{let Q=t.env.ALFRED_UNIFI_USERNAME??mt?.username??"";To=await F(l," Username",Q||"alfred");let Te=t.env.ALFRED_UNIFI_PASSWORD??mt?.password??"";Te&&console.log(` ${E(`Current password: ${_e(Te)}`)}`),Ds=(await l.question(` ${X}Password${v}: ${P}`)).trim(),process.stdout.write(v),!Ds&&Te&&(Ds=Te)}let L=mt?.verifyTls===!1?"y/N":"Y/n",H=(await l.question(` ${X}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${L}]`)}: ${P}`)).trim().toLowerCase()||(mt?.verifyTls===!1?"n":"y");process.stdout.write(v),Eo=H==="y"||H==="yes",console.log(` ${M(">")} UniFi: ${C(Ot)} ${E(`(TLS verify: ${Eo?"yes":"no"})`)}`)}else console.log(` ${E("UniFi disabled.")}`);let Zr=t.config.homeassistant,bo=t.env.ALFRED_HOMEASSISTANT_URL??Zr?.baseUrl??"",fu=bo?"Y/n":"y/N",Aa=(await l.question(`
1044
- ${X}Enable Home Assistant?${v} ${E(`[${fu}]`)}: ${P}`)).trim().toLowerCase()||(bo?"y":"n");process.stdout.write(v);let Qr=Aa==="y"||Aa==="yes",Ls="",Ns="",ko=!0;if(Qr){Ls=await F(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",bo||"http://homeassistant.local:8123");let _=t.env.ALFRED_HOMEASSISTANT_TOKEN??Zr?.accessToken??"";_&&console.log(` ${E(`Current token: ${_e(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),Ns=(await l.question(` ${X}Long-Lived Access Token${v}: ${P}`)).trim(),process.stdout.write(v),!Ns&&_&&(Ns=_);let $=Zr?.verifyTls===!1?"y/N":"Y/n",I=(await l.question(` ${X}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${$}]`)}: ${P}`)).trim().toLowerCase()||(Zr?.verifyTls===!1?"n":"y");process.stdout.write(v),ko=I==="y"||I==="yes",console.log(` ${M(">")} Home Assistant: ${C(Ls)} ${E(`(TLS verify: ${ko?"yes":"no"})`)}`)}else console.log(` ${E("Home Assistant disabled.")}`);let Ce=t.config.contacts,$o=t.env.ALFRED_CONTACTS_PROVIDER??Ce?.provider??"",gu=$o?"Y/n":"y/N",Ia=(await l.question(`
1045
- ${X}Enable Contacts management?${v} ${E(`[${gu}]`)}: ${P}`)).trim().toLowerCase()||($o?"y":"n");process.stdout.write(v);let en=Ia==="y"||Ia==="yes",De="",he={};if(en){let _=["carddav","google","microsoft"],$=_.indexOf($o),I=$>=0?$+1:1;console.log(` ${ge("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${ge("2)")} Google Contacts`),console.log(` ${ge("3)")} Microsoft 365`);let W=await Vr(l," > ",1,3,I);if(De=_[W-1],he.ALFRED_CONTACTS_PROVIDER=De,De==="carddav"){let L=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Ce?.carddav?.serverUrl??"";he.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await F(l," CardDAV Server URL",L||"https://cloud.example.com/remote.php/dav");let H=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Ce?.carddav?.username??"";he.ALFRED_CARDDAV_CONTACTS_USERNAME=await F(l," Username",H);let Q=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Ce?.carddav?.password??"";Q&&console.log(` ${E(`Current password: ${_e(Q)}`)}`);let Te=(await l.question(` ${X}Password${v}: ${P}`)).trim();process.stdout.write(v),he.ALFRED_CARDDAV_CONTACTS_PASSWORD=Te||Q}else if(De==="google"){let L=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Ce?.google?.clientId??"";L&&console.log(` ${E(`Current client ID: ${_e(L)}`)}`),he.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${X}Google Client ID${v}: ${P}`)).trim()||L,process.stdout.write(v);let H=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Ce?.google?.clientSecret??"";he.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${X}Google Client Secret${v}: ${P}`)).trim()||H,process.stdout.write(v);let Q=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Ce?.google?.refreshToken??"";he.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${X}Refresh Token${v}: ${P}`)).trim()||Q,process.stdout.write(v)}else if(De==="microsoft"){let L=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Ce?.microsoft?.clientId??"";L&&console.log(` ${E(`Current client ID: ${_e(L)}`)}`),he.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${X}Microsoft Client ID${v}: ${P}`)).trim()||L,process.stdout.write(v);let H=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Ce?.microsoft?.clientSecret??"";he.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${X}Microsoft Client Secret${v}: ${P}`)).trim()||H,process.stdout.write(v);let Q=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Ce?.microsoft?.tenantId??"";he.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await F(l," Tenant ID",Q||"common");let Te=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Ce?.microsoft?.refreshToken??"";console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),he.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${X}Refresh Token${v}: ${P}`)).trim()||Te,process.stdout.write(v)}console.log(` ${M(">")} Contacts: ${C(De)}`)}else console.log(` ${E("Contacts disabled.")}`);let Ra=t.config.docker,So=t.env.ALFRED_DOCKER_SOCKET_PATH??Ra?.socketPath??"",vo=t.env.ALFRED_DOCKER_HOST??Ra?.host??"",yu=So||vo?"Y/n":"y/N",xa=(await l.question(`
1043
+ ${X}Enable UniFi Network?${v} ${E(`[${hu}]`)}: ${P}`)).trim().toLowerCase()||(_o?"y":"n");process.stdout.write(v);let Cs=va==="y"||va==="yes",Ot="",pt="",To="",Ls="",Eo=!0;if(Cs){Ot=await F(l," UniFi URL (e.g. https://unifi.local)",_o||"https://unifi.local"),console.log(` ${E("Auth: API Key (recommended) or Username/Password")}`);let _=t.env.ALFRED_UNIFI_API_KEY??mt?.apiKey??"",$=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],I=_?"1":mt?.username?"2":"1";for(let Q of $)console.log(` ${P}${Q.num}${v}) ${Q.label}`);if(((await l.question(` ${P}> ${v}${E(`[${I}] `)}`)).trim()||I)==="1")_&&console.log(` ${E(`Current key: ${_e(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),pt=(await l.question(` ${X}API Key${v}: ${P}`)).trim(),process.stdout.write(v),!pt&&_&&(pt=_);else{let Q=t.env.ALFRED_UNIFI_USERNAME??mt?.username??"";To=await F(l," Username",Q||"alfred");let Te=t.env.ALFRED_UNIFI_PASSWORD??mt?.password??"";Te&&console.log(` ${E(`Current password: ${_e(Te)}`)}`),Ls=(await l.question(` ${X}Password${v}: ${P}`)).trim(),process.stdout.write(v),!Ls&&Te&&(Ls=Te)}let D=mt?.verifyTls===!1?"y/N":"Y/n",H=(await l.question(` ${X}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${D}]`)}: ${P}`)).trim().toLowerCase()||(mt?.verifyTls===!1?"n":"y");process.stdout.write(v),Eo=H==="y"||H==="yes",console.log(` ${M(">")} UniFi: ${C(Ot)} ${E(`(TLS verify: ${Eo?"yes":"no"})`)}`)}else console.log(` ${E("UniFi disabled.")}`);let Zr=t.config.homeassistant,bo=t.env.ALFRED_HOMEASSISTANT_URL??Zr?.baseUrl??"",fu=bo?"Y/n":"y/N",Aa=(await l.question(`
1044
+ ${X}Enable Home Assistant?${v} ${E(`[${fu}]`)}: ${P}`)).trim().toLowerCase()||(bo?"y":"n");process.stdout.write(v);let Qr=Aa==="y"||Aa==="yes",Ds="",Ns="",ko=!0;if(Qr){Ds=await F(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",bo||"http://homeassistant.local:8123");let _=t.env.ALFRED_HOMEASSISTANT_TOKEN??Zr?.accessToken??"";_&&console.log(` ${E(`Current token: ${_e(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),Ns=(await l.question(` ${X}Long-Lived Access Token${v}: ${P}`)).trim(),process.stdout.write(v),!Ns&&_&&(Ns=_);let $=Zr?.verifyTls===!1?"y/N":"Y/n",I=(await l.question(` ${X}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${$}]`)}: ${P}`)).trim().toLowerCase()||(Zr?.verifyTls===!1?"n":"y");process.stdout.write(v),ko=I==="y"||I==="yes",console.log(` ${M(">")} Home Assistant: ${C(Ds)} ${E(`(TLS verify: ${ko?"yes":"no"})`)}`)}else console.log(` ${E("Home Assistant disabled.")}`);let Ce=t.config.contacts,$o=t.env.ALFRED_CONTACTS_PROVIDER??Ce?.provider??"",gu=$o?"Y/n":"y/N",Ia=(await l.question(`
1045
+ ${X}Enable Contacts management?${v} ${E(`[${gu}]`)}: ${P}`)).trim().toLowerCase()||($o?"y":"n");process.stdout.write(v);let en=Ia==="y"||Ia==="yes",Le="",he={};if(en){let _=["carddav","google","microsoft"],$=_.indexOf($o),I=$>=0?$+1:1;console.log(` ${ge("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${ge("2)")} Google Contacts`),console.log(` ${ge("3)")} Microsoft 365`);let W=await Vr(l," > ",1,3,I);if(Le=_[W-1],he.ALFRED_CONTACTS_PROVIDER=Le,Le==="carddav"){let D=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Ce?.carddav?.serverUrl??"";he.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await F(l," CardDAV Server URL",D||"https://cloud.example.com/remote.php/dav");let H=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Ce?.carddav?.username??"";he.ALFRED_CARDDAV_CONTACTS_USERNAME=await F(l," Username",H);let Q=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Ce?.carddav?.password??"";Q&&console.log(` ${E(`Current password: ${_e(Q)}`)}`);let Te=(await l.question(` ${X}Password${v}: ${P}`)).trim();process.stdout.write(v),he.ALFRED_CARDDAV_CONTACTS_PASSWORD=Te||Q}else if(Le==="google"){let D=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Ce?.google?.clientId??"";D&&console.log(` ${E(`Current client ID: ${_e(D)}`)}`),he.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${X}Google Client ID${v}: ${P}`)).trim()||D,process.stdout.write(v);let H=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Ce?.google?.clientSecret??"";he.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${X}Google Client Secret${v}: ${P}`)).trim()||H,process.stdout.write(v);let Q=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Ce?.google?.refreshToken??"";he.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${X}Refresh Token${v}: ${P}`)).trim()||Q,process.stdout.write(v)}else if(Le==="microsoft"){let D=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Ce?.microsoft?.clientId??"";D&&console.log(` ${E(`Current client ID: ${_e(D)}`)}`),he.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${X}Microsoft Client ID${v}: ${P}`)).trim()||D,process.stdout.write(v);let H=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Ce?.microsoft?.clientSecret??"";he.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${X}Microsoft Client Secret${v}: ${P}`)).trim()||H,process.stdout.write(v);let Q=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Ce?.microsoft?.tenantId??"";he.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await F(l," Tenant ID",Q||"common");let Te=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Ce?.microsoft?.refreshToken??"";console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),he.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${X}Refresh Token${v}: ${P}`)).trim()||Te,process.stdout.write(v)}console.log(` ${M(">")} Contacts: ${C(Le)}`)}else console.log(` ${E("Contacts disabled.")}`);let Ra=t.config.docker,So=t.env.ALFRED_DOCKER_SOCKET_PATH??Ra?.socketPath??"",vo=t.env.ALFRED_DOCKER_HOST??Ra?.host??"",yu=So||vo?"Y/n":"y/N",xa=(await l.question(`
1046
1046
  ${X}Enable Docker management?${v} ${E(`[${yu}]`)}: ${P}`)).trim().toLowerCase()||(So||vo?"y":"n");process.stdout.write(v);let tn=xa==="y"||xa==="yes",ht="",ft="";if(tn){let _=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${E("Use socket path for local Docker, or host URL for remote.")}`),ht=await F(l," Docker socket path",So||_);let $=(await l.question(` ${X}Docker host URL (optional, for remote)${v}: ${P}`)).trim();process.stdout.write(v),ft=$||vo,console.log(` ${M(">")} Docker: ${C(ft||ht)}`)}else console.log(` ${E("Docker disabled.")}`);let wu=t.config.bmw,Ao=t.env.ALFRED_BMW_CLIENT_ID??wu?.clientId??"",_u=Ao?"Y/n":"y/N",Ca=(await l.question(`
1047
- ${X}Enable BMW CarData (vehicle status, charging)?${v} ${E(`[${_u}]`)}: ${P}`)).trim().toLowerCase()||(Ao?"y":"n");process.stdout.write(v);let sn=Ca==="y"||Ca==="yes",Io="";sn?(console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${E(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${E(" 3. Client-ID generieren")}`),console.log(` ${E(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),Io=await F(l," BMW CarData Client ID",Ao),console.log(` ${M(">")} BMW CarData: ${C("enabled")}`)):console.log(` ${E("BMW CarData disabled.")}`);let Tu=t.config.routing,Ro=t.env.ALFRED_ROUTING_API_KEY??Tu?.apiKey??"",Eu=Ro?"Y/n":"y/N",Da=(await l.question(`
1048
- ${X}Enable route planning with live traffic (Google Routes)?${v} ${E(`[${Eu}]`)}: ${P}`)).trim().toLowerCase()||(Ro?"y":"n");process.stdout.write(v);let rn=Da==="y"||Da==="yes",xo="";rn?(console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${E(" 2. Routes API aktivieren")}`),console.log(` ${E(" 3. API Key erstellen")}`),xo=await F(l," Google Maps API Key",Ro),console.log(` ${M(">")} Routing: ${C("enabled")}`)):console.log(` ${E("Routing disabled.")}`);let Ge=t.config.energy,bu=t.env.ALFRED_ENERGY_GRID_NAME??Ge?.gridName??"",Co=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(Ge?.gridUsageCt!=null?String(Ge.gridUsageCt):""),ku=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(Ge?.gridLossCt!=null?String(Ge.gridLossCt):""),$u=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(Ge?.gridCapacityFee!=null?String(Ge.gridCapacityFee):""),Su=t.env.ALFRED_ENERGY_GRID_METER_FEE??(Ge?.gridMeterFee!=null?String(Ge.gridMeterFee):""),vu=Co?"Y/n":"y/N",La=(await l.question(`
1049
- ${X}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${v} ${E(`[${vu}]`)}: ${P}`)).trim().toLowerCase()||(Co?"y":"n");process.stdout.write(v);let nn=La==="y"||La==="yes",gt="",yt="",on="",Ms="",Os="";nn?(console.log(` ${E('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${E("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),gt=await F(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",bu),yt=await F(l," Netznutzungsentgelt (ct/kWh netto)",Co),on=await F(l," Netzverlustentgelt (ct/kWh netto)",ku||"0.38"),Ms=await F(l," Leistungspauschale (\u20AC/Monat netto)",$u),Os=await F(l," Messentgelt (\u20AC/Monat netto)",Su||"2.22"),console.log(` ${M(">")} Energy: ${C(gt||"enabled")} (${yt} + ${on} ct/kWh)`)):console.log(` ${E("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
1050
- ${C("Security configuration:")}`);let Na=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",$e;if(Na)$e=await F(l,"Owner user ID (for elevated permissions)",Na);else{let _=(await l.question(`${X}Owner user ID${v} ${E("(optional, for elevated permissions)")}: ${P}`)).trim();process.stdout.write(v),$e=_}let Ps=!1;if($e){let _=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${C("Enable shell access (admin commands) for the owner?")}`),console.log(` ${E("Allows Alfred to execute shell commands. Only for the owner.")}`);let $=(await l.question(` ${P}> ${v}${E(`[${_}] `)}`)).trim().toLowerCase();$===""?Ps=t.shellEnabled:Ps=$==="y"||$==="yes",console.log(Ps?` ${M(">")} Shell access ${C("enabled")} for owner ${E($e)}`:` ${E("Shell access disabled.")}`)}let Au=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${C("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${E("By default, write actions are only allowed in DMs.")}`);let Do=(await l.question(` ${P}> ${v}${E(`[${Au}] `)}`)).trim().toLowerCase(),Us;Do===""?Us=t.writeInGroups:Us=Do==="y"||Do==="yes",console.log(Us?` ${M(">")} Write actions ${C("enabled")} in groups`:` ${E("Write actions only in DMs (default).")}`);let Iu=t.rateLimit??30;console.log("");let Ru=await F(l," Rate limit (max write actions per hour per user)",String(Iu)),an=Math.max(1,parseInt(Ru,10)||30);console.log(` ${M(">")} Rate limit: ${C(String(an))} per hour`),console.log(`
1051
- ${C("Writing configuration files...")}`);let A=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let _=a.envKeyName||"ALFRED_OLLAMA_API_KEY";A.push(`${_}=${c}`)}if(g!==a.defaultModel&&A.push(`ALFRED_LLM_MODEL=${g}`),u&&A.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(N).length>0){A.push("","# === Additional Model Tiers ===");for(let[_,$]of Object.entries(N)){let I=`ALFRED_LLM_${_.toUpperCase()}`;A.push(""),A.push(`${I}_PROVIDER=${$.provider}`),A.push(`${I}_MODEL=${$.model}`),$.apiKey&&A.push(`${I}_API_KEY=${$.apiKey}`),$.baseUrl&&A.push(`${I}_BASE_URL=${$.baseUrl}`)}}A.push("","# === Messaging Platforms ===","");for(let[_,$]of Object.entries(xe))A.push(`${_}=${$}`);if(A.push("","# === Web Search ===",""),oe?(A.push(`ALFRED_SEARCH_PROVIDER=${oe}`),J&&A.push(`ALFRED_SEARCH_API_KEY=${J}`),B&&A.push(`ALFRED_SEARCH_BASE_URL=${B}`)):(A.push("# ALFRED_SEARCH_PROVIDER=brave"),A.push("# ALFRED_SEARCH_API_KEY=")),A.push("","# === Email ===",""),K&&Z.length>0){let _=Z[0];_.provider==="microsoft"?(A.push("ALFRED_EMAIL_PROVIDER=microsoft"),_.msClientId?(A.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${_.msClientId}`),A.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${_.msClientSecret}`),A.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${_.msTenantId}`),A.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${_.msRefreshToken}`)):A.push("# Microsoft email credentials shared from calendar config")):(A.push(`ALFRED_EMAIL_USER=${_.user}`),A.push(`ALFRED_EMAIL_PASS=${_.pass}`)),Z.length>1&&A.push("# Additional email accounts configured in config/default.yml")}else A.push("# ALFRED_EMAIL_USER="),A.push("# ALFRED_EMAIL_PASS=");if(A.push("","# === Speech ===",""),qe?(A.push(`ALFRED_SPEECH_PROVIDER=${qe}`),A.push(`ALFRED_SPEECH_API_KEY=${st}`),ks&&A.push(`ALFRED_SPEECH_BASE_URL=${ks}`),$s&&(A.push("ALFRED_TTS_ENABLED=true"),A.push(`ALFRED_TTS_VOICE=${Ss}`))):(A.push("# ALFRED_SPEECH_PROVIDER=groq"),A.push("# ALFRED_SPEECH_API_KEY=")),A.push("","# === Forge (GitHub / GitLab) ===",""),ut==="github"?(A.push("ALFRED_FORGE_PROVIDER=github"),A.push(`ALFRED_GITHUB_TOKEN=${vs}`)):ut==="gitlab"?(A.push("ALFRED_FORGE_PROVIDER=gitlab"),A.push(`ALFRED_GITLAB_TOKEN=${As}`)):(A.push("# ALFRED_FORGE_PROVIDER=github"),A.push("# ALFRED_GITHUB_TOKEN=")),A.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),Jr?(A.push(`ALFRED_PROXMOX_BASE_URL=${Rs}`),A.push(`ALFRED_PROXMOX_TOKEN_ID=${yo}`),A.push(`ALFRED_PROXMOX_TOKEN_SECRET=${xs}`)):(A.push("# ALFRED_PROXMOX_BASE_URL="),A.push("# ALFRED_PROXMOX_TOKEN_ID="),A.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),Cs&&pt?(A.push(`ALFRED_UNIFI_BASE_URL=${Ot}`),A.push(`ALFRED_UNIFI_API_KEY=${pt}`)):Cs?(A.push(`ALFRED_UNIFI_BASE_URL=${Ot}`),A.push(`ALFRED_UNIFI_USERNAME=${To}`),A.push(`ALFRED_UNIFI_PASSWORD=${Ds}`)):(A.push("# ALFRED_UNIFI_BASE_URL="),A.push("# ALFRED_UNIFI_API_KEY=")),Qr?(A.push(`ALFRED_HOMEASSISTANT_URL=${Ls}`),A.push(`ALFRED_HOMEASSISTANT_TOKEN=${Ns}`)):(A.push("# ALFRED_HOMEASSISTANT_URL="),A.push("# ALFRED_HOMEASSISTANT_TOKEN=")),A.push("","# === Contacts ===",""),en)for(let[_,$]of Object.entries(he))A.push(`${_}=${$}`);else A.push("# ALFRED_CONTACTS_PROVIDER=carddav");A.push("","# === Docker ===",""),tn?(ht&&A.push(`ALFRED_DOCKER_SOCKET_PATH=${ht}`),ft&&A.push(`ALFRED_DOCKER_HOST=${ft}`)):(A.push("# ALFRED_DOCKER_SOCKET_PATH="),A.push("# ALFRED_DOCKER_HOST=")),A.push("","# === BMW CarData ===",""),sn?A.push(`ALFRED_BMW_CLIENT_ID=${Io}`):A.push("# ALFRED_BMW_CLIENT_ID="),A.push("","# === Routing ===",""),rn?A.push(`ALFRED_ROUTING_API_KEY=${xo}`):A.push("# ALFRED_ROUTING_API_KEY="),A.push("","# === Energy / aWATTar ===",""),nn&&yt?(gt&&A.push(`ALFRED_ENERGY_GRID_NAME=${gt}`),A.push(`ALFRED_ENERGY_GRID_USAGE_CT=${yt}`),A.push(`ALFRED_ENERGY_GRID_LOSS_CT=${on}`),Ms&&A.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Ms}`),Os&&A.push(`ALFRED_ENERGY_GRID_METER_FEE=${Os}`)):(A.push("# ALFRED_ENERGY_GRID_NAME="),A.push("# ALFRED_ENERGY_GRID_USAGE_CT="),A.push("# ALFRED_ENERGY_GRID_LOSS_CT="),A.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),A.push("# ALFRED_ENERGY_GRID_METER_FEE=")),A.push("","# === Security ===",""),$e?A.push(`ALFRED_OWNER_USER_ID=${$e}`):A.push("# ALFRED_OWNER_USER_ID="),A.push("");let xu=be.join(e,".env");ye.writeFileSync(xu,A.join(`
1052
- `),"utf-8"),console.log(` ${M("+")} ${E(".env")} written`);let cn=be.join(e,"config");ye.existsSync(cn)||ye.mkdirSync(cn,{recursive:!0});let Ma={name:r,telegram:{token:re.telegram?.token??"",enabled:x.some(_=>_.name==="telegram")},discord:{token:re.discord?.token??"",enabled:x.some(_=>_.name==="discord")},whatsapp:{enabled:x.some(_=>_.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:re.matrix?.homeserverUrl??"https://matrix.org",accessToken:re.matrix?.accessToken??"",userId:re.matrix?.userId??"",enabled:x.some(_=>_.name==="matrix")},signal:{apiUrl:re.signal?.apiUrl??"http://localhost:8080",phoneNumber:re.signal?.phoneNumber??"",enabled:x.some(_=>_.name==="signal")},llm:Object.keys(N).length>0?{default:{provider:a.name,model:g,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...N}:{provider:a.name,model:g,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...oe?{search:{provider:oe,...J?{apiKey:J}:{},...B?{baseUrl:B}:{}}}:{},...K&&Z.length>0?{email:{accounts:Z.map(_=>_.provider==="microsoft"?{name:_.name,provider:"microsoft",..._.msClientId?{microsoft:{clientId:_.msClientId,clientSecret:_.msClientSecret,tenantId:_.msTenantId,refreshToken:_.msRefreshToken}}:{}}:{name:_.name,imap:{host:_.imapHost,port:_.imapPort,secure:_.imapPort===993},smtp:{host:_.smtpHost,port:_.smtpPort,secure:_.smtpPort===465},auth:{user:_.user,pass:_.pass}})}}:{},...qe?{speech:{provider:qe,apiKey:st,...ks?{baseUrl:ks}:{},...$s?{ttsEnabled:!0,ttsVoice:Ss}:{}}}:{},...uo?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...dt.length>0||ut?{codeAgents:{enabled:dt.length>0,agents:dt,...ut==="github"?{forge:{provider:"github",github:{token:vs}}}:ut==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:As}}}:{}}}:{},...Jr?{proxmox:{baseUrl:Rs,tokenId:yo,tokenSecret:xs,verifyTls:wo}}:{},...Cs?{unifi:{baseUrl:Ot,...pt?{apiKey:pt}:{username:To,password:Ds},site:"default",verifyTls:Eo}}:{},...Qr?{homeassistant:{baseUrl:Ls,accessToken:Ns,verifyTls:ko}}:{},...en?{contacts:{provider:De,...De==="carddav"?{carddav:{serverUrl:he.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:he.ALFRED_CARDDAV_CONTACTS_USERNAME}}:De==="google"?{google:{clientId:he.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:De==="microsoft"?{microsoft:{clientId:he.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:he.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...tn?{docker:{...ht?{socketPath:ht}:{},...ft?{host:ft}:{}}}:{},...sn?{bmw:{clientId:Io}}:{},...rn?{routing:{apiKey:xo}}:{},...nn&&yt?{energy:{...gt?{gridName:gt}:{},gridUsageCt:parseFloat(yt),gridLossCt:parseFloat(on||"0"),...Ms?{gridCapacityFee:parseFloat(Ms)}:{},...Os?{gridMeterFee:parseFloat(Os)}:{}}}:{},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};$e&&(Ma.security.ownerUserId=$e);let Cu="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+ya.dump(Ma,{lineWidth:120,noRefs:!0,sortKeys:!1}),Du=be.join(cn,"default.yml");ye.writeFileSync(Du,Cu,"utf-8"),console.log(` ${M("+")} ${E("config/default.yml")} written`);let Lo=be.join(cn,"rules");ye.existsSync(Lo)||ye.mkdirSync(Lo,{recursive:!0});let Lu=Ps&&$e?`
1047
+ ${X}Enable BMW CarData (vehicle status, charging)?${v} ${E(`[${_u}]`)}: ${P}`)).trim().toLowerCase()||(Ao?"y":"n");process.stdout.write(v);let sn=Ca==="y"||Ca==="yes",Io="";sn?(console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${E(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${E(" 3. Client-ID generieren")}`),console.log(` ${E(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),Io=await F(l," BMW CarData Client ID",Ao),console.log(` ${M(">")} BMW CarData: ${C("enabled")}`)):console.log(` ${E("BMW CarData disabled.")}`);let Tu=t.config.routing,Ro=t.env.ALFRED_ROUTING_API_KEY??Tu?.apiKey??"",Eu=Ro?"Y/n":"y/N",La=(await l.question(`
1048
+ ${X}Enable route planning with live traffic (Google Routes)?${v} ${E(`[${Eu}]`)}: ${P}`)).trim().toLowerCase()||(Ro?"y":"n");process.stdout.write(v);let rn=La==="y"||La==="yes",xo="";rn?(console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${E(" 2. Routes API aktivieren")}`),console.log(` ${E(" 3. API Key erstellen")}`),xo=await F(l," Google Maps API Key",Ro),console.log(` ${M(">")} Routing: ${C("enabled")}`)):console.log(` ${E("Routing disabled.")}`);let Ge=t.config.energy,bu=t.env.ALFRED_ENERGY_GRID_NAME??Ge?.gridName??"",Co=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(Ge?.gridUsageCt!=null?String(Ge.gridUsageCt):""),ku=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(Ge?.gridLossCt!=null?String(Ge.gridLossCt):""),$u=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(Ge?.gridCapacityFee!=null?String(Ge.gridCapacityFee):""),Su=t.env.ALFRED_ENERGY_GRID_METER_FEE??(Ge?.gridMeterFee!=null?String(Ge.gridMeterFee):""),vu=Co?"Y/n":"y/N",Da=(await l.question(`
1049
+ ${X}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${v} ${E(`[${vu}]`)}: ${P}`)).trim().toLowerCase()||(Co?"y":"n");process.stdout.write(v);let nn=Da==="y"||Da==="yes",gt="",yt="",on="",Ms="",Os="";nn?(console.log(` ${E('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${E("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),gt=await F(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",bu),yt=await F(l," Netznutzungsentgelt (ct/kWh netto)",Co),on=await F(l," Netzverlustentgelt (ct/kWh netto)",ku||"0.38"),Ms=await F(l," Leistungspauschale (\u20AC/Monat netto)",$u),Os=await F(l," Messentgelt (\u20AC/Monat netto)",Su||"2.22"),console.log(` ${M(">")} Energy: ${C(gt||"enabled")} (${yt} + ${on} ct/kWh)`)):console.log(` ${E("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
1050
+ ${C("Security configuration:")}`);let Na=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",$e;if(Na)$e=await F(l,"Owner user ID (for elevated permissions)",Na);else{let _=(await l.question(`${X}Owner user ID${v} ${E("(optional, for elevated permissions)")}: ${P}`)).trim();process.stdout.write(v),$e=_}let Ps=!1;if($e){let _=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${C("Enable shell access (admin commands) for the owner?")}`),console.log(` ${E("Allows Alfred to execute shell commands. Only for the owner.")}`);let $=(await l.question(` ${P}> ${v}${E(`[${_}] `)}`)).trim().toLowerCase();$===""?Ps=t.shellEnabled:Ps=$==="y"||$==="yes",console.log(Ps?` ${M(">")} Shell access ${C("enabled")} for owner ${E($e)}`:` ${E("Shell access disabled.")}`)}let Au=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${C("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${E("By default, write actions are only allowed in DMs.")}`);let Lo=(await l.question(` ${P}> ${v}${E(`[${Au}] `)}`)).trim().toLowerCase(),Us;Lo===""?Us=t.writeInGroups:Us=Lo==="y"||Lo==="yes",console.log(Us?` ${M(">")} Write actions ${C("enabled")} in groups`:` ${E("Write actions only in DMs (default).")}`);let Iu=t.rateLimit??30;console.log("");let Ru=await F(l," Rate limit (max write actions per hour per user)",String(Iu)),an=Math.max(1,parseInt(Ru,10)||30);console.log(` ${M(">")} Rate limit: ${C(String(an))} per hour`),console.log(`
1051
+ ${C("Writing configuration files...")}`);let A=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let _=a.envKeyName||"ALFRED_OLLAMA_API_KEY";A.push(`${_}=${c}`)}if(g!==a.defaultModel&&A.push(`ALFRED_LLM_MODEL=${g}`),u&&A.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(N).length>0){A.push("","# === Additional Model Tiers ===");for(let[_,$]of Object.entries(N)){let I=`ALFRED_LLM_${_.toUpperCase()}`;A.push(""),A.push(`${I}_PROVIDER=${$.provider}`),A.push(`${I}_MODEL=${$.model}`),$.apiKey&&A.push(`${I}_API_KEY=${$.apiKey}`),$.baseUrl&&A.push(`${I}_BASE_URL=${$.baseUrl}`)}}A.push("","# === Messaging Platforms ===","");for(let[_,$]of Object.entries(xe))A.push(`${_}=${$}`);if(A.push("","# === Web Search ===",""),oe?(A.push(`ALFRED_SEARCH_PROVIDER=${oe}`),J&&A.push(`ALFRED_SEARCH_API_KEY=${J}`),B&&A.push(`ALFRED_SEARCH_BASE_URL=${B}`)):(A.push("# ALFRED_SEARCH_PROVIDER=brave"),A.push("# ALFRED_SEARCH_API_KEY=")),A.push("","# === Email ===",""),K&&Z.length>0){let _=Z[0];_.provider==="microsoft"?(A.push("ALFRED_EMAIL_PROVIDER=microsoft"),_.msClientId?(A.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${_.msClientId}`),A.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${_.msClientSecret}`),A.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${_.msTenantId}`),A.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${_.msRefreshToken}`)):A.push("# Microsoft email credentials shared from calendar config")):(A.push(`ALFRED_EMAIL_USER=${_.user}`),A.push(`ALFRED_EMAIL_PASS=${_.pass}`)),Z.length>1&&A.push("# Additional email accounts configured in config/default.yml")}else A.push("# ALFRED_EMAIL_USER="),A.push("# ALFRED_EMAIL_PASS=");if(A.push("","# === Speech ===",""),ze?(A.push(`ALFRED_SPEECH_PROVIDER=${ze}`),A.push(`ALFRED_SPEECH_API_KEY=${st}`),ks&&A.push(`ALFRED_SPEECH_BASE_URL=${ks}`),$s&&(A.push("ALFRED_TTS_ENABLED=true"),A.push(`ALFRED_TTS_VOICE=${Ss}`))):(A.push("# ALFRED_SPEECH_PROVIDER=groq"),A.push("# ALFRED_SPEECH_API_KEY=")),A.push("","# === Forge (GitHub / GitLab) ===",""),ut==="github"?(A.push("ALFRED_FORGE_PROVIDER=github"),A.push(`ALFRED_GITHUB_TOKEN=${vs}`)):ut==="gitlab"?(A.push("ALFRED_FORGE_PROVIDER=gitlab"),A.push(`ALFRED_GITLAB_TOKEN=${As}`)):(A.push("# ALFRED_FORGE_PROVIDER=github"),A.push("# ALFRED_GITHUB_TOKEN=")),A.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),Jr?(A.push(`ALFRED_PROXMOX_BASE_URL=${Rs}`),A.push(`ALFRED_PROXMOX_TOKEN_ID=${yo}`),A.push(`ALFRED_PROXMOX_TOKEN_SECRET=${xs}`)):(A.push("# ALFRED_PROXMOX_BASE_URL="),A.push("# ALFRED_PROXMOX_TOKEN_ID="),A.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),Cs&&pt?(A.push(`ALFRED_UNIFI_BASE_URL=${Ot}`),A.push(`ALFRED_UNIFI_API_KEY=${pt}`)):Cs?(A.push(`ALFRED_UNIFI_BASE_URL=${Ot}`),A.push(`ALFRED_UNIFI_USERNAME=${To}`),A.push(`ALFRED_UNIFI_PASSWORD=${Ls}`)):(A.push("# ALFRED_UNIFI_BASE_URL="),A.push("# ALFRED_UNIFI_API_KEY=")),Qr?(A.push(`ALFRED_HOMEASSISTANT_URL=${Ds}`),A.push(`ALFRED_HOMEASSISTANT_TOKEN=${Ns}`)):(A.push("# ALFRED_HOMEASSISTANT_URL="),A.push("# ALFRED_HOMEASSISTANT_TOKEN=")),A.push("","# === Contacts ===",""),en)for(let[_,$]of Object.entries(he))A.push(`${_}=${$}`);else A.push("# ALFRED_CONTACTS_PROVIDER=carddav");A.push("","# === Docker ===",""),tn?(ht&&A.push(`ALFRED_DOCKER_SOCKET_PATH=${ht}`),ft&&A.push(`ALFRED_DOCKER_HOST=${ft}`)):(A.push("# ALFRED_DOCKER_SOCKET_PATH="),A.push("# ALFRED_DOCKER_HOST=")),A.push("","# === BMW CarData ===",""),sn?A.push(`ALFRED_BMW_CLIENT_ID=${Io}`):A.push("# ALFRED_BMW_CLIENT_ID="),A.push("","# === Routing ===",""),rn?A.push(`ALFRED_ROUTING_API_KEY=${xo}`):A.push("# ALFRED_ROUTING_API_KEY="),A.push("","# === Energy / aWATTar ===",""),nn&&yt?(gt&&A.push(`ALFRED_ENERGY_GRID_NAME=${gt}`),A.push(`ALFRED_ENERGY_GRID_USAGE_CT=${yt}`),A.push(`ALFRED_ENERGY_GRID_LOSS_CT=${on}`),Ms&&A.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Ms}`),Os&&A.push(`ALFRED_ENERGY_GRID_METER_FEE=${Os}`)):(A.push("# ALFRED_ENERGY_GRID_NAME="),A.push("# ALFRED_ENERGY_GRID_USAGE_CT="),A.push("# ALFRED_ENERGY_GRID_LOSS_CT="),A.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),A.push("# ALFRED_ENERGY_GRID_METER_FEE=")),A.push("","# === Security ===",""),$e?A.push(`ALFRED_OWNER_USER_ID=${$e}`):A.push("# ALFRED_OWNER_USER_ID="),A.push("");let xu=be.join(e,".env");ye.writeFileSync(xu,A.join(`
1052
+ `),"utf-8"),console.log(` ${M("+")} ${E(".env")} written`);let cn=be.join(e,"config");ye.existsSync(cn)||ye.mkdirSync(cn,{recursive:!0});let Ma={name:r,telegram:{token:re.telegram?.token??"",enabled:x.some(_=>_.name==="telegram")},discord:{token:re.discord?.token??"",enabled:x.some(_=>_.name==="discord")},whatsapp:{enabled:x.some(_=>_.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:re.matrix?.homeserverUrl??"https://matrix.org",accessToken:re.matrix?.accessToken??"",userId:re.matrix?.userId??"",enabled:x.some(_=>_.name==="matrix")},signal:{apiUrl:re.signal?.apiUrl??"http://localhost:8080",phoneNumber:re.signal?.phoneNumber??"",enabled:x.some(_=>_.name==="signal")},llm:Object.keys(N).length>0?{default:{provider:a.name,model:g,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...N}:{provider:a.name,model:g,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...oe?{search:{provider:oe,...J?{apiKey:J}:{},...B?{baseUrl:B}:{}}}:{},...K&&Z.length>0?{email:{accounts:Z.map(_=>_.provider==="microsoft"?{name:_.name,provider:"microsoft",..._.msClientId?{microsoft:{clientId:_.msClientId,clientSecret:_.msClientSecret,tenantId:_.msTenantId,refreshToken:_.msRefreshToken}}:{}}:{name:_.name,imap:{host:_.imapHost,port:_.imapPort,secure:_.imapPort===993},smtp:{host:_.smtpHost,port:_.smtpPort,secure:_.smtpPort===465},auth:{user:_.user,pass:_.pass}})}}:{},...ze?{speech:{provider:ze,apiKey:st,...ks?{baseUrl:ks}:{},...$s?{ttsEnabled:!0,ttsVoice:Ss}:{}}}:{},...uo?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...dt.length>0||ut?{codeAgents:{enabled:dt.length>0,agents:dt,...ut==="github"?{forge:{provider:"github",github:{token:vs}}}:ut==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:As}}}:{}}}:{},...Jr?{proxmox:{baseUrl:Rs,tokenId:yo,tokenSecret:xs,verifyTls:wo}}:{},...Cs?{unifi:{baseUrl:Ot,...pt?{apiKey:pt}:{username:To,password:Ls},site:"default",verifyTls:Eo}}:{},...Qr?{homeassistant:{baseUrl:Ds,accessToken:Ns,verifyTls:ko}}:{},...en?{contacts:{provider:Le,...Le==="carddav"?{carddav:{serverUrl:he.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:he.ALFRED_CARDDAV_CONTACTS_USERNAME}}:Le==="google"?{google:{clientId:he.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:Le==="microsoft"?{microsoft:{clientId:he.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:he.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...tn?{docker:{...ht?{socketPath:ht}:{},...ft?{host:ft}:{}}}:{},...sn?{bmw:{clientId:Io}}:{},...rn?{routing:{apiKey:xo}}:{},...nn&&yt?{energy:{...gt?{gridName:gt}:{},gridUsageCt:parseFloat(yt),gridLossCt:parseFloat(on||"0"),...Ms?{gridCapacityFee:parseFloat(Ms)}:{},...Os?{gridMeterFee:parseFloat(Os)}:{}}}:{},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};$e&&(Ma.security.ownerUserId=$e);let Cu="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+ya.dump(Ma,{lineWidth:120,noRefs:!0,sortKeys:!1}),Lu=be.join(cn,"default.yml");ye.writeFileSync(Lu,Cu,"utf-8"),console.log(` ${M("+")} ${E("config/default.yml")} written`);let Do=be.join(cn,"rules");ye.existsSync(Do)||ye.mkdirSync(Do,{recursive:!0});let Du=Ps&&$e?`
1053
1053
  # Allow admin actions (shell, etc.) for the owner only
1054
1054
  - id: allow-owner-admin
1055
1055
  effect: allow
@@ -1109,7 +1109,7 @@ ${Us?` # Allow write-level skills everywhere (DMs and groups)
1109
1109
  rateLimit:
1110
1110
  maxInvocations: ${an}
1111
1111
  windowSeconds: 3600
1112
- ${Lu}
1112
+ ${Du}
1113
1113
  # Deny destructive and admin actions by default
1114
1114
  - id: deny-destructive
1115
1115
  effect: deny
@@ -1125,23 +1125,23 @@ ${Lu}
1125
1125
  scope: global
1126
1126
  actions: ["*"]
1127
1127
  riskLevels: [read, write, destructive, admin]
1128
- `,Mu=be.join(Lo,"default-rules.yml");ye.writeFileSync(Mu,Nu,"utf-8"),console.log(` ${M("+")} ${E("config/rules/default-rules.yml")} written`);let Oa=be.join(e,"data");ye.existsSync(Oa)||(ye.mkdirSync(Oa,{recursive:!0}),console.log(` ${M("+")} ${E("data/")} directory created`)),console.log(""),console.log(`${no}${"=".repeat(52)}${v}`),console.log(`${no}${X} Setup complete!${v}`),console.log(`${no}${"=".repeat(52)}${v}`),console.log(""),console.log(` ${C("Bot name:")} ${r}`),console.log(` ${C("LLM default:")} ${a.name} (${g})`),c&&console.log(` ${C("API key:")} ${_e(c)}`);for(let[_,$]of Object.entries(N)){let I=_.charAt(0).toUpperCase()+_.slice(1);console.log(` ${C(`LLM ${I}:`)}${" ".repeat(Math.max(1,10-I.length))}${$.provider} (${$.model})`)}if(x.length>0?console.log(` ${C("Platforms:")} ${x.map(_=>_.label).join(", ")}`):console.log(` ${C("Platforms:")} none (configure later)`),oe){let _={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${B})`};console.log(` ${C("Web search:")} ${_[oe]}`)}else console.log(` ${C("Web search:")} ${E("disabled")}`);if(K&&Z.length>0){let _=Z.map($=>$.provider==="microsoft"?`${$.name} (Microsoft 365)${$.msClientId?"":" \u2014 shared from Calendar"}`:`${$.name} (${$.imapHost})`);console.log(` ${C("Email:")} ${_.join(", ")}`)}else console.log(` ${C("Email:")} ${E("disabled")}`);if(qe){let _={openai:"OpenAI Whisper",groq:"Groq Whisper"},$=$s?`, TTS: ${Ss}`:"";console.log(` ${C("Voice:")} ${_[qe]}${$}`)}else console.log(` ${C("Voice:")} ${E("disabled")}`);console.log(` ${C("Code Sandbox:")} ${uo?M("enabled"):E("disabled")}`),Jr&&console.log(` ${C("Proxmox:")} ${M(Rs)}`),Cs&&console.log(` ${C("UniFi:")} ${M(Ot)}`),Qr&&console.log(` ${C("Home Assist.:")} ${M(Ls)}`),en&&console.log(` ${C("Contacts:")} ${M(De)}`),tn&&console.log(` ${C("Docker:")} ${M(ft||ht)}`),sn&&console.log(` ${C("BMW CarData:")} ${M("enabled")}`),rn&&console.log(` ${C("Routing:")} ${M("enabled")}`),nn&&console.log(` ${C("Energy:")} ${M(gt||"enabled")} ${E(`(${yt} ct/kWh)`)}`),$e&&(console.log(` ${C("Owner ID:")} ${$e}`),console.log(` ${C("Shell access:")} ${Ps?M("enabled"):E("disabled")}`)),console.log(` ${C("Write scope:")} ${Us?"DMs + Groups":"DMs only"}`),console.log(` ${C("Rate limit:")} ${an}/hour per user`),console.log(""),console.log(`${oo}Next steps:${v}`),console.log(` ${C("alfred start")} Start Alfred`),console.log(` ${C("alfred status")} Check configuration`),console.log(` ${C("alfred --help")} Show all commands`),console.log(""),console.log(`${ct}Edit ${C(".env")}${ct} or ${C("config/default.yml")}${ct} for manual configuration.${v}`),console.log("")}finally{l.close()}}async function F(l,e,t){let s=(await l.question(`${X}${e}${v} ${E(`[${t}]`)}: ${P}`)).trim();return process.stdout.write(v),s||t}async function Ae(l,e){for(;;){let t=(await l.question(`${X}${e}${v}: ${P}`)).trim();if(process.stdout.write(v),t)return t;console.log(` ${Gd("!")} This field is required. Please enter a value.`)}}async function Vr(l,e,t,s,r){for(;;){let n=(await l.question(`${P}${e}${v}`)).trim();if(!n)return r;let o=parseInt(n,10);if(!Number.isNaN(o)&&o>=t&&o<=s)return o;console.log(` ${Gd("!")} Please enter a number between ${t} and ${s}.`)}}function Ah(){console.log(`
1128
+ `,Mu=be.join(Do,"default-rules.yml");ye.writeFileSync(Mu,Nu,"utf-8"),console.log(` ${M("+")} ${E("config/rules/default-rules.yml")} written`);let Oa=be.join(e,"data");ye.existsSync(Oa)||(ye.mkdirSync(Oa,{recursive:!0}),console.log(` ${M("+")} ${E("data/")} directory created`)),console.log(""),console.log(`${no}${"=".repeat(52)}${v}`),console.log(`${no}${X} Setup complete!${v}`),console.log(`${no}${"=".repeat(52)}${v}`),console.log(""),console.log(` ${C("Bot name:")} ${r}`),console.log(` ${C("LLM default:")} ${a.name} (${g})`),c&&console.log(` ${C("API key:")} ${_e(c)}`);for(let[_,$]of Object.entries(N)){let I=_.charAt(0).toUpperCase()+_.slice(1);console.log(` ${C(`LLM ${I}:`)}${" ".repeat(Math.max(1,10-I.length))}${$.provider} (${$.model})`)}if(x.length>0?console.log(` ${C("Platforms:")} ${x.map(_=>_.label).join(", ")}`):console.log(` ${C("Platforms:")} none (configure later)`),oe){let _={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${B})`};console.log(` ${C("Web search:")} ${_[oe]}`)}else console.log(` ${C("Web search:")} ${E("disabled")}`);if(K&&Z.length>0){let _=Z.map($=>$.provider==="microsoft"?`${$.name} (Microsoft 365)${$.msClientId?"":" \u2014 shared from Calendar"}`:`${$.name} (${$.imapHost})`);console.log(` ${C("Email:")} ${_.join(", ")}`)}else console.log(` ${C("Email:")} ${E("disabled")}`);if(ze){let _={openai:"OpenAI Whisper",groq:"Groq Whisper"},$=$s?`, TTS: ${Ss}`:"";console.log(` ${C("Voice:")} ${_[ze]}${$}`)}else console.log(` ${C("Voice:")} ${E("disabled")}`);console.log(` ${C("Code Sandbox:")} ${uo?M("enabled"):E("disabled")}`),Jr&&console.log(` ${C("Proxmox:")} ${M(Rs)}`),Cs&&console.log(` ${C("UniFi:")} ${M(Ot)}`),Qr&&console.log(` ${C("Home Assist.:")} ${M(Ds)}`),en&&console.log(` ${C("Contacts:")} ${M(Le)}`),tn&&console.log(` ${C("Docker:")} ${M(ft||ht)}`),sn&&console.log(` ${C("BMW CarData:")} ${M("enabled")}`),rn&&console.log(` ${C("Routing:")} ${M("enabled")}`),nn&&console.log(` ${C("Energy:")} ${M(gt||"enabled")} ${E(`(${yt} ct/kWh)`)}`),$e&&(console.log(` ${C("Owner ID:")} ${$e}`),console.log(` ${C("Shell access:")} ${Ps?M("enabled"):E("disabled")}`)),console.log(` ${C("Write scope:")} ${Us?"DMs + Groups":"DMs only"}`),console.log(` ${C("Rate limit:")} ${an}/hour per user`),console.log(""),console.log(`${oo}Next steps:${v}`),console.log(` ${C("alfred start")} Start Alfred`),console.log(` ${C("alfred status")} Check configuration`),console.log(` ${C("alfred --help")} Show all commands`),console.log(""),console.log(`${ct}Edit ${C(".env")}${ct} or ${C("config/default.yml")}${ct} for manual configuration.${v}`),console.log("")}finally{l.close()}}async function F(l,e,t){let s=(await l.question(`${X}${e}${v} ${E(`[${t}]`)}: ${P}`)).trim();return process.stdout.write(v),s||t}async function Ae(l,e){for(;;){let t=(await l.question(`${X}${e}${v}: ${P}`)).trim();if(process.stdout.write(v),t)return t;console.log(` ${Gd("!")} This field is required. Please enter a value.`)}}async function Vr(l,e,t,s,r){for(;;){let n=(await l.question(`${P}${e}${v}`)).trim();if(!n)return r;let o=parseInt(n,10);if(!Number.isNaN(o)&&o>=t&&o<=s)return o;console.log(` ${Gd("!")} Please enter a number between ${t} and ${s}.`)}}function Ah(){console.log(`
1129
1129
  ${bh}${X} _ _ _____ ____ _____ ____
1130
1130
  / \\ | | | ___| _ \\| ____| _ \\
1131
1131
  / _ \\ | | | |_ | |_) | _| | | | |
1132
1132
  / ___ \\| |___| _| | _ <| |___| |_| |
1133
1133
  /_/ \\_\\_____|_| |_| \\_\\_____|____/ ${v}
1134
1134
  ${ct} Personal AI Assistant \u2014 Setup Wizard${v}
1135
- `)}var v,X,ct,no,P,oo,Eh,bh,et,Es,Wd,Kd=T(()=>{"use strict";ga();v="\x1B[0m",X="\x1B[1m",ct="\x1B[2m",no="\x1B[32m",P="\x1B[33m",oo="\x1B[36m",Eh="\x1B[31m",bh="\x1B[35m";m(M,"green");m(kh,"yellow");m(ge,"cyan");m(Gd,"red");m(C,"bold");m(E,"dim");m(_e,"maskKey");et=[{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"}]}],Es=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];m($h,"findCommand");Wd=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];m(Sh,"loadExistingConfig");m(vh,"setupCommand");m(F,"askWithDefault");m(Ae,"askRequired");m(Vr,"askNumber");m(Ah,"printBanner")});var Yd={};ue(Yd,{configCommand:()=>Ch});function Rh(l){let e=l.toLowerCase();return Ih.some(t=>e.includes(t))}function xh(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function Xd(l){let e={};for(let[t,s]of Object.entries(l))Rh(t)?e[t]=xh(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Xd(s):e[t]=s;return e}async function Ch(){let l=new le,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Xd(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var Ih,Jd=T(()=>{"use strict";Xe();Ih=["token","apikey","api_key","accesstoken","secret","password"];m(Rh,"isSensitiveKey");m(xh,"redactValue");m(Xd,"redactObject");m(Ch,"configCommand")});var Qd={};ue(Qd,{rulesCommand:()=>Lh});import io from"node:fs";import Zd from"node:path";import Dh from"js-yaml";async function Lh(){let l=new le,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=Zd.resolve(e.security.rulesPath);if(!io.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}io.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=io.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 $t,o=[],i=[];for(let a of r){let c=Zd.join(t,a);try{let d=io.readFileSync(c,"utf-8"),u=Dh.load(d),p=n.loadFromObject(u);o.push(...p)}catch(d){i.push(` ${a}: ${d.message}`)}}if(console.log("Alfred \u2014 Security Rules"),console.log("======================="),console.log(`Rules directory: ${t}`),console.log(`Rule files found: ${r.length}`),console.log(`Total rules loaded: ${o.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(o.length!==0){o.sort((a,c)=>a.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of o){let c=a.rateLimit?` | rate-limit: ${a.rateLimit.maxInvocations}/${a.rateLimit.windowSeconds}s`:"";console.log(` [${a.priority}] ${a.id}`),console.log(` effect: ${a.effect} | scope: ${a.scope}`),console.log(` actions: ${a.actions.join(", ")}`),console.log(` risk levels: ${a.riskLevels.join(", ")}${c}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var eu=T(()=>{"use strict";Xe();fn();m(Lh,"rulesCommand")});var tu={};ue(tu,{statusCommand:()=>Mh});import Kr from"node:fs";import wa from"node:path";import Nh from"js-yaml";async function Mh(){let l=new le,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=wa.resolve(e.storage.path),n=Kr.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=wa.resolve(e.security.rulesPath),i=0,a=0;if(Kr.existsSync(o)&&Kr.statSync(o).isDirectory()){let c=Kr.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new $t;for(let u of c){let p=wa.join(o,u);try{let f=Kr.readFileSync(p,"utf-8"),g=Nh.load(f),h=d.loadFromObject(g);i+=h.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 su=T(()=>{"use strict";Xe();fn();m(Mh,"statusCommand")});var ou={};ue(ou,{authCommand:()=>Jh});import{createServer as Oh}from"node:http";import{exec as Ph}from"node:child_process";import{readFileSync as Uh,writeFileSync as Fh,existsSync as jh}from"node:fs";import{createInterface as Bh}from"node:readline";import{resolve as Hh}from"node:path";async function _a(l){let e=Bh({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function qh(){let l={};try{let s=new le().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 Wh(){let l=qh(),e=l.clientId||await _a(" Client ID: "),t=l.clientSecret||await _a(" Client Secret: "),s=l.tenantId||await _a(' 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 Gh(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:ru,response_mode:"query",scope:nu,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function Vh(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:ru,grant_type:"authorization_code",scope:nu}),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 Kh(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&Ph(t,()=>{})}function Xh(l,e){let t=Hh(process.cwd(),".env"),s=[];jh(t)&&(s=Uh(t,"utf-8").split(`
1135
+ `)}var v,X,ct,no,P,oo,Eh,bh,et,Es,Wd,Kd=T(()=>{"use strict";ga();v="\x1B[0m",X="\x1B[1m",ct="\x1B[2m",no="\x1B[32m",P="\x1B[33m",oo="\x1B[36m",Eh="\x1B[31m",bh="\x1B[35m";m(M,"green");m(kh,"yellow");m(ge,"cyan");m(Gd,"red");m(C,"bold");m(E,"dim");m(_e,"maskKey");et=[{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"}]}],Es=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];m($h,"findCommand");Wd=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];m(Sh,"loadExistingConfig");m(vh,"setupCommand");m(F,"askWithDefault");m(Ae,"askRequired");m(Vr,"askNumber");m(Ah,"printBanner")});var Yd={};ue(Yd,{configCommand:()=>Ch});function Rh(l){let e=l.toLowerCase();return Ih.some(t=>e.includes(t))}function xh(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function Xd(l){let e={};for(let[t,s]of Object.entries(l))Rh(t)?e[t]=xh(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Xd(s):e[t]=s;return e}async function Ch(){let l=new le,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Xd(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var Ih,Jd=T(()=>{"use strict";Xe();Ih=["token","apikey","api_key","accesstoken","secret","password"];m(Rh,"isSensitiveKey");m(xh,"redactValue");m(Xd,"redactObject");m(Ch,"configCommand")});var Qd={};ue(Qd,{rulesCommand:()=>Dh});import io from"node:fs";import Zd from"node:path";import Lh from"js-yaml";async function Dh(){let l=new le,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=Zd.resolve(e.security.rulesPath);if(!io.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}io.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=io.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 $t,o=[],i=[];for(let a of r){let c=Zd.join(t,a);try{let d=io.readFileSync(c,"utf-8"),u=Lh.load(d),p=n.loadFromObject(u);o.push(...p)}catch(d){i.push(` ${a}: ${d.message}`)}}if(console.log("Alfred \u2014 Security Rules"),console.log("======================="),console.log(`Rules directory: ${t}`),console.log(`Rule files found: ${r.length}`),console.log(`Total rules loaded: ${o.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(o.length!==0){o.sort((a,c)=>a.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of o){let c=a.rateLimit?` | rate-limit: ${a.rateLimit.maxInvocations}/${a.rateLimit.windowSeconds}s`:"";console.log(` [${a.priority}] ${a.id}`),console.log(` effect: ${a.effect} | scope: ${a.scope}`),console.log(` actions: ${a.actions.join(", ")}`),console.log(` risk levels: ${a.riskLevels.join(", ")}${c}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var eu=T(()=>{"use strict";Xe();fn();m(Dh,"rulesCommand")});var tu={};ue(tu,{statusCommand:()=>Mh});import Kr from"node:fs";import wa from"node:path";import Nh from"js-yaml";async function Mh(){let l=new le,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=wa.resolve(e.storage.path),n=Kr.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=wa.resolve(e.security.rulesPath),i=0,a=0;if(Kr.existsSync(o)&&Kr.statSync(o).isDirectory()){let c=Kr.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new $t;for(let u of c){let p=wa.join(o,u);try{let f=Kr.readFileSync(p,"utf-8"),g=Nh.load(f),h=d.loadFromObject(g);i+=h.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 su=T(()=>{"use strict";Xe();fn();m(Mh,"statusCommand")});var ou={};ue(ou,{authCommand:()=>Jh});import{createServer as Oh}from"node:http";import{exec as Ph}from"node:child_process";import{readFileSync as Uh,writeFileSync as Fh,existsSync as jh}from"node:fs";import{createInterface as Bh}from"node:readline";import{resolve as Hh}from"node:path";async function _a(l){let e=Bh({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function zh(){let l={};try{let s=new le().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 Wh(){let l=zh(),e=l.clientId||await _a(" Client ID: "),t=l.clientSecret||await _a(" Client Secret: "),s=l.tenantId||await _a(' 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 Gh(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:ru,response_mode:"query",scope:nu,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function Vh(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:ru,grant_type:"authorization_code",scope:nu}),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 Kh(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&Ph(t,()=>{})}function Xh(l,e){let t=Hh(process.cwd(),".env"),s=[];jh(t)&&(s=Uh(t,"utf-8").split(`
1136
1136
  `));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(`
1137
1137
  `).replace(/\n*$/,`
1138
- `);Fh(t,o)}function Yh(l){return new Promise((e,t)=>{let s=Oh(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 Vh(i,l);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(zh),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 Jh(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 Wh(),t=Gh(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),Kh(t);try{let s=await Yh(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),Xh(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(`
1139
- Fehler: ${s.message}`),process.exit(1)}process.exit(0)}var ru,nu,zh,iu=T(()=>{"use strict";Xe();ru="http://localhost:3000/callback",nu=["offline_access","Mail.Read","Mail.ReadWrite","Mail.Send","Contacts.Read","Contacts.ReadWrite","Calendars.Read","Calendars.ReadWrite","Tasks.ReadWrite"].join(" "),zh=`<!DOCTYPE html>
1138
+ `);Fh(t,o)}function Yh(l){return new Promise((e,t)=>{let s=Oh(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 Vh(i,l);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(qh),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 Jh(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 Wh(),t=Gh(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),Kh(t);try{let s=await Yh(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),Xh(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(`
1139
+ Fehler: ${s.message}`),process.exit(1)}process.exit(0)}var ru,nu,qh,iu=T(()=>{"use strict";Xe();ru="http://localhost:3000/callback",nu=["offline_access","Mail.Read","Mail.ReadWrite","Mail.Send","Contacts.Read","Contacts.ReadWrite","Calendars.Read","Calendars.ReadWrite","Tasks.ReadWrite"].join(" "),qh=`<!DOCTYPE html>
1140
1140
  <html><head><meta charset="utf-8"><title>Alfred \u2014 Auth erfolgreich</title>
1141
1141
  <style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0d1117;color:#e6edf3}
1142
1142
  .card{text-align:center;padding:2rem;border:1px solid #30363d;border-radius:12px;background:#161b22}
1143
1143
  h1{color:#3fb950;margin-bottom:.5rem}p{color:#8b949e}</style></head>
1144
- <body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;m(_a,"askQuestion");m(qh,"resolveCredentials");m(Wh,"ensureCredentials");m(Gh,"buildAuthUrl");m(Vh,"exchangeCode");m(Kh,"openBrowser");m(Xh,"updateEnvFile");m(Yh,"waitForCallback");m(Jh,"authCommand")});var au={};ue(au,{logsCommand:()=>ef});import Zh from"node:fs";import Qh from"node:path";async function ef(l){let e=new le,t;try{t=e.loadConfig()}catch(n){console.error("Failed to load configuration:",n.message),process.exit(1)}let s=Qh.resolve(t.storage.path);if(!Zh.existsSync(s)){console.log(`Database not found at: ${s}`),console.log("No audit log entries. Alfred has not been run yet, or the database path is incorrect.");return}let r;try{r=new Tt(s);let n=new Et(r.getDb()),o=n.count({}),i=n.query({limit:l});if(console.log("Alfred \u2014 Audit Log"),console.log("==================="),console.log(`Total entries: ${o}`),console.log(`Showing last ${Math.min(l,o)} entries:`),console.log(""),i.length===0){console.log("No audit log entries found.");return}for(let a of i){let c=a.timestamp.toISOString(),d=a.effect==="allow"?"ALLOW":"DENY ";console.log(` ${c} [${d}] ${a.action}`),console.log(` user: ${a.userId} | platform: ${a.platform} | risk: ${a.riskLevel}`),a.ruleId&&console.log(` rule: ${a.ruleId}`),a.chatId&&console.log(` chat: ${a.chatId}`),a.context&&console.log(` context: ${JSON.stringify(a.context)}`),console.log("")}}catch(n){console.error("Failed to read audit log:",n.message),process.exit(1)}finally{r&&r.close()}}var cu=T(()=>{"use strict";Xe();Wo();m(ef,"logsCommand")});import{readFileSync as tf}from"node:fs";import{fileURLToPath as sf}from"node:url";import{dirname as rf,join as nf}from"node:path";function of(){try{let l=rf(sf(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(tf(nf(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}m(of,"getVersion");var lu=of(),Ta=`
1144
+ <body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;m(_a,"askQuestion");m(zh,"resolveCredentials");m(Wh,"ensureCredentials");m(Gh,"buildAuthUrl");m(Vh,"exchangeCode");m(Kh,"openBrowser");m(Xh,"updateEnvFile");m(Yh,"waitForCallback");m(Jh,"authCommand")});var au={};ue(au,{logsCommand:()=>ef});import Zh from"node:fs";import Qh from"node:path";async function ef(l){let e=new le,t;try{t=e.loadConfig()}catch(n){console.error("Failed to load configuration:",n.message),process.exit(1)}let s=Qh.resolve(t.storage.path);if(!Zh.existsSync(s)){console.log(`Database not found at: ${s}`),console.log("No audit log entries. Alfred has not been run yet, or the database path is incorrect.");return}let r;try{r=new Tt(s);let n=new Et(r.getDb()),o=n.count({}),i=n.query({limit:l});if(console.log("Alfred \u2014 Audit Log"),console.log("==================="),console.log(`Total entries: ${o}`),console.log(`Showing last ${Math.min(l,o)} entries:`),console.log(""),i.length===0){console.log("No audit log entries found.");return}for(let a of i){let c=a.timestamp.toISOString(),d=a.effect==="allow"?"ALLOW":"DENY ";console.log(` ${c} [${d}] ${a.action}`),console.log(` user: ${a.userId} | platform: ${a.platform} | risk: ${a.riskLevel}`),a.ruleId&&console.log(` rule: ${a.ruleId}`),a.chatId&&console.log(` chat: ${a.chatId}`),a.context&&console.log(` context: ${JSON.stringify(a.context)}`),console.log("")}}catch(n){console.error("Failed to read audit log:",n.message),process.exit(1)}finally{r&&r.close()}}var cu=T(()=>{"use strict";Xe();Wo();m(ef,"logsCommand")});import{readFileSync as tf}from"node:fs";import{fileURLToPath as sf}from"node:url";import{dirname as rf,join as nf}from"node:path";function of(){try{let l=rf(sf(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(tf(nf(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}m(of,"getVersion");var lu=of(),Ta=`
1145
1145
  Alfred CLI v${lu}
1146
1146
  Personal AI Assistant
1147
1147
 
@@ -1161,4 +1161,4 @@ Commands:
1161
1161
  Options:
1162
1162
  --help, -h Show this help message
1163
1163
  --version, -v Show version number
1164
- `.trim();function af(l){let e=l.slice(2),t=e.length>0&&!e[0].startsWith("-")?e[0]:"",s=t?e.slice(1):e,r={},n=[],o=0;for(;o<s.length;){let i=s[o];if(i.startsWith("--")){let a=i.slice(2);o+1<s.length&&!s[o+1].startsWith("-")?(r[a]=s[o+1],o+=2):(r[a]=!0,o+=1)}else if(i.startsWith("-")&&i.length===2){let a=i.slice(1);o+1<s.length&&!s[o+1].startsWith("-")?(r[a]=s[o+1],o+=2):(r[a]=!0,o+=1)}else n.push(i),o+=1}return{command:t,flags:r,positional:n}}m(af,"parseArgs");async function cf(){let l=af(process.argv);switch((l.flags.help||l.flags.h)&&(console.log(Ta),process.exit(0)),(l.flags.version||l.flags.v)&&(console.log(`alfred v${lu}`),process.exit(0)),l.command){case"start":{let{startCommand:e}=await Promise.resolve().then(()=>(Bd(),jd));await e();break}case"chat":{let{chatCommand:e}=await Promise.resolve().then(()=>(qd(),zd));await e({model:typeof l.flags.model=="string"?l.flags.model:void 0,tier:typeof l.flags.tier=="string"?l.flags.tier:void 0});break}case"setup":{let{setupCommand:e}=await Promise.resolve().then(()=>(Kd(),Vd));await e();break}case"config":{let{configCommand:e}=await Promise.resolve().then(()=>(Jd(),Yd));await e();break}case"rules":{let{rulesCommand:e}=await Promise.resolve().then(()=>(eu(),Qd));await e();break}case"status":{let{statusCommand:e}=await Promise.resolve().then(()=>(su(),tu));await e();break}case"auth":{let e=l.positional[0]??"",{authCommand:t}=await Promise.resolve().then(()=>(iu(),ou));await t(e);break}case"logs":{let e=l.flags.tail,t=20;if(typeof e=="string"){let r=parseInt(e,10);(Number.isNaN(r)||r<=0)&&(console.error("Error: --tail must be a positive integer"),process.exit(1)),t=r}let{logsCommand:s}=await Promise.resolve().then(()=>(cu(),au));await s(t);break}case"help":console.log(Ta);break;case"":console.log(Ta),process.exit(0);break;default:console.error(`Unknown command: ${l.command}`),console.error(""),console.error('Run "alfred --help" for usage information.'),process.exit(1)}}m(cf,"main");cf().catch(l=>{console.error("Fatal error:",l),process.exit(1)});
1164
+ `.trim();function af(l){let e=l.slice(2),t=e.length>0&&!e[0].startsWith("-")?e[0]:"",s=t?e.slice(1):e,r={},n=[],o=0;for(;o<s.length;){let i=s[o];if(i.startsWith("--")){let a=i.slice(2);o+1<s.length&&!s[o+1].startsWith("-")?(r[a]=s[o+1],o+=2):(r[a]=!0,o+=1)}else if(i.startsWith("-")&&i.length===2){let a=i.slice(1);o+1<s.length&&!s[o+1].startsWith("-")?(r[a]=s[o+1],o+=2):(r[a]=!0,o+=1)}else n.push(i),o+=1}return{command:t,flags:r,positional:n}}m(af,"parseArgs");async function cf(){let l=af(process.argv);switch((l.flags.help||l.flags.h)&&(console.log(Ta),process.exit(0)),(l.flags.version||l.flags.v)&&(console.log(`alfred v${lu}`),process.exit(0)),l.command){case"start":{let{startCommand:e}=await Promise.resolve().then(()=>(Bd(),jd));await e();break}case"chat":{let{chatCommand:e}=await Promise.resolve().then(()=>(zd(),qd));await e({model:typeof l.flags.model=="string"?l.flags.model:void 0,tier:typeof l.flags.tier=="string"?l.flags.tier:void 0});break}case"setup":{let{setupCommand:e}=await Promise.resolve().then(()=>(Kd(),Vd));await e();break}case"config":{let{configCommand:e}=await Promise.resolve().then(()=>(Jd(),Yd));await e();break}case"rules":{let{rulesCommand:e}=await Promise.resolve().then(()=>(eu(),Qd));await e();break}case"status":{let{statusCommand:e}=await Promise.resolve().then(()=>(su(),tu));await e();break}case"auth":{let e=l.positional[0]??"",{authCommand:t}=await Promise.resolve().then(()=>(iu(),ou));await t(e);break}case"logs":{let e=l.flags.tail,t=20;if(typeof e=="string"){let r=parseInt(e,10);(Number.isNaN(r)||r<=0)&&(console.error("Error: --tail must be a positive integer"),process.exit(1)),t=r}let{logsCommand:s}=await Promise.resolve().then(()=>(cu(),au));await s(t);break}case"help":console.log(Ta);break;case"":console.log(Ta),process.exit(0);break;default:console.error(`Unknown command: ${l.command}`),console.error(""),console.error('Run "alfred --help" for usage information.'),process.exit(1)}}m(cf,"main");cf().catch(l=>{console.error("Fatal error:",l),process.exit(1)});