@madh-io/alfred-ai 0.9.86 → 0.9.88

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 +91 -91
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- var ji=Object.defineProperty;var u=(c,e)=>ji(c,"name",{value:e,configurable:!0});var E=(c,e)=>()=>(c&&(e=c(c=0)),e);var oe=(c,e)=>{for(var t in e)ji(c,t,{get:e[t],enumerable:!0})};import{z as g}from"zod";var Hi,qi,zi,Wi,Vi,Gi,Ki,Xi,nt,md,pd,hd,Bi,fd,gd,yd,wd,Td,_d,Ed,bd,$d,vd,Sd,kd,Ad,Id,xd,Rd,Cd,Ld,Nd,Dd,Md,Od,Pd,Ud,Fd,jd,Bd,Jo,Zo=E(()=>{"use strict";Hi=g.object({token:g.string().optional(),enabled:g.boolean()}),qi=g.object({token:g.string().optional(),enabled:g.boolean()}),zi=g.object({enabled:g.boolean(),dataPath:g.string()}),Wi=g.object({homeserverUrl:g.string(),accessToken:g.string().optional(),userId:g.string().optional(),enabled:g.boolean()}),Vi=g.object({apiUrl:g.string(),phoneNumber:g.string().optional(),enabled:g.boolean()}),Gi=g.object({path:g.string()}),Ki=g.object({level:g.enum(["trace","debug","info","warn","error","fatal"]),pretty:g.boolean(),auditLogPath:g.string().optional()}),Xi=g.object({rulesPath:g.string(),defaultEffect:g.enum(["allow","deny"]),ownerUserId:g.string().optional()}),nt=g.object({provider:g.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:g.string().optional(),baseUrl:g.string().optional(),model:g.string(),temperature:g.number().optional(),maxTokens:g.number().optional()}),md=g.object({default:nt,strong:nt.optional(),fast:nt.optional(),embeddings:nt.optional(),local:nt.optional()}).passthrough(),pd=g.union([nt,md]),hd=g.object({provider:g.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:g.string().optional(),baseUrl:g.string().optional()}),Bi=g.object({name:g.string().optional(),provider:g.enum(["imap-smtp","microsoft"]).optional(),imap:g.object({host:g.string(),port:g.number(),secure:g.boolean()}).optional(),smtp:g.object({host:g.string(),port:g.number(),secure:g.boolean()}).optional(),auth:g.object({user:g.string(),pass:g.string()}).optional(),microsoft:g.object({clientId:g.string(),clientSecret:g.string(),tenantId:g.string(),refreshToken:g.string()}).optional()}),fd=g.union([g.object({accounts:g.array(Bi)}),Bi]),gd=g.object({provider:g.enum(["openai","groq","google"]),apiKey:g.string(),baseUrl:g.string().optional(),ttsEnabled:g.boolean().optional(),ttsModel:g.string().optional(),ttsVoice:g.string().optional()}),yd=g.object({serverUrl:g.string(),username:g.string(),password:g.string()}),wd=g.object({clientId:g.string(),clientSecret:g.string(),refreshToken:g.string()}),Td=g.object({clientId:g.string(),clientSecret:g.string(),tenantId:g.string(),refreshToken:g.string()}),_d=g.object({provider:g.enum(["caldav","google","microsoft"]),caldav:yd.optional(),google:wd.optional(),microsoft:Td.optional()}),Ed=g.object({name:g.string(),command:g.string().optional(),args:g.array(g.string()).optional(),env:g.record(g.string()).optional(),url:g.string().optional()}),bd=g.object({servers:g.array(Ed)}),$d=g.object({enabled:g.boolean(),allowedLanguages:g.array(g.enum(["javascript","python"])).optional(),maxTimeoutMs:g.number().optional(),allowNetwork:g.boolean().optional()}),vd=g.object({enabled:g.boolean().optional(),minMessageLength:g.number().optional(),minConfidence:g.number().min(0).max(1).optional(),maxExtractionsPerMinute:g.number().optional()}),Sd=g.object({enabled:g.boolean(),port:g.coerce.number().int().min(1).max(65535),host:g.string()}),kd=g.object({name:g.string(),command:g.string(),argsTemplate:g.array(g.string()),promptVia:g.enum(["arg","stdin"]).default("arg"),env:g.record(g.string()).optional(),cwd:g.string().optional(),timeoutMs:g.number().max(9e5).optional()}),Ad=g.object({token:g.string(),baseUrl:g.string().optional()}),Id=g.object({token:g.string(),baseUrl:g.string().optional()}),xd=g.object({provider:g.enum(["github","gitlab"]),baseBranch:g.string().optional(),github:Ad.optional(),gitlab:Id.optional()}),Rd=g.object({enabled:g.boolean(),agents:g.array(kd),forge:xd.optional()}),Cd=g.object({baseUrl:g.string(),tokenId:g.string(),tokenSecret:g.string(),verifyTls:g.boolean().optional(),defaultNode:g.string().optional()}),Ld=g.object({baseUrl:g.string(),apiKey:g.string().optional(),username:g.string().optional(),password:g.string().optional(),site:g.string().optional(),verifyTls:g.boolean().optional()}),Nd=g.object({baseUrl:g.string(),accessToken:g.string(),verifyTls:g.boolean().optional()}),Dd=g.object({serverUrl:g.string(),username:g.string(),password:g.string(),addressBookPath:g.string().optional()}),Md=g.object({clientId:g.string(),clientSecret:g.string(),refreshToken:g.string()}),Od=g.object({clientId:g.string(),clientSecret:g.string(),tenantId:g.string(),refreshToken:g.string()}),Pd=g.object({provider:g.enum(["carddav","google","microsoft"]),carddav:Dd.optional(),google:Md.optional(),microsoft:Od.optional()}),Ud=g.object({socketPath:g.string().optional(),host:g.string().optional(),verifyTls:g.boolean().optional()}),Fd=g.object({clientId:g.string()}),jd=g.object({apiKey:g.string()}),Bd=g.object({maxHistoryMessages:g.number().min(10).max(500).optional()}).optional(),Jo=g.object({name:g.string(),telegram:Hi,discord:qi.optional(),whatsapp:zi.optional(),matrix:Wi.optional(),signal:Vi.optional(),llm:pd,storage:Gi,logger:Ki,security:Xi,search:hd.optional(),email:fd.optional(),speech:gd.optional(),calendar:_d.optional(),mcp:bd.optional(),codeSandbox:$d.optional(),activeLearning:vd.optional(),api:Sd.optional(),codeAgents:Rd.optional(),proxmox:Cd.optional(),unifi:Ld.optional(),homeassistant:Nd.optional(),contacts:Pd.optional(),docker:Ud.optional(),bmw:Fd.optional(),routing:jd.optional(),conversation:Bd})});var Qo,en=E(()=>{"use strict";Qo={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 Yi from"node:fs";import Hd from"node:path";import{config as Ji}from"dotenv";import qd from"js-yaml";function Zi(c,e){let t={...c};for(let s of Object.keys(e)){let r=e[s],o=t[s];r!=null&&typeof r=="object"&&!Array.isArray(r)&&o!==null&&o!==void 0&&typeof o=="object"&&!Array.isArray(o)?t[s]=Zi(o,r):t[s]=r}return t}function Wd(c){let e={...c};for(let[t,s]of Object.entries(zd)){let r=process.env[t];if(r===void 0)continue;let o=e;for(let n=0;n<s.length-1;n++){let i=s[n];(o[i]===void 0||o[i]===null||typeof o[i]!="object")&&(o[i]={}),o[i]={...o[i]},o=o[i]}o[s[s.length-1]]=r}return e}function tn(){Ji({override:!0})}var zd,se,Qi=E(()=>{"use strict";Zo();en();u(Zi,"deepMerge");zd={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"]};u(Wd,"applyEnvOverrides");u(tn,"reloadDotenv");se=class{static{u(this,"ConfigLoader")}loadConfig(e){Ji();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Hd.resolve(t);if(Yi.existsSync(r)){let T=Yi.readFileSync(r,"utf-8"),y=qd.load(T);y&&typeof y=="object"&&(s=y)}let o=Zi(Qo,s),n=Wd(o),i=["strong","fast","embeddings","local"],a=n.llm;if(a&&"provider"in a&&i.some(y=>a[y]&&typeof a[y]=="object")){let y={};for(let[_,S]of Object.entries(a))!i.includes(_)&&_!=="default"&&(y[_]=S);let f={default:y};for(let _ of i)a[_]&&(f[_]=a[_]);n.llm=f}let l=Jo.parse(n),d=l.llm;d&&"provider"in d&&(l.llm={default:d});let m=l.llm;if(m&&typeof m=="object"){let T=m.apiKey??m.default?.apiKey;if(T)for(let y of["default","strong","fast","embeddings","local"]){let f=m[y];f&&!f.apiKey&&(f.apiKey=T)}}let p=l.email;if(p&&!("accounts"in p))l.email={accounts:[{name:"default",...p}]};else if(p&&"accounts"in p&&"microsoft"in p){let T=p.microsoft;if(T){let f=p.accounts.find(_=>_.provider==="microsoft");if(f){let _=f.microsoft??{};f.microsoft={..._,...T}}delete p.microsoft}}return l}}});var Be=E(()=>{"use strict";Zo();en();Qi()});import sn from"pino";function Es(c,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=sn.transport({target:"pino-pretty",options:{colorize:!0}});return sn({name:c,level:t},r)}return sn({name:c,level:t})}var ea=E(()=>{"use strict";u(Es,"createLogger")});import Vp from"pino";var ta=E(()=>{"use strict"});var rn=E(()=>{"use strict";ea();ta()});var St,Mr=E(()=>{"use strict";St=class{static{u(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
2
+ var ji=Object.defineProperty;var u=(c,e)=>ji(c,"name",{value:e,configurable:!0});var E=(c,e)=>()=>(c&&(e=c(c=0)),e);var oe=(c,e)=>{for(var t in e)ji(c,t,{get:e[t],enumerable:!0})};import{z as g}from"zod";var Hi,qi,zi,Wi,Vi,Gi,Ki,Xi,nt,md,pd,hd,Bi,fd,gd,yd,wd,Td,_d,Ed,bd,$d,vd,Sd,kd,Ad,Id,xd,Rd,Cd,Ld,Nd,Dd,Md,Od,Pd,Ud,Fd,jd,Bd,Jo,Zo=E(()=>{"use strict";Hi=g.object({token:g.string().optional(),enabled:g.boolean()}),qi=g.object({token:g.string().optional(),enabled:g.boolean()}),zi=g.object({enabled:g.boolean(),dataPath:g.string()}),Wi=g.object({homeserverUrl:g.string(),accessToken:g.string().optional(),userId:g.string().optional(),enabled:g.boolean()}),Vi=g.object({apiUrl:g.string(),phoneNumber:g.string().optional(),enabled:g.boolean()}),Gi=g.object({path:g.string()}),Ki=g.object({level:g.enum(["trace","debug","info","warn","error","fatal"]),pretty:g.boolean(),auditLogPath:g.string().optional()}),Xi=g.object({rulesPath:g.string(),defaultEffect:g.enum(["allow","deny"]),ownerUserId:g.string().optional()}),nt=g.object({provider:g.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:g.string().optional(),baseUrl:g.string().optional(),model:g.string(),temperature:g.number().optional(),maxTokens:g.number().optional()}),md=g.object({default:nt,strong:nt.optional(),fast:nt.optional(),embeddings:nt.optional(),local:nt.optional()}).passthrough(),pd=g.union([nt,md]),hd=g.object({provider:g.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:g.string().optional(),baseUrl:g.string().optional()}),Bi=g.object({name:g.string().optional(),provider:g.enum(["imap-smtp","microsoft"]).optional(),imap:g.object({host:g.string(),port:g.number(),secure:g.boolean()}).optional(),smtp:g.object({host:g.string(),port:g.number(),secure:g.boolean()}).optional(),auth:g.object({user:g.string(),pass:g.string()}).optional(),microsoft:g.object({clientId:g.string(),clientSecret:g.string(),tenantId:g.string(),refreshToken:g.string()}).optional()}),fd=g.union([g.object({accounts:g.array(Bi)}),Bi]),gd=g.object({provider:g.enum(["openai","groq","google"]),apiKey:g.string(),baseUrl:g.string().optional(),ttsEnabled:g.boolean().optional(),ttsModel:g.string().optional(),ttsVoice:g.string().optional()}),yd=g.object({serverUrl:g.string(),username:g.string(),password:g.string()}),wd=g.object({clientId:g.string(),clientSecret:g.string(),refreshToken:g.string()}),Td=g.object({clientId:g.string(),clientSecret:g.string(),tenantId:g.string(),refreshToken:g.string()}),_d=g.object({provider:g.enum(["caldav","google","microsoft"]),caldav:yd.optional(),google:wd.optional(),microsoft:Td.optional()}),Ed=g.object({name:g.string(),command:g.string().optional(),args:g.array(g.string()).optional(),env:g.record(g.string()).optional(),url:g.string().optional()}),bd=g.object({servers:g.array(Ed)}),$d=g.object({enabled:g.boolean(),allowedLanguages:g.array(g.enum(["javascript","python"])).optional(),maxTimeoutMs:g.number().optional(),allowNetwork:g.boolean().optional()}),vd=g.object({enabled:g.boolean().optional(),minMessageLength:g.number().optional(),minConfidence:g.number().min(0).max(1).optional(),maxExtractionsPerMinute:g.number().optional()}),Sd=g.object({enabled:g.boolean(),port:g.coerce.number().int().min(1).max(65535),host:g.string()}),kd=g.object({name:g.string(),command:g.string(),argsTemplate:g.array(g.string()),promptVia:g.enum(["arg","stdin"]).default("arg"),env:g.record(g.string()).optional(),cwd:g.string().optional(),timeoutMs:g.number().max(9e5).optional()}),Ad=g.object({token:g.string(),baseUrl:g.string().optional()}),Id=g.object({token:g.string(),baseUrl:g.string().optional()}),xd=g.object({provider:g.enum(["github","gitlab"]),baseBranch:g.string().optional(),github:Ad.optional(),gitlab:Id.optional()}),Rd=g.object({enabled:g.boolean(),agents:g.array(kd),forge:xd.optional()}),Cd=g.object({baseUrl:g.string(),tokenId:g.string(),tokenSecret:g.string(),verifyTls:g.boolean().optional(),defaultNode:g.string().optional()}),Ld=g.object({baseUrl:g.string(),apiKey:g.string().optional(),username:g.string().optional(),password:g.string().optional(),site:g.string().optional(),verifyTls:g.boolean().optional()}),Nd=g.object({baseUrl:g.string(),accessToken:g.string(),verifyTls:g.boolean().optional()}),Dd=g.object({serverUrl:g.string(),username:g.string(),password:g.string(),addressBookPath:g.string().optional()}),Md=g.object({clientId:g.string(),clientSecret:g.string(),refreshToken:g.string()}),Od=g.object({clientId:g.string(),clientSecret:g.string(),tenantId:g.string(),refreshToken:g.string()}),Pd=g.object({provider:g.enum(["carddav","google","microsoft"]),carddav:Dd.optional(),google:Md.optional(),microsoft:Od.optional()}),Ud=g.object({socketPath:g.string().optional(),host:g.string().optional(),verifyTls:g.boolean().optional()}),Fd=g.object({clientId:g.string()}),jd=g.object({apiKey:g.string()}),Bd=g.object({maxHistoryMessages:g.number().min(10).max(500).optional()}).optional(),Jo=g.object({name:g.string(),telegram:Hi,discord:qi.optional(),whatsapp:zi.optional(),matrix:Wi.optional(),signal:Vi.optional(),llm:pd,storage:Gi,logger:Ki,security:Xi,search:hd.optional(),email:fd.optional(),speech:gd.optional(),calendar:_d.optional(),mcp:bd.optional(),codeSandbox:$d.optional(),activeLearning:vd.optional(),api:Sd.optional(),codeAgents:Rd.optional(),proxmox:Cd.optional(),unifi:Ld.optional(),homeassistant:Nd.optional(),contacts:Pd.optional(),docker:Ud.optional(),bmw:Fd.optional(),routing:jd.optional(),conversation:Bd})});var Qo,en=E(()=>{"use strict";Qo={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 Yi from"node:fs";import Hd from"node:path";import{config as Ji}from"dotenv";import qd from"js-yaml";function Zi(c,e){let t={...c};for(let s of Object.keys(e)){let r=e[s],o=t[s];r!=null&&typeof r=="object"&&!Array.isArray(r)&&o!==null&&o!==void 0&&typeof o=="object"&&!Array.isArray(o)?t[s]=Zi(o,r):t[s]=r}return t}function Wd(c){let e={...c};for(let[t,s]of Object.entries(zd)){let r=process.env[t];if(r===void 0)continue;let o=e;for(let n=0;n<s.length-1;n++){let i=s[n];(o[i]===void 0||o[i]===null||typeof o[i]!="object")&&(o[i]={}),o[i]={...o[i]},o=o[i]}o[s[s.length-1]]=r}return e}function tn(){Ji({override:!0})}var zd,se,Qi=E(()=>{"use strict";Zo();en();u(Zi,"deepMerge");zd={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"]};u(Wd,"applyEnvOverrides");u(tn,"reloadDotenv");se=class{static{u(this,"ConfigLoader")}loadConfig(e){Ji();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Hd.resolve(t);if(Yi.existsSync(r)){let w=Yi.readFileSync(r,"utf-8"),y=qd.load(w);y&&typeof y=="object"&&(s=y)}let o=Zi(Qo,s),n=Wd(o),i=["strong","fast","embeddings","local"],a=n.llm;if(a&&"provider"in a&&i.some(y=>a[y]&&typeof a[y]=="object")){let y={};for(let[T,$]of Object.entries(a))!i.includes(T)&&T!=="default"&&(y[T]=$);let h={default:y};for(let T of i)a[T]&&(h[T]=a[T]);n.llm=h}let l=Jo.parse(n),d=l.llm;d&&"provider"in d&&(l.llm={default:d});let m=l.llm;if(m&&typeof m=="object"){let w=m.apiKey??m.default?.apiKey;if(w)for(let y of["default","strong","fast","embeddings","local"]){let h=m[y];h&&!h.apiKey&&(h.apiKey=w)}}let p=l.email;if(p&&!("accounts"in p))l.email={accounts:[{name:"default",...p}]};else if(p&&"accounts"in p&&"microsoft"in p){let w=p.microsoft;if(w){let h=p.accounts.find(T=>T.provider==="microsoft");if(h){let T=h.microsoft??{};h.microsoft={...T,...w}}delete p.microsoft}}return l}}});var Be=E(()=>{"use strict";Zo();en();Qi()});import sn from"pino";function Es(c,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=sn.transport({target:"pino-pretty",options:{colorize:!0}});return sn({name:c,level:t},r)}return sn({name:c,level:t})}var ea=E(()=>{"use strict";u(Es,"createLogger")});import Vp from"pino";var ta=E(()=>{"use strict"});var rn=E(()=>{"use strict";ea();ta()});var St,Mr=E(()=>{"use strict";St=class{static{u(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,
@@ -283,7 +283,7 @@ var ji=Object.defineProperty;var u=(c,e)=>ji(c,"name",{value:e,configurable:!0})
283
283
  type = excluded.type,
284
284
  confidence = excluded.confidence,
285
285
  source = excluded.source,
286
- updated_at = excluded.updated_at`).run(l,e,t,s,r,o,n,i,a,a);let d=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);return this.mapRow(d)}recall(e,t){let s=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);if(s)return this.mapRow(s)}search(e,t){let s=`%${t}%`;return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND (key LIKE ? OR value LIKE ?) ORDER BY updated_at DESC").all(e,s,s).map(o=>this.mapRow(o))}keywordSearch(e,t,s=20){let r=t.toLowerCase().split(/\s+/).filter(l=>l.length>=2);if(r.length===0)return[];let o=r.map(()=>"(LOWER(key) LIKE ? OR LOWER(value) LIKE ?)").join(" OR "),n=[e];for(let l of r)n.push(`%${l}%`,`%${l}%`);let a=this.db.prepare(`SELECT * FROM memories WHERE user_id = ? AND (${o}) ORDER BY updated_at DESC`).all(...n).map(l=>{let d=this.mapRow(l),m=`${d.key} ${d.value}`.toLowerCase(),p=0;for(let T of r)m.includes(T)&&(p+=1);return{entry:d,score:p/r.length}});return a.sort((l,d)=>d.score-l.score),a.slice(0,s).map(l=>l.entry)}recordAccess(e){let t=new Date().toISOString();this.db.prepare("UPDATE memories SET last_accessed_at = ?, access_count = access_count + 1 WHERE id = ?").run(t,e)}findStale(e,t,s){let r=new Date(Date.now()-t*24*60*60*1e3).toISOString();return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND updated_at < ? AND confidence <= ? ORDER BY confidence ASC").all(e,r,s).map(n=>this.mapRow(n))}deleteByIds(e){if(e.length===0)return 0;let t=e.map(()=>"?").join(",");return this.db.prepare(`DELETE FROM memories WHERE id IN (${t})`).run(...e).changes}listByCategory(e,t){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND category = ? ORDER BY updated_at DESC").all(e,t).map(r=>this.mapRow(r))}listAll(e){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC").all(e).map(s=>this.mapRow(s))}delete(e,t){return this.db.prepare("DELETE FROM memories WHERE user_id = ? AND key = ?").run(e,t).changes>0}getRecentForPrompt(e,t=20){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}mapRow(e){return{id:e.id,userId:e.user_id,key:e.key,value:e.value,category:e.category||"general",type:e.type||"general",confidence:e.confidence??1,source:e.source||"manual",lastAccessedAt:e.last_accessed_at||null,accessCount:e.access_count??0,createdAt:e.created_at,updatedAt:e.updated_at}}}});import{randomUUID as Jd}from"node:crypto";var Ss,ca=E(()=>{"use strict";Ss=class{static{u(this,"ReminderRepository")}db;constructor(e){this.db=e}create(e,t,s,r,o){let n={id:Jd(),userId:e,platform:t,chatId:s,message:r,triggerAt:o.toISOString(),createdAt:new Date().toISOString(),fired:!1};return this.db.prepare(`
286
+ updated_at = excluded.updated_at`).run(l,e,t,s,r,o,n,i,a,a);let d=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);return this.mapRow(d)}recall(e,t){let s=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);if(s)return this.mapRow(s)}search(e,t){let s=`%${t}%`;return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND (key LIKE ? OR value LIKE ?) ORDER BY updated_at DESC").all(e,s,s).map(o=>this.mapRow(o))}keywordSearch(e,t,s=20){let r=t.toLowerCase().split(/\s+/).filter(l=>l.length>=2);if(r.length===0)return[];let o=r.map(()=>"(LOWER(key) LIKE ? OR LOWER(value) LIKE ?)").join(" OR "),n=[e];for(let l of r)n.push(`%${l}%`,`%${l}%`);let a=this.db.prepare(`SELECT * FROM memories WHERE user_id = ? AND (${o}) ORDER BY updated_at DESC`).all(...n).map(l=>{let d=this.mapRow(l),m=`${d.key} ${d.value}`.toLowerCase(),p=0;for(let w of r)m.includes(w)&&(p+=1);return{entry:d,score:p/r.length}});return a.sort((l,d)=>d.score-l.score),a.slice(0,s).map(l=>l.entry)}recordAccess(e){let t=new Date().toISOString();this.db.prepare("UPDATE memories SET last_accessed_at = ?, access_count = access_count + 1 WHERE id = ?").run(t,e)}findStale(e,t,s){let r=new Date(Date.now()-t*24*60*60*1e3).toISOString();return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND updated_at < ? AND confidence <= ? ORDER BY confidence ASC").all(e,r,s).map(n=>this.mapRow(n))}deleteByIds(e){if(e.length===0)return 0;let t=e.map(()=>"?").join(",");return this.db.prepare(`DELETE FROM memories WHERE id IN (${t})`).run(...e).changes}listByCategory(e,t){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND category = ? ORDER BY updated_at DESC").all(e,t).map(r=>this.mapRow(r))}listAll(e){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC").all(e).map(s=>this.mapRow(s))}delete(e,t){return this.db.prepare("DELETE FROM memories WHERE user_id = ? AND key = ?").run(e,t).changes>0}getRecentForPrompt(e,t=20){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}mapRow(e){return{id:e.id,userId:e.user_id,key:e.key,value:e.value,category:e.category||"general",type:e.type||"general",confidence:e.confidence??1,source:e.source||"manual",lastAccessedAt:e.last_accessed_at||null,accessCount:e.access_count??0,createdAt:e.created_at,updatedAt:e.updated_at}}}});import{randomUUID as Jd}from"node:crypto";var Ss,ca=E(()=>{"use strict";Ss=class{static{u(this,"ReminderRepository")}db;constructor(e){this.db=e}create(e,t,s,r,o){let n={id:Jd(),userId:e,platform:t,chatId:s,message:r,triggerAt:o.toISOString(),createdAt:new Date().toISOString(),fired:!1};return this.db.prepare(`
287
287
  INSERT INTO reminders (id, user_id, platform, chat_id, message, trigger_at, created_at, fired)
288
288
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
289
289
  `).run(n.id,n.userId,n.platform,n.chatId,n.message,n.triggerAt,n.createdAt,0),n}getDue(){let e=new Date().toISOString();return this.db.prepare("SELECT * FROM reminders WHERE fired = 0 AND trigger_at <= ? ORDER BY trigger_at ASC").all(e).map(s=>this.mapRow(s))}getByUser(e){return this.db.prepare("SELECT * FROM reminders WHERE fired = 0 AND user_id = ? ORDER BY trigger_at ASC").all(e).map(s=>this.mapRow(s))}markFired(e){this.db.prepare("UPDATE reminders SET fired = 1 WHERE id = ?").run(e)}cancel(e){return this.db.prepare("DELETE FROM reminders WHERE id = ?").run(e).changes>0}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,message:e.message,triggerAt:e.trigger_at,createdAt:e.created_at,fired:e.fired===1}}}});import{randomUUID as Zd}from"node:crypto";var ks,la=E(()=>{"use strict";ks=class{static{u(this,"NoteRepository")}db;constructor(e){this.db=e}save(e,t,s){let r=new Date().toISOString(),o=Zd();return this.db.prepare("INSERT INTO notes (id, user_id, title, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").run(o,e,t,s,r,r),{id:o,userId:e,title:t,content:s,createdAt:r,updatedAt:r}}getById(e){let t=this.db.prepare("SELECT * FROM notes WHERE id = ?").get(e);return t?this.mapRow(t):void 0}list(e,t=50){return this.db.prepare("SELECT * FROM notes WHERE user_id = ? ORDER BY updated_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}search(e,t){let s=`%${t}%`;return this.db.prepare("SELECT * FROM notes WHERE user_id = ? AND (title LIKE ? OR content LIKE ?) ORDER BY updated_at DESC").all(e,s,s).map(o=>this.mapRow(o))}update(e,t,s){let r=this.getById(e);if(!r)return;let o=new Date().toISOString(),n=t??r.title,i=s??r.content;return this.db.prepare("UPDATE notes SET title = ?, content = ?, updated_at = ? WHERE id = ?").run(n,i,o,e),{...r,title:n,content:i,updatedAt:o}}delete(e){return this.db.prepare("DELETE FROM notes WHERE id = ?").run(e).changes>0}mapRow(e){return{id:e.id,userId:e.user_id,title:e.title,content:e.content,createdAt:e.created_at,updatedAt:e.updated_at}}}});import{randomUUID as Qd}from"node:crypto";var As,da=E(()=>{"use strict";As=class{static{u(this,"EmbeddingRepository")}db;constructor(e){this.db=e}store(e){let t=Qd(),s=new Date().toISOString(),r=Buffer.from(new Float32Array(e.embedding).buffer);return this.db.transaction(()=>{this.db.prepare("DELETE FROM embeddings WHERE user_id = ? AND source_type = ? AND source_id = ?").run(e.userId,e.sourceType,e.sourceId),this.db.prepare("INSERT INTO embeddings (id, user_id, source_type, source_id, content, embedding, model, dimensions, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(t,e.userId,e.sourceType,e.sourceId,e.content,r,e.model,e.dimensions,s)})(),{id:t,userId:e.userId,sourceType:e.sourceType,sourceId:e.sourceId,content:e.content,embedding:e.embedding,model:e.model,dimensions:e.dimensions,createdAt:s}}findByUser(e){return this.db.prepare("SELECT * FROM embeddings WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapRow(s))}findBySource(e,t){let s=this.db.prepare("SELECT * FROM embeddings WHERE source_type = ? AND source_id = ?").get(e,t);if(s)return this.mapRow(s)}delete(e,t){return this.db.prepare("DELETE FROM embeddings WHERE source_type = ? AND source_id = ?").run(e,t).changes>0}mapRow(e){let t=e.embedding,s=new Float32Array(t.buffer,t.byteOffset,t.byteLength/4),r=Array.from(s);return{id:e.id,userId:e.user_id,sourceType:e.source_type,sourceId:e.source_id,content:e.content,embedding:r,model:e.model,dimensions:e.dimensions,createdAt:e.created_at}}}});import eu from"node:crypto";var Is,ua=E(()=>{"use strict";Is=class{static{u(this,"LinkTokenRepository")}db;constructor(e){this.db=e}create(e,t){for(let s=0;s<5;s++){let r={id:eu.randomUUID(),code:String(Math.floor(1e5+Math.random()*9e5)),userId:e,platform:t,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+6e5).toISOString()};try{return this.db.prepare(`
@@ -320,8 +320,8 @@ var ji=Object.defineProperty;var u=(c,e)=>ji(c,"name",{value:e,configurable:!0})
320
320
  SUM(CASE WHEN completed = 0 THEN 1 ELSE 0 END) as open,
321
321
  SUM(CASE WHEN completed = 1 THEN 1 ELSE 0 END) as completed,
322
322
  COUNT(*) as total
323
- FROM todos WHERE user_id = ? GROUP BY list ORDER BY list`).all(e).map(s=>({list:s.list,open:Number(s.open),completed:Number(s.completed),total:Number(s.total)}))}mapRow(e){return{id:e.id,userId:e.user_id,list:e.list,title:e.title,description:e.description,priority:e.priority,dueDate:e.due_date,completed:e.completed===1,createdAt:e.created_at,updatedAt:e.updated_at}}}});var an=E(()=>{"use strict";sa();oa();na();ia();aa();Mr();nn();ca();la();da();ua();ma();pa();fa();ga()});function ct(c){if(cn[c])return cn[c];let e=Object.entries(cn).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(c.startsWith(t))return s}var cn,ou,Ie,kt=E(()=>{"use strict";cn={"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},"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-latest":{maxInputTokens:256e3,maxOutputTokens:8192},"mistral-medium-latest":{maxInputTokens:128e3,maxOutputTokens:8192},"mistral-small-latest":{maxInputTokens:128e3,maxOutputTokens:8192},"codestral-latest":{maxInputTokens:256e3,maxOutputTokens:8192},"magistral-medium-latest":{maxInputTokens:4e4,maxOutputTokens:8192},"magistral-small-latest":{maxInputTokens:4e4,maxOutputTokens:8192},"ministral-8b-latest":{maxInputTokens:128e3,maxOutputTokens:4096},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},mistral:{maxInputTokens:32e3,maxOutputTokens:4096},"mistral-small":{maxInputTokens:32e3,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}},ou={maxInputTokens:128e3,maxOutputTokens:8192};u(ct,"lookupContextWindow");Ie=class{static{u(this,"LLMProvider")}config;contextWindow=ou;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import nu from"@anthropic-ai/sdk";var Ns,ln=E(()=>{"use strict";kt();Ns=class extends Ie{static{u(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new nu({apiKey:this.config.apiKey,maxRetries:5});let e=ct(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,messages:t,tools:s},o=await this.client.messages.create(r);return this.mapResponse(o)}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,messages:t,tools:s});for await(let o of r)if(o.type==="content_block_delta")o.delta.type==="text_delta"?yield{type:"text_delta",text:o.delta.text}:o.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:o.delta.partial_json}});else if(o.type==="content_block_start")o.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:o.content_block.id,name:o.content_block.name}});else if(o.type==="message_stop"){let n=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(n)}}}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){return e.map(t=>({name:t.name,description:t.description,input_schema:t.inputSchema}))}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,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens},stopReason:e.stop_reason}}}});import iu from"openai";var be,lt=E(()=>{"use strict";kt();be=class extends Ie{static{u(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new iu({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=ct(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,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,messages:t,...s?{tools:s}:{}},o=await this.client.chat.completions.create(r);return this.mapResponse(o)}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,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,messages:t,...s?{tools:s}:{},stream:!0}),o,n,i="",a="",l=[],d=null,m=0,p=0;for await(let T of r){let y=T.choices[0];if(!y)continue;let f=y.delta;if(f?.content&&(a+=f.content,yield{type:"text_delta",text:f.content}),f?.tool_calls)for(let _ of f.tool_calls)if(_.id){if(o){let S;try{S=JSON.parse(i||"{}")}catch{S={}}l.push({id:o,name:n,input:S})}o=_.id,n=_.function?.name,i=_.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:o,name:n}}}else _.function?.arguments&&(i+=_.function.arguments,yield{type:"tool_use_delta",toolCall:{input:_.function.arguments}});y.finish_reason&&(d=y.finish_reason),T.usage&&(m=T.usage.prompt_tokens,p=T.usage.completion_tokens)}if(o){let T;try{T=JSON.parse(i||"{}")}catch{T={}}l.push({id:o,name:n,input:T})}yield{type:"message_complete",response:{content:a,toolCalls:l.length>0?l:void 0,usage:{inputTokens:m,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}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 o=[],n=[],i=[];for(let a of r.content)switch(a.type){case"text":o.push({type:"text",text:a.text});break;case"image":o.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":n.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"&&n.length>0){let a=o.map(l=>l.text).join("");s.push({role:"assistant",content:a||null,tool_calls:n})}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 o.length>0&&(r.role==="user"?s.push({role:"user",content:o}):s.push({role:r.role,content:o.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??"",o=s?.tool_calls?.map(n=>({id:n.id,name:n.function.name,input:(()=>{try{return JSON.parse(n.function.arguments)}catch{return{}}})()}));return{content:r,toolCalls:o&&o.length>0?o: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 Ds,dn=E(()=>{"use strict";lt();Ds=class extends be{static{u(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Ms,un=E(()=>{"use strict";kt();Ms=class extends Ie{static{u(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=ct(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(n=>n.includes("context_length")||n==="num_ctx"),o=r?Number(s[r]):0;o>0&&(this.contextWindow={maxInputTokens:o,maxOutputTokens:Math.min(o,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 o=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!o.ok){let i=await o.text();throw new Error(`Ollama API error (${o.status}): ${i}`)}let n=await o.json();return this.mapResponse(n)}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 o=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!o.ok){let T=await o.text();throw new Error(`Ollama API error (${o.status}): ${T}`)}if(!o.body)throw new Error("Ollama streaming response has no body");let n=o.body.getReader(),i=new TextDecoder,a="",l="",d=0,m=0,p=[];try{for(;;){let{done:T,value:y}=await n.read();if(T)break;a+=i.decode(y,{stream:!0});let f=a.split(`
324
- `);a=f.pop()??"";for(let _ of f){let S=_.trim();if(!S)continue;let A;try{A=JSON.parse(S)}catch{continue}if(A.message?.content&&(l+=A.message.content,yield{type:"text_delta",text:A.message.content}),A.message?.tool_calls)for(let I of A.message.tool_calls){let P={id:`ollama_tool_${p.length}`,name:I.function.name,input:I.function.arguments};p.push(P),yield{type:"tool_use_start",toolCall:{id:P.id,name:P.name}},yield{type:"tool_use_delta",toolCall:{input:P.input}}}A.done&&(d=A.prompt_eval_count??0,m=A.eval_count??0,yield{type:"message_complete",response:{content:l,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:m},stopReason:p.length>0?"tool_use":"end_turn"}})}}if(a.trim()){let T;try{T=JSON.parse(a.trim())}catch{return}if(T.message?.content&&(l+=T.message.content,yield{type:"text_delta",text:T.message.content}),T.message?.tool_calls)for(let y of T.message.tool_calls){let f={id:`ollama_tool_${p.length}`,name:y.function.name,input:y.function.arguments};p.push(f),yield{type:"tool_use_start",toolCall:{id:f.id,name:f.name}},yield{type:"tool_use_delta",toolCall:{input:f.input}}}T.done&&(d=T.prompt_eval_count??0,m=T.eval_count??0,yield{type:"message_complete",response:{content:l,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:m},stopReason:p.length>0?"tool_use":"end_turn"}})}}finally{n.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 n of t)switch(n.type){case"text":s.push(n.text);break;case"image":r.push(n.source.data);break;case"tool_use":s.push(`[Tool call: ${n.name}(${JSON.stringify(n.input)})]`);break;case"tool_result":s.push(`[Tool result for ${n.tool_use_id}]: ${n.content}`);break}let o={role:e,content:s.join(`
323
+ FROM todos WHERE user_id = ? GROUP BY list ORDER BY list`).all(e).map(s=>({list:s.list,open:Number(s.open),completed:Number(s.completed),total:Number(s.total)}))}mapRow(e){return{id:e.id,userId:e.user_id,list:e.list,title:e.title,description:e.description,priority:e.priority,dueDate:e.due_date,completed:e.completed===1,createdAt:e.created_at,updatedAt:e.updated_at}}}});var an=E(()=>{"use strict";sa();oa();na();ia();aa();Mr();nn();ca();la();da();ua();ma();pa();fa();ga()});function ct(c){if(cn[c])return cn[c];let e=Object.entries(cn).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(c.startsWith(t))return s}var cn,ou,Ie,kt=E(()=>{"use strict";cn={"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},"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-latest":{maxInputTokens:256e3,maxOutputTokens:8192},"mistral-medium-latest":{maxInputTokens:128e3,maxOutputTokens:8192},"mistral-small-latest":{maxInputTokens:128e3,maxOutputTokens:8192},"codestral-latest":{maxInputTokens:256e3,maxOutputTokens:8192},"magistral-medium-latest":{maxInputTokens:4e4,maxOutputTokens:8192},"magistral-small-latest":{maxInputTokens:4e4,maxOutputTokens:8192},"ministral-8b-latest":{maxInputTokens:128e3,maxOutputTokens:4096},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},mistral:{maxInputTokens:32e3,maxOutputTokens:4096},"mistral-small":{maxInputTokens:32e3,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}},ou={maxInputTokens:128e3,maxOutputTokens:8192};u(ct,"lookupContextWindow");Ie=class{static{u(this,"LLMProvider")}config;contextWindow=ou;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import nu from"@anthropic-ai/sdk";var Ns,ln=E(()=>{"use strict";kt();Ns=class extends Ie{static{u(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new nu({apiKey:this.config.apiKey,maxRetries:5});let e=ct(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,messages:t,tools:s},o=await this.client.messages.create(r);return this.mapResponse(o)}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,messages:t,tools:s});for await(let o of r)if(o.type==="content_block_delta")o.delta.type==="text_delta"?yield{type:"text_delta",text:o.delta.text}:o.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:o.delta.partial_json}});else if(o.type==="content_block_start")o.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:o.content_block.id,name:o.content_block.name}});else if(o.type==="message_stop"){let n=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(n)}}}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){return e.map(t=>({name:t.name,description:t.description,input_schema:t.inputSchema}))}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,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens},stopReason:e.stop_reason}}}});import iu from"openai";var be,lt=E(()=>{"use strict";kt();be=class extends Ie{static{u(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new iu({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=ct(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,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,messages:t,...s?{tools:s}:{}},o=await this.client.chat.completions.create(r);return this.mapResponse(o)}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,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,messages:t,...s?{tools:s}:{},stream:!0}),o,n,i="",a="",l=[],d=null,m=0,p=0;for await(let w of r){let y=w.choices[0];if(!y)continue;let h=y.delta;if(h?.content&&(a+=h.content,yield{type:"text_delta",text:h.content}),h?.tool_calls)for(let T of h.tool_calls)if(T.id){if(o){let $;try{$=JSON.parse(i||"{}")}catch{$={}}l.push({id:o,name:n,input:$})}o=T.id,n=T.function?.name,i=T.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:o,name:n}}}else T.function?.arguments&&(i+=T.function.arguments,yield{type:"tool_use_delta",toolCall:{input:T.function.arguments}});y.finish_reason&&(d=y.finish_reason),w.usage&&(m=w.usage.prompt_tokens,p=w.usage.completion_tokens)}if(o){let w;try{w=JSON.parse(i||"{}")}catch{w={}}l.push({id:o,name:n,input:w})}yield{type:"message_complete",response:{content:a,toolCalls:l.length>0?l:void 0,usage:{inputTokens:m,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}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 o=[],n=[],i=[];for(let a of r.content)switch(a.type){case"text":o.push({type:"text",text:a.text});break;case"image":o.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":n.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"&&n.length>0){let a=o.map(l=>l.text).join("");s.push({role:"assistant",content:a||null,tool_calls:n})}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 o.length>0&&(r.role==="user"?s.push({role:"user",content:o}):s.push({role:r.role,content:o.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??"",o=s?.tool_calls?.map(n=>({id:n.id,name:n.function.name,input:(()=>{try{return JSON.parse(n.function.arguments)}catch{return{}}})()}));return{content:r,toolCalls:o&&o.length>0?o: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 Ds,dn=E(()=>{"use strict";lt();Ds=class extends be{static{u(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Ms,un=E(()=>{"use strict";kt();Ms=class extends Ie{static{u(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=ct(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(n=>n.includes("context_length")||n==="num_ctx"),o=r?Number(s[r]):0;o>0&&(this.contextWindow={maxInputTokens:o,maxOutputTokens:Math.min(o,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 o=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!o.ok){let i=await o.text();throw new Error(`Ollama API error (${o.status}): ${i}`)}let n=await o.json();return this.mapResponse(n)}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 o=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!o.ok){let w=await o.text();throw new Error(`Ollama API error (${o.status}): ${w}`)}if(!o.body)throw new Error("Ollama streaming response has no body");let n=o.body.getReader(),i=new TextDecoder,a="",l="",d=0,m=0,p=[];try{for(;;){let{done:w,value:y}=await n.read();if(w)break;a+=i.decode(y,{stream:!0});let h=a.split(`
324
+ `);a=h.pop()??"";for(let T of h){let $=T.trim();if(!$)continue;let A;try{A=JSON.parse($)}catch{continue}if(A.message?.content&&(l+=A.message.content,yield{type:"text_delta",text:A.message.content}),A.message?.tool_calls)for(let I of A.message.tool_calls){let P={id:`ollama_tool_${p.length}`,name:I.function.name,input:I.function.arguments};p.push(P),yield{type:"tool_use_start",toolCall:{id:P.id,name:P.name}},yield{type:"tool_use_delta",toolCall:{input:P.input}}}A.done&&(d=A.prompt_eval_count??0,m=A.eval_count??0,yield{type:"message_complete",response:{content:l,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:m},stopReason:p.length>0?"tool_use":"end_turn"}})}}if(a.trim()){let w;try{w=JSON.parse(a.trim())}catch{return}if(w.message?.content&&(l+=w.message.content,yield{type:"text_delta",text:w.message.content}),w.message?.tool_calls)for(let y of w.message.tool_calls){let h={id:`ollama_tool_${p.length}`,name:y.function.name,input:y.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}}}w.done&&(d=w.prompt_eval_count??0,m=w.eval_count??0,yield{type:"message_complete",response:{content:l,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:m},stopReason:p.length>0?"tool_use":"end_turn"}})}}finally{n.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 n of t)switch(n.type){case"text":s.push(n.text);break;case"image":r.push(n.source.data);break;case"tool_use":s.push(`[Tool call: ${n.name}(${JSON.stringify(n.input)})]`);break;case"tool_result":s.push(`[Tool result for ${n.tool_use_id}]: ${n.content}`);break}let o={role:e,content:s.join(`
325
325
  `)};return r.length>0&&(o.images=r),o}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,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 Os,mn=E(()=>{"use strict";lt();Os=class extends be{static{u(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});var Ps,pn=E(()=>{"use strict";lt();Ps=class extends be{static{u(this,"GoogleProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://generativelanguage.googleapis.com/v1beta/openai/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Us,hn=E(()=>{"use strict";lt();Us=class extends be{static{u(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function fn(c){switch(c.provider){case"anthropic":return new Ns(c);case"openai":return new be(c);case"openrouter":return new Ds(c);case"ollama":return new Ms(c);case"openwebui":return new Os(c);case"google":return new Ps(c);case"mistral":return new Us(c);default:throw new Error(`Unknown LLM provider: ${c.provider}`)}}var gn=E(()=>{"use strict";ln();lt();dn();un();mn();pn();hn();u(fn,"createLLMProvider")});function yn(c,e){return new Or(c,e)}var au,Or,ya=E(()=>{"use strict";kt();gn();au=["default","strong","fast","embeddings","local"],Or=class extends Ie{static{u(this,"ModelRouter")}providers=new Map;multiConfig;logger;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of au){let t=this.multiConfig[e];if(t){let s=fn(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 o=await t.complete(e);return this.logger?.info({tier:s,model:r?.model,inputTokens:o.usage?.inputTokens,outputTokens:o.usage?.outputTokens},"LLM call completed"),o}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()}};u(yn,"createModelRouter")});function xe(c){return Math.ceil(c.length/3.5)}function js(c){if(typeof c.content=="string")return xe(c.content)+4;let e=4;for(let t of c.content)switch(t.type){case"text":e+=xe(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=xe(t.name)+xe(JSON.stringify(t.input));break;case"tool_result":e+=xe(t.content);break}return e}var Fs,wa=E(()=>{"use strict";u(xe,"estimateTokens");u(js,"estimateMessageTokens");Fs=class{static{u(this,"PromptBuilder")}buildSystemPrompt(e={}){let{memories:t,skills:s,userProfile:r,todayEvents:o}=e,n=process.platform==="darwin"?"macOS":process.platform==="win32"?"Windows":"Linux",i=process.env.HOME||process.env.USERPROFILE||"~",a=`You are Alfred, a personal AI assistant. You run on ${n} (home: ${i}).
326
326
 
327
327
  ## Core principles
@@ -351,17 +351,17 @@ For complex tasks, work through multiple steps:
351
351
  - Home: ${i}
352
352
  - Documents: ${i}/Documents
353
353
  - Desktop: ${i}/Desktop
354
- - Downloads: ${i}/Downloads`,l=Intl.DateTimeFormat().resolvedOptions().timeZone,d=r?.timezone||l,m=new Date,p=m.toLocaleTimeString("en-GB",{timeZone:d,hour:"2-digit",minute:"2-digit"}),T=m.toLocaleDateString("en-CA",{timeZone:d}),y=m.toLocaleDateString("en-US",{timeZone:d,weekday:"long"});if(a+=`
354
+ - Downloads: ${i}/Downloads`,l=Intl.DateTimeFormat().resolvedOptions().timeZone,d=r?.timezone||l,m=new Date,p=m.toLocaleTimeString("en-GB",{timeZone:d,hour:"2-digit",minute:"2-digit"}),w=m.toLocaleDateString("en-CA",{timeZone:d}),y=m.toLocaleDateString("en-US",{timeZone:d,weekday:"long"});if(a+=`
355
355
 
356
356
  ## Current date & time`,a+=`
357
357
  - Timezone: ${d}`,a+=`
358
- - Date: ${T} (${y})`,a+=`
358
+ - Date: ${w} (${y})`,a+=`
359
359
  - Time: ${p}`,r?.timezone&&r.timezone!==l&&(a+=`
360
360
  - Server timezone: ${l}`),s&&s.length>0){a+=`
361
361
 
362
362
  ## Available tools
363
- `;for(let f of s)a+=`- **${f.name}** (${f.riskLevel}): ${f.description}
364
- `;s.some(f=>f.name==="code_agent")&&(a+='\n## Code agent delegation\nWhen the user asks you to **write code, edit files, fix bugs, refactor, implement features, or perform any coding task**, you MUST delegate to the `code_agent` tool instead of doing it yourself. You are an orchestrator, not a coder.\n\n- For **single, focused tasks**: use `code_agent` with `action: "run"` and pick the best agent.\n- For **complex, multi-step tasks**: use `code_agent` with `action: "orchestrate"` \u2014 the system will decompose the task, run agents in parallel, and validate results.\n- Add `git: true` when the user wants the changes committed, pushed, and a PR/MR created.\n- Use `action: "list_agents"` if you\'re unsure which agents are available.\n\n**Do NOT** attempt to write code or edit files yourself through conversation. Always delegate to a code agent.')}if(r&&(a+=`
363
+ `;for(let h of s)a+=`- **${h.name}** (${h.riskLevel}): ${h.description}
364
+ `;s.some(h=>h.name==="code_agent")&&(a+='\n## Code agent delegation\nWhen the user asks you to **write code, edit files, fix bugs, refactor, implement features, or perform any coding task**, you MUST delegate to the `code_agent` tool instead of doing it yourself. You are an orchestrator, not a coder.\n\n- For **single, focused tasks**: use `code_agent` with `action: "run"` and pick the best agent.\n- For **complex, multi-step tasks**: use `code_agent` with `action: "orchestrate"` \u2014 the system will decompose the task, run agents in parallel, and validate results.\n- Add `git: true` when the user wants the changes committed, pushed, and a PR/MR created.\n- Use `action: "list_agents"` if you\'re unsure which agents are available.\n\n**Do NOT** attempt to write code or edit files yourself through conversation. Always delegate to a code agent.')}if(r&&(a+=`
365
365
 
366
366
  ## User profile`,r.displayName&&(a+=`
367
367
  - Name: ${r.displayName}`),r.timezone&&(a+=`
@@ -369,24 +369,24 @@ For complex tasks, work through multiple steps:
369
369
  - Language: ${r.language}`),r.bio&&(a+=`
370
370
  - Bio: ${r.bio}`)),o&&o.length>0){a+=`
371
371
 
372
- ## Today's events`;for(let f of o){let _=f.allDay?"All day":f.start.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...r?.timezone?{timeZone:r.timezone}:{}}),S=f.allDay?"":`-${f.end.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...r?.timezone?{timeZone:r.timezone}:{}})}`,A=f.location?` @ ${f.location}`:"";a+=`
373
- - ${_}${S}: ${f.title}${A}`}}if(t&&t.length>0){if(a+=`
372
+ ## Today's events`;for(let h of o){let T=h.allDay?"All day":h.start.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...r?.timezone?{timeZone:r.timezone}:{}}),$=h.allDay?"":`-${h.end.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...r?.timezone?{timeZone:r.timezone}:{}})}`,A=h.location?` @ ${h.location}`:"";a+=`
373
+ - ${T}${$}: ${h.title}${A}`}}if(t&&t.length>0){if(a+=`
374
374
 
375
375
  ## Memories about this user
376
- `,t.some(_=>_.type&&_.type!=="general")){let _=new Map;for(let A of t){let I=A.type||"general",P=_.get(I);P||(P=[],_.set(I,P)),P.push(A)}let S={fact:"Facts",preference:"Preferences",correction:"Corrections",entity:"Entities",decision:"Decisions",relationship:"Relationships",principle:"Principles",commitment:"Commitments",moment:"Moments",skill:"Skills",general:"General"};for(let[A,I]of _){a+=`
377
- ### ${S[A]||A}
376
+ `,t.some(T=>T.type&&T.type!=="general")){let T=new Map;for(let A of t){let I=A.type||"general",P=T.get(I);P||(P=[],T.set(I,P)),P.push(A)}let $={fact:"Facts",preference:"Preferences",correction:"Corrections",entity:"Entities",decision:"Decisions",relationship:"Relationships",principle:"Principles",commitment:"Commitments",moment:"Moments",skill:"Skills",general:"General"};for(let[A,I]of T){a+=`
377
+ ### ${$[A]||A}
378
378
  `;for(let P of I)a+=`- ${P.key}: ${P.value}
379
- `}}else for(let _ of t)a+=`- [${_.category}] ${_.key}: ${_.value}
379
+ `}}else for(let T of t)a+=`- [${T.category}] ${T.key}: ${T.value}
380
380
  `;a+=`
381
381
  Use these memories to personalize your responses. When the user tells you new facts or preferences, use the memory tool to save them.`}else a+=`
382
382
 
383
- When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return a}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 l of i)a.push({type:"tool_use",id:l.id,name:l.name,input:l.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let o=r,n=[];for(let i of o)i.type==="tool_result"&&n.push(i);return n.length>0?{role:"user",content:n}:{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 l of a.content)l.type==="tool_use"&&t.add(l.id);else if(a.role==="user"&&Array.isArray(a.content))for(let l of a.content)l.type==="tool_result"&&t.has(l.tool_use_id)&&s.add(l.tool_use_id);let r=new Set,o=new Set,n=[];for(let a of e){if(!Array.isArray(a.content)){n.push(a);continue}let l=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)||o.has(d.tool_use_id)?!1:(o.add(d.tool_use_id),!0):!0);l.length!==0&&n.push({...a,content:l})}let i=[];for(let a of n){let l=i[i.length-1];if(l&&l.role===a.role){let d=typeof l.content=="string"?[{type:"text",text:l.content}]:l.content,m=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...l,content:[...d,...m]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var wn=E(()=>{"use strict";kt();ln();lt();dn();un();mn();pn();hn();gn();ya();wa()});var Bs,Tn=E(()=>{"use strict";Bs=class{static{u(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,o=this.buckets.get(e);if(!o)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>o.windowStart+r)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let n=Math.max(0,t.maxInvocations-o.count);return{allowed:o.count<t.maxInvocations,remaining:n,resetsAt:o.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,o=this.buckets.get(e);!o||s>o.windowStart+r?this.buckets.set(e,{count:1,windowStart:s}):o.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 Hs,Ta=E(()=>{"use strict";Tn();Hs=class{static{u(this,"RuleEngine")}rules=[];rateLimiter=new Bs;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 _a,Ea,ba,dt,$a=E(()=>{"use strict";_a=["allow","deny"],Ea=["global","user","conversation","platform"],ba=["read","write","destructive","admin"],dt=class{static{u(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"||!_a.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${_a.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"||!Ea.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Ea.join(", ")}`);if(!Array.isArray(s.actions)||s.actions.length===0)throw new Error(`Rule "${s.id}" is missing a valid "actions" array`);for(let o of s.actions)if(typeof o!="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 o of s.riskLevels)if(!ba.includes(o))throw new Error(`Rule "${s.id}" has invalid risk level "${o}": expected one of ${ba.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 o=s.rateLimit;if(typeof o.maxInvocations!="number"||typeof o.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import cu from"node:crypto";var qs,va=E(()=>{"use strict";qs=class{static{u(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:cu.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 Pr=E(()=>{"use strict";Ta();Tn();$a();va()});var x,F=E(()=>{"use strict";x=class{static{u(this,"Skill")}}});function Z(c){return c.masterUserId??c.userId}function W(c){let e=new Set;if(e.add(Z(c)),e.add(c.userId),c.linkedPlatformUserIds)for(let t of c.linkedPlatformUserIds)e.add(t);return[...e]}var Me=E(()=>{"use strict";u(Z,"effectiveUserId");u(W,"allUserIds")});var At,Sa=E(()=>{"use strict";At=class{static{u(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 It,ka=E(()=>{"use strict";It=class{static{u(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,o){r=r??e.metadata.timeoutMs??3e4;let{name:n}=e.metadata;return this.logger.info({skill:n,input:t},"Skill execution started"),o?this.executeWithTracker(e,t,s,n,r,o):this.executeWithHardTimeout(e,t,s,n,r)}async executeWithTracker(e,t,s,r,o,n){return new Promise(i=>{let a=!1,l,d,m,p=u(()=>{l&&clearInterval(l),d&&clearTimeout(d),m&&clearTimeout(m)},"cleanup"),T=u(y=>{a||(a=!0,p(),i(y))},"finish");e.execute(t,s).then(y=>{this.logger.info({skill:r,success:y.success},"Skill execution completed"),T(y)},y=>{let f=y instanceof Error?y.message:String(y);this.logger.error({skill:r,error:f},"Skill execution failed"),T({success:!1,error:f})}),m=setTimeout(()=>{if(a)return;let y=n.getIdleMs();if(y>=12e4){let _=n.getSnapshot();this.logger.warn({skill:r,idleMs:y,state:_.state,iteration:_.iteration},"Agent inactive after initial timeout \u2014 aborting"),T({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${_.state})`});return}let f=n.getSnapshot();this.logger.info({skill:r,idleMs:y,state:f.state,iteration:f.iteration,totalMs:f.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),l=setInterval(()=>{if(a){p();return}let _=n.getIdleMs(),S=n.getSnapshot();_>=12e4?(this.logger.warn({skill:r,idleMs:_,state:S.state,iteration:S.iteration,totalMs:S.totalElapsedMs},"Agent went inactive \u2014 aborting"),T({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(_/1e3)}s (last state: ${S.state})`})):this.logger.debug({skill:r,idleMs:_,state:S.state,iteration:S.iteration},"Agent still active, continuing...")},1e4)},o),d=setTimeout(()=>{if(a)return;let y=n.getSnapshot();this.logger.error({skill:r,totalMs:y.totalElapsedMs,state:y.state,iteration:y.iteration},"Absolute time limit reached \u2014 force killing agent"),T({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,o){try{let n=await Promise.race([e.execute(t,s),new Promise((i,a)=>{setTimeout(()=>a(new Error(`Skill "${r}" timed out after ${o}ms`)),o)})]);return this.logger.info({skill:r,success:n.success},"Skill execution completed"),n}catch(n){let i=n instanceof Error?n.message:String(n);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var ut,_n=E(()=>{"use strict";ut=class{static{u(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 lu from"node:fs";import En from"node:path";var Ur,Aa=E(()=>{"use strict";F();Ur=class{static{u(this,"PluginLoader")}async loadFromDirectory(e){let t=En.resolve(e),s;try{s=await lu.promises.readdir(t)}catch(n){let i=n instanceof Error?n.message:String(n);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(n=>n.endsWith(".js")),o=[];for(let n of r){let i=En.join(t,n);try{let a=await this.loadFromFile(i);o.push(a)}catch(a){let l=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${l}`)}}return o}async loadFromFile(e){let t=En.resolve(e),o=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof o!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let n=new o;if(!(n instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(n,t),n}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 du,uu,xt,Ia=E(()=>{"use strict";F();du=/Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)/g,uu=/^[\d+\-*/().,\s%]*(Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)[\d+\-*/().,\s(%)]*)*$/,xt=class extends x{static{u(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(!uu.test(r))return{success:!1,error:`Invalid expression: "${r}" contains disallowed constructs`};let o=r.replace(du,"");if(/[a-zA-Z]/.test(o))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 Rt,xa=E(()=>{"use strict";F();Rt=class extends x{static{u(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=u(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),o={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:o,display:`Uptime: ${o.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 Ct,Ra=E(()=>{"use strict";F();Ct=class extends x{static{u(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 n;switch(this.config.provider){case"brave":n=await this.searchBrave(s,r);break;case"searxng":n=await this.searchSearXNG(s,r);break;case"tavily":n=await this.searchTavily(s,r);break;case"duckduckgo":n=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(n.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=n.map((a,l)=>`${l+1}. **${a.title}**
383
+ When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return a}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 l of i)a.push({type:"tool_use",id:l.id,name:l.name,input:l.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let o=r,n=[];for(let i of o)i.type==="tool_result"&&n.push(i);return n.length>0?{role:"user",content:n}:{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 l of a.content)l.type==="tool_use"&&t.add(l.id);else if(a.role==="user"&&Array.isArray(a.content))for(let l of a.content)l.type==="tool_result"&&t.has(l.tool_use_id)&&s.add(l.tool_use_id);let r=new Set,o=new Set,n=[];for(let a of e){if(!Array.isArray(a.content)){n.push(a);continue}let l=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)||o.has(d.tool_use_id)?!1:(o.add(d.tool_use_id),!0):!0);l.length!==0&&n.push({...a,content:l})}let i=[];for(let a of n){let l=i[i.length-1];if(l&&l.role===a.role){let d=typeof l.content=="string"?[{type:"text",text:l.content}]:l.content,m=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...l,content:[...d,...m]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var wn=E(()=>{"use strict";kt();ln();lt();dn();un();mn();pn();hn();gn();ya();wa()});var Bs,Tn=E(()=>{"use strict";Bs=class{static{u(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,o=this.buckets.get(e);if(!o)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>o.windowStart+r)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let n=Math.max(0,t.maxInvocations-o.count);return{allowed:o.count<t.maxInvocations,remaining:n,resetsAt:o.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,o=this.buckets.get(e);!o||s>o.windowStart+r?this.buckets.set(e,{count:1,windowStart:s}):o.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 Hs,Ta=E(()=>{"use strict";Tn();Hs=class{static{u(this,"RuleEngine")}rules=[];rateLimiter=new Bs;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 _a,Ea,ba,dt,$a=E(()=>{"use strict";_a=["allow","deny"],Ea=["global","user","conversation","platform"],ba=["read","write","destructive","admin"],dt=class{static{u(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"||!_a.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${_a.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"||!Ea.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Ea.join(", ")}`);if(!Array.isArray(s.actions)||s.actions.length===0)throw new Error(`Rule "${s.id}" is missing a valid "actions" array`);for(let o of s.actions)if(typeof o!="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 o of s.riskLevels)if(!ba.includes(o))throw new Error(`Rule "${s.id}" has invalid risk level "${o}": expected one of ${ba.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 o=s.rateLimit;if(typeof o.maxInvocations!="number"||typeof o.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import cu from"node:crypto";var qs,va=E(()=>{"use strict";qs=class{static{u(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:cu.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 Pr=E(()=>{"use strict";Ta();Tn();$a();va()});var x,F=E(()=>{"use strict";x=class{static{u(this,"Skill")}}});function Z(c){return c.masterUserId??c.userId}function W(c){let e=new Set;if(e.add(Z(c)),e.add(c.userId),c.linkedPlatformUserIds)for(let t of c.linkedPlatformUserIds)e.add(t);return[...e]}var Me=E(()=>{"use strict";u(Z,"effectiveUserId");u(W,"allUserIds")});var At,Sa=E(()=>{"use strict";At=class{static{u(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 It,ka=E(()=>{"use strict";It=class{static{u(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,o){r=r??e.metadata.timeoutMs??3e4;let{name:n}=e.metadata;return this.logger.info({skill:n,input:t},"Skill execution started"),o?this.executeWithTracker(e,t,s,n,r,o):this.executeWithHardTimeout(e,t,s,n,r)}async executeWithTracker(e,t,s,r,o,n){return new Promise(i=>{let a=!1,l,d,m,p=u(()=>{l&&clearInterval(l),d&&clearTimeout(d),m&&clearTimeout(m)},"cleanup"),w=u(y=>{a||(a=!0,p(),i(y))},"finish");e.execute(t,s).then(y=>{this.logger.info({skill:r,success:y.success},"Skill execution completed"),w(y)},y=>{let h=y instanceof Error?y.message:String(y);this.logger.error({skill:r,error:h},"Skill execution failed"),w({success:!1,error:h})}),m=setTimeout(()=>{if(a)return;let y=n.getIdleMs();if(y>=12e4){let T=n.getSnapshot();this.logger.warn({skill:r,idleMs:y,state:T.state,iteration:T.iteration},"Agent inactive after initial timeout \u2014 aborting"),w({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${T.state})`});return}let h=n.getSnapshot();this.logger.info({skill:r,idleMs:y,state:h.state,iteration:h.iteration,totalMs:h.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),l=setInterval(()=>{if(a){p();return}let T=n.getIdleMs(),$=n.getSnapshot();T>=12e4?(this.logger.warn({skill:r,idleMs:T,state:$.state,iteration:$.iteration,totalMs:$.totalElapsedMs},"Agent went inactive \u2014 aborting"),w({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(T/1e3)}s (last state: ${$.state})`})):this.logger.debug({skill:r,idleMs:T,state:$.state,iteration:$.iteration},"Agent still active, continuing...")},1e4)},o),d=setTimeout(()=>{if(a)return;let y=n.getSnapshot();this.logger.error({skill:r,totalMs:y.totalElapsedMs,state:y.state,iteration:y.iteration},"Absolute time limit reached \u2014 force killing agent"),w({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,o){try{let n=await Promise.race([e.execute(t,s),new Promise((i,a)=>{setTimeout(()=>a(new Error(`Skill "${r}" timed out after ${o}ms`)),o)})]);return this.logger.info({skill:r,success:n.success},"Skill execution completed"),n}catch(n){let i=n instanceof Error?n.message:String(n);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var ut,_n=E(()=>{"use strict";ut=class{static{u(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 lu from"node:fs";import En from"node:path";var Ur,Aa=E(()=>{"use strict";F();Ur=class{static{u(this,"PluginLoader")}async loadFromDirectory(e){let t=En.resolve(e),s;try{s=await lu.promises.readdir(t)}catch(n){let i=n instanceof Error?n.message:String(n);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(n=>n.endsWith(".js")),o=[];for(let n of r){let i=En.join(t,n);try{let a=await this.loadFromFile(i);o.push(a)}catch(a){let l=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${l}`)}}return o}async loadFromFile(e){let t=En.resolve(e),o=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof o!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let n=new o;if(!(n instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(n,t),n}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 du,uu,xt,Ia=E(()=>{"use strict";F();du=/Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)/g,uu=/^[\d+\-*/().,\s%]*(Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)[\d+\-*/().,\s(%)]*)*$/,xt=class extends x{static{u(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(!uu.test(r))return{success:!1,error:`Invalid expression: "${r}" contains disallowed constructs`};let o=r.replace(du,"");if(/[a-zA-Z]/.test(o))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 Rt,xa=E(()=>{"use strict";F();Rt=class extends x{static{u(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=u(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),o={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:o,display:`Uptime: ${o.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 Ct,Ra=E(()=>{"use strict";F();Ct=class extends x{static{u(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 n;switch(this.config.provider){case"brave":n=await this.searchBrave(s,r);break;case"searxng":n=await this.searchSearXNG(s,r);break;case"tavily":n=await this.searchTavily(s,r);break;case"duckduckgo":n=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(n.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=n.map((a,l)=>`${l+1}. **${a.title}**
384
384
  ${a.url}
385
385
  ${a.snippet}`).join(`
386
386
 
387
387
  `);return{success:!0,data:{query:s,results:n},display:`Search results for "${s}":
388
388
 
389
- ${i}`}}catch(n){return{success:!1,error:`Search failed: ${n instanceof Error?n.message:String(n)}`}}}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(n=>({title:n.title,url:n.url,snippet:n.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 o=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!o.ok)throw new Error(`SearXNG returned ${o.status}: ${o.statusText}`);return((await o.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(o=>({title:o.title,url:o.url,snippet:o.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 o=await r.text();return this.parseDuckDuckGoHtml(o,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,o=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,n=[],i;for(;(i=r.exec(e))!==null;){let l=i[1],d=this.stripHtml(i[2]).trim(),m=this.extractDdgUrl(l);d&&m&&n.push({url:m,title:d})}let a=[];for(;(i=o.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let l=0;l<Math.min(n.length,t);l++)s.push({title:n[l].title,url:n[l].url,snippet:a[l]??""});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 Lt,Ca=E(()=>{"use strict";F();Me();Lt=class extends x{static{u(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 W(e))for(let o of this.reminderRepo.getByUser(r))t.has(o.id)||(t.add(o.id),s.push(o));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,o=e.delayMinutes;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "message" for set action'};let n;if(r&&typeof r=="string"){let m=this.parseTriggerAt(r,t.timezone);if(!m)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(m.getTime()<=Date.now())return{success:!1,error:`The time "${r}" is in the past. Please specify a future time.`};n=m}else if(o!==void 0&&typeof o=="number"&&o>0)n=new Date(Date.now()+o*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(Z(t),t.platform,t.chatId,s,n),a=n.getTime()-Date.now(),l=Math.round(a/6e4),d=n.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 ${l} min)`}}parseTriggerAt(e,t){let s=e.trim(),r=/^(\d{1,2}):(\d{2})$/.exec(s);if(r){let n=parseInt(r[1],10),i=parseInt(r[2],10);return n>23||i>59?void 0:this.buildDateInTimezone(n,i,void 0,t)}let o=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(o){let n=parseInt(o[1],10),i=parseInt(o[2],10)-1,a=parseInt(o[3],10),l=parseInt(o[4],10),d=parseInt(o[5],10);return l>23||d>59||i>11||a>31?void 0:this.buildDateInTimezone(l,d,{year:n,month:i,day:a},t)}}buildDateInTimezone(e,t,s,r){if(!r){let T=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||T.setHours(e,t,0,0),T}let o=new Date,n=s?new Date(Date.UTC(s.year,s.month,s.day,e,t,0)):new Date(Date.UTC(o.getFullYear(),o.getMonth(),o.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 T=i.formatToParts(o),y=parseInt(T.find(X=>X.type==="year").value,10),f=parseInt(T.find(X=>X.type==="month").value,10)-1,_=parseInt(T.find(X=>X.type==="day").value,10),S=new Date(Date.UTC(y,f,_,e,t,0)),A=i.formatToParts(S),I=parseInt(A.find(X=>X.type==="hour").value,10),P=parseInt(A.find(X=>X.type==="minute").value,10),L=(e-I)*60+(t-P);return S=new Date(S.getTime()+L*6e4),S}let a=n,l=i.formatToParts(a),d=parseInt(l.find(T=>T.type==="hour").value,10),m=parseInt(l.find(T=>T.type==="minute").value,10),p=(e-d)*60+(t-m);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:
389
+ ${i}`}}catch(n){return{success:!1,error:`Search failed: ${n instanceof Error?n.message:String(n)}`}}}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(n=>({title:n.title,url:n.url,snippet:n.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 o=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!o.ok)throw new Error(`SearXNG returned ${o.status}: ${o.statusText}`);return((await o.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(o=>({title:o.title,url:o.url,snippet:o.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 o=await r.text();return this.parseDuckDuckGoHtml(o,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,o=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,n=[],i;for(;(i=r.exec(e))!==null;){let l=i[1],d=this.stripHtml(i[2]).trim(),m=this.extractDdgUrl(l);d&&m&&n.push({url:m,title:d})}let a=[];for(;(i=o.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let l=0;l<Math.min(n.length,t);l++)s.push({title:n[l].title,url:n[l].url,snippet:a[l]??""});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 Lt,Ca=E(()=>{"use strict";F();Me();Lt=class extends x{static{u(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 W(e))for(let o of this.reminderRepo.getByUser(r))t.has(o.id)||(t.add(o.id),s.push(o));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,o=e.delayMinutes;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "message" for set action'};let n;if(r&&typeof r=="string"){let m=this.parseTriggerAt(r,t.timezone);if(!m)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(m.getTime()<=Date.now())return{success:!1,error:`The time "${r}" is in the past. Please specify a future time.`};n=m}else if(o!==void 0&&typeof o=="number"&&o>0)n=new Date(Date.now()+o*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(Z(t),t.platform,t.chatId,s,n),a=n.getTime()-Date.now(),l=Math.round(a/6e4),d=n.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 ${l} min)`}}parseTriggerAt(e,t){let s=e.trim(),r=/^(\d{1,2}):(\d{2})$/.exec(s);if(r){let n=parseInt(r[1],10),i=parseInt(r[2],10);return n>23||i>59?void 0:this.buildDateInTimezone(n,i,void 0,t)}let o=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(o){let n=parseInt(o[1],10),i=parseInt(o[2],10)-1,a=parseInt(o[3],10),l=parseInt(o[4],10),d=parseInt(o[5],10);return l>23||d>59||i>11||a>31?void 0:this.buildDateInTimezone(l,d,{year:n,month:i,day:a},t)}}buildDateInTimezone(e,t,s,r){if(!r){let w=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||w.setHours(e,t,0,0),w}let o=new Date,n=s?new Date(Date.UTC(s.year,s.month,s.day,e,t,0)):new Date(Date.UTC(o.getFullYear(),o.getMonth(),o.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 w=i.formatToParts(o),y=parseInt(w.find(X=>X.type==="year").value,10),h=parseInt(w.find(X=>X.type==="month").value,10)-1,T=parseInt(w.find(X=>X.type==="day").value,10),$=new Date(Date.UTC(y,h,T,e,t,0)),A=i.formatToParts($),I=parseInt(A.find(X=>X.type==="hour").value,10),P=parseInt(A.find(X=>X.type==="minute").value,10),L=(e-I)*60+(t-P);return $=new Date($.getTime()+L*6e4),$}let a=n,l=i.formatToParts(a),d=parseInt(l.find(w=>w.type==="hour").value,10),m=parseInt(l.find(w=>w.type==="minute").value,10),p=(e-d)*60+(t-m);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:
390
390
  ${s.map(r=>`- ${r.reminderId}: "${r.message}" (triggers at ${r.triggerAt})`).join(`
391
391
  `)}`}}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 Nt,La=E(()=>{"use strict";F();Me();Nt=class extends x{static{u(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 o=this.noteRepo.save(Z(t),s,r);return{success:!0,data:{noteId:o.id,title:o.title},display:`Note saved: "${s}"`}}listNotes(e){let t=new Set,s=[];for(let o of W(e))for(let n of this.noteRepo.list(o))t.has(n.id)||(t.add(n.id),s.push(n));if(s.length===0)return{success:!0,data:[],display:"No notes found."};let r=s.map(o=>`- **${o.title}** (${o.id.slice(0,8)}\u2026)
392
392
  ${o.content.slice(0,100)}${o.content.length>100?"\u2026":""}`).join(`
@@ -408,12 +408,12 @@ ${o.map(i=>`- [${i.category}] ${i.key}: "${i.value}"`).join(`
408
408
  ${o.map(n=>`- ${n.key}: "${n.value}" (score: ${n.score.toFixed(2)})`).join(`
409
409
  `)}`}}}});var fu,gu,yu,Pt,Ua=E(()=>{"use strict";F();_n();fu=5,gu=15,yu=12e4,Pt=class extends x{static{u(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 5, max 15).',riskLevel:"write",version:"3.0.0",timeoutMs:yu,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-15). Use higher values for complex multi-step tasks. Default: 5."}},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 ut(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 o=e.max_iterations,n=o?Math.max(1,Math.min(gu,Math.round(o))):fu,i=t.onProgress??this.onProgress,a=t.tracker?t.tracker:new ut(i);a.ping("starting",{maxIterations:n});let l=this.buildSubAgentTools(),d="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.",m=s;r&&typeof r=="string"&&(m=`${s}
410
410
 
411
- Additional context: ${r}`);let p=[{role:"user",content:m}];try{let T=0,y=0,f=0;for(;;){a.ping("llm_call",{iteration:T,maxIterations:n});let _=await this.llm.complete({messages:p,system:d,tools:l.length>0?l:void 0,maxTokens:2048,tier:"strong"});if(y+=_.usage.inputTokens,f+=_.usage.outputTokens,a.ping("processing",{iteration:T,maxIterations:n}),!_.toolCalls||_.toolCalls.length===0||T>=n)return a.ping("done",{iteration:T,maxIterations:n}),{success:!0,data:{response:_.content,iterations:T,usage:{inputTokens:y,outputTokens:f}},display:_.content};T++;let S=[];_.content&&S.push({type:"text",text:_.content});for(let I of _.toolCalls)S.push({type:"tool_use",id:I.id,name:I.name,input:I.input});p.push({role:"assistant",content:S});let A=[];for(let I of _.toolCalls){a.ping("tool_call",{iteration:T,maxIterations:n,tool:I.name});let P=await this.executeSubAgentTool(I,t);A.push({type:"tool_result",tool_use_id:I.id,content:P.content,is_error:P.isError})}p.push({role:"user",content:A})}}catch(T){return{success:!1,error:`Sub-agent failed: ${T instanceof Error?T.message:String(T)}`}}}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}}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}}catch(r){return{content:`Skill execution failed: ${r instanceof Error?r.message:String(r)}`,isError:!0}}}}});var He,Fr=E(()=>{"use strict";He=class{static{u(this,"EmailProvider")}}});var Fa={};oe(Fa,{MicrosoftGraphEmailProvider:()=>jr});var jr,bn=E(()=>{"use strict";Fr();jr=class extends He{static{u(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 o=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${o.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=u(o=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let o=await s(this.accessToken);if(!o.ok)throw new Error(`Graph API error: ${o.status}`);return o.status===204?void 0:o.json()}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async graphRequestRaw(e){let t=u(o=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${o}`}}),"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(n=>({id:n.id,name:n.name,contentType:n.contentType,size:n.size??0}))),{id:s.id,from:this.formatGraphAddress(s.from),to:(s.toRecipients??[]).map(o=>this.formatGraphAddress(o)),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(o=>this.formatGraphAddress(o)),bcc:s.bccRecipients?.map(o=>this.formatGraphAddress(o)),hasAttachments:s.hasAttachments,attachments:r}}async searchMessages(e,t){let s=new URLSearchParams({$search:`"${e}"`,$top:String(Math.min(Math.max(1,t),50)),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/messages?${s}`)).value??[]).map(o=>this.mapMessage(o))}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 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 o=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?${o}`)).value??[]).map(i=>this.mapMessage(i))}async downloadAttachment(e,t){return this.graphRequestRaw(`/me/messages/${e}/attachments/${t}/$value`)}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,`
411
+ Additional context: ${r}`);let p=[{role:"user",content:m}];try{let w=0,y=0,h=0;for(;;){a.ping("llm_call",{iteration:w,maxIterations:n});let T=await this.llm.complete({messages:p,system:d,tools:l.length>0?l:void 0,maxTokens:2048,tier:"strong"});if(y+=T.usage.inputTokens,h+=T.usage.outputTokens,a.ping("processing",{iteration:w,maxIterations:n}),!T.toolCalls||T.toolCalls.length===0||w>=n)return a.ping("done",{iteration:w,maxIterations:n}),{success:!0,data:{response:T.content,iterations:w,usage:{inputTokens:y,outputTokens:h}},display:T.content};w++;let $=[];T.content&&$.push({type:"text",text:T.content});for(let I of T.toolCalls)$.push({type:"tool_use",id:I.id,name:I.name,input:I.input});p.push({role:"assistant",content:$});let A=[];for(let I of T.toolCalls){a.ping("tool_call",{iteration:w,maxIterations:n,tool:I.name});let P=await this.executeSubAgentTool(I,t);A.push({type:"tool_result",tool_use_id:I.id,content:P.content,is_error:P.isError})}p.push({role:"user",content:A})}}catch(w){return{success:!1,error:`Sub-agent failed: ${w instanceof Error?w.message:String(w)}`}}}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}}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}}catch(r){return{content:`Skill execution failed: ${r instanceof Error?r.message:String(r)}`,isError:!0}}}}});var He,Fr=E(()=>{"use strict";He=class{static{u(this,"EmailProvider")}}});var Fa={};oe(Fa,{MicrosoftGraphEmailProvider:()=>jr});var jr,bn=E(()=>{"use strict";Fr();jr=class extends He{static{u(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 o=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${o.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=u(o=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let o=await s(this.accessToken);if(!o.ok)throw new Error(`Graph API error: ${o.status}`);return o.status===204?void 0:o.json()}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async graphRequestRaw(e){let t=u(o=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${o}`}}),"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(n=>({id:n.id,name:n.name,contentType:n.contentType,size:n.size??0}))),{id:s.id,from:this.formatGraphAddress(s.from),to:(s.toRecipients??[]).map(o=>this.formatGraphAddress(o)),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(o=>this.formatGraphAddress(o)),bcc:s.bccRecipients?.map(o=>this.formatGraphAddress(o)),hasAttachments:s.hasAttachments,attachments:r}}async searchMessages(e,t){let s=new URLSearchParams({$search:`"${e}"`,$top:String(Math.min(Math.max(1,t),50)),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/messages?${s}`)).value??[]).map(o=>this.mapMessage(o))}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 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 o=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?${o}`)).value??[]).map(i=>this.mapMessage(i))}async downloadAttachment(e,t){return this.graphRequestRaw(`/me/messages/${e}/attachments/${t}/$value`)}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,`
412
412
  `).replace(/<\/p>/gi,`
413
413
 
414
414
  `).replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\n{3,}/g,`
415
415
 
416
- `).trim()}}});var ja={};oe(ja,{StandardEmailProvider:()=>Br});var Br,$n=E(()=>{"use strict";Fr();Br=class extends He{static{u(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 o=await s.fetchOne(String(t),{envelope:!0,source:!0,bodyStructure:!0});if(!o)throw new Error(`Message #${t} not found.`);let n=this.formatAddress(o.envelope?.from?.[0]),i=o.envelope?.to?.map(p=>p.name?`${p.name} <${p.address}>`:p.address??"")??[],a=o.envelope?.cc?.map(p=>p.name?`${p.name} <${p.address}>`:p.address??""),l=o.source?.toString()??"",d=this.extractTextBody(l),m=this.extractAttachmentInfo(o.bodyStructure);return{id:String(t),from:n,to:i,subject:o.envelope?.subject??"(no subject)",date:o.envelope?.date??new Date,read:o.flags?.has("\\Seen")??!1,body:d,cc:a,attachments:m}}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 o=await r.getMailboxLock("INBOX");try{let n=await r.search({or:[{subject:e},{from:e},{body:e}]}),i=Array.isArray(n)?n:[];if(i.length===0)return[];let a=i.slice(-s),l=[];for await(let d of r.fetch(a,{envelope:!0,flags:!0}))l.push({id:String(d.seq),from:this.formatAddress(d.envelope?.from?.[0]),to:d.envelope?.to?.map(m=>m.name?`${m.name} <${m.address}>`:m.address??"")??[],subject:d.envelope?.subject??"(no subject)",date:d.envelope?.date??new Date,read:d.flags?.has("\\Seen")??!1});return l.reverse(),l}finally{o.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 o=await r.getMailboxLock(e);try{let n=[],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 m of r.fetch(d,{envelope:!0,flags:!0})){let p=this.formatAddress(m.envelope?.from?.[0]);n.push({id:String(m.seq),from:p,to:m.envelope?.to?.map(T=>T.name?`${T.name} <${T.address}>`:T.address??"")??[],subject:m.envelope?.subject??"(no subject)",date:m.envelope?.date??new Date,read:m.flags?.has("\\Seen")??!1})}return n.reverse(),n}finally{o.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 o=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{o.release()}}finally{await r.logout()}}extractAttachmentInfo(e){let t=[];if(!e)return t;let s=u((r,o)=>{if(r.childNodes){for(let i=0;i<r.childNodes.length;i++)s(r.childNodes[i],o?`${o}.${i+1}`:String(i+1));return}let n=r.disposition?.toLowerCase();if(n==="attachment"||r.type&&!r.type.startsWith("text/")&&n!=="inline"){let i=r.dispositionParameters?.filename??r.parameters?.name??`part-${o}`;t.push({id:r.part??o,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(`
416
+ `).trim()}}});var ja={};oe(ja,{StandardEmailProvider:()=>Br});var Br,$n=E(()=>{"use strict";Fr();Br=class extends He{static{u(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 o=await s.fetchOne(String(t),{envelope:!0,source:!0,bodyStructure:!0});if(!o)throw new Error(`Message #${t} not found.`);let n=this.formatAddress(o.envelope?.from?.[0]),i=o.envelope?.to?.map(p=>p.name?`${p.name} <${p.address}>`:p.address??"")??[],a=o.envelope?.cc?.map(p=>p.name?`${p.name} <${p.address}>`:p.address??""),l=o.source?.toString()??"",d=this.extractTextBody(l),m=this.extractAttachmentInfo(o.bodyStructure);return{id:String(t),from:n,to:i,subject:o.envelope?.subject??"(no subject)",date:o.envelope?.date??new Date,read:o.flags?.has("\\Seen")??!1,body:d,cc:a,attachments:m}}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 o=await r.getMailboxLock("INBOX");try{let n=await r.search({or:[{subject:e},{from:e},{body:e}]}),i=Array.isArray(n)?n:[];if(i.length===0)return[];let a=i.slice(-s),l=[];for await(let d of r.fetch(a,{envelope:!0,flags:!0}))l.push({id:String(d.seq),from:this.formatAddress(d.envelope?.from?.[0]),to:d.envelope?.to?.map(m=>m.name?`${m.name} <${m.address}>`:m.address??"")??[],subject:d.envelope?.subject??"(no subject)",date:d.envelope?.date??new Date,read:d.flags?.has("\\Seen")??!1});return l.reverse(),l}finally{o.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 o=await r.getMailboxLock(e);try{let n=[],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 m of r.fetch(d,{envelope:!0,flags:!0})){let p=this.formatAddress(m.envelope?.from?.[0]);n.push({id:String(m.seq),from:p,to:m.envelope?.to?.map(w=>w.name?`${w.name} <${w.address}>`:w.address??"")??[],subject:m.envelope?.subject??"(no subject)",date:m.envelope?.date??new Date,read:m.flags?.has("\\Seen")??!1})}return n.reverse(),n}finally{o.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 o=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{o.release()}}finally{await r.logout()}}extractAttachmentInfo(e){let t=[];if(!e)return t;let s=u((r,o)=>{if(r.childNodes){for(let i=0;i<r.childNodes.length;i++)s(r.childNodes[i],o?`${o}.${i+1}`:String(i+1));return}let n=r.disposition?.toLowerCase();if(n==="attachment"||r.type&&!r.type.startsWith("text/")&&n!=="inline"){let i=r.dispositionParameters?.filename??r.parameters?.name??`part-${o}`;t.push({id:r.part??o,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(`
417
417
 
418
418
  `));let r=s.match(/boundary="?([^"\s;]+)"?/i)??e.match(/boundary="?([^"\s;]+)"?/i);if(!r)return t.slice(1).join(`
419
419
 
@@ -449,11 +449,11 @@ ${o.map((n,i)=>` ${i+1}. ${n}`).join(`
449
449
 
450
450
  `);return{success:!0,data:{folder:t,messages:i.map(l=>({...l,id:this.encodeId(o,l.id)}))},display:this.accountLabel(o,`Folder "${t}" (${i.length} messages):
451
451
 
452
- ${a}`)}}async handleReply(e){let t=e.messageId,s=e.body;if(!t)return{success:!1,error:'"messageId" is required for reply.'};if(!s)return{success:!1,error:'"body" is required for reply.'};let{account:r,rawId:o}=this.decodeId(t),n=this.providers.get(r);return n?{success:!0,data:{messageId:(await n.sendMessage({to:"",subject:"",body:s,replyTo:o})).messageId},display:this.accountLabel(r,`Reply sent to message ${o}.`)}:{success:!1,error:`Unknown email account "${r}".`}}async handleAttachment(e){let t=e.messageId,s=e.attachmentId;if(!t)return{success:!1,error:'"messageId" is required.'};if(!s)return{success:!1,error:'"attachmentId" is required.'};let{account:r,rawId:o}=this.decodeId(t),n=this.providers.get(r);if(!n)return{success:!1,error:`Unknown email account "${r}".`};let a=(await n.readMessage(o)).attachments?.find(p=>p.id===s),l=await n.downloadAttachment(o,s),d=a?.name??`attachment-${s}`,m=a?.contentType??"application/octet-stream";return{success:!0,data:{messageId:t,attachmentId:s,fileName:d,size:l.length},display:this.accountLabel(r,`Downloaded attachment: ${d} (${this.formatSize(l.length)})`),attachments:[{fileName:d,data:l,mimeType:m}]}}formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var qa,Ut,za=E(()=>{"use strict";F();qa=1e5,Ut=class extends x{static{u(this,"HttpSkill")}metadata={name:"http",category:"files",description:"Make HTTP requests to fetch web pages or call REST APIs. Use when you need to read a URL, call an API endpoint, or fetch data from the web. Supports GET, POST, PUT, PATCH, DELETE methods.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{url:{type:"string",description:"The URL to request"},method:{type:"string",enum:["GET","POST","PUT","PATCH","DELETE"],description:"HTTP method (default: GET)"},headers:{type:"object",description:"Request headers as key-value pairs (optional)"},body:{type:"string",description:"Request body for POST/PUT/PATCH (optional)"}},required:["url"]}};async execute(e,t){let s=e.url,r=(e.method??"GET").toUpperCase(),o=e.headers,n=e.body;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "url"'};let i;try{i=new URL(s)}catch{return{success:!1,error:`Invalid URL: "${s}"`}}if(i.protocol!=="http:"&&i.protocol!=="https:")return{success:!1,error:`Unsupported URL scheme "${i.protocol}". Only http: and https: are allowed.`};if(this.isPrivateHost(i.hostname))return{success:!1,error:`Access to private/internal network address "${i.hostname}" is blocked.`};try{let a={method:r,headers:{"User-Agent":"Alfred/1.0",...o??{}},signal:AbortSignal.timeout(15e3)};n&&["POST","PUT","PATCH"].includes(r)&&(a.body=n,!o?.["Content-Type"]&&!o?.["content-type"]&&(a.headers["Content-Type"]="application/json"));let l=await fetch(s,a),d=l.headers.get("content-type")??"",m=await l.text(),p=m.length>qa,T=p?m.slice(0,qa)+`
452
+ ${a}`)}}async handleReply(e){let t=e.messageId,s=e.body;if(!t)return{success:!1,error:'"messageId" is required for reply.'};if(!s)return{success:!1,error:'"body" is required for reply.'};let{account:r,rawId:o}=this.decodeId(t),n=this.providers.get(r);return n?{success:!0,data:{messageId:(await n.sendMessage({to:"",subject:"",body:s,replyTo:o})).messageId},display:this.accountLabel(r,`Reply sent to message ${o}.`)}:{success:!1,error:`Unknown email account "${r}".`}}async handleAttachment(e){let t=e.messageId,s=e.attachmentId;if(!t)return{success:!1,error:'"messageId" is required.'};if(!s)return{success:!1,error:'"attachmentId" is required.'};let{account:r,rawId:o}=this.decodeId(t),n=this.providers.get(r);if(!n)return{success:!1,error:`Unknown email account "${r}".`};let a=(await n.readMessage(o)).attachments?.find(p=>p.id===s),l=await n.downloadAttachment(o,s),d=a?.name??`attachment-${s}`,m=a?.contentType??"application/octet-stream";return{success:!0,data:{messageId:t,attachmentId:s,fileName:d,size:l.length},display:this.accountLabel(r,`Downloaded attachment: ${d} (${this.formatSize(l.length)})`),attachments:[{fileName:d,data:l,mimeType:m}]}}formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var qa,Ut,za=E(()=>{"use strict";F();qa=1e5,Ut=class extends x{static{u(this,"HttpSkill")}metadata={name:"http",category:"files",description:"Make HTTP requests to fetch web pages or call REST APIs. Use when you need to read a URL, call an API endpoint, or fetch data from the web. Supports GET, POST, PUT, PATCH, DELETE methods.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{url:{type:"string",description:"The URL to request"},method:{type:"string",enum:["GET","POST","PUT","PATCH","DELETE"],description:"HTTP method (default: GET)"},headers:{type:"object",description:"Request headers as key-value pairs (optional)"},body:{type:"string",description:"Request body for POST/PUT/PATCH (optional)"}},required:["url"]}};async execute(e,t){let s=e.url,r=(e.method??"GET").toUpperCase(),o=e.headers,n=e.body;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "url"'};let i;try{i=new URL(s)}catch{return{success:!1,error:`Invalid URL: "${s}"`}}if(i.protocol!=="http:"&&i.protocol!=="https:")return{success:!1,error:`Unsupported URL scheme "${i.protocol}". Only http: and https: are allowed.`};if(this.isPrivateHost(i.hostname))return{success:!1,error:`Access to private/internal network address "${i.hostname}" is blocked.`};try{let a={method:r,headers:{"User-Agent":"Alfred/1.0",...o??{}},signal:AbortSignal.timeout(15e3)};n&&["POST","PUT","PATCH"].includes(r)&&(a.body=n,!o?.["Content-Type"]&&!o?.["content-type"]&&(a.headers["Content-Type"]="application/json"));let l=await fetch(s,a),d=l.headers.get("content-type")??"",m=await l.text(),p=m.length>qa,w=p?m.slice(0,qa)+`
453
453
 
454
- [... truncated]`:m,y=T;d.includes("text/html")&&(y=this.stripHtml(T).slice(0,1e4));let f={status:l.status,statusText:l.statusText,contentType:d,bodyLength:m.length,truncated:p,body:T};return l.ok?{success:!0,data:f,display:`HTTP ${l.status} OK (${m.length} bytes)
454
+ [... truncated]`:m,y=w;d.includes("text/html")&&(y=this.stripHtml(w).slice(0,1e4));let h={status:l.status,statusText:l.statusText,contentType:d,bodyLength:m.length,truncated:p,body:w};return l.ok?{success:!0,data:h,display:`HTTP ${l.status} OK (${m.length} bytes)
455
455
 
456
- ${y.slice(0,5e3)}`}:{success:!0,data:f,display:`HTTP ${l.status} ${l.statusText}
456
+ ${y.slice(0,5e3)}`}:{success:!0,data:h,display:`HTTP ${l.status} ${l.statusText}
457
457
 
458
458
  ${y.slice(0,2e3)}`}}catch(a){return{success:!1,error:`HTTP request failed: ${a instanceof Error?a.message:String(a)}`}}}isPrivateHost(e){if(e==="localhost"||e==="127.0.0.1"||e==="::1")return!0;let t=e.replace(/[\[\]]/g,"").toLowerCase();if(t.startsWith("fc")||t.startsWith("fd")||t==="::1")return!0;let s=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(s){let[,r,o]=s.map(Number);if(r===10||r===172&&o>=16&&o<=31||r===192&&o===168||r===127||r===169&&o===254||r===0)return!0}return!1}stripHtml(e){return e.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,"").replace(/<style[^>]*>[\s\S]*?<\/style>/gi,"").replace(/<[^>]+>/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ").trim()}}});import K from"node:fs";import Ke from"node:path";var vn,Wa,wu,Ft,Va=E(()=>{"use strict";F();vn=5e5,Wa=5e7,wu={".pdf":"application/pdf",".doc":"application/msword",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xls":"application/vnd.ms-excel",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".ppt":"application/vnd.ms-powerpoint",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".odt":"application/vnd.oasis.opendocument.text",".ods":"application/vnd.oasis.opendocument.spreadsheet",".odp":"application/vnd.oasis.opendocument.presentation",".rtf":"application/rtf",".epub":"application/epub+zip",".txt":"text/plain",".md":"text/markdown",".csv":"text/csv",".tsv":"text/tab-separated-values",".html":"text/html",".htm":"text/html",".xml":"application/xml",".yaml":"application/yaml",".yml":"application/yaml",".toml":"application/toml",".ini":"text/plain",".cfg":"text/plain",".log":"text/plain",".json":"application/json",".js":"application/javascript",".ts":"application/typescript",".py":"text/x-python",".sh":"application/x-sh",".sql":"application/sql",".css":"text/css",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".ico":"image/x-icon",".tiff":"image/tiff",".tif":"image/tiff",".mp3":"audio/mpeg",".wav":"audio/wav",".ogg":"audio/ogg",".flac":"audio/flac",".aac":"audio/aac",".m4a":"audio/mp4",".mp4":"video/mp4",".webm":"video/webm",".mkv":"video/x-matroska",".avi":"video/x-msvideo",".mov":"video/quicktime",".zip":"application/zip",".tar":"application/x-tar",".gz":"application/gzip",".7z":"application/x-7z-compressed",".rar":"application/vnd.rar",".ttf":"font/ttf",".otf":"font/otf",".woff":"font/woff",".woff2":"font/woff2"},Ft=class extends x{static{u(this,"FileSkill")}metadata={name:"file",category:"files",description:'Read, write, move, copy, or send files. Use for reading file contents, writing text to files, saving binary data, listing directory contents, moving/copying files, or getting file info. Use "send" to deliver a file to the user in the chat (PDF, images, etc.). Prefer this over shell for file operations. When a user sends a file attachment, it is saved to the inbox \u2014 use "move" to relocate it. IMPORTANT: For large content (HTML pages, long text), use code_sandbox instead to generate the file programmatically.',riskLevel:"write",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["read","write","write_binary","append","list","info","exists","move","copy","delete","send"],description:"The file operation to perform"},path:{type:"string",description:"Absolute or relative file/directory path (~ expands to home)"},destination:{type:"string",description:"Destination path for move/copy actions (~ expands to home)"},content:{type:"string",description:"Content to write (required for write/append; base64-encoded for write_binary)"}},required:["action","path"]}};async execute(e,t){let s=e.action,r=e.path,o=e.content,n=e.destination;if(!s||!r)return{success:!1,error:'Missing required fields "action" and "path"'};if((s==="write"||s==="write_binary"||s==="append")&&!o)return{success:!1,error:`Missing "content" field for "${s}" action. The content is likely too large to include in a tool call. Use the code_sandbox skill instead \u2014 write COMPACT data-driven code: define your data as arrays/objects, then build HTML/text programmatically with .map()/.join(). Example: const data = [{h:8,p:5.2},{h:9,p:4.1}]; const rows = data.map(r => \`<tr><td>\${r.h}</td><td>\${r.p}</td></tr>\`).join(''); fs.writeFileSync('output.html', \`<table>\${rows}</table>\`); \u2014 the sandbox collects output files automatically. Do NOT embed large string literals.`};let i=this.resolvePath(r),a=this.checkBlocked(i);if(a)return a;try{if(K.existsSync(i)&&K.lstatSync(i).isSymbolicLink()){let l=K.realpathSync(i);if(this.checkBlocked(l))return{success:!1,error:"Access denied: symlink target is a blocked path"}}}catch{}switch(s){case"read":return this.readFile(i);case"write":return this.writeFile(i,o);case"write_binary":return this.writeBinaryFile(i,o);case"append":return this.appendFile(i,o);case"list":return this.listDir(i);case"info":return this.fileInfo(i);case"exists":return this.fileExists(i);case"move":return this.moveFile(i,n);case"copy":return this.copyFile(i,n);case"delete":return this.deleteFile(i);case"send":return this.sendFile(i);default:return{success:!1,error:`Unknown action "${s}". Valid: read, write, write_binary, append, list, info, exists, move, copy, delete, send`}}}resolvePath(e){let t=process.env.HOME||process.env.USERPROFILE||"",s=e.startsWith("~")?e.replace("~",t):e;return Ke.resolve(s)}checkBlocked(e){let t=e.toLowerCase().replace(/\\/g,"/"),s=(process.env.HOME||process.env.USERPROFILE||"").toLowerCase().replace(/\\/g,"/"),r=["/etc/shadow","/etc/passwd","/etc/sudoers","/proc/","/sys/","/dev/","c:/windows/system32","c:/windows/syswow64"],o=["/.ssh","/.aws","/.gnupg"],n=[".env"];if(r.some(a=>t.startsWith(a)||t===a.replace(/\/$/,"")))return{success:!1,error:"Access to system directories/files is blocked for security"};if(s&&o.some(a=>t.startsWith(s+a)))return{success:!1,error:"Access to sensitive user directories is blocked for security"};let i=Ke.basename(e);return n.includes(i.toLowerCase())?{success:!1,error:"Access to sensitive files is blocked for security"}:null}readFile(e){try{let t=K.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file. Use action "list" instead.`};if(t.size>vn){let r=K.readFileSync(e,"utf-8").slice(0,vn);return{success:!0,data:{path:e,size:t.size,truncated:!0},display:`${e} (${t.size} bytes, truncated to ${vn}):
459
459
 
@@ -477,7 +477,7 @@ Or add it to Alfred: npm install puppeteer`};switch(s){case"open":return this.op
477
477
  ${l}`}}catch(o){return{success:!1,error:`Failed to open "${s}": ${o.message}`}}}async screenshotPage(e,t){try{let s=await this.ensurePage(e),r=t.url;r&&await s.goto(r,{waitUntil:"networkidle2",timeout:3e4});let o=s.url();if(o==="about:blank")return{success:!1,error:'No page is open. Use action "open" with a URL first, or provide a URL.'};let n=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),i=t.path||_u.join(Eu.homedir(),"Desktop",`browser-${n}.png`);return await s.screenshot({path:i,fullPage:!1}),{success:!0,data:{path:i,url:o},display:`Screenshot saved to ${i}`}}catch(s){return{success:!1,error:`Screenshot failed: ${s.message}`}}}async clickElement(e){let t=e.selector;if(!t)return{success:!1,error:'Missing "selector" for click action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t);try{await this.page.waitForNavigation({timeout:3e3})}catch{}let s=await this.page.title();return{success:!0,data:{selector:t,url:this.page.url(),title:s},display:`Clicked "${t}" \u2014 now on: ${s} (${this.page.url()})`}}catch(s){return{success:!1,error:`Click failed on "${t}": ${s.message}`}}}async typeText(e){let t=e.selector,s=e.text;if(!t)return{success:!1,error:'Missing "selector" for type action'};if(!s)return{success:!1,error:'Missing "text" for type action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{return await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t),await this.page.type(t,s,{delay:50}),{success:!0,data:{selector:t,textLength:s.length},display:`Typed ${s.length} characters into "${t}"`}}catch(r){return{success:!1,error:`Type failed on "${t}": ${r.message}`}}}async evaluateScript(e){let t=e.script;if(!t)return{success:!1,error:'Missing "script" for evaluate action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{let s=await this.page.evaluate(t),r=typeof s=="string"?s:JSON.stringify(s,null,2);return{success:!0,data:{result:s},display:r?.slice(0,1e4)??"(no output)"}}catch(s){return{success:!1,error:`Evaluate failed: ${s.message}`}}}validateUrl(e){let t;try{t=new URL(e)}catch{return`Invalid URL: "${e}"`}if(["file:","chrome:","about:","data:","javascript:"].includes(t.protocol))return`Blocked URL protocol "${t.protocol}". Only http: and https: are allowed.`;if(t.protocol!=="http:"&&t.protocol!=="https:")return`Unsupported URL protocol "${t.protocol}". Only http: and https: are allowed.`;let r=t.hostname;return this.isPrivateHost(r)?`Access to private/internal network address "${r}" is blocked.`:null}isPrivateHost(e){if(e==="localhost"||e==="127.0.0.1"||e==="::1")return!0;if(e.startsWith("[")||e.toLowerCase().startsWith("fc")||e.toLowerCase().startsWith("fd")){let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s.startsWith("fc")||s.startsWith("fd")||s==="::1")return!0}let t=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(t){let[,s,r]=t.map(Number);if(s===10||s===172&&r>=16&&r<=31||s===192&&r===168||s===127||s===169&&r===254||s===0)return!0}return!1}async closeBrowser(){try{return this.page=null,this.browser&&(await this.browser.close(),this.browser=null),{success:!0,display:"Browser closed."}}catch(e){return this.browser=null,this.page=null,{success:!1,error:`Close failed: ${e.message}`}}}}});var zt,Za=E(()=>{"use strict";F();Me();zt=class extends x{static{u(this,"ProfileSkill")}userRepo;metadata={name:"profile",category:"core",description:"Manage user profile settings including timezone, language, and bio. Use this to personalize Alfred for each user.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get","set_timezone","set_language","set_bio","set_preference"],description:"The profile action to perform"},value:{type:"string",description:"The value to set (for set_* actions)"},preference_key:{type:"string",description:"The preference key (for set_preference)"},preference_value:{type:"string",description:"The preference value (for set_preference)"}},required:["action"]}};constructor(e){super(),this.userRepo=e}async execute(e,t){let s=e.action,r=Z(t);switch(s){case"get":return this.getProfile(r);case"set_timezone":return this.setField(r,"timezone",e.value);case"set_language":return this.setField(r,"language",e.value);case"set_bio":return this.setField(r,"bio",e.value);case"set_preference":return this.setPreference(r,e.preference_key,e.preference_value);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}getProfile(e){let t=this.userRepo.getProfile(e);if(!t)return{success:!0,data:null,display:"No profile found. Set your timezone, language, or bio to create one."};let s=[];if(t.displayName&&s.push(`Name: ${t.displayName}`),t.timezone&&s.push(`Timezone: ${t.timezone}`),t.language&&s.push(`Language: ${t.language}`),t.bio&&s.push(`Bio: ${t.bio}`),t.preferences)for(let[r,o]of Object.entries(t.preferences))s.push(`${r}: ${String(o)}`);return{success:!0,data:t,display:s.length>0?`Profile:
478
478
  ${s.map(r=>`- ${r}`).join(`
479
479
  `)}`:"Profile is empty."}}setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let o=this.userRepo.getProfile(e)?.preferences??{};return o[t]=s,this.userRepo.updateProfile(e,{preferences:o}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var Re,Vs=E(()=>{"use strict";Re=class{static{u(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var Qa={};oe(Qa,{CalDAVProvider:()=>Hr});var Hr,Sn=E(()=>{"use strict";Vs();Hr=class extends Re{static{u(this,"CalDAVProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"caldav"})}catch(e){throw new Error(`CalDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){let s=await this.client.fetchCalendars();if(!s||s.length===0)return[];let r=[];for(let o of s){let n=await this.client.fetchCalendarObjects({calendar:o,timeRange:{start:e.toISOString(),end:t.toISOString()}});for(let i of n){let a=this.parseICalEvent(i.data,i.url);a&&r.push(a)}}return r.sort((o,n)=>o.start.getTime()-n.start.getTime())}async createEvent(e){let t=await this.client.fetchCalendars();if(!t||t.length===0)throw new Error("No calendars found");let s=`alfred-${Date.now()}@alfred`,r=this.buildICalEvent(s,e);return await this.client.createCalendarObject({calendar:t[0],filename:`${s}.ics`,iCalString:r}),{id:s,title:e.title,start:e.start,end:e.end,location:e.location,description:e.description,allDay:e.allDay}}async updateEvent(e,t){let s=await this.client.fetchCalendars();for(let r of s){let o=await this.client.fetchCalendarObjects({calendar:r});for(let n of o)if(n.url?.includes(e)||n.data?.includes(e)){let i=this.parseICalEvent(n.data,n.url);if(!i)continue;let a={title:t.title??i.title,start:t.start??i.start,end:t.end??i.end,location:t.location??i.location,description:t.description??i.description,allDay:t.allDay??i.allDay},l=this.buildICalEvent(e,a);return await this.client.updateCalendarObject({calendarObject:{...n,data:l}}),{id:e,...a}}}throw new Error(`Event ${e} not found`)}async deleteEvent(e){let t=await this.client.fetchCalendars();for(let s of t){let r=await this.client.fetchCalendarObjects({calendar:s});for(let o of r)if(o.url?.includes(e)||o.data?.includes(e)){await this.client.deleteCalendarObject({calendarObject:o});return}}throw new Error(`Event ${e} not found`)}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(o=>!o.allDay&&o.start<t&&o.end>e);return{available:r.length===0,conflicts:r}}parseICalEvent(e,t){try{let s=e.split(`
480
- `).map(p=>p.trim()),r=u(p=>s.find(T=>T.startsWith(p+":"))?.slice(p.length+1),"get"),o=r("SUMMARY"),n=r("DTSTART")??r("DTSTART;VALUE=DATE"),i=r("DTEND")??r("DTEND;VALUE=DATE"),a=r("LOCATION"),l=r("DESCRIPTION"),d=r("UID")??t;if(!o||!n)return;let m=n.length===8;return{id:d,title:o,start:this.parseICalDate(n),end:i?this.parseICalDate(i):this.parseICalDate(n),location:a||void 0,description:l||void 0,allDay:m}}catch(s){console.error("[caldav] Failed to parse iCal event",s);return}}parseICalDate(e){if(e.length===8)return new Date(`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`);let t=e.replace(/[^0-9TZ]/g,"");return t.length>=15?new Date(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T${t.slice(9,11)}:${t.slice(11,13)}:${t.slice(13,15)}Z`):new Date(e)}buildICalEvent(e,t){let s=u((o,n)=>n?o.toISOString().slice(0,10).replace(/-/g,""):o.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),"formatDate"),r=`BEGIN:VCALENDAR\r
480
+ `).map(p=>p.trim()),r=u(p=>s.find(w=>w.startsWith(p+":"))?.slice(p.length+1),"get"),o=r("SUMMARY"),n=r("DTSTART")??r("DTSTART;VALUE=DATE"),i=r("DTEND")??r("DTEND;VALUE=DATE"),a=r("LOCATION"),l=r("DESCRIPTION"),d=r("UID")??t;if(!o||!n)return;let m=n.length===8;return{id:d,title:o,start:this.parseICalDate(n),end:i?this.parseICalDate(i):this.parseICalDate(n),location:a||void 0,description:l||void 0,allDay:m}}catch(s){console.error("[caldav] Failed to parse iCal event",s);return}}parseICalDate(e){if(e.length===8)return new Date(`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`);let t=e.replace(/[^0-9TZ]/g,"");return t.length>=15?new Date(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T${t.slice(9,11)}:${t.slice(11,13)}:${t.slice(13,15)}Z`):new Date(e)}buildICalEvent(e,t){let s=u((o,n)=>n?o.toISOString().slice(0,10).replace(/-/g,""):o.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),"formatDate"),r=`BEGIN:VCALENDAR\r
481
481
  VERSION:2.0\r
482
482
  PRODID:-//Alfred//EN\r
483
483
  BEGIN:VEVENT\r
@@ -499,7 +499,7 @@ ${r.conflicts.map(n=>this.formatEvent(n)).join(`
499
499
  `)}`;return{success:!0,data:r,display:o}}catch(r){return{success:!1,error:`Failed to check availability: ${r instanceof Error?r.message:String(r)}`}}}formatEvent(e){let t={hour:"2-digit",minute:"2-digit",...this.timezone?{timeZone:this.timezone}:{}},s=e.location?` @ ${e.location}`:"",r=e.id?` [id:${e.id}]`:"";if(e.allDay)return`- All day: ${e.title}${s}${r}`;let o=e.start.toLocaleTimeString("en-GB",t),n=e.end.toLocaleTimeString("en-GB",t);return`- ${o}-${n}: ${e.title}${s}${r}`}}});var oc=E(()=>{"use strict";Vs();Sn();kn();An();sc();rc()});var Wt,nc=E(()=>{"use strict";F();Wt=class extends x{static{u(this,"CrossPlatformSkill")}users;linkTokens;adapters;findConversation;metadata={name:"cross_platform",category:"identity",description:"Manage cross-platform identity linking and messaging. Actions: link_start (generate a linking code on current platform), link_confirm (enter a code from another platform to link accounts), send_message (send a message to a linked platform), list_identities (show all linked platforms), unlink (remove a platform link).",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["link_start","link_confirm","send_message","list_identities","unlink"],description:"The action to perform"},code:{type:"string",description:"The 6-digit linking code (for link_confirm)"},platform:{type:"string",description:"Target platform (for send_message or unlink)"},chat_id:{type:"string",description:"Target chat ID (for send_message)"},message:{type:"string",description:"Message text to send (for send_message)"}},required:["action"]}};constructor(e,t,s,r){super(),this.users=e,this.linkTokens=t,this.adapters=s,this.findConversation=r}resolveInternalId(e){return this.users.findOrCreate(e.platform,e.userId).id}async execute(e,t){let s=e.action;switch(s){case"link_start":return this.linkStart(t);case"link_confirm":return this.linkConfirm(e,t);case"send_message":return this.sendMessage(e,t);case"list_identities":return this.listIdentities(t);case"unlink":return this.unlink(e,t);default:return{success:!1,error:`Unknown action: ${s}`}}}failedConfirmAttempts=new Map;checkConfirmRateLimit(e){let t=Date.now(),s=this.failedConfirmAttempts.get(e);return s&&t<s.resetAt&&s.count>=5?`Too many failed attempts. Please wait ${Math.ceil((s.resetAt-t)/1e3)}s before trying again.`:null}recordFailedConfirm(e){let t=Date.now(),s=this.failedConfirmAttempts.get(e);s&&t<s.resetAt?s.count++:this.failedConfirmAttempts.set(e,{count:1,resetAt:t+5*6e4})}async linkStart(e){this.linkTokens.cleanup();let t=this.resolveInternalId(e);if(this.linkTokens.countRecentByUser(t,10)>=5)return{success:!1,error:"Too many linking codes generated recently. Please wait a few minutes."};let r=this.linkTokens.create(t,e.platform);return{success:!0,data:{code:r.code,expiresAt:r.expiresAt},display:`Your linking code is: **${r.code}**
500
500
 
501
501
  Enter this code on your other platform within 10 minutes using:
502
- "Link my account with code ${r.code}"`}}async linkConfirm(e,t){let s=e.code;if(!s)return{success:!1,error:'Missing required field "code"'};let r=this.resolveInternalId(t),o=this.checkConfirmRateLimit(r);if(o)return{success:!1,error:o};let n=this.linkTokens.findByCode(s.trim());if(!n)return this.recordFailedConfirm(r),{success:!1,error:"Invalid or expired linking code. Please generate a new one."};let i=n.userId;if(i===r)return{success:!1,error:"Cannot link an account to itself. Use the code on a different platform."};let a=this.users.getMasterUserId(i),l=this.users.getMasterUserId(r),d;if(a!==i?d=a:l!==r?d=l:d=i,a!==i&&l!==r&&a!==l){let T=this.users.getLinkedUsers(l);for(let y of T)this.users.setMasterUser(y.id,d)}i!==d&&this.users.setMasterUser(i,d),r!==d&&this.users.setMasterUser(r,d),this.linkTokens.consume(n.id);let m=this.users.findById(i),p=n.platform;return{success:!0,data:{masterUserId:d,linkedPlatform:p},display:`Account linked successfully! Your ${p} account (${m?.displayName??m?.username??"unknown"}) is now linked to this ${t.platform} account.
502
+ "Link my account with code ${r.code}"`}}async linkConfirm(e,t){let s=e.code;if(!s)return{success:!1,error:'Missing required field "code"'};let r=this.resolveInternalId(t),o=this.checkConfirmRateLimit(r);if(o)return{success:!1,error:o};let n=this.linkTokens.findByCode(s.trim());if(!n)return this.recordFailedConfirm(r),{success:!1,error:"Invalid or expired linking code. Please generate a new one."};let i=n.userId;if(i===r)return{success:!1,error:"Cannot link an account to itself. Use the code on a different platform."};let a=this.users.getMasterUserId(i),l=this.users.getMasterUserId(r),d;if(a!==i?d=a:l!==r?d=l:d=i,a!==i&&l!==r&&a!==l){let w=this.users.getLinkedUsers(l);for(let y of w)this.users.setMasterUser(y.id,d)}i!==d&&this.users.setMasterUser(i,d),r!==d&&this.users.setMasterUser(r,d),this.linkTokens.consume(n.id);let m=this.users.findById(i),p=n.platform;return{success:!0,data:{masterUserId:d,linkedPlatform:p},display:`Account linked successfully! Your ${p} account (${m?.displayName??m?.username??"unknown"}) is now linked to this ${t.platform} account.
503
503
 
504
504
  Your memories, preferences, and context are now shared across platforms.`}}async sendMessage(e,t){let s=e.platform,r=e.chat_id,o=e.message;if(!s)return{success:!1,error:'Missing required field "platform"'};if(!o)return{success:!1,error:'Missing required field "message"'};let n=this.adapters.get(s);if(!n)return{success:!1,error:`Platform "${s}" is not connected. Available: ${[...this.adapters.keys()].join(", ")}`};if(!r||!/^[!0-9]/.test(r)){let i=this.resolveInternalId(t),a=this.users.getMasterUserId(i),d=this.users.getLinkedUsers(a).find(m=>m.platform===s);if(d&&this.findConversation){let m=this.findConversation(s,d.id);m&&(r=m.chatId)}!r&&d&&(r=d.platformUserId)}if(!r)return{success:!1,error:"Could not resolve chat_id for target platform. No linked account or conversation found."};try{return{success:!0,data:{messageId:await n.sendMessage(r,o),platform:s,chatId:r},display:`Message sent to ${s}.`}}catch(i){return{success:!1,error:`Failed to send message: ${i instanceof Error?i.message:String(i)}`}}}async listIdentities(e){let t=this.resolveInternalId(e),s=this.users.getMasterUserId(t),r=this.users.getLinkedUsers(s);if(r.length<=1)return{success:!0,data:{identities:r},display:`No linked accounts found. To link another platform, use:
505
505
  "Start linking my account" on the platform you want to link from, then enter the code on the other platform.`};let o=r.map(n=>{let i=n.id===t?" (current)":"",a=n.displayName??n.username??n.platformUserId;return`- **${n.platform}**: ${a}${i}`});return{success:!0,data:{identities:r.map(n=>({platform:n.platform,username:n.username,displayName:n.displayName}))},display:`Linked accounts:
@@ -509,7 +509,7 @@ ${r.join(`
509
509
  `)}`}}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 Gt,ac=E(()=>{"use strict";F();Me();Gt=class extends x{static{u(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.',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 W(e))for(let o of this.actionRepo.getByUser(r))t.has(o.id)||(t.add(o.id),s.push(o));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,o=e.schedule_type,n=e.schedule_value,i=e.skill_name,a=e.skill_input,l=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(!o||!["cron","interval","once"].includes(o))return{success:!1,error:'Missing or invalid "schedule_type". Must be "cron", "interval", or "once"'};if(!n||typeof n!="string")return{success:!1,error:'Missing required field "schedule_value" for create action'};if((!i||typeof i!="string")&&!l)return{success:!1,error:'Missing required field "skill_name" (or "prompt_template") for create action'};if(o==="interval"){let p=parseInt(n,10);if(isNaN(p)||p<=0)return{success:!1,error:"For interval schedule, value must be a positive number of minutes"}}if(o==="cron"&&n.trim().split(/\s+/).length!==5)return{success:!1,error:"Cron expression must have 5 fields: minute hour dayOfMonth month dayOfWeek"};if(o==="once"){let p=new Date(n);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:Z(t),platform:t.platform,chatId:t.chatId,name:s,description:r,scheduleType:o,scheduleValue:n,skillName:i??"llm_prompt",skillInput:JSON.stringify(a??{}),promptTemplate:l}),m=o==="cron"?`cron: ${n}`:o==="interval"?`every ${n} minutes`:`once at ${n}`;return{success:!0,data:{actionId:d.id,name:s,scheduleType:o,scheduleValue:n,skillName:i},display:`Scheduled action created (${d.id}): "${s}" \u2014 ${m}, 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 o=r.enabled?"\u2705":"\u23F8\uFE0F",n=r.scheduleType==="cron"?`cron: ${r.scheduleValue}`:r.scheduleType==="interval"?`every ${r.scheduleValue} min`:`once: ${r.scheduleValue}`,i=r.nextRunAt?` | next: ${r.nextRunAt}`:"";return`- ${o} ${r.id}: "${r.name}" [${n}] \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:
510
510
  ${s.join(`
511
511
  `)}`}}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 o=this.actionRepo.findById(r),n=W(s);return!o||!n.includes(o.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),o=W(t);return!r||!o.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 pt,In=E(()=>{"use strict";pt=class{static{u(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,o]of Object.entries(this.config.env))s[r]=o.replace(/\$\{(\w+)\}/g,(n,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(o=>o.text??JSON.stringify(o)).join(`
512
- `),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 bu,ht,xn=E(()=>{"use strict";F();bu=["read","write","destructive","admin"],ht=class extends x{static{u(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,o,n){super(),this.client=e,this.serverName=t,this.toolName=s;let i=n&&bu.includes(n)?n:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:i,version:"1.0.0",inputSchema:o}}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 Ks,cc=E(()=>{"use strict";In();xn();Ks=class{static{u(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new pt(t.name,t,this.logger.child({mcp:t.name}));await s.connect(),this.clients.push(s);let r=await s.listTools();for(let o of r){let n=new ht(s,t.name,o.name,o.description??"",o.inputSchema);this.skills.push(n)}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 lc=E(()=>{"use strict";In();xn();cc()});import{spawn as $u}from"node:child_process";import Kt from"node:fs";import Rn from"node:path";import vu from"node:os";import Su from"node:crypto";var ft,Cn=E(()=>{"use strict";ft=class{static{u(this,"CodeExecutor")}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),o=Rn.join(vu.tmpdir(),`alfred-sandbox-${Su.randomUUID()}`);Kt.mkdirSync(o,{recursive:!0});try{let n=t==="javascript"?"js":"py",i=Rn.join(o,`script.${n}`);Kt.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",l=[i],d=Date.now();return await new Promise(m=>{let p=$u(a,l,{cwd:o,timeout:r,env:{PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:"sandbox",PYTHONDONTWRITEBYTECODE:"1",...s?.env,TMPDIR:o,TEMP:o,TMP:o},stdio:["pipe","pipe","pipe"]}),T="",y="";p.stdout.on("data",f=>{T+=f.toString()}),p.stderr.on("data",f=>{y+=f.toString()}),p.on("close",f=>{let _=Date.now()-d,S=[];try{let A=Kt.readdirSync(o).filter(I=>!I.startsWith("script."));for(let I of A){let P=Rn.join(o,I),L=Kt.statSync(P);if(L.isFile()&&L.size<1e7){let X=Kt.readFileSync(P),Oe=I.endsWith(".png")?"image/png":I.endsWith(".jpg")||I.endsWith(".jpeg")?"image/jpeg":I.endsWith(".svg")?"image/svg+xml":I.endsWith(".csv")?"text/csv":I.endsWith(".json")?"application/json":I.endsWith(".html")||I.endsWith(".htm")?"text/html":I.endsWith(".txt")?"text/plain":I.endsWith(".md")?"text/markdown":I.endsWith(".xml")?"application/xml":I.endsWith(".pdf")?"application/pdf":"application/octet-stream";S.push({name:I,data:X,mimeType:Oe})}}}catch{}m({stdout:T.slice(0,5e4),stderr:y.slice(0,1e4),exitCode:f??1,files:S.length>0?S:void 0,durationMs:_})}),p.on("error",f=>{m({stdout:"",stderr:f.message,exitCode:1,durationMs:Date.now()-d})}),p.stdin.end()})}finally{try{Kt.rmSync(o,{recursive:!0,force:!0})}catch{}}}}});var Xs,dc=E(()=>{"use strict";F();Cn();Xs=class extends x{static{u(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 (HTML, CSV, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. 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:"destructive",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 to pass (available as DATA env var or stdin)"},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new ft;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,o=e.language,n=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(!o)return{success:!1,error:'Missing required field "language"'};if(!this.allowedLanguages.has(o))return{success:!1,error:`Language "${o}" is not allowed. Allowed: ${[...this.allowedLanguages].join(", ")}`};let a=r;s==="run_with_data"&&n&&(o==="javascript"?a=`const INPUT_DATA = ${JSON.stringify(n)};
512
+ `),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 bu,ht,xn=E(()=>{"use strict";F();bu=["read","write","destructive","admin"],ht=class extends x{static{u(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,o,n){super(),this.client=e,this.serverName=t,this.toolName=s;let i=n&&bu.includes(n)?n:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:i,version:"1.0.0",inputSchema:o}}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 Ks,cc=E(()=>{"use strict";In();xn();Ks=class{static{u(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new pt(t.name,t,this.logger.child({mcp:t.name}));await s.connect(),this.clients.push(s);let r=await s.listTools();for(let o of r){let n=new ht(s,t.name,o.name,o.description??"",o.inputSchema);this.skills.push(n)}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 lc=E(()=>{"use strict";In();xn();cc()});import{spawn as $u}from"node:child_process";import Kt from"node:fs";import Rn from"node:path";import vu from"node:os";import Su from"node:crypto";var ft,Cn=E(()=>{"use strict";ft=class{static{u(this,"CodeExecutor")}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),o=Rn.join(vu.tmpdir(),`alfred-sandbox-${Su.randomUUID()}`);Kt.mkdirSync(o,{recursive:!0});try{let n=t==="javascript"?"js":"py",i=Rn.join(o,`script.${n}`);Kt.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",l=[i],d=Date.now();return await new Promise(m=>{let p=$u(a,l,{cwd:o,timeout:r,env:{PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:"sandbox",PYTHONDONTWRITEBYTECODE:"1",...s?.env,TMPDIR:o,TEMP:o,TMP:o},stdio:["pipe","pipe","pipe"]}),w="",y="";p.stdout.on("data",h=>{w+=h.toString()}),p.stderr.on("data",h=>{y+=h.toString()}),p.on("close",h=>{let T=Date.now()-d,$=[];try{let A=Kt.readdirSync(o).filter(I=>!I.startsWith("script."));for(let I of A){let P=Rn.join(o,I),L=Kt.statSync(P);if(L.isFile()&&L.size<1e7){let X=Kt.readFileSync(P),Oe=I.endsWith(".png")?"image/png":I.endsWith(".jpg")||I.endsWith(".jpeg")?"image/jpeg":I.endsWith(".svg")?"image/svg+xml":I.endsWith(".csv")?"text/csv":I.endsWith(".json")?"application/json":I.endsWith(".html")||I.endsWith(".htm")?"text/html":I.endsWith(".txt")?"text/plain":I.endsWith(".md")?"text/markdown":I.endsWith(".xml")?"application/xml":I.endsWith(".pdf")?"application/pdf":"application/octet-stream";$.push({name:I,data:X,mimeType:Oe})}}}catch{}m({stdout:w.slice(0,5e4),stderr:y.slice(0,1e4),exitCode:h??1,files:$.length>0?$:void 0,durationMs:T})}),p.on("error",h=>{m({stdout:"",stderr:h.message,exitCode:1,durationMs:Date.now()-d})}),p.stdin.end()})}finally{try{Kt.rmSync(o,{recursive:!0,force:!0})}catch{}}}}});var Xs,dc=E(()=>{"use strict";F();Cn();Xs=class extends x{static{u(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 (HTML, CSV, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. 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:"destructive",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 to pass (available as DATA env var or stdin)"},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new ft;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,o=e.language,n=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(!o)return{success:!1,error:'Missing required field "language"'};if(!this.allowedLanguages.has(o))return{success:!1,error:`Language "${o}" is not allowed. Allowed: ${[...this.allowedLanguages].join(", ")}`};let a=r;s==="run_with_data"&&n&&(o==="javascript"?a=`const INPUT_DATA = ${JSON.stringify(n)};
513
513
  ${r}`:a=`INPUT_DATA = ${JSON.stringify(n)}
514
514
  ${r}`);let l=await this.executor.execute(a,o,{timeout:i}),d=l.files?.map(p=>({fileName:p.name,data:p.data,mimeType:p.mimeType})),m=[l.stdout?`Output:
515
515
  ${l.stdout}`:"",l.stderr?`Errors:
@@ -570,20 +570,20 @@ Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this
570
570
  `)}}async callService(e,t,s,r){if(!e)return{success:!1,error:'Missing required "domain" parameter for call_service'};if(!t)return{success:!1,error:'Missing required "service" parameter for call_service'};let o={};if(s&&(o.entity_id=s),r)try{let l=JSON.parse(r);Object.assign(o,l)}catch{return{success:!1,error:'Invalid "serviceData" \u2014 must be valid JSON'}}let n=await this.api("POST",`/api/services/${e}/${t}`,o),i=n?.length??0,a=[`**Service called:** \`${e}.${t}\``,s?`**Entity:** ${s}`:"",`**Affected entities:** ${i}`].filter(Boolean);if(n&&n.length>0){a.push("");for(let l of n){let d=l.attributes?.friendly_name??l.entity_id??"unknown";a.push(`- **${d}**: ${l.state}`)}}return{success:!0,data:n,display:a.join(`
571
571
  `)}}async getAreas(e){if(e){let n=`{% for eid in area_entities('${e.replace(/'/g,"\\'")}') %}{{ eid }}||{{ states(eid) }}||{{ state_attr(eid, 'friendly_name') }}
572
572
  {% endfor %}`,a=(await this.apiText("POST","/api/template",{template:n})).trim().split(`
573
- `).filter(Boolean),l=[`## Area: ${e}`,"","| Entity ID | State | Name |","|-----------|-------|------|"];for(let d of a){let[m,p,T]=d.split("||");l.push(`| ${m} | ${p} | ${T??"-"} |`)}return a.length===0&&l.push(`| - | No entities found for area "${e}" | - |`),{success:!0,data:a,display:l.join(`
573
+ `).filter(Boolean),l=[`## Area: ${e}`,"","| Entity ID | State | Name |","|-----------|-------|------|"];for(let d of a){let[m,p,w]=d.split("||");l.push(`| ${m} | ${p} | ${w??"-"} |`)}return a.length===0&&l.push(`| - | No entities found for area "${e}" | - |`),{success:!0,data:a,display:l.join(`
574
574
  `)}}let r=(await this.apiText("POST","/api/template",{template:`{% for aid in areas() %}{{ area_name(aid) }}||{{ aid }}||{{ area_entities(aid) | length }}
575
575
  {% endfor %}`})).trim().split(`
576
576
  `).filter(Boolean),o=["## Areas","","| Area Name | Area ID | Entity Count |","|-----------|---------|--------------|"];for(let n of r){let[i,a,l]=n.split("||");o.push(`| ${i} | ${a} | ${l} |`)}return r.length===0&&o.push("| - | No areas configured | - |"),{success:!0,data:r,display:o.join(`
577
577
  `)}}async renderTemplate(e){if(!e)return{success:!1,error:'Missing required "template" parameter'};let t=await this.apiText("POST","/api/template",{template:e});return{success:!0,data:t,display:t}}async getPresence(){let t=(await this.api("GET","/api/states")).filter(r=>r.entity_id.startsWith("person.")),s=["## Presence","","| Person | Status | Last Changed |","|--------|--------|--------------|"];for(let r of t){let o=r.attributes?.friendly_name??r.entity_id,n=r.state??"unknown",i=r.last_changed?new Date(r.last_changed).toLocaleString():"-";s.push(`| ${o} | ${n} | ${i} |`)}return t.length===0&&s.push("| - | No person entities found | - |"),{success:!0,data:t,display:s.join(`
578
578
  `)}}async sendNotification(e,t,s){if(!e)return{success:!1,error:'Missing required "message" parameter'};let r=s??"notify",o={message:e};return t&&(o.title=t),{success:!0,data:await this.api("POST",`/api/services/notify/${r}`,o),display:[`**Notification sent** \u2192 \`notify.${r}\``,t?`**Title:** ${t}`:"",`**Message:** ${e.slice(0,200)}${e.length>200?"\u2026":""}`].filter(Boolean).join(`
579
579
  `)}}async activateScene(e){if(!e){let o=(await this.api("GET","/api/states")).filter(i=>i.entity_id.startsWith("scene.")),n=["## Available Scenes","","| Entity ID | Name |","|-----------|------|"];for(let i of o){let a=i.attributes?.friendly_name??i.entity_id;n.push(`| ${i.entity_id} | ${a} |`)}return o.length===0&&n.push("| - | No scenes found |"),{success:!0,data:o,display:n.join(`
580
- `)}}let t=await this.api("POST","/api/services/scene/turn_on",{entity_id:e}),s=t?.[0]?.attributes?.friendly_name??e;return{success:!0,data:t,display:`**Scene activated:** ${s} (\`${e}\`)`}}async triggerAutomation(e,t){if(!e){let d=(await this.api("GET","/api/states")).filter(p=>p.entity_id.startsWith("automation.")),m=["## Automations","","| Entity ID | Name | State | Last Triggered |","|-----------|------|-------|----------------|"];for(let p of d){let T=p.attributes?.friendly_name??p.entity_id,y=p.attributes?.last_triggered?new Date(p.attributes.last_triggered).toLocaleString():"-";m.push(`| ${p.entity_id} | ${T} | ${p.state} | ${y} |`)}return d.length===0&&m.push("| - | No automations found | - | - |"),{success:!0,data:d,display:m.join(`
580
+ `)}}let t=await this.api("POST","/api/services/scene/turn_on",{entity_id:e}),s=t?.[0]?.attributes?.friendly_name??e;return{success:!0,data:t,display:`**Scene activated:** ${s} (\`${e}\`)`}}async triggerAutomation(e,t){if(!e){let d=(await this.api("GET","/api/states")).filter(p=>p.entity_id.startsWith("automation.")),m=["## Automations","","| Entity ID | Name | State | Last Triggered |","|-----------|------|-------|----------------|"];for(let p of d){let w=p.attributes?.friendly_name??p.entity_id,y=p.attributes?.last_triggered?new Date(p.attributes.last_triggered).toLocaleString():"-";m.push(`| ${p.entity_id} | ${w} | ${p.state} | ${y} |`)}return d.length===0&&m.push("| - | No automations found | - | - |"),{success:!0,data:d,display:m.join(`
581
581
  `)}}let s={trigger:"trigger",enable:"turn_on",disable:"turn_off"},r=t??"trigger",o=s[r]??"trigger",n=await this.api("POST",`/api/services/automation/${o}`,{entity_id:e}),i=n?.[0]?.attributes?.friendly_name??e,a=n?.[0]?.attributes?.last_triggered?new Date(n[0].attributes.last_triggered).toLocaleString():"-";return{success:!0,data:n,display:[`**Automation ${r}:** ${i} (\`${e}\`)`,`**Last triggered:** ${a}`].join(`
582
582
  `)}}async runScript(e,t){if(!e){let i=(await this.api("GET","/api/states")).filter(l=>l.entity_id.startsWith("script.")),a=["## Scripts","","| Entity ID | Name | State |","|-----------|------|-------|"];for(let l of i){let d=l.attributes?.friendly_name??l.entity_id;a.push(`| ${l.entity_id} | ${d} | ${l.state} |`)}return i.length===0&&a.push("| - | No scripts found | - |"),{success:!0,data:i,display:a.join(`
583
583
  `)}}let s=e.startsWith("script.")?e.slice(7):e,r={};if(t)try{r=JSON.parse(t)}catch{return{success:!1,error:'Invalid "variables" \u2014 must be valid JSON'}}return{success:!0,data:await this.api("POST",`/api/services/script/${s}`,r),display:`**Script executed:** \`script.${s}\``}}async getCalendarEvents(e,t,s){if(!e){let a=await this.api("GET","/api/calendars"),l=["## Calendars","","| Entity ID | Name |","|-----------|------|"];for(let d of a){let m=d.name??d.entity_id??"-";l.push(`| ${d.entity_id} | ${m} |`)}return a.length===0&&l.push("| - | No calendars found |"),{success:!0,data:a,display:l.join(`
584
584
  `)}}let r=t??new Date().toISOString(),o=s??new Date(Date.now()+864e5).toISOString(),n=await this.api("GET",`/api/calendars/${e}?start=${encodeURIComponent(r)}&end=${encodeURIComponent(o)}`),i=[`## Calendar Events: ${e}`,"","| Start | End | Summary | Location |","|-------|-----|---------|----------|"];for(let a of n){let l=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(`| ${l} | ${d} | ${a.summary??"-"} | ${a.location??"-"} |`)}return n.length===0&&i.push("| - | - | No events in range | - |"),{success:!0,data:n,display:i.join(`
585
585
  `)}}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(`
586
- `)}}}});var Ce,Js=E(()=>{"use strict";Ce=class{static{u(this,"ContactsProvider")}}});var wc={};oe(wc,{CardDAVContactsProvider:()=>Xr});var Xr,Ln=E(()=>{"use strict";Js();Xr=class extends Ce{static{u(this,"CardDAVContactsProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"carddav"})}catch(e){throw new Error(`CardDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async list(e,t){let s=await this.client.fetchAddressBooks();if(!s||s.length===0)return[];let r=[];for(let o of s){let n=await this.client.fetchVCards({addressBook:o});for(let i of n){let a=this.parseVCard(i.data,i.url);a&&r.push(a)}}return r.sort((o,n)=>o.displayName.localeCompare(n.displayName)),e?r.slice(0,e):r}async search(e){let t=await this.list(),s=e.toLowerCase();return t.filter(r=>r.displayName.toLowerCase().includes(s)||r.emails.some(o=>o.address.toLowerCase().includes(s))||r.phones.some(o=>o.number.includes(s)))}async get(e){return(await this.list()).find(s=>s.id===e)}async create(e){let t=await this.client.fetchAddressBooks();if(!t||t.length===0)throw new Error("No address books found");let s=`alfred-${Date.now()}@alfred`,r=this.buildVCard(s,e);await this.client.createVCard({addressBook:t[0],filename:`${s}.vcf`,vCardString:r});let o=e.displayName??([e.firstName,e.lastName].filter(Boolean).join(" ")||"Unknown");return{id:s,displayName:o,firstName:e.firstName,lastName:e.lastName,emails:e.emails??[],phones:e.phones??[],addresses:e.addresses??[],organization:e.organization,birthday:e.birthday,notes:e.notes}}async update(e,t){let s=await this.client.fetchAddressBooks();for(let r of s){let o=await this.client.fetchVCards({addressBook:r});for(let n of o)if(n.url?.includes(e)||n.data?.includes(e)){let i=this.parseVCard(n.data,n.url);if(!i)continue;let a={firstName:t.firstName??i.firstName,lastName:t.lastName??i.lastName,displayName:t.displayName??i.displayName,emails:t.emails??i.emails,phones:t.phones??i.phones,addresses:t.addresses??i.addresses,organization:t.organization??i.organization,birthday:t.birthday??i.birthday,notes:t.notes??i.notes},l=this.buildVCard(e,a);await this.client.updateVCard({vCard:{...n,data:l}});let d=a.displayName??([a.firstName,a.lastName].filter(Boolean).join(" ")||"Unknown");return{id:e,displayName:d,firstName:a.firstName,lastName:a.lastName,emails:a.emails??[],phones:a.phones??[],addresses:a.addresses??[],organization:a.organization,birthday:a.birthday,notes:a.notes}}}throw new Error(`Contact ${e} not found`)}async delete(e){let t=await this.client.fetchAddressBooks();for(let s of t){let r=await this.client.fetchVCards({addressBook:s});for(let o of r)if(o.url?.includes(e)||o.data?.includes(e)){await this.client.deleteVCard({vCard:o});return}}throw new Error(`Contact ${e} not found`)}parseVCard(e,t){let s=u(f=>e.match(new RegExp(`^${f}[;:](.*)$`,"mi"))?.[1]?.trim(),"get"),r=s("FN");if(!r)return;let o=s("N"),[n,i]=o?o.split(";"):[void 0,void 0],a=[];for(let f of e.matchAll(/^EMAIL[^:]*:(.+)$/gmi)){let _=f[0],S=f[1].trim(),A=_.match(/TYPE=([^;:,]+)/i)?.[1],I=/TYPE=pref/i.test(_);a.push({address:S,label:A,primary:I})}let l=[];for(let f of e.matchAll(/^TEL[^:]*:(.+)$/gmi)){let _=f[0],S=f[1].trim(),A=_.match(/TYPE=([^;:,]+)/i)?.[1],I=/TYPE=pref/i.test(_);l.push({number:S,label:A,primary:I})}let d=[];for(let f of e.matchAll(/^ADR[^:]*:(.+)$/gmi)){let _=f[1].split(";");d.push({street:_[2]?.trim()||void 0,city:_[3]?.trim()||void 0,region:_[4]?.trim()||void 0,postalCode:_[5]?.trim()||void 0,country:_[6]?.trim()||void 0})}let m=s("ORG")?.replace(/;.*$/,""),p=s("BDAY"),T=s("NOTE");return{id:s("UID")??t,displayName:r,firstName:i,lastName:n,emails:a,phones:l,addresses:d,organization:m,birthday:p,notes:T}}buildVCard(e,t){let s=t.displayName??([t.firstName,t.lastName].filter(Boolean).join(" ")||"Unknown"),r=`BEGIN:VCARD\r
586
+ `)}}}});var Ce,Js=E(()=>{"use strict";Ce=class{static{u(this,"ContactsProvider")}}});var wc={};oe(wc,{CardDAVContactsProvider:()=>Xr});var Xr,Ln=E(()=>{"use strict";Js();Xr=class extends Ce{static{u(this,"CardDAVContactsProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"carddav"})}catch(e){throw new Error(`CardDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async list(e,t){let s=await this.client.fetchAddressBooks();if(!s||s.length===0)return[];let r=[];for(let o of s){let n=await this.client.fetchVCards({addressBook:o});for(let i of n){let a=this.parseVCard(i.data,i.url);a&&r.push(a)}}return r.sort((o,n)=>o.displayName.localeCompare(n.displayName)),e?r.slice(0,e):r}async search(e){let t=await this.list(),s=e.toLowerCase();return t.filter(r=>r.displayName.toLowerCase().includes(s)||r.emails.some(o=>o.address.toLowerCase().includes(s))||r.phones.some(o=>o.number.includes(s)))}async get(e){return(await this.list()).find(s=>s.id===e)}async create(e){let t=await this.client.fetchAddressBooks();if(!t||t.length===0)throw new Error("No address books found");let s=`alfred-${Date.now()}@alfred`,r=this.buildVCard(s,e);await this.client.createVCard({addressBook:t[0],filename:`${s}.vcf`,vCardString:r});let o=e.displayName??([e.firstName,e.lastName].filter(Boolean).join(" ")||"Unknown");return{id:s,displayName:o,firstName:e.firstName,lastName:e.lastName,emails:e.emails??[],phones:e.phones??[],addresses:e.addresses??[],organization:e.organization,birthday:e.birthday,notes:e.notes}}async update(e,t){let s=await this.client.fetchAddressBooks();for(let r of s){let o=await this.client.fetchVCards({addressBook:r});for(let n of o)if(n.url?.includes(e)||n.data?.includes(e)){let i=this.parseVCard(n.data,n.url);if(!i)continue;let a={firstName:t.firstName??i.firstName,lastName:t.lastName??i.lastName,displayName:t.displayName??i.displayName,emails:t.emails??i.emails,phones:t.phones??i.phones,addresses:t.addresses??i.addresses,organization:t.organization??i.organization,birthday:t.birthday??i.birthday,notes:t.notes??i.notes},l=this.buildVCard(e,a);await this.client.updateVCard({vCard:{...n,data:l}});let d=a.displayName??([a.firstName,a.lastName].filter(Boolean).join(" ")||"Unknown");return{id:e,displayName:d,firstName:a.firstName,lastName:a.lastName,emails:a.emails??[],phones:a.phones??[],addresses:a.addresses??[],organization:a.organization,birthday:a.birthday,notes:a.notes}}}throw new Error(`Contact ${e} not found`)}async delete(e){let t=await this.client.fetchAddressBooks();for(let s of t){let r=await this.client.fetchVCards({addressBook:s});for(let o of r)if(o.url?.includes(e)||o.data?.includes(e)){await this.client.deleteVCard({vCard:o});return}}throw new Error(`Contact ${e} not found`)}parseVCard(e,t){let s=u(h=>e.match(new RegExp(`^${h}[;:](.*)$`,"mi"))?.[1]?.trim(),"get"),r=s("FN");if(!r)return;let o=s("N"),[n,i]=o?o.split(";"):[void 0,void 0],a=[];for(let h of e.matchAll(/^EMAIL[^:]*:(.+)$/gmi)){let T=h[0],$=h[1].trim(),A=T.match(/TYPE=([^;:,]+)/i)?.[1],I=/TYPE=pref/i.test(T);a.push({address:$,label:A,primary:I})}let l=[];for(let h of e.matchAll(/^TEL[^:]*:(.+)$/gmi)){let T=h[0],$=h[1].trim(),A=T.match(/TYPE=([^;:,]+)/i)?.[1],I=/TYPE=pref/i.test(T);l.push({number:$,label:A,primary:I})}let d=[];for(let h of e.matchAll(/^ADR[^:]*:(.+)$/gmi)){let T=h[1].split(";");d.push({street:T[2]?.trim()||void 0,city:T[3]?.trim()||void 0,region:T[4]?.trim()||void 0,postalCode:T[5]?.trim()||void 0,country:T[6]?.trim()||void 0})}let m=s("ORG")?.replace(/;.*$/,""),p=s("BDAY"),w=s("NOTE");return{id:s("UID")??t,displayName:r,firstName:i,lastName:n,emails:a,phones:l,addresses:d,organization:m,birthday:p,notes:w}}buildVCard(e,t){let s=t.displayName??([t.firstName,t.lastName].filter(Boolean).join(" ")||"Unknown"),r=`BEGIN:VCARD\r
587
587
  VERSION:3.0\r
588
588
  `;r+=`UID:${e}\r
589
589
  `,r+=`FN:${s}\r
@@ -610,7 +610,7 @@ ${a}`}}completeTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success
610
610
  `);return{success:!0,data:s,display:`${s.length} list(s):
611
611
  ${r}
612
612
  ${o}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(Z(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import Sc from"node:http";import kc from"node:https";import{execFile as Au}from"node:child_process";import{promisify as Iu}from"node:util";function On(c){return c==null||c<0?"-":c===0?"0 B":c<1024?`${c} B`:c<1024**2?`${(c/1024).toFixed(1)} KiB`:c<1024**3?`${(c/1024**2).toFixed(1)} MiB`:`${(c/1024**3).toFixed(2)} GiB`}function Ic(c){return!c||c.length===0?"-":c.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 Pn(c){return!c||c.length===0?"-":c.map(e=>e.replace(/^\//,"")).join(", ")}function xu(c){let e=Buffer.from(c,"binary"),t=[],s=0;for(;s<e.length;)if(s+8<=e.length){let r=e.readUInt32BE(s+4),o=e.subarray(s+8,s+8+r).toString("utf8");t.push(o),s+=8+r}else{t.push(e.subarray(s).toString("utf8"));break}return t.join("")}function Ru(c){return c?new Date(c*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var Ac,Qr,xc=E(()=>{"use strict";F();Ac=Iu(Au);u(On,"formatBytes");u(Ic,"formatPorts");u(Pn,"containerName");u(xu,"stripDockerStreamHeaders");u(Ru,"relativeTime");Qr=class extends x{static{u(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,o)=>{let n={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let l=new URL(this.config.host);n.hostname=l.hostname,n.port=l.port}else n.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?kc:Sc).request(n,l=>{let d="";l.on("data",m=>{d+=m}),l.on("end",()=>{if(l.statusCode&&l.statusCode>=400){o(new Error(`Docker API ${l.statusCode}: ${d.slice(0,500)}`));return}try{r(d?JSON.parse(d):void 0)}catch{o(new Error(`Invalid JSON from Docker API: ${d.slice(0,200)}`))}})});a.on("error",o),a.setTimeout(3e4,()=>{a.destroy(),o(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}apiRaw(e,t,s){return new Promise((r,o)=>{let n={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let l=new URL(this.config.host);n.hostname=l.hostname,n.port=l.port}else n.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?kc:Sc).request(n,l=>{let d=[];l.on("data",m=>{d.push(m)}),l.on("end",()=>{if(l.statusCode&&l.statusCode>=400){let m=Buffer.concat(d).toString("utf8");o(new Error(`Docker API ${l.statusCode}: ${m.slice(0,500)}`));return}r(Buffer.concat(d).toString("binary"))})});a.on("error",o),a.setTimeout(3e4,()=>{a.destroy(),o(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(`| ${Pn(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${Ic(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
613
- `)}}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??{},o=t.NetworkSettings??{},n=t.Mounts??[],a=Object.entries(o.Ports??{}).filter(([,p])=>p&&p.length>0).map(([p,T])=>`${T.map(f=>`${f.HostIp??"0.0.0.0"}:${f.HostPort}`).join(", ")} -> ${p}`),l=n.map(p=>`- ${p.Source??"-"} -> ${p.Destination??"-"} (${p.Type??"-"}, ${p.RW?"rw":"ro"})`),d=o.IPAddress||Object.values(o.Networks??{}).map(p=>p.IPAddress).filter(Boolean).join(", ")||"-",m=[`## Container: ${Pn(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(`
613
+ `)}}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??{},o=t.NetworkSettings??{},n=t.Mounts??[],a=Object.entries(o.Ports??{}).filter(([,p])=>p&&p.length>0).map(([p,w])=>`${w.map(h=>`${h.HostIp??"0.0.0.0"}:${h.HostPort}`).join(", ")} -> ${p}`),l=n.map(p=>`- ${p.Source??"-"} -> ${p.Destination??"-"} (${p.Type??"-"}, ${p.RW?"rw":"ro"})`),d=o.IPAddress||Object.values(o.Networks??{}).map(p=>p.IPAddress).filter(Boolean).join(", ")||"-",m=[`## Container: ${Pn(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(`
614
614
  `):"- No port bindings","","### Mounts",l.length>0?l.join(`
615
615
  `):"- No mounts"];return{success:!0,data:t,display:m.join(`
616
616
  `)}}async getLogs(e,t){if(!e)return{success:!1,error:'Missing required "containerId" parameter'};let s=t??100,r=await this.apiRaw("GET",`/containers/${encodeURIComponent(e)}/logs?stdout=1&stderr=1&tail=${s}`),o=xu(r),n=[`## Logs: ${e} (last ${s} lines)`,"","```",o.trimEnd(),"```"];return{success:!0,data:o,display:n.join(`
@@ -629,9 +629,9 @@ ${o}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(Z(t),s);r
629
629
  `)}}}});import{readFile as Rc,writeFile as Cc,mkdir as Lc}from"node:fs/promises";import{homedir as Un}from"node:os";import{join as Fn}from"node:path";import Mc from"node:crypto";function Mu(){let c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Mc.randomBytes(86);return Array.from(e).map(t=>c[t%c.length]).join("")}function Ou(c){return Mc.createHash("sha256").update(c).digest("base64url")}function ue(c,e){return c[e]?.value??"?"}var Cu,Nc,eo,Lu,Nu,Du,Dc,to,Pu,so,Oc=E(()=>{"use strict";F();Cu="https://customer.bmwgroup.com/gcdm/oauth/device/code",Nc="https://customer.bmwgroup.com/gcdm/oauth/token",eo="https://api-cardata.bmwgroup.com",Lu="v1",Nu="authenticate_user openid cardata:api:read cardata:streaming:read",Du=5*6e4,Dc="Alfred",to=Fn(Un(),".alfred","bmw-tokens.json");u(Mu,"generateCodeVerifier");u(Ou,"generateCodeChallenge");Pu=["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"];u(ue,"tv");so=class extends x{static{u(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).',riskLevel:"read",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["authorize","status","charging","charging_sessions"],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)"}},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);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=Mu(),s=Ou(t),r=await fetch(Cu,{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:Nu}),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 o=await r.json(),n={codeVerifier:t,deviceCode:o.device_code};return await this.savePartialTokens(n),{success:!0,data:o,display:["## BMW Autorisierung","",`1. \xD6ffne: **${o.verification_uri_complete??o.verification_uri}**`,`2. Gib diesen Code ein: **${o.user_code}**`,"",`Danach ruf diese Action erneut auf mit \`device_code: "${o.device_code}"\` um den Token abzuholen.`].join(`
630
630
  `)}}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(Nc,{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 o=await r.json(),n=o.access_token,i={accessToken:n,refreshToken:o.refresh_token,idToken:o.id_token,expiresAt:Date.now()+(o.expires_in??3600)*1e3,vin:"",containerId:""},a=await this.fetchVin(n);i.vin=a,await this.saveTokens(i);let l="",d="";try{l=await this.ensureContainer(n),i.containerId=l,await this.saveTokens(i)}catch(p){d=p instanceof Error?p.message:String(p)}this.tokens=i;let m=["## BMW Autorisierung erfolgreich","",`**VIN:** ${a}`];return l?(m.push(`**Container:** ${l}`),m.push("Tokens gespeichert. Du kannst jetzt Fahrzeugdaten abrufen.")):(m.push(`**Container-Fehler:** ${d}`),m.push("Tokens + VIN gespeichert, aber Container konnte nicht erstellt werden."),m.push("Erstelle den Container manuell im BMW CarData Portal oder versuche es erneut.")),{success:l!=="",data:{vin:a,containerId:l,containerError:d||void 0},display:m.join(`
631
631
  `)}}async fetchVin(e){let t=await fetch(`${eo}/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(n=>n.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(`${eo}/customers/containers`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(t.ok){let o=await t.json(),i=(Array.isArray(o)?o:Array.isArray(o.containers)?o.containers:[]).find(a=>a.name===Dc);if(i)return i.containerId}let s=await fetch(`${eo}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:Dc,purpose:"Alfred AI Assistant",technicalDescriptors:Pu}),signal:AbortSignal.timeout(15e3)});if(!s.ok){let o=await s.text().catch(()=>"");throw new Error(`Container creation failed: HTTP ${s.status} \u2014 ${o.slice(0,300)}`)}return(await s.json()).containerId}apiHeaders(e){return{Authorization:`Bearer ${e}`,"x-version":Lu,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<Du)return s.data;let r=await this.ensureToken(),o=`${eo}${e}`,n=await fetch(o,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)});if(n.status===401){let a=await this.loadTokens();a&&(r=await this.refreshAccessToken(a),n=await fetch(o,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)}))}if(!n.ok){let a=await n.text().catch(()=>"");throw new Error(`HTTP ${n.status} \u2014 ${a.slice(0,300)}`)}let i=await n.json();return this.cache.set(t,{data:i,ts:Date.now()}),i}async loadTokens(){if(this.tokens)return this.tokens;try{let e=await Rc(to,"utf-8");return this.tokens=JSON.parse(e),this.tokens}catch{return null}}async saveTokens(e){await Lc(Fn(Un(),".alfred"),{recursive:!0}),await Cc(to,JSON.stringify(e,null,2),"utf-8")}async savePartialTokens(e){await Lc(Fn(Un(),".alfred"),{recursive:!0});let t={};try{let s=await Rc(to,"utf-8");t=JSON.parse(s)}catch{}await Cc(to,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(Nc,{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,o]=await Promise.all([this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`),this.apiGet(`/customers/vehicles/${t}/basicData`)]),n=r.telematicData??{},i=ue(n,"vehicle.drivetrain.batteryManagement.header"),a=ue(n,"vehicle.drivetrain.electricEngine.remainingElectricRange"),l=ue(n,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=ue(n,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),p=["## BMW Fahrzeugstatus","",`**Modell:** ${o.modelName??o.model??"?"}`,`**VIN:** ${t}`,`**Ladestand (SoC):** ${i} %`,`**Elektrische Reichweite:** ${a} km`,`**Batteriekapazit\xE4t:** ${l} kWh`,`**Batterie-Gesundheit (SoH):** ${d} %`];return{success:!0,data:{telematic:n,basic:o},display:p.join(`
632
- `)}}async getCharging(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),o=(await this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`)).telematicData??{},n=ue(o,"vehicle.drivetrain.electricEngine.charging.status"),i=ue(o,"vehicle.drivetrain.batteryManagement.header"),a=ue(o,"vehicle.drivetrain.electricEngine.charging.level"),l=ue(o,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=ue(o,"vehicle.powertrain.electric.battery.charging.power"),m=ue(o,"vehicle.drivetrain.electricEngine.charging.hvStatus"),p=ue(o,"vehicle.powertrain.electric.battery.stateOfCharge.target"),T=ue(o,"vehicle.drivetrain.electricEngine.charging.acVoltage"),y=ue(o,"vehicle.drivetrain.electricEngine.charging.acAmpere"),f=ue(o,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"),_=ue(o,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen"),S=ue(o,"vehicle.body.chargingPort.lockedStatus"),A=["## BMW Ladestatus","",`**Status:** ${n}`,`**Ladestand:** ${i} %`,`**Ladelevel:** ${a}`,`**Ladeleistung:** ${d} kW`,`**Restzeit:** ${l} min`,`**Ziel-SoC:** ${p} %`,`**HV-Batterie:** ${m}`,`**AC Spannung:** ${T} V`,`**AC Strom:** ${y} A`,`**Stecker eingesteckt:** ${f}`,`**Ladeklappe offen:** ${_}`,`**Ladeport-Schloss:** ${S}`];return{success:!0,data:o,display:A.join(`
633
- `)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),o=new Date,n=s??o.toISOString(),i=t??new Date(o.getTime()-30*24*60*6e4).toISOString(),a=await this.apiGet(`/customers/vehicles/${r}/chargingHistory?from=${encodeURIComponent(i)}&to=${encodeURIComponent(n)}`),l=a.data??a.chargingSessions??[],d=[`## BMW Lade-Sessions (${i.slice(0,10)} \u2013 ${n.slice(0,10)})`,"","| Datum | Dauer | Energie | Start-SoC | End-SoC |","|-------|-------|---------|-----------|---------|"];for(let m of l.slice(0,20)){let p=m.startTime,T=p?new Date(p).toLocaleDateString("de-AT"):"-",y=m.totalChargingDurationSec,f=y!=null?Math.round(y/60):"-",_=m.energyConsumedFromPowerGridKwh??"-",S=m.displayedStartSoc??"-",A=m.displayedSoc??"-";d.push(`| ${T} | ${f} min | ${_} kWh | ${S}% | ${A}% |`)}return l.length===0&&d.push("| - | Keine Sessions gefunden | - | - | - |"),{success:!0,data:a,display:d.join(`
634
- `)}}}});var Uu,ro,Pc=E(()=>{"use strict";F();Uu="https://routes.googleapis.com/directions/v2:computeRoutes",ro=class extends x{static{u(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 oder "lat,lng" 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 oder "lat,lng"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng"'},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,o=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!o)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,o,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,o,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(n){return{success:!1,error:`Google Routes API error: ${n instanceof Error?n.message:String(n)}`}}}async computeRoute(e,t,s,r){let o=this.buildRequestBody(e,t,r,s),i=(await this.callRoutesApi(o)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=(i.distanceMeters/1e3).toFixed(1),l=this.parseDuration(i.duration),d=this.parseDuration(i.staticDuration),m=l-d,p=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(l)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(m>1&&p.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(m)}`),s){let T=new Date(new Date(s).getTime()+l*6e4);p.push(`**Gesch\xE4tzte Ankunft:** ${T.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:l,staticDurationMinutes:d},display:p.join(`
632
+ `)}}async getCharging(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),o=(await this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`)).telematicData??{},n=ue(o,"vehicle.drivetrain.electricEngine.charging.status"),i=ue(o,"vehicle.drivetrain.batteryManagement.header"),a=ue(o,"vehicle.drivetrain.electricEngine.charging.level"),l=ue(o,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=ue(o,"vehicle.powertrain.electric.battery.charging.power"),m=ue(o,"vehicle.drivetrain.electricEngine.charging.hvStatus"),p=ue(o,"vehicle.powertrain.electric.battery.stateOfCharge.target"),w=ue(o,"vehicle.drivetrain.electricEngine.charging.acVoltage"),y=ue(o,"vehicle.drivetrain.electricEngine.charging.acAmpere"),h=ue(o,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"),T=ue(o,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen"),$=ue(o,"vehicle.body.chargingPort.lockedStatus"),A=["## BMW Ladestatus","",`**Status:** ${n}`,`**Ladestand:** ${i} %`,`**Ladelevel:** ${a}`,`**Ladeleistung:** ${d} kW`,`**Restzeit:** ${l} min`,`**Ziel-SoC:** ${p} %`,`**HV-Batterie:** ${m}`,`**AC Spannung:** ${w} V`,`**AC Strom:** ${y} A`,`**Stecker eingesteckt:** ${h}`,`**Ladeklappe offen:** ${T}`,`**Ladeport-Schloss:** ${$}`];return{success:!0,data:o,display:A.join(`
633
+ `)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),o=new Date,n=s??o.toISOString(),i=t??new Date(o.getTime()-30*24*60*6e4).toISOString(),a=await this.apiGet(`/customers/vehicles/${r}/chargingHistory?from=${encodeURIComponent(i)}&to=${encodeURIComponent(n)}`),l=a.data??a.chargingSessions??[],d=[`## BMW Lade-Sessions (${i.slice(0,10)} \u2013 ${n.slice(0,10)})`,"","| Datum | Dauer | Energie | Start-SoC | End-SoC |","|-------|-------|---------|-----------|---------|"];for(let m of l.slice(0,20)){let p=m.startTime,w=p?new Date(p).toLocaleDateString("de-AT"):"-",y=m.totalChargingDurationSec,h=y!=null?Math.round(y/60):"-",T=m.energyConsumedFromPowerGridKwh??"-",$=m.displayedStartSoc??"-",A=m.displayedSoc??"-";d.push(`| ${w} | ${h} min | ${T} kWh | ${$}% | ${A}% |`)}return l.length===0&&d.push("| - | Keine Sessions gefunden | - | - | - |"),{success:!0,data:a,display:d.join(`
634
+ `)}}}});var Uu,ro,Pc=E(()=>{"use strict";F();Uu="https://routes.googleapis.com/directions/v2:computeRoutes",ro=class extends x{static{u(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 oder "lat,lng" 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 oder "lat,lng"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng"'},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,o=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!o)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,o,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,o,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(n){return{success:!1,error:`Google Routes API error: ${n instanceof Error?n.message:String(n)}`}}}async computeRoute(e,t,s,r){let o=this.buildRequestBody(e,t,r,s),i=(await this.callRoutesApi(o)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=(i.distanceMeters/1e3).toFixed(1),l=this.parseDuration(i.duration),d=this.parseDuration(i.staticDuration),m=l-d,p=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(l)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(m>1&&p.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(m)}`),s){let w=new Date(new Date(s).getTime()+l*6e4);p.push(`**Gesch\xE4tzte Ankunft:** ${w.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:l,staticDurationMinutes:d},display:p.join(`
635
635
  `)}}async computeDepartureTime(e,t,s,r){if(!s)return{success:!1,error:'Missing required field "arrival_time" for departure_time action'};let o=this.buildRequestBody(e,t,r),i=(await this.callRoutesApi(o)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=this.parseDuration(i.duration),l=Math.max(5,Math.round(a*.15)),d=new Date(s),m=new Date(d.getTime()-(a+l)*6e4),p=["## Abfahrtszeit-Empfehlung","",`**Route:** ${e} \u2192 ${t}`,`**Gew\xFCnschte Ankunft:** ${d.toLocaleString("de-AT")}`,`**Gesch\xE4tzte Fahrzeit:** ${this.formatMinutes(a)} (inkl. Verkehr)`,`**Puffer:** ${l} min`,"",`**Empfohlene Abfahrt:** ${m.toLocaleString("de-AT")}`];return{success:!0,data:{departureTime:m.toISOString(),durationMinutes:a,bufferMinutes:l},display:p.join(`
636
636
  `)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",o=Math.abs(s),n=String(Math.floor(o/60)).padStart(2,"0"),i=String(o%60).padStart(2,"0"),a=u(l=>String(l).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}${n}:${i}`}buildRequestBody(e,t,s,r,o){let n={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&&(n.departureTime=i)}if(o){let i=this.normalizeTimestamp(o);new Date(i).getTime()>Date.now()+6e4&&(n.arrivalTime=i)}return n}async callRoutesApi(e){let t=await fetch(Uu,{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`}}});import jn from"node:fs";import Uc from"node:path";function Fc(c){return c.length<=4?"****":"*".repeat(c.length-4)+c.slice(-4)}function Fu(){let c=process.cwd();for(let e=0;e<10;e++){let t=Uc.join(c,".env");if(jn.existsSync(t))return t;let s=Uc.dirname(c);if(s===c)break;c=s}return null}var Zt,Qt,jc=E(()=>{"use strict";F();Zt={proxmox:{label:"Proxmox VE",fields:[{env:"ALFRED_PROXMOX_BASE_URL",label:"Base URL (e.g. https://pve.local:8006)",required:!0},{env:"ALFRED_PROXMOX_TOKEN_ID",label:"API Token ID (user@realm!name)",required:!0},{env:"ALFRED_PROXMOX_TOKEN_SECRET",label:"API Token Secret",required:!0,secret:!0}]},unifi:{label:"UniFi Network",fields:[{env:"ALFRED_UNIFI_BASE_URL",label:"Base URL (e.g. https://unifi.local)",required:!0},{env:"ALFRED_UNIFI_API_KEY",label:"API Key (preferred, UniFi OS)",secret:!0},{env:"ALFRED_UNIFI_USERNAME",label:"Username (alternative to API key)"},{env:"ALFRED_UNIFI_PASSWORD",label:"Password (alternative to API key)",secret:!0},{env:"ALFRED_UNIFI_SITE",label:'Site name (default: "default")'}]},homeassistant:{label:"Home Assistant",fields:[{env:"ALFRED_HOMEASSISTANT_URL",label:"Base URL (e.g. http://homeassistant.local:8123)",required:!0},{env:"ALFRED_HOMEASSISTANT_TOKEN",label:"Long-Lived Access Token",required:!0,secret:!0}]},contacts:{label:"Contacts",fields:[{env:"ALFRED_CONTACTS_PROVIDER",label:"Provider (carddav, google, microsoft)",required:!0},{env:"ALFRED_CARDDAV_CONTACTS_SERVER_URL",label:"CardDAV Server URL (if carddav)"},{env:"ALFRED_CARDDAV_CONTACTS_USERNAME",label:"CardDAV Username (if carddav)"},{env:"ALFRED_CARDDAV_CONTACTS_PASSWORD",label:"CardDAV Password (if carddav)",secret:!0},{env:"ALFRED_GOOGLE_CONTACTS_CLIENT_ID",label:"Google Client ID (if google)",secret:!0},{env:"ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET",label:"Google Client Secret (if google)",secret:!0},{env:"ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN",label:"Google Refresh Token (if google)",secret:!0},{env:"ALFRED_MICROSOFT_CONTACTS_CLIENT_ID",label:"Microsoft Client ID (if microsoft)",secret:!0},{env:"ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET",label:"Microsoft Client Secret (if microsoft)",secret:!0},{env:"ALFRED_MICROSOFT_CONTACTS_TENANT_ID",label:"Microsoft Tenant ID (if microsoft)"},{env:"ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN",label:"Microsoft Refresh Token (if microsoft)",secret:!0}]},docker:{label:"Docker",fields:[{env:"ALFRED_DOCKER_SOCKET_PATH",label:"Docker socket path (e.g. /var/run/docker.sock)"},{env:"ALFRED_DOCKER_HOST",label:"Docker host (e.g. http://192.168.1.10:2375)"}]}},Qt=class extends x{static{u(this,"ConfigureSkill")}reloadCallback;setReloadCallback(e){this.reloadCallback=e}metadata={name:"configure",category:"core",description:'Configure Alfred services (Proxmox, UniFi, Home Assistant, Contacts, Docker) by writing environment variables. Use action "list_services" to see available services. Use action "show" to check current config of a service. Use action "set" to write config \u2014 provide service name and values. After setting config, the service is activated immediately \u2014 no restart needed.',riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_services","show","set"],description:"Action to perform"},service:{type:"string",enum:["proxmox","unifi","homeassistant","contacts","docker"],description:"Service to configure (required for show/set)"},values:{type:"object",description:'Key-value pairs to set. Keys are the ENV variable names (e.g. ALFRED_PROXMOX_BASE_URL). Only for action "set".'}},required:["action"]}};async execute(e,t){let s=e.action;switch(s){case"list_services":return this.listServices();case"show":return this.showService(e.service);case"set":return this.setService(e.service,e.values);default:return{success:!1,error:`Unknown action "${s}". Use list_services, show, or set.`}}}listServices(){let e=["| Service | Status | ENV Prefix |","|---|---|---|"];for(let[t,s]of Object.entries(Zt)){let o=s.fields.filter(i=>i.required).every(i=>!!process.env[i.env])?"configured":"not configured",n=`ALFRED_${t.toUpperCase()}_*`;e.push(`| ${s.label} | ${o} | \`${n}\` |`)}return{success:!0,data:Object.keys(Zt),display:e.join(`
637
637
  `)}}showService(e){let t=Zt[e];if(!t)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Zt).join(", ")}`};let s=[`**${t.label}** configuration:
@@ -640,7 +640,7 @@ ${o}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(Z(t),s);r
640
640
 
641
641
  Available keys for ${s.label}:
642
642
  ${s.fields.map(d=>`- \`${d.env}\`: ${d.label}${d.required?" (required)":""}`).join(`
643
- `)}`};let r=new Set(s.fields.map(d=>d.env));for(let d of Object.keys(t))if(!r.has(d))return{success:!1,error:`Invalid key "${d}" for ${s.label}. Valid keys: ${[...r].join(", ")}`};let o=Fu();if(!o)return{success:!1,error:"Could not find .env file. Run `alfred setup` first or create a .env in your project root."};let n=jn.readFileSync(o,"utf-8"),i=[];for(let[d,m]of Object.entries(t)){let p=m.replace(/\n/g,"\\n"),T=new RegExp(`^#?\\s*${d}=.*$`,"m");T.test(n)?n=n.replace(T,`${d}=${p}`):n=n.trimEnd()+`
643
+ `)}`};let r=new Set(s.fields.map(d=>d.env));for(let d of Object.keys(t))if(!r.has(d))return{success:!1,error:`Invalid key "${d}" for ${s.label}. Valid keys: ${[...r].join(", ")}`};let o=Fu();if(!o)return{success:!1,error:"Could not find .env file. Run `alfred setup` first or create a .env in your project root."};let n=jn.readFileSync(o,"utf-8"),i=[];for(let[d,m]of Object.entries(t)){let p=m.replace(/\n/g,"\\n"),w=new RegExp(`^#?\\s*${d}=.*$`,"m");w.test(n)?n=n.replace(w,`${d}=${p}`):n=n.trimEnd()+`
644
644
  ${d}=${p}
645
645
  `,i.push(d)}jn.writeFileSync(o,n,"utf-8");let a=s.fields.filter(d=>d.required).filter(d=>!t[d.env]&&!process.env[d.env]).map(d=>`\`${d.env}\``),l=[`Written to \`${o}\`:
646
646
  `,...i.map(d=>`- \`${d}\` = ${s.fields.find(m=>m.env===d)?.secret?Fc(t[d]):t[d]}`)];if(a.length>0)l.push(`
@@ -649,9 +649,9 @@ ${d}=${p}
649
649
  **${s.label} is fully configured.** Hot-Reload fehlgeschlagen: ${d.error??"unbekannter Fehler"}. Restart Alfred: \`alfred start\``)}else l.push(`
650
650
  **${s.label} is fully configured.** Restart Alfred to activate: \`alfred start\``);return{success:!0,data:{envPath:o,written:i},display:l.join(`
651
651
  `)}}};u(Fc,"maskValue");u(Fu,"findEnvFile")});import{spawn as ju}from"node:child_process";import Bc from"node:fs";import zc from"node:path";function zu(c){let e={};for(let[t,s]of Object.entries(c))e[t]=s.replace(/\$\{(\w+)\}/g,(r,o)=>process.env[o]??"");return e}function Wu(c,e){return c.map(t=>t.replace(/\{\{prompt\}\}/g,e))}function oo(c){return c.length<=Hc?c:`[...truncated...]
652
- `+c.slice(-Hc)}function qc(c){let e=new Map;function t(s){let r;try{r=Bc.readdirSync(s,{withFileTypes:!0})}catch{return}for(let o of r){if(qu.has(o.name))continue;let n=zc.join(s,o.name);if(o.isDirectory())t(n);else if(o.isFile())try{let i=Bc.statSync(n);e.set(n,i.mtimeMs)}catch{}}}return u(t,"walk"),t(c),e}function Vu(c,e,t){let s=[];for(let[r,o]of e){let n=c.get(r);(n===void 0||o>n)&&s.push(zc.relative(t,r))}return s.sort()}async function Qs(c,e,t={}){let s=t.cwd??c.cwd??process.cwd(),r=t.timeoutMs??c.timeoutMs??Bu,o=Math.min(r,Hu),n=Wu(c.argsTemplate,e),i={...process.env,...c.env?zu(c.env):{}},a=process.platform==="win32",l=qc(s),d=Date.now();return new Promise(m=>{let p=ju(c.command,n,{cwd:s,env:i,shell:a,stdio:c.promptVia==="stdin"?["pipe","pipe","pipe"]:["ignore","pipe","pipe"]}),T="",y="",f=!1,_=setTimeout(()=>{f=!0,p.kill("SIGTERM"),setTimeout(()=>p.kill("SIGKILL"),5e3)},o);p.stdout?.on("data",S=>{T+=S.toString()}),p.stderr?.on("data",S=>{let A=S.toString();if(y+=A,t.onProgress){let I=A.trim().split(`
653
- `).pop();I&&t.onProgress(`[${c.name}] ${I}`)}}),c.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",S=>{clearTimeout(_);let A=Date.now()-d,I=qc(s),P=Vu(l,I,s);m({stdout:oo(T),stderr:oo(y),exitCode:f?124:S??1,durationMs:A,modifiedFiles:P})}),p.on("error",S=>{clearTimeout(_);let A=Date.now()-d;m({stdout:oo(T),stderr:oo(y+`
654
- `+S.message),exitCode:127,durationMs:A,modifiedFiles:[]})})})}var Bu,Hu,Hc,qu,no=E(()=>{"use strict";Bu=3e5,Hu=9e5,Hc=1e5,qu=new Set([".git","node_modules",".next","dist",".cache"]);u(zu,"resolveEnv");u(Wu,"buildArgs");u(oo,"truncateOutput");u(qc,"snapshotMtimes");u(Vu,"detectModifiedFiles");u(Qs,"executeAgent")});import{execFile as Gu}from"node:child_process";function Le(c,e){return new Promise((t,s)=>{Gu("git",c,{cwd:e.cwd,maxBuffer:10*1024*1024},(r,o,n)=>{if(r){let i=n?.trim()||r.message;s(new Error(`git ${c[0]} failed: ${i}`));return}t(o.trim())})})}async function io(c){try{let e=await Le(["rev-parse","--abbrev-ref","HEAD"],c),t=await Le(["status","--porcelain"],c);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function Bn(c,e){await Le(["checkout","-b",c],e)}async function Hn(c){await Le(["add","-A"],c)}async function qn(c,e){await Le(["commit","-m",c],e);let t=await Le(["rev-parse","--short","HEAD"],e),r=(await Le(["diff","--stat","HEAD~1","HEAD"],e)).split(`
652
+ `+c.slice(-Hc)}function qc(c){let e=new Map;function t(s){let r;try{r=Bc.readdirSync(s,{withFileTypes:!0})}catch{return}for(let o of r){if(qu.has(o.name))continue;let n=zc.join(s,o.name);if(o.isDirectory())t(n);else if(o.isFile())try{let i=Bc.statSync(n);e.set(n,i.mtimeMs)}catch{}}}return u(t,"walk"),t(c),e}function Vu(c,e,t){let s=[];for(let[r,o]of e){let n=c.get(r);(n===void 0||o>n)&&s.push(zc.relative(t,r))}return s.sort()}async function Qs(c,e,t={}){let s=t.cwd??c.cwd??process.cwd(),r=t.timeoutMs??c.timeoutMs??Bu,o=Math.min(r,Hu),n=Wu(c.argsTemplate,e),i={...process.env,...c.env?zu(c.env):{}},a=process.platform==="win32",l=qc(s),d=Date.now();return new Promise(m=>{let p=ju(c.command,n,{cwd:s,env:i,shell:a,stdio:c.promptVia==="stdin"?["pipe","pipe","pipe"]:["ignore","pipe","pipe"]}),w="",y="",h=!1,T=setTimeout(()=>{h=!0,p.kill("SIGTERM"),setTimeout(()=>p.kill("SIGKILL"),5e3)},o);p.stdout?.on("data",$=>{w+=$.toString()}),p.stderr?.on("data",$=>{let A=$.toString();if(y+=A,t.onProgress){let I=A.trim().split(`
653
+ `).pop();I&&t.onProgress(`[${c.name}] ${I}`)}}),c.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",$=>{clearTimeout(T);let A=Date.now()-d,I=qc(s),P=Vu(l,I,s);m({stdout:oo(w),stderr:oo(y),exitCode:h?124:$??1,durationMs:A,modifiedFiles:P})}),p.on("error",$=>{clearTimeout(T);let A=Date.now()-d;m({stdout:oo(w),stderr:oo(y+`
654
+ `+$.message),exitCode:127,durationMs:A,modifiedFiles:[]})})})}var Bu,Hu,Hc,qu,no=E(()=>{"use strict";Bu=3e5,Hu=9e5,Hc=1e5,qu=new Set([".git","node_modules",".next","dist",".cache"]);u(zu,"resolveEnv");u(Wu,"buildArgs");u(oo,"truncateOutput");u(qc,"snapshotMtimes");u(Vu,"detectModifiedFiles");u(Qs,"executeAgent")});import{execFile as Gu}from"node:child_process";function Le(c,e){return new Promise((t,s)=>{Gu("git",c,{cwd:e.cwd,maxBuffer:10*1024*1024},(r,o,n)=>{if(r){let i=n?.trim()||r.message;s(new Error(`git ${c[0]} failed: ${i}`));return}t(o.trim())})})}async function io(c){try{let e=await Le(["rev-parse","--abbrev-ref","HEAD"],c),t=await Le(["status","--porcelain"],c);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function Bn(c,e){await Le(["checkout","-b",c],e)}async function Hn(c){await Le(["add","-A"],c)}async function qn(c,e){await Le(["commit","-m",c],e);let t=await Le(["rev-parse","--short","HEAD"],e),r=(await Le(["diff","--stat","HEAD~1","HEAD"],e)).split(`
655
655
  `).length-1;return{sha:t,message:c,filesChanged:Math.max(r,0)}}async function zn(c,e,t){await Le(["push","-u",c,e],t)}function Wn(c){return`alfred/${c.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function es(c,e){try{return await Le(["remote","get-url",c],e)}catch{return null}}function ts(c){let e=c.match(/^git@([^:]+):(.+?)(?:\.git)?$/);if(e){let s=e[1],o=e[2].split("/");if(o.length<2)return null;let n=o.pop();return{owner:o.join("/"),repo:n,baseUrl:`https://${s}`}}let t=c.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);if(t){let s=t[1],o=t[2].split("/");if(o.length<2)return null;let n=o.pop();return{owner:o.join("/"),repo:n,baseUrl:`https://${s}`}}return null}async function er(c){await Le(["init"],c)}async function tr(c,e,t){await Le(["remote","add",c,e],t)}var Vn=E(()=>{"use strict";u(Le,"git");u(io,"gitStatus");u(Bn,"gitCreateBranch");u(Hn,"gitStageAll");u(qn,"gitCommit");u(zn,"gitPush");u(Wn,"slugifyBranch");u(es,"gitGetRemoteUrl");u(ts,"parseRemoteUrl");u(er,"gitInitRepo");u(tr,"gitAddRemote")});function ss(c){switch(c.provider){case"github":{if(!c.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Gn(c.github)}case"gitlab":{if(!c.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new Kn(c.gitlab)}default:throw new Error(`Unknown forge provider: ${c.provider}`)}}var yt,Gn,Kn,Xn=E(()=>{"use strict";yt=class{static{u(this,"ForgeClient")}},Gn=class extends yt{static{u(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 n=await r.text();throw new Error(`GitHub PR creation failed (${r.status}): ${n}`)}let o=await r.json();return{id:o.id,url:o.html_url,number:o.number,state:o.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 n=(await r.json()).state;return{state:{pending:"pending",success:"success",failure:"failure",error:"failure"}[n]??"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 o=await s.text();throw new Error(`GitHub project creation failed (${s.status}): ${o}`)}let r=await s.json();return{id:r.id,url:r.html_url,cloneUrl:r.clone_url}}},Kn=class extends yt{static{u(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`,o=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(!o.ok){let i=await o.text();throw new Error(`GitLab MR creation failed (${o.status}): ${i}`)}let n=await o.json();return{id:n.id,url:n.web_url,number:n.iid,state:n.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`,o=await fetch(r,{headers:{"PRIVATE-TOKEN":this.config.token}});if(!o.ok)return{state:"unknown"};let n=await o.json();if(n.length===0)return{state:"unknown"};let i=n[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 o=await s.text();throw new Error(`GitLab project creation failed (${s.status}): ${o}`)}let r=await s.json();return{id:r.id,url:r.web_url,cloneUrl:r.http_url_to_repo}}};u(ss,"createForgeClient")});function Wc(c,e){return c.length<=e?c:c.slice(0,e)+`
656
656
  [...truncated]`}function Vc(c){let e=c.replace(/^```(?:json)?\s*\n?/m,"").replace(/\n?```\s*$/m,"");return JSON.parse(e)}async function tm(c,e,t){let r=`Available agents:
657
657
  ${e.map(a=>`- ${a.name}: command="${a.command}"`).join(`
@@ -667,11 +667,11 @@ ${a}`:""].filter(Boolean).join(`
667
667
  ${c}
668
668
 
669
669
  Results:
670
- ${s}`,o=await t.complete({system:em,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let n=Vc(o.content);return{approved:n.approved??!0,summary:n.summary??"",fixTasks:Array.isArray(n.fixTasks)?n.fixTasks:[]}}catch{return{approved:!0,summary:o.content,fixTasks:[]}}}async function wt(c,e,t,s={}){let r=Math.min(s.maxIterations??Ku,Xu),o=s.maxConcurrent??Yu,n=s.onProgress,i=Date.now(),a=new Map(e.map(f=>[f.name,f]));n?.("Planning subtasks...");let l=await tm(c,e,t);n?.(`Plan created: ${l.subtasks.length} subtask(s) \u2014 ${l.reasoning}`);let d=[],m=l.subtasks,p=0,T="";for(;p<r;){p++,n?.(`Iteration ${p}: executing ${m.length} subtask(s)...`);let f=await sm(m,a,o,n);d=d.concat(f),n?.(`Iteration ${p}: validating results...`);let _=await rm(c,d,t);if(T=_.summary,_.approved||_.fixTasks.length===0)break;let S=_.fixTasks.filter(A=>a.has(A.agent)?!0:(n?.(`Warning: fix task "${A.id}" references unknown agent "${A.agent}", skipping`),!1));if(S.length===0)break;m=S,n?.(`Validation requested ${S.length} fix task(s), iterating...`)}let y=[...new Set(d.flatMap(f=>f.execution.modifiedFiles))].sort();return{plan:l,iterations:p,subtaskResults:d,allModifiedFiles:y,summary:T,totalDurationMs:Date.now()-i}}async function sr(c,e,t,s={}){let r=s.onProgress,o=s.cwd??process.cwd(),n={warnings:[]},i=await io({cwd:o});if(!i.isRepo)try{await er({cwd:o}),i=await io({cwd:o}),r?.("Initialised new git repository")}catch{return n.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await wt(c,e,t,s),git:n}}let a=null,l=await es("origin",{cwd:o});if(l){let y=ts(l);y?(a={owner:y.owner,repo:y.repo},r?.(`Detected remote: ${y.owner}/${y.repo} (${y.baseUrl})`)):n.warnings.push(`Could not parse remote URL: ${l}`)}let d=s.forge;if(!l&&d)try{let y=ss(d),f=o.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${f}" on forge...`);let _=await y.createProject({name:f,visibility:"private"});await tr("origin",_.cloneUrl,{cwd:o});let S=ts(_.cloneUrl);S&&(a={owner:S.owner,repo:S.repo}),r?.(`Project created: ${_.url} \u2014 remote "origin" set`)}catch(y){let f=y instanceof Error?y.message:String(y);n.warnings.push(`Project creation failed: ${f}`),r?.(`Warning: project creation failed \u2014 ${f}`)}let m=Wn(c);try{await Bn(m,{cwd:o}),n.branch=m,r?.(`Created branch: ${m}`)}catch(y){throw new Error(`Failed to create branch "${m}": ${y instanceof Error?y.message:String(y)}`)}let p=await wt(c,e,t,s);try{await Hn({cwd:o});let y=`feat: ${c.slice(0,72)}
670
+ ${s}`,o=await t.complete({system:em,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let n=Vc(o.content);return{approved:n.approved??!0,summary:n.summary??"",fixTasks:Array.isArray(n.fixTasks)?n.fixTasks:[]}}catch{return{approved:!0,summary:o.content,fixTasks:[]}}}async function wt(c,e,t,s={}){let r=Math.min(s.maxIterations??Ku,Xu),o=s.maxConcurrent??Yu,n=s.onProgress,i=Date.now(),a=new Map(e.map(h=>[h.name,h]));n?.("Planning subtasks...");let l=await tm(c,e,t);n?.(`Plan created: ${l.subtasks.length} subtask(s) \u2014 ${l.reasoning}`);let d=[],m=l.subtasks,p=0,w="";for(;p<r;){p++,n?.(`Iteration ${p}: executing ${m.length} subtask(s)...`);let h=await sm(m,a,o,n);d=d.concat(h),n?.(`Iteration ${p}: validating results...`);let T=await rm(c,d,t);if(w=T.summary,T.approved||T.fixTasks.length===0)break;let $=T.fixTasks.filter(A=>a.has(A.agent)?!0:(n?.(`Warning: fix task "${A.id}" references unknown agent "${A.agent}", skipping`),!1));if($.length===0)break;m=$,n?.(`Validation requested ${$.length} fix task(s), iterating...`)}let y=[...new Set(d.flatMap(h=>h.execution.modifiedFiles))].sort();return{plan:l,iterations:p,subtaskResults:d,allModifiedFiles:y,summary:w,totalDurationMs:Date.now()-i}}async function sr(c,e,t,s={}){let r=s.onProgress,o=s.cwd??process.cwd(),n={warnings:[]},i=await io({cwd:o});if(!i.isRepo)try{await er({cwd:o}),i=await io({cwd:o}),r?.("Initialised new git repository")}catch{return n.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await wt(c,e,t,s),git:n}}let a=null,l=await es("origin",{cwd:o});if(l){let y=ts(l);y?(a={owner:y.owner,repo:y.repo},r?.(`Detected remote: ${y.owner}/${y.repo} (${y.baseUrl})`)):n.warnings.push(`Could not parse remote URL: ${l}`)}let d=s.forge;if(!l&&d)try{let y=ss(d),h=o.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${h}" on forge...`);let T=await y.createProject({name:h,visibility:"private"});await tr("origin",T.cloneUrl,{cwd:o});let $=ts(T.cloneUrl);$&&(a={owner:$.owner,repo:$.repo}),r?.(`Project created: ${T.url} \u2014 remote "origin" set`)}catch(y){let h=y instanceof Error?y.message:String(y);n.warnings.push(`Project creation failed: ${h}`),r?.(`Warning: project creation failed \u2014 ${h}`)}let m=Wn(c);try{await Bn(m,{cwd:o}),n.branch=m,r?.(`Created branch: ${m}`)}catch(y){throw new Error(`Failed to create branch "${m}": ${y instanceof Error?y.message:String(y)}`)}let p=await wt(c,e,t,s);try{await Hn({cwd:o});let y=`feat: ${c.slice(0,72)}
671
671
 
672
- Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,f=await qn(y,{cwd:o});n.commit=f,r?.(`Committed: ${f.sha} (${f.filesChanged} files changed)`)}catch(y){let f=y instanceof Error?y.message:String(y);return n.warnings.push(`Commit failed: ${f}`),r?.(`Warning: commit failed \u2014 ${f}`),{...p,git:n}}if(!await es("origin",{cwd:o}))return n.warnings.push("No remote configured \u2014 skipping push and PR creation"),r?.("No remote configured, skipping push and PR"),{...p,git:n};try{await zn("origin",m,{cwd:o}),r?.(`Pushed branch: ${m}`)}catch(y){let f=y instanceof Error?y.message:String(y);return n.warnings.push(`Push failed: ${f}`),r?.(`Warning: push failed \u2014 ${f}`),{...p,git:n}}if(d&&a)try{let y=ss(d),f=s.baseBranch??d.baseBranch??"main",_=s.prTitle??`feat: ${c.slice(0,72)}`,S=["## Summary",p.summary,"",`**Iterations:** ${p.iterations}`,`**Modified files:** ${p.allModifiedFiles.length}`,p.allModifiedFiles.map(I=>`- \`${I}\``).join(`
672
+ Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,h=await qn(y,{cwd:o});n.commit=h,r?.(`Committed: ${h.sha} (${h.filesChanged} files changed)`)}catch(y){let h=y instanceof Error?y.message:String(y);return n.warnings.push(`Commit failed: ${h}`),r?.(`Warning: commit failed \u2014 ${h}`),{...p,git:n}}if(!await es("origin",{cwd:o}))return n.warnings.push("No remote configured \u2014 skipping push and PR creation"),r?.("No remote configured, skipping push and PR"),{...p,git:n};try{await zn("origin",m,{cwd:o}),r?.(`Pushed branch: ${m}`)}catch(y){let h=y instanceof Error?y.message:String(y);return n.warnings.push(`Push failed: ${h}`),r?.(`Warning: push failed \u2014 ${h}`),{...p,git:n}}if(d&&a)try{let y=ss(d),h=s.baseBranch??d.baseBranch??"main",T=s.prTitle??`feat: ${c.slice(0,72)}`,$=["## Summary",p.summary,"",`**Iterations:** ${p.iterations}`,`**Modified files:** ${p.allModifiedFiles.length}`,p.allModifiedFiles.map(I=>`- \`${I}\``).join(`
673
673
  `),"","_Automated by Alfred_"].join(`
674
- `),A=await y.createPullRequest(a,{title:_,body:S,head:m,base:f});n.pullRequest=A,r?.(`PR created: ${A.url}`)}catch(y){let f=y instanceof Error?y.message:String(y);n.warnings.push(`PR creation failed: ${f}`),r?.(`Warning: PR creation failed \u2014 ${f}`)}else d||(n.warnings.push("No forge configured \u2014 skipping PR creation"),r?.("No forge configured, skipping PR creation"));return{...p,git:n}}var Ku,Xu,Yu,Ju,Zu,Qu,em,Yn,Jn=E(()=>{"use strict";no();Vn();Xn();Ku=3,Xu=5,Yu=3,Ju=2048,Zu=1024,Qu=`You are a task planner for a multi-agent coding system.
674
+ `),A=await y.createPullRequest(a,{title:T,body:$,head:m,base:h});n.pullRequest=A,r?.(`PR created: ${A.url}`)}catch(y){let h=y instanceof Error?y.message:String(y);n.warnings.push(`PR creation failed: ${h}`),r?.(`Warning: PR creation failed \u2014 ${h}`)}else d||(n.warnings.push("No forge configured \u2014 skipping PR creation"),r?.("No forge configured, skipping PR creation"));return{...p,git:n}}var Ku,Xu,Yu,Ju,Zu,Qu,em,Yn,Jn=E(()=>{"use strict";no();Vn();Xn();Ku=3,Xu=5,Yu=3,Ju=2048,Zu=1024,Qu=`You are a task planner for a multi-agent coding system.
675
675
  You receive a high-level task and a list of available coding agents.
676
676
  Your job is to decompose the task into concrete subtasks, each assigned to an agent.
677
677
 
@@ -722,18 +722,18 @@ ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
722
722
 
723
723
  **Git:**
724
724
  ${s.join(`
725
- `)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+o}}}});var Kc=E(()=>{"use strict";Gc();no();Jn();Vn();Xn()});var re={};oe(re,{ActivityTracker:()=>ut,BMWSkill:()=>so,BackgroundTaskSkill:()=>Vt,BrowserSkill:()=>qt,CalculatorSkill:()=>xt,CalendarProvider:()=>Re,CalendarSkill:()=>mt,ClipboardSkill:()=>Bt,CodeAgentSkill:()=>rr,CodeExecutionSkill:()=>Xs,CodeExecutor:()=>ft,ConfigureSkill:()=>Qt,ContactsProvider:()=>Ce,ContactsSkill:()=>Zs,CrossPlatformSkill:()=>Wt,DelegateSkill:()=>Pt,DockerSkill:()=>Qr,DocumentSkill:()=>Xt,EmailProvider:()=>He,EmailSkill:()=>Ge,FileSkill:()=>Ft,ForgeClient:()=>yt,HomeAssistantSkill:()=>Kr,HttpSkill:()=>Ut,MCPClient:()=>pt,MCPManager:()=>Ks,MCPSkillAdapter:()=>ht,MemorySkill:()=>Ot,NoteSkill:()=>Nt,PluginLoader:()=>Ur,ProfileSkill:()=>zt,ProxmoxSkill:()=>Vr,ReminderSkill:()=>Lt,RoutingSkill:()=>ro,ScheduledTaskSkill:()=>Gt,ScreenshotSkill:()=>Ht,ShellSkill:()=>Mt,Skill:()=>x,SkillRegistry:()=>At,SkillSandbox:()=>It,SystemInfoSkill:()=>Rt,TTSSkill:()=>Yt,TodoSkill:()=>Jt,UniFiSkill:()=>Gr,WeatherSkill:()=>Dt,WebSearchSkill:()=>Ct,allUserIds:()=>W,createCalendarProvider:()=>Gs,createContactsProvider:()=>Mn,createEmailProvider:()=>zs,createForgeClient:()=>ss,effectiveUserId:()=>Z,gitAddRemote:()=>tr,gitGetRemoteUrl:()=>es,gitInitRepo:()=>er,orchestrate:()=>wt,orchestrateWithGit:()=>sr,parseRemoteUrl:()=>ts});var te=E(()=>{"use strict";F();Me();Sa();ka();_n();Aa();Ia();xa();Ra();Ca();La();Na();Oa();Pa();Ua();Ha();za();Va();Ga();Xa();Ja();Za();oc();nc();ic();ac();lc();uc();mc();pc();hc();fc();yc();$c();vc();xc();Oc();Pc();jc();Kc()});var or,Zn=E(()=>{"use strict";or=class{static{u(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 Tt(c,e){let t;if(e.platformUserId)t=c.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=c.findById(e.userId)??c.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in c?c.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in c&&(r=c.getLinkedUsers(s).map(a=>a.platformUserId));let o;try{"getProfile"in c?o=c.getProfile(s)?.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone:o=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{o=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:o},user:t,masterUserId:s,linkedPlatformUserIds:r}}var nr=E(()=>{"use strict";u(Tt,"buildSkillContext")});function Xc(c,e){let t=new Set(["core"]),s=!1;for(let[r,o]of Object.entries(om))e.has(r)&&o.test(c)&&(t.add(r),s=!0);if(!s)for(let r of e)t.add(r);return t}function Yc(c,e){return c.filter(t=>e.has(t.category??"core"))}var om,Jc=E(()=>{"use strict";om={productivity:/\b(todo|note|remind|calendar|termin|event|email|e-mail|mail|contact|kontakt)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info)\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)\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)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};u(Xc,"selectCategories");u(Yc,"filterSkills")});import Zc from"node:fs";import Qc from"node:path";var nm,el,im,tl,am,cm,lm,sl,ir,Qn=E(()=>{"use strict";wn();nr();Jc();nm=15*60*1e3,el=50,im=2,tl=.85,am=1e5,cm=2e3,lm=.1,sl=3,ir=class{static{u(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;activeAgents=new Map;agentIdCounter=0;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??100,this.promptBuilder=new Fs}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:o,linkedPlatformUserIds:n,context:i}=Tt(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),l=this.conversationManager.getHistory(a.id,this.maxHistoryMessages);this.conversationManager.addMessage(a.id,"user",e.text);let d,m=this.isSyntheticLabel(e.text),p=e.attachments?.some(H=>H.type==="audio")??!1,T=m&&!p;if(this.memoryRetriever&&e.text&&!T)try{d=await this.memoryRetriever.retrieve(o,e.text,15,n)}catch(H){this.logger.debug({err:H},"Hybrid memory retrieval failed")}if(!d&&this.memoryRepo&&!T)try{let H=[o,...(n??[]).filter(Y=>Y!==o)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let Y=new Set;d=[];for(let ee of H)for(let J of await this.embeddingService.semanticSearch(ee,e.text,10))Y.has(J.key)||(Y.add(J.key),d.push(J));for(let ee of H)for(let J of this.memoryRepo.getRecentForPrompt(ee,5))Y.has(J.key)||(Y.add(J.key),d.push(J))}else{let Y=new Set;d=[];for(let ee of H)for(let J of this.memoryRepo.getRecentForPrompt(ee,20))Y.has(J.key)||(Y.add(J.key),d.push(J))}}catch(H){this.logger.debug({err:H},"Memory loading failed")}d&&d.length>0&&(d=this.applyMemoryBudget(d));let y;try{"getProfile"in this.users&&(y=this.users.getProfile(o),y&&!y.displayName&&(y.displayName=r.displayName??r.username))}catch(H){this.logger.debug({err:H},"Profile loading failed")}let f=i.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,_=this.skillRegistry?this.skillRegistry.getAll().map(H=>H.metadata):void 0,S=_;if(_&&e.text){let H=new Set(_.map(ee=>ee.category??"core")),Y=Xc(e.text,H);S=Yc(_,Y)}let A=S?this.promptBuilder.buildTools(S):void 0,I=this.promptBuilder.buildSystemPrompt({memories:d,skills:S,userProfile:y}),P=this.buildActiveAgentStatus();P&&(I+=`
725
+ `)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+o}}}});var Kc=E(()=>{"use strict";Gc();no();Jn();Vn();Xn()});var re={};oe(re,{ActivityTracker:()=>ut,BMWSkill:()=>so,BackgroundTaskSkill:()=>Vt,BrowserSkill:()=>qt,CalculatorSkill:()=>xt,CalendarProvider:()=>Re,CalendarSkill:()=>mt,ClipboardSkill:()=>Bt,CodeAgentSkill:()=>rr,CodeExecutionSkill:()=>Xs,CodeExecutor:()=>ft,ConfigureSkill:()=>Qt,ContactsProvider:()=>Ce,ContactsSkill:()=>Zs,CrossPlatformSkill:()=>Wt,DelegateSkill:()=>Pt,DockerSkill:()=>Qr,DocumentSkill:()=>Xt,EmailProvider:()=>He,EmailSkill:()=>Ge,FileSkill:()=>Ft,ForgeClient:()=>yt,HomeAssistantSkill:()=>Kr,HttpSkill:()=>Ut,MCPClient:()=>pt,MCPManager:()=>Ks,MCPSkillAdapter:()=>ht,MemorySkill:()=>Ot,NoteSkill:()=>Nt,PluginLoader:()=>Ur,ProfileSkill:()=>zt,ProxmoxSkill:()=>Vr,ReminderSkill:()=>Lt,RoutingSkill:()=>ro,ScheduledTaskSkill:()=>Gt,ScreenshotSkill:()=>Ht,ShellSkill:()=>Mt,Skill:()=>x,SkillRegistry:()=>At,SkillSandbox:()=>It,SystemInfoSkill:()=>Rt,TTSSkill:()=>Yt,TodoSkill:()=>Jt,UniFiSkill:()=>Gr,WeatherSkill:()=>Dt,WebSearchSkill:()=>Ct,allUserIds:()=>W,createCalendarProvider:()=>Gs,createContactsProvider:()=>Mn,createEmailProvider:()=>zs,createForgeClient:()=>ss,effectiveUserId:()=>Z,gitAddRemote:()=>tr,gitGetRemoteUrl:()=>es,gitInitRepo:()=>er,orchestrate:()=>wt,orchestrateWithGit:()=>sr,parseRemoteUrl:()=>ts});var te=E(()=>{"use strict";F();Me();Sa();ka();_n();Aa();Ia();xa();Ra();Ca();La();Na();Oa();Pa();Ua();Ha();za();Va();Ga();Xa();Ja();Za();oc();nc();ic();ac();lc();uc();mc();pc();hc();fc();yc();$c();vc();xc();Oc();Pc();jc();Kc()});var or,Zn=E(()=>{"use strict";or=class{static{u(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 Tt(c,e){let t;if(e.platformUserId)t=c.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=c.findById(e.userId)??c.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in c?c.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in c&&(r=c.getLinkedUsers(s).map(a=>a.platformUserId));let o;try{"getProfile"in c?o=c.getProfile(s)?.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone:o=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{o=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:o},user:t,masterUserId:s,linkedPlatformUserIds:r}}var nr=E(()=>{"use strict";u(Tt,"buildSkillContext")});function Xc(c,e){let t=new Set(["core"]),s=!1;for(let[r,o]of Object.entries(om))e.has(r)&&o.test(c)&&(t.add(r),s=!0);if(!s)for(let r of e)t.add(r);return t}function Yc(c,e){return c.filter(t=>e.has(t.category??"core"))}var om,Jc=E(()=>{"use strict";om={productivity:/\b(todo|note|remind|calendar|termin|event|email|e-mail|mail|contact|kontakt)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info)\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)\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)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};u(Xc,"selectCategories");u(Yc,"filterSkills")});import Zc from"node:fs";import Qc from"node:path";var nm,el,im,tl,am,cm,lm,sl,ir,Qn=E(()=>{"use strict";wn();nr();Jc();nm=15*60*1e3,el=50,im=2,tl=.85,am=1e5,cm=2e3,lm=.1,sl=3,ir=class{static{u(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;activeAgents=new Map;agentIdCounter=0;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??100,this.promptBuilder=new Fs}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:o,linkedPlatformUserIds:n,context:i}=Tt(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),l=this.conversationManager.getHistory(a.id,this.maxHistoryMessages);this.conversationManager.addMessage(a.id,"user",e.text);let d,m=this.isSyntheticLabel(e.text),p=e.attachments?.some(H=>H.type==="audio")??!1,w=m&&!p;if(this.memoryRetriever&&e.text&&!w)try{d=await this.memoryRetriever.retrieve(o,e.text,15,n)}catch(H){this.logger.debug({err:H},"Hybrid memory retrieval failed")}if(!d&&this.memoryRepo&&!w)try{let H=[o,...(n??[]).filter(Y=>Y!==o)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let Y=new Set;d=[];for(let ee of H)for(let J of await this.embeddingService.semanticSearch(ee,e.text,10))Y.has(J.key)||(Y.add(J.key),d.push(J));for(let ee of H)for(let J of this.memoryRepo.getRecentForPrompt(ee,5))Y.has(J.key)||(Y.add(J.key),d.push(J))}else{let Y=new Set;d=[];for(let ee of H)for(let J of this.memoryRepo.getRecentForPrompt(ee,20))Y.has(J.key)||(Y.add(J.key),d.push(J))}}catch(H){this.logger.debug({err:H},"Memory loading failed")}d&&d.length>0&&(d=this.applyMemoryBudget(d));let y;try{"getProfile"in this.users&&(y=this.users.getProfile(o),y&&!y.displayName&&(y.displayName=r.displayName??r.username))}catch(H){this.logger.debug({err:H},"Profile loading failed")}let h=i.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,T=this.skillRegistry?this.skillRegistry.getAll().map(H=>H.metadata):void 0,$=T;if(T&&e.text){let H=new Set(T.map(ee=>ee.category??"core")),Y=Xc(e.text,H);$=Yc(T,Y)}let A=$?this.promptBuilder.buildTools($):void 0,I=this.promptBuilder.buildSystemPrompt({memories:d,skills:$,userProfile:y}),P=this.buildActiveAgentStatus();P&&(I+=`
726
726
 
727
- `+P);let L=this.promptBuilder.buildMessages(l),X=this.collapseRepeatedToolErrors(L),Oe=await this.buildUserContent(e,t);X.push({role:"user",content:Oe});let ve=A?xe(JSON.stringify(A)):0,Pe=1,ae=this.trimToContextWindow(I,X,ve,Pe),V,pe=0,he=Date.now(),C="",U=0,fe=0,Ue=0,os=[];for(t?.("Thinking...");;){pe>0&&this.compressToolLoop(ae,I,ve);try{V=await this.llm.complete({messages:ae,system:I,tools:A&&A.length>0?A:void 0}),fe+=V.usage?.inputTokens??0,Ue+=V.usage?.outputTokens??0}catch(Te){if((Te instanceof Error?Te.message:String(Te)).includes("prompt is too long")&&Pe>.3){Pe*=.5,this.logger.warn({budgetMultiplier:Pe},"Prompt too long, retrimming with reduced budget"),ae=this.trimToContextWindow(I,X,ve,Pe);continue}throw Te}if(!V.toolCalls||V.toolCalls.length===0)break;let H=Date.now()-he;if(H>=nm){let Te=Math.round(H/6e4);this.logger.warn({iteration:pe,elapsedMin:Te,pendingToolCalls:V.toolCalls.length},"Tool loop timeout reached"),V=await this.abortToolLoop(ae,V,a.id,I,`Das Zeitlimit von ${Te} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`);break}if(pe>=el){this.logger.warn({iteration:pe,pendingToolCalls:V.toolCalls.length},"Tool loop iteration cap reached"),V=await this.abortToolLoop(ae,V,a.id,I,`Das Iterationslimit von ${el} Tool-Aufrufen wurde erreicht.`);break}pe++,this.logger.info({iteration:pe,toolCalls:V.toolCalls.length},"Processing tool calls");let Y=[];V.content&&Y.push({type:"text",text:V.content});for(let Te of V.toolCalls)Y.push({type:"tool_use",id:Te.id,name:Te.name,input:Te.input});ae.push({role:"assistant",content:Y});let ee=await this.executeToolCallsParallel(V.toolCalls,{...i,conversationId:a.id,timezone:f},t),J=ee.blocks;ee.attachments.length>0&&os.push(...ee.attachments),this.conversationManager.addMessage(a.id,"assistant",V.content??"",JSON.stringify(V.toolCalls)),this.conversationManager.addMessage(a.id,"user","",JSON.stringify(J));let bt=this.buildErrorSignature(J);if(bt){if(bt===C?U++:(U=1,C=bt),U>=im){this.logger.warn({iteration:pe,consecutiveErrors:U,errorSignature:bt},"Tool loop aborted: same error repeated consecutively"),V=await this.abortToolLoop(ae,V,a.id,I,`Der gleiche Tool-Fehler ist ${U}x hintereinander aufgetreten: "${C.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0);break}}else U=0,C="";ae.push({role:"user",content:J}),t?.("Thinking...")}let Q=V.content;if(!Q)for(let H=ae.length-1;H>=0;H--){let Y=ae[H];if(Y.role==="assistant"&&Array.isArray(Y.content)){let ee=Y.content.find(J=>J.type==="text");if(ee&&"text"in ee&&ee.text){Q=ee.text;break}}}Q||(Q="(no response)"),this.conversationManager.addMessage(a.id,"assistant",Q),this.activeLearning&&this.activeLearning.onMessageProcessed(o,e.text,Q);let ns=Date.now()-s;return this.logger.info({duration:ns,tokens:V.usage,totalTokens:{inputTokens:fe,outputTokens:Ue},stopReason:V.stopReason,toolIterations:pe},"Message processed"),{text:Q,attachments:os.length>0?os:void 0}}catch(r){throw this.logger.error({err:r},"Failed to process message"),r}}async abortToolLoop(e,t,s,r,o,n=!1){if(!n){let a=[];t.content&&a.push({type:"text",text:t.content});for(let l of t.toolCalls)a.push({type:"tool_use",id:l.id,name:l.name,input:l.input});e.push({role:"assistant",content:a})}let i=t.toolCalls.map(a=>({type:"tool_result",tool_use_id:a.id,content:`Error: tool loop aborted \u2014 ${o}`,is_error:!0}));return e.push({role:"user",content:i}),n||this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),this.conversationManager.addMessage(s,"user","",JSON.stringify(i)),e.push({role:"user",content:`[System: ${o} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}),await this.llm.complete({messages:e,system:r})}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(o=>o.type==="tool_use")){let o=s+1<e.length?e[s+1]:null;if(o&&o.role==="user"&&Array.isArray(o.content)&&o.content.every(n=>n.type==="tool_result"&&n.is_error)){let n=this.toolPairSignature(r,o),i=1,a=s+2;for(;a+1<e.length;){let l=e[a],d=e[a+1];if(l.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(l,d)===n)i++,a+=2;else break}if(i>1){t.push(r),t.push(o),t.push({role:"assistant",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(o=>o.type==="tool_use").map(o=>`${o.name}:${JSON.stringify(o.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(o=>o.type==="tool_result").map(o=>o.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],o=u((a,l)=>{let d=l.content;if(l.attachments&&l.attachments.length>0){r.push(...l.attachments);let m=l.attachments.map(p=>p.fileName).join(", ");d+=`
727
+ `+P);let L=this.promptBuilder.buildMessages(l),X=this.collapseRepeatedToolErrors(L),Oe=await this.buildUserContent(e,t);X.push({role:"user",content:Oe});let ve=A?xe(JSON.stringify(A)):0,Pe=1,ae=this.trimToContextWindow(I,X,ve,Pe),V,pe=0,he=Date.now(),C="",U=0,fe=0,Ue=0,os=[];for(t?.("Thinking...");;){pe>0&&this.compressToolLoop(ae,I,ve);try{V=await this.llm.complete({messages:ae,system:I,tools:A&&A.length>0?A:void 0}),fe+=V.usage?.inputTokens??0,Ue+=V.usage?.outputTokens??0}catch(Te){if((Te instanceof Error?Te.message:String(Te)).includes("prompt is too long")&&Pe>.3){Pe*=.5,this.logger.warn({budgetMultiplier:Pe},"Prompt too long, retrimming with reduced budget"),ae=this.trimToContextWindow(I,X,ve,Pe);continue}throw Te}if(!V.toolCalls||V.toolCalls.length===0)break;let H=Date.now()-he;if(H>=nm){let Te=Math.round(H/6e4);this.logger.warn({iteration:pe,elapsedMin:Te,pendingToolCalls:V.toolCalls.length},"Tool loop timeout reached"),V=await this.abortToolLoop(ae,V,a.id,I,`Das Zeitlimit von ${Te} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`);break}if(pe>=el){this.logger.warn({iteration:pe,pendingToolCalls:V.toolCalls.length},"Tool loop iteration cap reached"),V=await this.abortToolLoop(ae,V,a.id,I,`Das Iterationslimit von ${el} Tool-Aufrufen wurde erreicht.`);break}pe++,this.logger.info({iteration:pe,toolCalls:V.toolCalls.length},"Processing tool calls");let Y=[];V.content&&Y.push({type:"text",text:V.content});for(let Te of V.toolCalls)Y.push({type:"tool_use",id:Te.id,name:Te.name,input:Te.input});ae.push({role:"assistant",content:Y});let ee=await this.executeToolCallsParallel(V.toolCalls,{...i,conversationId:a.id,timezone:h},t),J=ee.blocks;ee.attachments.length>0&&os.push(...ee.attachments),this.conversationManager.addMessage(a.id,"assistant",V.content??"",JSON.stringify(V.toolCalls)),this.conversationManager.addMessage(a.id,"user","",JSON.stringify(J));let bt=this.buildErrorSignature(J);if(bt){if(bt===C?U++:(U=1,C=bt),U>=im){this.logger.warn({iteration:pe,consecutiveErrors:U,errorSignature:bt},"Tool loop aborted: same error repeated consecutively"),V=await this.abortToolLoop(ae,V,a.id,I,`Der gleiche Tool-Fehler ist ${U}x hintereinander aufgetreten: "${C.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0);break}}else U=0,C="";ae.push({role:"user",content:J}),t?.("Thinking...")}let Q=V.content;if(!Q)for(let H=ae.length-1;H>=0;H--){let Y=ae[H];if(Y.role==="assistant"&&Array.isArray(Y.content)){let ee=Y.content.find(J=>J.type==="text");if(ee&&"text"in ee&&ee.text){Q=ee.text;break}}}Q||(Q="(no response)"),this.conversationManager.addMessage(a.id,"assistant",Q),this.activeLearning&&this.activeLearning.onMessageProcessed(o,e.text,Q);let ns=Date.now()-s;return this.logger.info({duration:ns,tokens:V.usage,totalTokens:{inputTokens:fe,outputTokens:Ue},stopReason:V.stopReason,toolIterations:pe},"Message processed"),{text:Q,attachments:os.length>0?os:void 0}}catch(r){throw this.logger.error({err:r},"Failed to process message"),r}}async abortToolLoop(e,t,s,r,o,n=!1){if(!n){let a=[];t.content&&a.push({type:"text",text:t.content});for(let l of t.toolCalls)a.push({type:"tool_use",id:l.id,name:l.name,input:l.input});e.push({role:"assistant",content:a})}let i=t.toolCalls.map(a=>({type:"tool_result",tool_use_id:a.id,content:`Error: tool loop aborted \u2014 ${o}`,is_error:!0}));return e.push({role:"user",content:i}),n||this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),this.conversationManager.addMessage(s,"user","",JSON.stringify(i)),e.push({role:"user",content:`[System: ${o} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}),await this.llm.complete({messages:e,system:r})}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(o=>o.type==="tool_use")){let o=s+1<e.length?e[s+1]:null;if(o&&o.role==="user"&&Array.isArray(o.content)&&o.content.every(n=>n.type==="tool_result"&&n.is_error)){let n=this.toolPairSignature(r,o),i=1,a=s+2;for(;a+1<e.length;){let l=e[a],d=e[a+1];if(l.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(l,d)===n)i++,a+=2;else break}if(i>1){t.push(r),t.push(o),t.push({role:"assistant",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(o=>o.type==="tool_use").map(o=>`${o.name}:${JSON.stringify(o.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(o=>o.type==="tool_result").map(o=>o.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],o=u((a,l)=>{let d=l.content;if(l.attachments&&l.attachments.length>0){r.push(...l.attachments);let m=l.attachments.map(p=>p.fileName).join(", ");d+=`
728
728
 
729
729
  [${l.attachments.length} Datei(en) werden dem User gesendet: ${m}]`}return{type:"tool_result",tool_use_id:a.id,content:d,is_error:l.isError}},"buildBlock");if(e.length===1){let a=e[0],l=this.getToolLabel(a.name,a.input);s?.(l);let d=await this.executeToolCall(a,t,s);return{blocks:[o(a,d)],attachments:r}}s?.(`Running ${e.length} tools in parallel...`);let n=await Promise.allSettled(e.map(a=>this.executeToolCall(a,t,s)));return{blocks:e.map((a,l)=>{let d=n[l];return d.status==="fulfilled"?o(a,d.value):{type:"tool_result",tool_use_id:a.id,content:`Tool execution failed: ${d.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 o=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:r.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!o.allowed)return this.logger.warn({tool:e.name,reason:o.reason,rule:o.matchedRule?.id},"Skill execution denied by security rules"),{content:`Access denied: ${o.reason}`,isError:!0}}if(this.skillSandbox){let o,n;if(e.name==="delegate"){let{ActivityTracker:a}=await Promise.resolve().then(()=>(te(),re));o=new a(s),n=`agent-${++this.agentIdCounter}`,this.activeAgents.set(n,{chatId:t.chatId,task:String(e.input.task??"").slice(0,200),tracker:o,startedAt:Date.now()})}let i=e.name==="delegate"?{...t,tracker:o,onProgress:s}:s?{...t,onProgress:s}:t;try{let a=await this.skillSandbox.execute(r,e.input,i,void 0,o);return{content:a.display??(a.success?JSON.stringify(a.data):a.error??"Unknown error"),isError:!a.success,attachments:a.attachments}}finally{n&&this.activeAgents.delete(n)}}try{let o=await r.execute(e.input,t);return{content:o.display??(o.success?JSON.stringify(o.data):o.error??"Unknown error"),isError:!o.success,attachments:o.attachments}}catch(o){return{content:`Skill execution failed: ${o instanceof Error?o.message:String(o)}`,isError:!0}}}getToolLabel(e,t){switch(e){case"shell":return`Running: ${String(t.command??"").slice(0,60)}`;case"web_search":return`Searching: ${String(t.query??"")}`;case"email":return`Email: ${String(t.action??"")}`;case"memory":return`Memory: ${String(t.action??"")}`;case"reminder":return`Reminder: ${String(t.action??"")}`;case"calculator":return"Calculating...";case"system_info":return"Getting system info...";case"delegate":return"Delegating sub-task...";case"http":return`Fetching: ${String(t.url??"").slice(0,60)}`;case"file":return`File: ${String(t.action??"")} ${String(t.path??"").slice(0,50)}`;case"clipboard":return`Clipboard: ${String(t.action??"")}`;case"screenshot":return"Taking screenshot...";case"browser":return`Browser: ${String(t.action??"")} ${String(t.url??"").slice(0,50)}`;case"weather":return`Weather: ${String(t.location??"")}`;case"note":return`Note: ${String(t.action??"")}`;case"profile":return`Profile: ${String(t.action??"")}`;case"calendar":return`Calendar: ${String(t.action??"")}`;case"background_task":return`Background task: ${String(t.action??"")}`;case"scheduled_task":return`Scheduled task: ${String(t.action??"")}`;case"cross_platform":return`Cross-platform: ${String(t.action??"")}`;case"code_sandbox":return"Running code...";case"document":return`Document: ${String(t.action??"")}`;default:return`Using ${e}...`}}buildActiveAgentStatus(){if(this.activeAgents.size===0)return;let e=["## Currently running sub-agents"];for(let[t,s]of this.activeAgents){let r=s.tracker.getSnapshot(),o=Math.round(r.totalElapsedMs/1e3);e.push(`- **${t}**: "${s.task}"`,` Status: ${s.tracker.formatStatus()}`,` Running for ${o}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(`
730
- `)}applyMemoryBudget(e){let t=e.some(n=>n.score!=null&&n.score>0),s=e;t&&(s=e.filter(n=>(n.score??1)>=lm));let r=0,o=[];for(let n of s){let i=xe(`[${n.category}] ${n.key}: ${n.value}`);if(r+i>cm)break;r+=i,o.push(n)}return o.length<e.length&&this.logger.info({original:e.length,kept:o.length,tokenCount:r,droppedByScore:e.length-s.length},"Memory budget applied"),o}compressToolLoop(e,t,s=0){let r=this.llm.getContextWindow(),o=Math.floor(r.maxInputTokens*tl);if(xe(t)+s+e.reduce((f,_)=>f+js(_),0)<=o)return;let a=[];for(let f=0;f<e.length-1;f++){let _=e[f],S=e[f+1];_.role==="assistant"&&Array.isArray(_.content)&&_.content.some(A=>A.type==="tool_use")&&S.role==="user"&&Array.isArray(S.content)&&S.content.some(A=>A.type==="tool_result")&&a.push({start:f,end:f+1})}if(a.length<=sl)return;let l=a.length-sl,d=a.slice(0,l),m=[];for(let f of d){let _=e[f.start],S=[];if(Array.isArray(_.content))for(let P of _.content)P.type==="tool_use"&&S.push(P.name);let A=e[f.end],I="ok";Array.isArray(A.content)&&A.content.some(L=>L.type==="tool_result"&&L.is_error)&&(I="error"),m.push(`- ${S.join(", ")}: ${I}`)}let p=d[0].start,y=d[d.length-1].end-p+1;e.splice(p,y,{role:"assistant",content:`[Earlier tool interactions compressed (${d.length} pairs):
730
+ `)}applyMemoryBudget(e){let t=e.some(n=>n.score!=null&&n.score>0),s=e;t&&(s=e.filter(n=>(n.score??1)>=lm));let r=0,o=[];for(let n of s){let i=xe(`[${n.category}] ${n.key}: ${n.value}`);if(r+i>cm)break;r+=i,o.push(n)}return o.length<e.length&&this.logger.info({original:e.length,kept:o.length,tokenCount:r,droppedByScore:e.length-s.length},"Memory budget applied"),o}compressToolLoop(e,t,s=0){let r=this.llm.getContextWindow(),o=Math.floor(r.maxInputTokens*tl);if(xe(t)+s+e.reduce((h,T)=>h+js(T),0)<=o)return;let a=[];for(let h=0;h<e.length-1;h++){let T=e[h],$=e[h+1];T.role==="assistant"&&Array.isArray(T.content)&&T.content.some(A=>A.type==="tool_use")&&$.role==="user"&&Array.isArray($.content)&&$.content.some(A=>A.type==="tool_result")&&a.push({start:h,end:h+1})}if(a.length<=sl)return;let l=a.length-sl,d=a.slice(0,l),m=[];for(let h of d){let T=e[h.start],$=[];if(Array.isArray(T.content))for(let P of T.content)P.type==="tool_use"&&$.push(P.name);let A=e[h.end],I="ok";Array.isArray(A.content)&&A.content.some(L=>L.type==="tool_result"&&L.is_error)&&(I="error"),m.push(`- ${$.join(", ")}: ${I}`)}let p=d[0].start,y=d[d.length-1].end-p+1;e.splice(p,y,{role:"assistant",content:`[Earlier tool interactions compressed (${d.length} pairs):
731
731
  ${m.join(`
732
732
  `)}
733
- ]`},{role:"user",content:"[Context compressed to fit context window. Continue with the current task.]"}),this.logger.info({compressedPairs:d.length,removedMessages:y-2},"Compressed tool loop to fit context window")}trimToContextWindow(e,t,s=0,r=1){let o=this.llm.getContextWindow(),n=Math.floor(o.maxInputTokens*tl*r),i=xe(e)+s,a=t[t.length-1],l=js(a),m=i+l+200+500,p=n-m;if(p<=0)return this.logger.warn({maxInputTokens:n,systemTokens:i,latestTokens:l},"Context window very tight, sending only latest message"),[a];let T=t.slice(0,-1),y=this.groupToolPairs(T),f=[];for(let A=y.length-1;A>=0;A--){let I=y[A].reduce((P,L)=>P+js(L),0);if(I>p)break;p-=I,f.unshift(y[A])}let _=f.flat(),S=T.length-_.length;if(S>0){this.logger.info({trimmedCount:S,totalMessages:t.length,maxInputTokens:n},"Trimmed conversation history to fit context window");let A=T.slice(0,T.length-_.length),I=this.summarizeTrimmedMessages(A);_.unshift({role:"assistant",content:`[Earlier conversation summary \u2014 ${S} messages were trimmed to fit the context window:
733
+ ]`},{role:"user",content:"[Context compressed to fit context window. Continue with the current task.]"}),this.logger.info({compressedPairs:d.length,removedMessages:y-2},"Compressed tool loop to fit context window")}trimToContextWindow(e,t,s=0,r=1){let o=this.llm.getContextWindow(),n=Math.floor(o.maxInputTokens*tl*r),i=xe(e)+s,a=t[t.length-1],l=js(a),m=i+l+200+500,p=n-m;if(p<=0)return this.logger.warn({maxInputTokens:n,systemTokens:i,latestTokens:l},"Context window very tight, sending only latest message"),[a];let w=t.slice(0,-1),y=this.groupToolPairs(w),h=[];for(let A=y.length-1;A>=0;A--){let I=y[A].reduce((P,L)=>P+js(L),0);if(I>p)break;p-=I,h.unshift(y[A])}let T=h.flat(),$=w.length-T.length;if($>0){this.logger.info({trimmedCount:$,totalMessages:t.length,maxInputTokens:n},"Trimmed conversation history to fit context window");let A=w.slice(0,w.length-T.length),I=this.summarizeTrimmedMessages(A);T.unshift({role:"assistant",content:`[Earlier conversation summary \u2014 ${$} messages were trimmed to fit the context window:
734
734
  ${I}
735
735
 
736
- The conversation continues below with the most recent messages.]`})}return _.push(a),this.promptBuilder.sanitizeToolMessages(_)}summarizeTrimmedMessages(e){let t=[];for(let r of e){let o=this.extractMessageText(r);if(!o)continue;let n=o.length>150?o.slice(0,150)+"...":o,i=r.role==="user"?"User":"Assistant";if(t.push(`- ${i}: ${n}`),r.role==="assistant"&&Array.isArray(r.content)){for(let a of r.content)if(a.type==="tool_use"){let l=JSON.stringify(a.input).slice(0,80);t.push(` \u2192 Tool: ${a.name}(${l})`)}}}let s=40;if(t.length>s){let r=t.slice(0,s);return r.push(` ... and ${t.length-s} more interactions`),r.join(`
736
+ The conversation continues below with the most recent messages.]`})}return T.push(a),this.promptBuilder.sanitizeToolMessages(T)}summarizeTrimmedMessages(e){let t=[];for(let r of e){let o=this.extractMessageText(r);if(!o)continue;let n=o.length>150?o.slice(0,150)+"...":o,i=r.role==="user"?"User":"Assistant";if(t.push(`- ${i}: ${n}`),r.role==="assistant"&&Array.isArray(r.content)){for(let a of r.content)if(a.type==="tool_use"){let l=JSON.stringify(a.input).slice(0,80);t.push(` \u2192 Tool: ${a.name}(${l})`)}}}let s=40;if(t.length>s){let r=t.slice(0,s);return r.push(` ... and ${t.length-s} more interactions`),r.join(`
737
737
  `)}return t.join(`
738
738
  `)}extractMessageText(e){if(typeof e.content=="string")return e.content;if(!Array.isArray(e.content))return"";let t=[];for(let s of e.content)s.type==="text"&&s.text&&t.push(s.text);return t.join(" ")}groupToolPairs(e){let t=[],s=0;for(;s<e.length;){let r=e[s];if(r.role==="assistant"&&Array.isArray(r.content)&&r.content.some(o=>o.type==="tool_use")){let o=[r];if(s+1<e.length&&e[s+1].role==="user"){let n=e[s+1];if(Array.isArray(n.content)&&n.content.some(i=>i.type==="tool_result")){o.push(n),s+=2,t.push(o);continue}}if(o.length===1&&s+1<e.length&&e[s+1].role==="user"){o.push(e[s+1]),s+=2,t.push(o);continue}t.push(o),s++}else t.push([r]),s++}return t}async buildUserContent(e,t){let s=e.attachments?.filter(i=>i.data)??[];if(s.length===0)return e.text;let r=[];for(let i of s)if(i.type==="image"&&i.data)r.push({type:"image",source:{type:"base64",media_type:i.mimeType??"image/jpeg",data:i.data.toString("base64")}}),this.logger.info({mimeType:i.mimeType,size:i.size},"Image attached to LLM request");else if(i.type==="audio"&&i.data)if(this.speechTranscriber){t?.("Transcribing voice...");try{let a=await this.speechTranscriber.transcribe(i.data,i.mimeType??"audio/ogg"),l=e.text==="[Voice message]"?"":`${e.text}
739
739
 
@@ -742,16 +742,16 @@ The conversation continues below with the most recent messages.]`})}return _.pus
742
742
  [File content]:
743
743
  ${m}`}r.push({type:"text",text:d}),this.logger.info({fileName:i.fileName,savedPath:a,size:i.data.length},"File saved to inbox")}}let o=this.isSyntheticLabel(e.text);e.text&&!o&&r.push({type:"text",text:e.text});let n=r.some(i=>i.type==="text");return r.some(i=>i.type==="image")&&!n?r.push({type:"text",text:"What do you see in this image?"}):o&&r.some(i=>i.type==="text"&&i.text.startsWith("[File received:"))?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."}):r.length===0&&r.push({type:"text",text:e.text||"(empty message)"}),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??Qc.resolve("./data/inbox");try{Zc.mkdirSync(t,{recursive:!0})}catch{this.logger.error({inboxDir:t},"Cannot create inbox directory");return}let s=new Date().toISOString().replace(/[:.]/g,"-"),o=(e.fileName??`file_${s}`).replace(/[<>:"/\\|?*]/g,"_"),n=`${s}_${o}`,i=Qc.join(t,n);try{return Zc.writeFileSync(i,e.data),i}catch(a){this.logger.error({err:a,filePath:i},"Failed to save file to inbox");return}}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 ar,ei=E(()=>{"use strict";ar=class{static{u(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;constructor(e,t,s,r=15e3,o){this.reminderRepo=e,this.sendMessage=t,this.logger=s,this.linkedUsers=o,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),o=this.linkedUsers.getLinkedUsers(r);for(let n of o){if(n.platform===t.platform)continue;let i=this.linkedUsers.findConversation(n.platform,n.id);i&&await this.sendMessage(n.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 cr,ti=E(()=>{"use strict";cr=class{static{u(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 o=await fetch(`${this.baseUrl}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:r});if(!o.ok){let i=await o.text();throw new Error(`Whisper API ${o.status}: ${i}`)}let n=await o.json();return this.logger.info({textLength:n.text.length},"Voice transcribed"),n.text}catch(o){throw this.logger.error({err:o},"Voice transcription failed"),o}}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 lr,si=E(()=>{"use strict";lr=class{static{u(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 dr,ri=E(()=>{"use strict";dr=class{static{u(this,"ResponseFormatter")}format(e,t){switch(t){case"telegram":return{text:this.toTelegramHTML(e),parseMode:"html"};case"discord":return{text:e,parseMode:"markdown"};case"matrix":return{text:this.toMatrixHTML(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;return t=t.replace(/```(\w*)\n([\s\S]*?)```/g,(s,r,o)=>`<pre>${this.escapeHTML(o.trimEnd())}</pre>`),t=t.replace(/`([^`]+)`/g,(s,r)=>`<code>${this.escapeHTML(r)}</code>`),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(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))/gi,"&lt;"),t}toMatrixHTML(e){return this.toTelegramHTML(e)}toWhatsApp(e){let t=e;return 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(/```\w*\n?/g,""),t=t.replace(/`([^`]+)`/g,"$1"),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,oi=E(()=>{"use strict";ur=class{static{u(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 o=await this.llm.embed(t);if(!o)return;this.embeddingRepo.store({userId:e,sourceType:s,sourceId:r,content:t,embedding:o.embedding,model:o.model,dimensions:o.dimensions}),this.logger.debug({userId:e,sourceType:s,sourceId:r},"Embedding stored")}catch(o){this.logger.error({err:o,userId:e,sourceType:s,sourceId:r},"Failed to embed content")}}async semanticSearch(e,t,s=10){if(!this.llm.supportsEmbeddings())return[];try{let r=await this.llm.embed(t);if(!r)return[];let o=this.embeddingRepo.findByUser(e);if(o.length===0)return[];let n=o.map(a=>{let l=this.cosineSimilarity(r.embedding,a.embedding);return{...a,score:l}});return n.sort((a,l)=>l.score-a.score),n.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,o=0;for(let i=0;i<e.length;i++)s+=e[i]*t[i],r+=e[i]*e[i],o+=t[i]*t[i];let n=Math.sqrt(r)*Math.sqrt(o);return n===0?0:s/n}}});var mr,ni=E(()=>{"use strict";mr=class{static{u(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 o=await this.extractText(t,r),i=(await import("node:fs")).statSync(t),a=this.docRepo.createDocument(e,s,r,i.size),l=this.chunkText(o,500,50);for(let d=0;d<l.length;d++){let m;try{await this.embeddingService.embedAndStore(e,l[d],"document",`${a.id}:${d}`),m=`${a.id}:${d}`}catch(p){this.logger.warn({documentId:a.id,chunkIndex:d,err:p},"Embedding failed for chunk, continuing")}this.docRepo.addChunk(a.id,d,l[d],m)}return this.docRepo.updateChunkCount(a.id,l.length),this.logger.info({documentId:a.id,filename:s,chunkCount:l.length},"Document ingested"),{documentId:a.id,chunkCount:l.length}}async extractText(e,t){let s=await import("node:fs");if(t==="application/pdf")try{let r=(await import("pdf-parse")).default,o=s.readFileSync(e);return(await r(o)).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 o=Math.round(t*3.5),n=Math.round(s*3.5),i=[],a=0;for(;a<e.length;){let l=a+o;if(l>=e.length){i.push(e.slice(a).trim());break}let d=Math.max(l-200,a),m=e.slice(d,l+200),p=m.lastIndexOf(`
744
744
 
745
- `);if(p>0)l=d+p;else{let y=m.lastIndexOf(". ");y>0&&(l=d+y+1)}let T=e.slice(a,l).trim();T&&i.push(T),a=l-n}return i.filter(l=>l.length>0)}}});var pr,ii=E(()=>{"use strict";nr();pr=class{static{u(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;pollTimer;running=0;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;constructor(e,t,s,r,o,n){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=o,this.logger=n}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(l){this.logger.warn({taskId:e.id,err:l},"Malformed skill input JSON"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:r}=Tt(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o=new Promise((l,d)=>setTimeout(()=>d(new Error("Background task timed out")),this.taskTimeoutMs)),n=await Promise.race([this.skillSandbox.execute(t,s,r),o]),i=JSON.stringify(n.data??n.display??n.error);this.taskRepo.updateStatus(e.id,n.success?"completed":"failed",i,n.error);let a=this.adapters.get(e.platform);if(a){let l=n.success?`\u2705 Background task completed: ${e.description}
745
+ `);if(p>0)l=d+p;else{let y=m.lastIndexOf(". ");y>0&&(l=d+y+1)}let w=e.slice(a,l).trim();w&&i.push(w),a=l-n}return i.filter(l=>l.length>0)}}});var pr,ii=E(()=>{"use strict";nr();pr=class{static{u(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;pollTimer;running=0;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;constructor(e,t,s,r,o,n){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=o,this.logger=n}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(l){this.logger.warn({taskId:e.id,err:l},"Malformed skill input JSON"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:r}=Tt(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o=new Promise((l,d)=>setTimeout(()=>d(new Error("Background task timed out")),this.taskTimeoutMs)),n=await Promise.race([this.skillSandbox.execute(t,s,r),o]),i=JSON.stringify(n.data??n.display??n.error);this.taskRepo.updateStatus(e.id,n.success?"completed":"failed",i,n.error);let a=this.adapters.get(e.platform);if(a){let l=n.success?`\u2705 Background task completed: ${e.description}
746
746
 
747
747
  Result: ${n.display??JSON.stringify(n.data)}`:`\u274C Background task failed: ${e.description}
748
748
 
749
749
  Error: ${n.error}`;await a.sendMessage(e.chatId,l)}}catch(t){let s=t instanceof Error?t.message:String(t);this.taskRepo.updateStatus(e.id,"failed",void 0,s),this.logger.error({taskId:e.id,err:t},"Background task failed");let r=this.adapters.get(e.platform);r&&await r.sendMessage(e.chatId,`\u274C Background task failed: ${e.description}
750
750
 
751
- Error: ${s}`)}}}});import dm from"node:crypto";var hr,ai=E(()=>{"use strict";nr();hr=class{static{u(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,o,n,i,a,l,d){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=o,this.users=n,this.logger=i,this.pipeline=a,this.formatter=l,this.conversationManager=d}start(){this.tickTimer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Proactive scheduler started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0),this.logger.info("Proactive scheduler stopped")}async tick(){try{let e=this.actionRepo.getDue();for(let t of e)try{await this.executeAction(t)}catch(s){this.logger.error({err:s,actionId:t.id},"Failed to execute scheduled action")}}catch(e){this.logger.error({err:e},"Error during proactive scheduler tick")}}async executeAction(e){let t=new Date().toISOString();this.logger.info({actionId:e.id,name:e.name},"Executing scheduled action");let s;if(e.promptTemplate&&this.pipeline)try{let i=`scheduled-${e.id}`,a={id:`scheduled-${dm.randomUUID()}`,platform:e.platform,chatId:i,chatType:"dm",userId:e.userId,userName:e.userId,text:e.promptTemplate,timestamp:new Date},l=await this.pipeline.process(a);s=(this.formatter?this.formatter.format(l.text,e.platform):{text:l.text,parseMode:"text"}).text;let m=this.adapters.get(e.platform);if(m&&l.attachments)for(let p of l.attachments)try{let T=p.mimeType.startsWith("image/"),y=p.mimeType==="audio/ogg"||p.mimeType==="audio/opus";T?await m.sendPhoto(e.chatId,p.data,p.fileName):y?await m.sendVoice(e.chatId,p.data):await m.sendFile(e.chatId,p.data,p.fileName)}catch(T){this.logger.warn({err:T,fileName:p.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(i){let a=i instanceof Error?i.message:String(i);this.logger.error({actionId:e.id,err:i},"Pipeline execution failed for scheduled action"),s=`Scheduled action "${e.name}" failed: ${a}`}else if(e.promptTemplate)try{s=(await this.llm.complete({messages:[{role:"user",content:e.promptTemplate}],maxTokens:1024,tier:"fast"})).content}catch(i){let a=i instanceof Error?i.message:String(i);this.logger.error({actionId:e.id,err:i},"LLM call failed for scheduled action"),s=`Scheduled action "${e.name}" failed: ${a}`}else{let i=this.skillRegistry.get(e.skillName);if(!i)this.logger.warn({actionId:e.id,skillName:e.skillName},"Unknown skill for scheduled action"),s=`Scheduled action "${e.name}" failed: unknown skill "${e.skillName}"`;else try{let a;try{a=JSON.parse(e.skillInput)}catch{a={},this.logger.warn({actionId:e.id},"Invalid skillInput JSON, using empty input")}let{context:l}=Tt(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),d=await this.skillSandbox.execute(i,a,l);s=d.success?`\u{1F514} Scheduled: ${e.name}
751
+ Error: ${s}`)}}}});import dm from"node:crypto";var hr,ai=E(()=>{"use strict";nr();hr=class{static{u(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,o,n,i,a,l,d){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=o,this.users=n,this.logger=i,this.pipeline=a,this.formatter=l,this.conversationManager=d}start(){this.tickTimer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Proactive scheduler started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0),this.logger.info("Proactive scheduler stopped")}async tick(){try{let e=this.actionRepo.getDue();for(let t of e)try{await this.executeAction(t)}catch(s){this.logger.error({err:s,actionId:t.id},"Failed to execute scheduled action")}}catch(e){this.logger.error({err:e},"Error during proactive scheduler tick")}}async executeAction(e){let t=new Date().toISOString();this.logger.info({actionId:e.id,name:e.name},"Executing scheduled action");let s;if(e.promptTemplate&&this.pipeline)try{let d=`scheduled-${e.id}`,m={id:`scheduled-${dm.randomUUID()}`,platform:e.platform,chatId:d,chatType:"dm",userId:e.userId,userName:e.userId,text:e.promptTemplate,timestamp:new Date},p=await this.pipeline.process(m);s=(this.formatter?this.formatter.format(p.text,e.platform):{text:p.text,parseMode:"text"}).text;let y=this.adapters.get(e.platform);if(y&&p.attachments)for(let h of p.attachments)try{let T=h.mimeType.startsWith("image/"),$=h.mimeType==="audio/ogg"||h.mimeType==="audio/opus";T?await y.sendPhoto(e.chatId,h.data,h.fileName):$?await y.sendVoice(e.chatId,h.data):await y.sendFile(e.chatId,h.data,h.fileName)}catch(T){this.logger.warn({err:T,fileName:h.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(d){let m=d instanceof Error?d.message:String(d);this.logger.error({actionId:e.id,err:d},"Pipeline execution failed for scheduled action"),s=`Scheduled action "${e.name}" failed: ${m}`}else if(e.promptTemplate)try{s=(await this.llm.complete({messages:[{role:"user",content:e.promptTemplate}],maxTokens:1024,tier:"fast"})).content}catch(d){let m=d instanceof Error?d.message:String(d);this.logger.error({actionId:e.id,err:d},"LLM call failed for scheduled action"),s=`Scheduled action "${e.name}" failed: ${m}`}else{let d=this.skillRegistry.get(e.skillName);if(!d)this.logger.warn({actionId:e.id,skillName:e.skillName},"Unknown skill for scheduled action"),s=`Scheduled action "${e.name}" failed: unknown skill "${e.skillName}"`;else try{let m;try{m=JSON.parse(e.skillInput)}catch{m={},this.logger.warn({actionId:e.id},"Invalid skillInput JSON, using empty input")}let{context:p}=Tt(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),w=await this.skillSandbox.execute(d,m,p);s=w.success?`\u{1F514} Scheduled: ${e.name}
752
752
 
753
- ${d.display??JSON.stringify(d.data)}`:`\u274C Scheduled action "${e.name}" failed: ${d.error}`}catch(a){let l=a instanceof Error?a.message:String(a);s=`\u274C Scheduled action "${e.name}" failed: ${l}`}}let r=s.trim();if(!r||r.length<3||/^(alles\s+(in\s+ordnung|ok|gut|klar)|no\s+issues?|nothing\s+to\s+report|all\s+(clear|good|ok)|keine\s+(probleme|auff[aä]lligkeiten|fehler))/i.test(r))this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let i=this.adapters.get(e.platform);if(i)try{if(await i.sendMessage(e.chatId,s),this.conversationManager){let a=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),l=`[Scheduled Alert: ${e.name}]
754
- ${s}`;this.conversationManager.addMessage(a.id,"system",l)}}catch(a){this.logger.error({err:a,actionId:e.id},"Failed to send scheduled action result")}}if(e.promptTemplate&&this.conversationManager)try{let i=`scheduled-${e.id}`,a=this.conversationManager.getOrCreateConversation(e.platform,i,e.userId);this.conversationManager.pruneMessages(a.id,20)}catch{}let n=this.calculateNextRun(e);n?this.actionRepo.updateLastRun(e.id,t,n):(this.actionRepo.updateLastRun(e.id,t,null),this.actionRepo.setEnabled(e.id,!1))}calculateNextRun(e){let t=new Date;switch(e.scheduleType){case"interval":{let s=parseInt(e.scheduleValue,10);return isNaN(s)||s<=0?null:new Date(t.getTime()+s*6e4).toISOString()}case"once":return null;case"cron":return this.getNextCronDate(e.scheduleValue,t)?.toISOString()??null;default:return null}}getNextCronDate(e,t){let s=e.trim().split(/\s+/);if(s.length!==5)return null;let r=new Date(t.getTime()+6e4);r.setSeconds(0,0);for(let o=0;o<1440;o++){if(this.matchesCron(s,r))return r;r.setTime(r.getTime()+6e4)}return null}matchesCron(e,t){let s=t.getMinutes(),r=t.getHours(),o=t.getDate(),n=t.getMonth()+1,i=t.getDay();return this.matchCronField(e[0],s)&&this.matchCronField(e[1],r)&&this.matchCronField(e[2],o)&&this.matchCronField(e[3],n)&&this.matchCronField(e[4],i)}matchCronField(e,t){if(e==="*")return!0;let s=/^\*\/(\d+)$/.exec(e);if(s){let o=parseInt(s[1],10);return t%o===0}let r=parseInt(e,10);return isNaN(r)?!1:t===r}}});function ci(c){let e=c.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of um)if(s.test(e))return{level:"low",matchedPatterns:[]};let t=[];for(let s of mm)for(let r of s.patterns)if(r.test(e)){t.push(s.name);break}return t.length>0?{level:"high",matchedPatterns:t}:{level:"low",matchedPatterns:[]}}var um,mm,li=E(()=>{"use strict";um=[/^(what|where|when|who|why|how|which|can you|could you|do you|is there|are there|was |wer |wo |wann |warum |wie |welch|kannst du|könntest du|gibt es)/i,/^(hi|hey|hello|hallo|guten (morgen|tag|abend)|moin|servus|grüß|na\b|yo\b|sup\b|good (morning|evening|night))\b/i,/^(tell me|show me|find|search|help|explain|describe|translate|summarize|zeig|such|hilf|erklär|beschreib|übersetze|fass zusammen)/i,/^(ok|okay|yes|no|ja|nein|danke|thanks|thank you|sure|alright|klar|gut|cool|nice|great|perfect|genau|stimmt|richtig)\b/i],mm=[{name:"fact:name",patterns:[/\b(my name is|i'm called|i am called|ich heiße|ich bin der|ich bin die|mein name ist)\b/i]},{name:"fact:location",patterns:[/\b(i live in|i'm from|i am from|ich wohne|ich lebe in|ich komme aus|ich bin aus)\b/i]},{name:"fact:work",patterns:[/\b(i work at|i work as|i work for|ich arbeite|mein job|mein beruf|ich bin .{0,20}(entwickler|ingenieur|lehrer|arzt|designer))\b/i]},{name:"fact:birthday",patterns:[/\b(my birthday|i was born|ich bin geboren|mein geburtstag|ich habe am .{1,15} geburtstag)\b/i]},{name:"fact:age",patterns:[/\b(i'm \d+ years|i am \d+ years|ich bin \d+ (jahre|jahr))\b/i]},{name:"preference:like",patterns:[/\b(i love|i really like|i enjoy|ich liebe|ich mag|mir gefällt|mir gefallen)\b/i]},{name:"preference:dislike",patterns:[/\b(i hate|i dislike|i can't stand|ich hasse|ich mag .{0,5} nicht|ich kann .{0,10} nicht leiden)\b/i]},{name:"preference:prefer",patterns:[/\b(i prefer|i'd rather|ich bevorzuge|ich nehme lieber|mir ist .{0,10} lieber)\b/i]},{name:"preference:favorite",patterns:[/\b(my fav|my favorite|my favourite|mein lieblings|meine lieblings|am liebsten)\b/i]},{name:"correction",patterns:[/\b(actually|actually,? (i|my|it)|eigentlich|das stimmt nicht|nein,? ich|that's not right|that's wrong|nicht ganz)\b/i]},{name:"relationship:family",patterns:[/\b(my wife|my husband|my partner|meine frau|mein mann|mein partner|meine partnerin|my daughter|my son|mein sohn|meine tochter|my kids|meine kinder|my mother|my father|meine mutter|mein vater)\b/i]},{name:"relationship:professional",patterns:[/\b(my boss|my manager|my colleague|mein chef|mein vorgesetzter|mein kollege|meine kollegin)\b/i]},{name:"relationship:social",patterns:[/\b(my friend|my best friend|mein freund|meine freundin|mein bester freund)\b/i]},{name:"fact:language",patterns:[/\b(i speak|ich spreche|my native|meine muttersprache)\b/i]},{name:"fact:education",patterns:[/\b(i studied|i went to|ich habe .{0,10} studiert|ich war auf der|mein studium)\b/i]},{name:"fact:hobby",patterns:[/\b(my hobby|i play .{0,10}(guitar|piano|football|tennis|chess)|mein hobby|ich spiele|in my free time|in meiner freizeit)\b/i]},{name:"decision",patterns:[/\b(i've decided|i decided|i will always|ich habe (mich )?entschieden|ich werde immer)\b/i]},{name:"commitment",patterns:[/\b(i always|i never|ich mache immer|ich mache nie|i'm trying to|ich versuche)\b/i]}];u(ci,"scanSignal")});var pm,hm,fr,di=E(()=>{"use strict";pm=["fact","preference","correction","entity","decision","relationship","principle","commitment","moment","skill"],hm=`You are a memory extraction system. Analyze the user message and extract personal facts about the USER (not about what they're asking).
753
+ ${w.display??JSON.stringify(w.data)}`:`\u274C Scheduled action "${e.name}" failed: ${w.error}`}catch(m){let p=m instanceof Error?m.message:String(m);s=`\u274C Scheduled action "${e.name}" failed: ${p}`}}let r=s.trim(),o=(e.promptTemplate??"").toLowerCase(),n=/nichts|silent|no\s*output|don't\s*respond|do\s*not\s*respond/i.test(o),i=/offline|down|fehler|error|warn|critical|alert|fail|nicht\s+(erreichbar|verf[uü]gbar|gefunden|online)|ausgefallen|stopped|unreachable|unavailable|⚠|❌|🚨|🔴/i.test(r)&&!/keine\s+(probleme|fehler|auff[aä]lligkeiten)/i.test(r);if(!r||r.length<3||n&&!i)this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let d=this.adapters.get(e.platform);if(d)try{if(await d.sendMessage(e.chatId,s),e.promptTemplate&&this.conversationManager){let m=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),p=`[Automated Scheduled Alert: ${e.name}]
754
+ ${s}`;this.conversationManager.addMessage(m.id,"assistant",p)}}catch(m){this.logger.error({err:m,actionId:e.id},"Failed to send scheduled action result")}}if(e.promptTemplate&&this.conversationManager)try{let d=`scheduled-${e.id}`,m=this.conversationManager.getOrCreateConversation(e.platform,d,e.userId);this.conversationManager.pruneMessages(m.id,20)}catch{}let l=this.calculateNextRun(e);l?this.actionRepo.updateLastRun(e.id,t,l):(this.actionRepo.updateLastRun(e.id,t,null),this.actionRepo.setEnabled(e.id,!1))}calculateNextRun(e){let t=new Date;switch(e.scheduleType){case"interval":{let s=parseInt(e.scheduleValue,10);return isNaN(s)||s<=0?null:new Date(t.getTime()+s*6e4).toISOString()}case"once":return null;case"cron":return this.getNextCronDate(e.scheduleValue,t)?.toISOString()??null;default:return null}}getNextCronDate(e,t){let s=e.trim().split(/\s+/);if(s.length!==5)return null;let r=new Date(t.getTime()+6e4);r.setSeconds(0,0);for(let o=0;o<1440;o++){if(this.matchesCron(s,r))return r;r.setTime(r.getTime()+6e4)}return null}matchesCron(e,t){let s=t.getMinutes(),r=t.getHours(),o=t.getDate(),n=t.getMonth()+1,i=t.getDay();return this.matchCronField(e[0],s)&&this.matchCronField(e[1],r)&&this.matchCronField(e[2],o)&&this.matchCronField(e[3],n)&&this.matchCronField(e[4],i)}matchCronField(e,t){if(e==="*")return!0;let s=/^\*\/(\d+)$/.exec(e);if(s){let o=parseInt(s[1],10);return t%o===0}let r=parseInt(e,10);return isNaN(r)?!1:t===r}}});function ci(c){let e=c.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of um)if(s.test(e))return{level:"low",matchedPatterns:[]};let t=[];for(let s of mm)for(let r of s.patterns)if(r.test(e)){t.push(s.name);break}return t.length>0?{level:"high",matchedPatterns:t}:{level:"low",matchedPatterns:[]}}var um,mm,li=E(()=>{"use strict";um=[/^(what|where|when|who|why|how|which|can you|could you|do you|is there|are there|was |wer |wo |wann |warum |wie |welch|kannst du|könntest du|gibt es)/i,/^(hi|hey|hello|hallo|guten (morgen|tag|abend)|moin|servus|grüß|na\b|yo\b|sup\b|good (morning|evening|night))\b/i,/^(tell me|show me|find|search|help|explain|describe|translate|summarize|zeig|such|hilf|erklär|beschreib|übersetze|fass zusammen)/i,/^(ok|okay|yes|no|ja|nein|danke|thanks|thank you|sure|alright|klar|gut|cool|nice|great|perfect|genau|stimmt|richtig)\b/i],mm=[{name:"fact:name",patterns:[/\b(my name is|i'm called|i am called|ich heiße|ich bin der|ich bin die|mein name ist)\b/i]},{name:"fact:location",patterns:[/\b(i live in|i'm from|i am from|ich wohne|ich lebe in|ich komme aus|ich bin aus)\b/i]},{name:"fact:work",patterns:[/\b(i work at|i work as|i work for|ich arbeite|mein job|mein beruf|ich bin .{0,20}(entwickler|ingenieur|lehrer|arzt|designer))\b/i]},{name:"fact:birthday",patterns:[/\b(my birthday|i was born|ich bin geboren|mein geburtstag|ich habe am .{1,15} geburtstag)\b/i]},{name:"fact:age",patterns:[/\b(i'm \d+ years|i am \d+ years|ich bin \d+ (jahre|jahr))\b/i]},{name:"preference:like",patterns:[/\b(i love|i really like|i enjoy|ich liebe|ich mag|mir gefällt|mir gefallen)\b/i]},{name:"preference:dislike",patterns:[/\b(i hate|i dislike|i can't stand|ich hasse|ich mag .{0,5} nicht|ich kann .{0,10} nicht leiden)\b/i]},{name:"preference:prefer",patterns:[/\b(i prefer|i'd rather|ich bevorzuge|ich nehme lieber|mir ist .{0,10} lieber)\b/i]},{name:"preference:favorite",patterns:[/\b(my fav|my favorite|my favourite|mein lieblings|meine lieblings|am liebsten)\b/i]},{name:"correction",patterns:[/\b(actually|actually,? (i|my|it)|eigentlich|das stimmt nicht|nein,? ich|that's not right|that's wrong|nicht ganz)\b/i]},{name:"relationship:family",patterns:[/\b(my wife|my husband|my partner|meine frau|mein mann|mein partner|meine partnerin|my daughter|my son|mein sohn|meine tochter|my kids|meine kinder|my mother|my father|meine mutter|mein vater)\b/i]},{name:"relationship:professional",patterns:[/\b(my boss|my manager|my colleague|mein chef|mein vorgesetzter|mein kollege|meine kollegin)\b/i]},{name:"relationship:social",patterns:[/\b(my friend|my best friend|mein freund|meine freundin|mein bester freund)\b/i]},{name:"fact:language",patterns:[/\b(i speak|ich spreche|my native|meine muttersprache)\b/i]},{name:"fact:education",patterns:[/\b(i studied|i went to|ich habe .{0,10} studiert|ich war auf der|mein studium)\b/i]},{name:"fact:hobby",patterns:[/\b(my hobby|i play .{0,10}(guitar|piano|football|tennis|chess)|mein hobby|ich spiele|in my free time|in meiner freizeit)\b/i]},{name:"decision",patterns:[/\b(i've decided|i decided|i will always|ich habe (mich )?entschieden|ich werde immer)\b/i]},{name:"commitment",patterns:[/\b(i always|i never|ich mache immer|ich mache nie|i'm trying to|ich versuche)\b/i]}];u(ci,"scanSignal")});var pm,hm,fr,di=E(()=>{"use strict";pm=["fact","preference","correction","entity","decision","relationship","principle","commitment","moment","skill"],hm=`You are a memory extraction system. Analyze the user message and extract personal facts about the USER (not about what they're asking).
755
755
 
756
756
  Rules:
757
757
  - Only extract information the user STATES about themselves
@@ -771,9 +771,9 @@ Extract memories from this conversation:
771
771
  User: {USER_MESSAGE}
772
772
  Assistant: {ASSISTANT_RESPONSE}
773
773
 
774
- Return ONLY a valid JSON array, no explanation:`,fr=class{static{u(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,o=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=o}async extract(e,t,s){try{let r=hm.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),o=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),n=this.parseResponse(o.content);if(n.length===0)return 0;let i=0;for(let a of n)if(!(a.confidence<this.minConfidence))try{let l=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",l.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(l){this.logger.warn({err:l,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 pm.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});var gr,ui=E(()=>{"use strict";li();di();gr=class{static{u(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 fr(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;let r=ci(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(o=>{o>0&&this.logger.info({userId:e,extractedCount:o},"Auto-extraction complete")}).catch(o=>{this.logger.error({err:o},"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 o=r.filter(n=>n>s);return this.extractionTimestamps.set(e,o),o.length>=this.maxExtractionsPerMinute?!1:(o.push(t),!0)}}});var fm,gm,ym,wm,yr,mi=E(()=>{"use strict";fm=Math.LN2,gm=.3,ym=.7,wm=3,yr=class{static{u(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 o=[e];if(r)for(let n of r)n!==e&&o.push(n);try{let n=new Set,i=[];for(let f of o)for(let _ of this.memoryRepo.keywordSearch(f,t,30))n.has(_.id)||(n.add(_.id),i.push(_));let a=[],l=!1;if(this.embeddingService)try{let f=new Set;for(let _ of o)for(let S of await this.embeddingService.semanticSearch(_,t,30))f.has(S.key)||(f.add(S.key),a.push(S));l=a.length>0}catch(f){this.logger.debug({err:f},"Semantic search failed, falling back to keyword-only")}let d=new Map,m=i.length;for(let f=0;f<i.length;f++){let _=i[f],S=m>0?1-f/m:0,A=l?gm:1,I=this.applyBoosts(S*A,_);d.set(_.key,{memory:{key:_.key,value:_.value,category:_.category,type:_.type,score:I},score:I}),this.memoryRepo.recordAccess(_.id)}if(l)for(let f of a){let _=f.score*ym,S=d.get(f.key);if(S)S.score+=_,S.memory.score=S.score;else{let A=this.memoryRepo.recall(e,f.key),I=this.applyBoosts(_,A||void 0);d.set(f.key,{memory:{key:f.key,value:f.value,category:f.category,type:A?.type||"general",score:I},score:I}),A&&this.memoryRepo.recordAccess(A.id)}}let p=Array.from(d.values()).sort((f,_)=>_.score-f.score),T=new Map,y=[];for(let{memory:f}of p){let _=T.get(f.type)||0;if(!(_>=wm)&&(T.set(f.type,_+1),y.push(f),y.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:y.length,hasSemanticSearch:l},"Hybrid memory retrieval complete"),y}catch(n){this.logger.error({err:n},"Memory retrieval failed");let i=new Set,a=[];for(let l of o)for(let d of this.memoryRepo.getRecentForPrompt(l,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(),o=Date.now()-r,n=Math.exp(-fm*o/2592e6);s*=n}return s}}});import{EventEmitter as Tm}from"node:events";var ie,qe=E(()=>{"use strict";ie=class extends Tm{static{u(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 o=-1,i=r.slice(0,t).lastIndexOf(`
774
+ Return ONLY a valid JSON array, no explanation:`,fr=class{static{u(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,o=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=o}async extract(e,t,s){try{let r=hm.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),o=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),n=this.parseResponse(o.content);if(n.length===0)return 0;let i=0;for(let a of n)if(!(a.confidence<this.minConfidence))try{let l=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",l.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(l){this.logger.warn({err:l,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 pm.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});var gr,ui=E(()=>{"use strict";li();di();gr=class{static{u(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 fr(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;let r=ci(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(o=>{o>0&&this.logger.info({userId:e,extractedCount:o},"Auto-extraction complete")}).catch(o=>{this.logger.error({err:o},"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 o=r.filter(n=>n>s);return this.extractionTimestamps.set(e,o),o.length>=this.maxExtractionsPerMinute?!1:(o.push(t),!0)}}});var fm,gm,ym,wm,yr,mi=E(()=>{"use strict";fm=Math.LN2,gm=.3,ym=.7,wm=3,yr=class{static{u(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 o=[e];if(r)for(let n of r)n!==e&&o.push(n);try{let n=new Set,i=[];for(let h of o)for(let T of this.memoryRepo.keywordSearch(h,t,30))n.has(T.id)||(n.add(T.id),i.push(T));let a=[],l=!1;if(this.embeddingService)try{let h=new Set;for(let T of o)for(let $ of await this.embeddingService.semanticSearch(T,t,30))h.has($.key)||(h.add($.key),a.push($));l=a.length>0}catch(h){this.logger.debug({err:h},"Semantic search failed, falling back to keyword-only")}let d=new Map,m=i.length;for(let h=0;h<i.length;h++){let T=i[h],$=m>0?1-h/m:0,A=l?gm:1,I=this.applyBoosts($*A,T);d.set(T.key,{memory:{key:T.key,value:T.value,category:T.category,type:T.type,score:I},score:I}),this.memoryRepo.recordAccess(T.id)}if(l)for(let h of a){let T=h.score*ym,$=d.get(h.key);if($)$.score+=T,$.memory.score=$.score;else{let A=this.memoryRepo.recall(e,h.key),I=this.applyBoosts(T,A||void 0);d.set(h.key,{memory:{key:h.key,value:h.value,category:h.category,type:A?.type||"general",score:I},score:I}),A&&this.memoryRepo.recordAccess(A.id)}}let p=Array.from(d.values()).sort((h,T)=>T.score-h.score),w=new Map,y=[];for(let{memory:h}of p){let T=w.get(h.type)||0;if(!(T>=wm)&&(w.set(h.type,T+1),y.push(h),y.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:y.length,hasSemanticSearch:l},"Hybrid memory retrieval complete"),y}catch(n){this.logger.error({err:n},"Memory retrieval failed");let i=new Set,a=[];for(let l of o)for(let d of this.memoryRepo.getRecentForPrompt(l,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(),o=Date.now()-r,n=Math.exp(-fm*o/2592e6);s*=n}return s}}});import{EventEmitter as Tm}from"node:events";var ie,qe=E(()=>{"use strict";ie=class extends Tm{static{u(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 o=-1,i=r.slice(0,t).lastIndexOf(`
775
775
 
776
- `);if(i>0&&(o=i),o<0){let l=r.slice(0,t).match(/.*[.!?]\s/s);l&&(o=l[0].length)}o<0&&(o=t),s.push(r.slice(0,o).trimEnd()),r=r.slice(o).trimStart()}return s}}});import{Bot as _m,InputFile as pi}from"grammy";function rl(c){if(c==="markdown")return"MarkdownV2";if(c==="html")return"HTML"}var ao,ol=E(()=>{"use strict";qe();u(rl,"mapParseMode");ao=class extends ie{static{u(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new _m(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]",o=t.photo[t.photo.length-1],n=await this.downloadAttachment(o.file_id,"image","image/jpeg"),i=this.normalizeMessage(t,r);i.attachments=n?[n]: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"}]`,o=await this.downloadAttachment(t.audio.file_id,"audio",t.audio.mime_type??"audio/mpeg"),n=this.normalizeMessage(t,r);n.attachments=o?[o]:void 0,this.emit("message",n)}),this.bot.on("message:video",async e=>{let t=e.message,r=(t.caption??"")||"[Video]",o=await this.downloadAttachment(t.video.file_id,"video",t.video.mime_type??"video/mp4"),n=this.normalizeMessage(t,r);n.attachments=o?[o]:void 0,this.emit("message",n)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,o=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,n=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),i=this.normalizeMessage(t,o);i.attachments=n?[n]: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:u(()=>{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),o="";for(let n of r){let i=await this.bot.api.sendMessage(Number(e),n,{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:rl(s?.parseMode)});o=String(i.message_id)}return o}async editMessage(e,t,s,r){await this.bot.api.editMessageText(Number(e),Number(t),s,{parse_mode:rl(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 pi(t,"image.png"),{caption:s});return String(r.message_id)}async sendFile(e,t,s,r){let o=await this.bot.api.sendDocument(Number(e),new pi(t,s),{caption:r});return String(o.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new pi(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 n=(await this.bot.api.getFile(e)).file_path;if(!n)return;let i=`https://api.telegram.org/file/bot${this.bot.token}/${n}`,a=await fetch(i);if(!a.ok)return;let l=Buffer.from(await a.arrayBuffer());return{type:t,mimeType:s,fileName:r??n.split("/").pop(),size:l.length,data:l}}catch(o){console.error("[telegram] Failed to download file",e,o);return}}}});import{Client as Em,GatewayIntentBits as co,Events as hi}from"discord.js";var lo,nl=E(()=>{"use strict";qe();lo=class extends ie{static{u(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new Em({intents:[co.Guilds,co.GuildMessages,co.MessageContent,co.DirectMessages]}),this.client.on(hi.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(hi.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(hi.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 o=this.splitText(t,2e3),n="";for(let i=0;i<o.length;i++)i===0&&s?.replyToMessageId?n=(await(await r.messages.fetch(s.replyToMessageId)).reply(o[i])).id:n=(await r.send(o[i])).id;return n}async editMessage(e,t,s,r){if(!this.client)throw new Error("Client is not connected");let o=await this.client.channels.fetch(e);if(!o?.isTextBased()||!("messages"in o))throw new Error(`Channel ${e} is not a text channel`);await(await o.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 o=await this.client.channels.fetch(e);return!o?.isTextBased()||!("send"in o)?void 0:(await o.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 o=await fetch(r.url);if(!o.ok)continue;let n=await o.arrayBuffer(),i=Buffer.from(n),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(o){console.error("[discord] Failed to download attachment",r.url,o)}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 uo,il=E(()=>{"use strict";qe();uo=class extends ie{static{u(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(o,n)=>{if(n.sender===this.botUserId)return;let i=n.content?.msgtype;if(i)try{let a=await this.normalizeEvent(o,n,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),o="";for(let n of r)s?.parseMode==="html"?o=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:n.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:n}):o=await this.client.sendText(e,n);return o}async editMessage(e,t,s,r){let o=r?.parseMode==="html",n={msgtype:"m.text",body:"* "+(o?s.replace(/<[^>]*>/g,""):s),"m.new_content":{msgtype:"m.text",body:o?s.replace(/<[^>]*>/g,""):s,...o?{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",n)}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"),o={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",o)}async sendFile(e,t,s,r){let o=this.guessMimeType(s),n=await this.client.uploadContent(t,o,s),i={msgtype:"m.file",body:r??s,filename:s,url:n,info:{mimetype:o,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 o={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{...o,text:t.content.body};case"m.image":{let n=await this.downloadAttachment(t.content,"image");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Photo]",attachments:n?[n]:void 0}}case"m.audio":{let n=await this.downloadAttachment(t.content,"audio");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Voice message]",attachments:n?[n]:void 0}}case"m.video":{let n=await this.downloadAttachment(t.content,"video");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Video]",attachments:n?[n]:void 0}}case"m.file":{let n=await this.downloadAttachment(t.content,"document");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Document]",attachments:n?[n]:void 0}}default:return t.content.body?{...o,text:t.content.body}:void 0}}async downloadAttachment(e,t){let s=e.url;if(!s||!s.startsWith("mxc://"))return;let r=e.info??{},o=r.mimetype,n=r.size,i=e.filename??e.body??"file",a=s.slice(6),l=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${a}`,`${this.homeserverUrl}/_matrix/media/v3/download/${a}`];for(let d of l)try{let m=await fetch(d,{headers:{Authorization:`Bearer ${this.accessToken}`}});if(m.status===404)continue;if(!m.ok){console.error(`[matrix] Download failed (${m.status})`,s,d);continue}let p=await m.arrayBuffer(),T=Buffer.from(p);return{type:t,mimeType:o,fileName:i,size:n??T.length,data:T}}catch(m){console.error("[matrix] Download error",s,d,m);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 mo,al=E(()=>{"use strict";qe();mo=class extends ie{static{u(this,"WhatsAppAdapter")}platform="whatsapp";socket;downloadMedia;dataPath;reconnectAttempts=0;reconnectTimer;constructor(e){super(),this.dataPath=e}async connect(){this.status="connecting";let e=await import("@whiskeysockets/baileys"),t=e.default??e,{makeWASocket:s,useMultiFileAuthState:r,DisconnectReason:o,downloadMediaMessage:n}=t;this.downloadMedia=n;let{state:i,saveCreds:a}=await r(this.dataPath);this.socket=s({auth:i,printQRInTerminal:!0}),this.socket.ev.on("creds.update",a),this.socket.ev.on("connection.update",l=>{if(l.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),l.connection==="close"){let m=l.lastDisconnect?.error?.output?.statusCode!==o.loggedOut;if(this.status="disconnected",this.emit("disconnected"),m){let p=Math.min(1e3*Math.pow(2,this.reconnectAttempts),6e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>this.connect(),p)}}}),this.socket.ev.on("messages.upsert",({messages:l,type:d})=>{if(d==="notify")for(let m of l)m.message&&(m.key.fromMe||this.processMessage(m).catch(p=>{this.emit("error",p instanceof Error?p:new Error(String(p)))}))})}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),o="";for(let n=0;n<r.length;n++)o=(await this.socket.sendMessage(e,{text:r[n]},n===0&&s?.replyToMessageId?{quoted:{key:{remoteJid:e,id:s.replyToMessageId},message:{}}}:void 0))?.key?.id??"";return o}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=[],o=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})}o||(o="[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})}o||(o="[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}),o||(o="[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}),o||(o="[Document]")}else if(t.stickerMessage&&!s)return;if(!o&&r.length===0)return;let n={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:o,timestamp:new Date(e.messageTimestamp*1e3),replyToMessageId:t.extendedTextMessage?.contextInfo?.stanzaId??void 0,attachments:r.length>0?r:void 0};this.emit("message",n)}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 po,cl=E(()=>{"use strict";qe();po=class extends ie{static{u(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(o=>{this.emit("error",o instanceof Error?o:new Error(String(o)))})},2e3),this.status="connected",this.emit("connected");return}catch(r){if(t=r instanceof Error?r:new Error(String(r)),s<e){let o=1e3*Math.pow(2,s);await new Promise(n=>setTimeout(n,o))}}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),o="";for(let n of r){let i=e.startsWith("group."),a={message:n,number:this.phoneNumber};i?a.recipients=[e.replace("group.","")]:a.recipients=[e];let l=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!l.ok)throw new Error(`Signal send failed: ${l.status} ${await l.text()}`);let d=await l.json();o=String(d.timestamp??Date.now())}return o}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 o=s.envelope,n=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:o.sourceNumber??o.source??"",i=[];if(r.attachments)for(let d of r.attachments){let m=await this.downloadAttachment(d);m&&i.push(m)}let a=r.message||this.inferTextFromAttachments(i)||"";if(!a&&i.length===0)continue;let l={id:String(r.timestamp??Date.now()),platform:"signal",chatId:n,chatType:r.groupInfo?"group":"dm",userId:o.sourceNumber??o.source??"",userName:o.sourceName??o.sourceNumber??o.source??"",displayName:o.sourceName,text:a,timestamp:new Date(r.timestamp??Date.now()),attachments:i.length>0?i:void 0};this.emit("message",l)}}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 fi from"node:readline";var ho,ll=E(()=>{"use strict";qe();ho=class extends ie{static{u(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=fi.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
776
+ `);if(i>0&&(o=i),o<0){let l=r.slice(0,t).match(/.*[.!?]\s/s);l&&(o=l[0].length)}o<0&&(o=t),s.push(r.slice(0,o).trimEnd()),r=r.slice(o).trimStart()}return s}}});import{Bot as _m,InputFile as pi}from"grammy";function rl(c){if(c==="markdown")return"MarkdownV2";if(c==="html")return"HTML"}var ao,ol=E(()=>{"use strict";qe();u(rl,"mapParseMode");ao=class extends ie{static{u(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new _m(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]",o=t.photo[t.photo.length-1],n=await this.downloadAttachment(o.file_id,"image","image/jpeg"),i=this.normalizeMessage(t,r);i.attachments=n?[n]: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"}]`,o=await this.downloadAttachment(t.audio.file_id,"audio",t.audio.mime_type??"audio/mpeg"),n=this.normalizeMessage(t,r);n.attachments=o?[o]:void 0,this.emit("message",n)}),this.bot.on("message:video",async e=>{let t=e.message,r=(t.caption??"")||"[Video]",o=await this.downloadAttachment(t.video.file_id,"video",t.video.mime_type??"video/mp4"),n=this.normalizeMessage(t,r);n.attachments=o?[o]:void 0,this.emit("message",n)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,o=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,n=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),i=this.normalizeMessage(t,o);i.attachments=n?[n]: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:u(()=>{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),o="";for(let n of r){let i=await this.bot.api.sendMessage(Number(e),n,{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:rl(s?.parseMode)});o=String(i.message_id)}return o}async editMessage(e,t,s,r){await this.bot.api.editMessageText(Number(e),Number(t),s,{parse_mode:rl(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 pi(t,"image.png"),{caption:s});return String(r.message_id)}async sendFile(e,t,s,r){let o=await this.bot.api.sendDocument(Number(e),new pi(t,s),{caption:r});return String(o.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new pi(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 n=(await this.bot.api.getFile(e)).file_path;if(!n)return;let i=`https://api.telegram.org/file/bot${this.bot.token}/${n}`,a=await fetch(i);if(!a.ok)return;let l=Buffer.from(await a.arrayBuffer());return{type:t,mimeType:s,fileName:r??n.split("/").pop(),size:l.length,data:l}}catch(o){console.error("[telegram] Failed to download file",e,o);return}}}});import{Client as Em,GatewayIntentBits as co,Events as hi}from"discord.js";var lo,nl=E(()=>{"use strict";qe();lo=class extends ie{static{u(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new Em({intents:[co.Guilds,co.GuildMessages,co.MessageContent,co.DirectMessages]}),this.client.on(hi.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(hi.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(hi.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 o=this.splitText(t,2e3),n="";for(let i=0;i<o.length;i++)i===0&&s?.replyToMessageId?n=(await(await r.messages.fetch(s.replyToMessageId)).reply(o[i])).id:n=(await r.send(o[i])).id;return n}async editMessage(e,t,s,r){if(!this.client)throw new Error("Client is not connected");let o=await this.client.channels.fetch(e);if(!o?.isTextBased()||!("messages"in o))throw new Error(`Channel ${e} is not a text channel`);await(await o.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 o=await this.client.channels.fetch(e);return!o?.isTextBased()||!("send"in o)?void 0:(await o.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 o=await fetch(r.url);if(!o.ok)continue;let n=await o.arrayBuffer(),i=Buffer.from(n),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(o){console.error("[discord] Failed to download attachment",r.url,o)}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 uo,il=E(()=>{"use strict";qe();uo=class extends ie{static{u(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(o,n)=>{if(n.sender===this.botUserId)return;let i=n.content?.msgtype;if(i)try{let a=await this.normalizeEvent(o,n,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),o="";for(let n of r)s?.parseMode==="html"?o=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:n.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:n}):o=await this.client.sendText(e,n);return o}async editMessage(e,t,s,r){let o=r?.parseMode==="html",n={msgtype:"m.text",body:"* "+(o?s.replace(/<[^>]*>/g,""):s),"m.new_content":{msgtype:"m.text",body:o?s.replace(/<[^>]*>/g,""):s,...o?{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",n)}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"),o={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",o)}async sendFile(e,t,s,r){let o=this.guessMimeType(s),n=await this.client.uploadContent(t,o,s),i={msgtype:"m.file",body:r??s,filename:s,url:n,info:{mimetype:o,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 o={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{...o,text:t.content.body};case"m.image":{let n=await this.downloadAttachment(t.content,"image");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Photo]",attachments:n?[n]:void 0}}case"m.audio":{let n=await this.downloadAttachment(t.content,"audio");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Voice message]",attachments:n?[n]:void 0}}case"m.video":{let n=await this.downloadAttachment(t.content,"video");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Video]",attachments:n?[n]:void 0}}case"m.file":{let n=await this.downloadAttachment(t.content,"document");return n&&t.content.body&&(n.fileName=t.content.body),{...o,text:"[Document]",attachments:n?[n]:void 0}}default:return t.content.body?{...o,text:t.content.body}:void 0}}async downloadAttachment(e,t){let s=e.url;if(!s||!s.startsWith("mxc://"))return;let r=e.info??{},o=r.mimetype,n=r.size,i=e.filename??e.body??"file",a=s.slice(6),l=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${a}`,`${this.homeserverUrl}/_matrix/media/v3/download/${a}`];for(let d of l)try{let m=await fetch(d,{headers:{Authorization:`Bearer ${this.accessToken}`}});if(m.status===404)continue;if(!m.ok){console.error(`[matrix] Download failed (${m.status})`,s,d);continue}let p=await m.arrayBuffer(),w=Buffer.from(p);return{type:t,mimeType:o,fileName:i,size:n??w.length,data:w}}catch(m){console.error("[matrix] Download error",s,d,m);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 mo,al=E(()=>{"use strict";qe();mo=class extends ie{static{u(this,"WhatsAppAdapter")}platform="whatsapp";socket;downloadMedia;dataPath;reconnectAttempts=0;reconnectTimer;constructor(e){super(),this.dataPath=e}async connect(){this.status="connecting";let e=await import("@whiskeysockets/baileys"),t=e.default??e,{makeWASocket:s,useMultiFileAuthState:r,DisconnectReason:o,downloadMediaMessage:n}=t;this.downloadMedia=n;let{state:i,saveCreds:a}=await r(this.dataPath);this.socket=s({auth:i,printQRInTerminal:!0}),this.socket.ev.on("creds.update",a),this.socket.ev.on("connection.update",l=>{if(l.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),l.connection==="close"){let m=l.lastDisconnect?.error?.output?.statusCode!==o.loggedOut;if(this.status="disconnected",this.emit("disconnected"),m){let p=Math.min(1e3*Math.pow(2,this.reconnectAttempts),6e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>this.connect(),p)}}}),this.socket.ev.on("messages.upsert",({messages:l,type:d})=>{if(d==="notify")for(let m of l)m.message&&(m.key.fromMe||this.processMessage(m).catch(p=>{this.emit("error",p instanceof Error?p:new Error(String(p)))}))})}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),o="";for(let n=0;n<r.length;n++)o=(await this.socket.sendMessage(e,{text:r[n]},n===0&&s?.replyToMessageId?{quoted:{key:{remoteJid:e,id:s.replyToMessageId},message:{}}}:void 0))?.key?.id??"";return o}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=[],o=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})}o||(o="[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})}o||(o="[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}),o||(o="[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}),o||(o="[Document]")}else if(t.stickerMessage&&!s)return;if(!o&&r.length===0)return;let n={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:o,timestamp:new Date(e.messageTimestamp*1e3),replyToMessageId:t.extendedTextMessage?.contextInfo?.stanzaId??void 0,attachments:r.length>0?r:void 0};this.emit("message",n)}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 po,cl=E(()=>{"use strict";qe();po=class extends ie{static{u(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(o=>{this.emit("error",o instanceof Error?o:new Error(String(o)))})},2e3),this.status="connected",this.emit("connected");return}catch(r){if(t=r instanceof Error?r:new Error(String(r)),s<e){let o=1e3*Math.pow(2,s);await new Promise(n=>setTimeout(n,o))}}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),o="";for(let n of r){let i=e.startsWith("group."),a={message:n,number:this.phoneNumber};i?a.recipients=[e.replace("group.","")]:a.recipients=[e];let l=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!l.ok)throw new Error(`Signal send failed: ${l.status} ${await l.text()}`);let d=await l.json();o=String(d.timestamp??Date.now())}return o}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 o=s.envelope,n=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:o.sourceNumber??o.source??"",i=[];if(r.attachments)for(let d of r.attachments){let m=await this.downloadAttachment(d);m&&i.push(m)}let a=r.message||this.inferTextFromAttachments(i)||"";if(!a&&i.length===0)continue;let l={id:String(r.timestamp??Date.now()),platform:"signal",chatId:n,chatType:r.groupInfo?"group":"dm",userId:o.sourceNumber??o.source??"",userName:o.sourceName??o.sourceNumber??o.source??"",displayName:o.sourceName,text:a,timestamp:new Date(r.timestamp??Date.now()),attachments:i.length>0?i:void 0};this.emit("message",l)}}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 fi from"node:readline";var ho,ll=E(()=>{"use strict";qe();ho=class extends ie{static{u(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=fi.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
777
777
  Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leave.
778
778
  `),this.rl.on("line",e=>{let t=e.trim();if(!t){this.prompt();return}if(t==="/quit"||t==="/exit"){console.log(`
779
779
  Goodbye!
@@ -782,56 +782,56 @@ Alfred: ${t}
782
782
  `),this.prompt(),r}async editMessage(e,t,s,r){fi.clearLine(process.stdout,0),fi.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import bm from"node:http";import $m from"node:crypto";var fo,dl=E(()=>{"use strict";qe();fo=class extends ie{static{u(this,"HttpAdapter")}port;host;platform="api";server=null;streams=new Map;messageCounter=0;constructor(e,t){super(),this.port=e,this.host=t}async connect(){this.status="connecting",this.server=bm.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}`,o=this.streams.get(e);return o&&this.writeSseEvent(o,"response",{type:"response",text:t}),r}async editMessage(e,t,s,r){let o=this.streams.get(e);o&&this.writeSseEvent(o,"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 o=this.streams.get(e);return o&&this.writeSseEvent(o,"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("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type"),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/message"&&e.method==="POST"?this.handleMessage(e,t):(t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"})))}handleHealth(e){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:"ok"}))}handleMessage(e,t){let s="";e.on("data",r=>{s+=r.toString()}),e.on("end",()=>{try{let r=JSON.parse(s),o=r.text;if(!o||typeof o!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:'Missing or invalid "text" field'}));return}let n=r.chatId??`api-chat-${$m.randomUUID()}`,i=r.userId??"api-user",a=this.streams.get(n);a&&(this.writeSseEvent(a,"done",{type:"done"}),a.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this.streams.set(n,t),e.on("close",()=>{this.streams.delete(n)}),this.messageCounter++;let l={id:`api-${this.messageCounter}`,platform:"api",chatId:n,chatType:"dm",userId:i,userName:i,displayName:"API User",text:o,timestamp:new Date};this.emit("message",l)}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}
783
783
  data: ${JSON.stringify(s)}
784
784
 
785
- `)}}});var Xe={};oe(Xe,{CLIAdapter:()=>ho,DiscordAdapter:()=>lo,HttpAdapter:()=>fo,MatrixAdapter:()=>uo,MessagingAdapter:()=>ie,SignalAdapter:()=>po,TelegramAdapter:()=>ao,WhatsAppAdapter:()=>mo});var Ye=E(()=>{"use strict";qe();ol();nl();il();al();cl();ll();dl()});import go from"node:fs";import yo from"node:path";import vm from"js-yaml";var _t,ul=E(()=>{"use strict";rn();an();Be();wn();Pr();te();Zn();Qn();ei();ti();si();ri();oi();ni();ii();ai();ui();mi();_t=class{static{u(this,"Alfred")}config;logger;database;pipeline;reminderScheduler;backgroundTaskRunner;proactiveScheduler;adapters=new Map;formatter=new dr;userRepo;skillRegistry;mcpManager;calendarSkill;constructor(e){this.config=e,this.logger=Es("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new it(this.config.storage.path);let e=this.database.getDb(),t=new bs(e),s=new $s(e);this.userRepo=s;let r=new at(e),o=new vs(e),n=new Ss(e),i=new ks(e),a=new As(e),l=new Is(e),d=new xs(e),m=new Rs(e);this.logger.info("Storage initialized");let p=new Hs,T=this.loadSecurityRules();p.loadRules(T);let y=new qs(p,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:T.length},"Security engine initialized");let f=yn(this.config.llm,this.logger.child({component:"llm"}));await f.initialize();let _=new ur(f,a,this.logger.child({component:"embeddings"})),S=this.config.activeLearning?.enabled!==!1,A,I;S&&(A=new gr({llm:f,memoryRepo:o,logger:this.logger.child({component:"active-learning"}),embeddingService:_,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),I=new yr(o,this.logger.child({component:"memory-retriever"}),_),this.logger.info("Active learning & memory retriever initialized"));let P=new It(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new At;L.register(new xt),L.register(new Rt),L.register(new Ct(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new Lt(n)),L.register(new Nt(i));let X=new Ls(e);if(L.register(new Jt(X)),L.register(new Dt),L.register(new Mt),L.register(new Ot(o,_)),L.register(new Pt(f,L,P,y)),this.config.email?.accounts?.length){let C=new Map;for(let U of this.config.email.accounts)try{U.provider==="microsoft"&&!U.microsoft?.clientId&&this.config.calendar?.microsoft&&(U.microsoft={...this.config.calendar.microsoft});let fe=await zs(U);C.set(U.name,fe),this.logger.info({account:U.name,provider:U.provider??"imap-smtp"},"Email account initialized")}catch(fe){this.logger.warn({err:fe,account:U.name},"Email account initialization failed, skipping")}L.register(C.size>0?new Ge(C):new Ge)}else L.register(new Ge);L.register(new Ut),L.register(new Ft);let Oe=new Qt;Oe.setReloadCallback(C=>this.reloadService(C)),L.register(Oe),L.register(new Bt),L.register(new Ht),L.register(new qt),L.register(new zt(s)),L.register(new Wt(s,l,this.adapters,(C,U)=>t.findByPlatformAndUser(C,U))),L.register(new Vt(d)),L.register(new Gt(m));let ve=new Cs(e),Pe=new mr(ve,_,this.logger.child({component:"documents"}));L.register(new Xt(ve,Pe,_));let ae;if(this.config.calendar)try{let C=await Gs(this.config.calendar);ae=new mt(C),L.register(ae),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(C){this.logger.warn({err:C},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=ae,this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(te(),re));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let U of this.mcpManager.getSkills())L.register(U);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},f)),this.logger.info({agents:this.config.codeAgents.agents.map(U=>U.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:C,createContactsProvider:U}=await Promise.resolve().then(()=>(te(),re)),fe=await U(this.config.contacts);L.register(new C(fe)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(C){this.logger.warn({err:C},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let V;if(this.config.speech?.apiKey&&(V=new cr(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let C=new lr(this.config.speech,this.logger.child({component:"tts"}));L.register(new Yt(C)),this.logger.info("Text-to-speech skill registered")}let pe=new or(t),he=yo.resolve(yo.dirname(this.config.storage.path),"inbox");this.pipeline=new ir({llm:f,conversationManager:pe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:P,securityManager:y,memoryRepo:o,speechTranscriber:V,inboxPath:he,embeddingService:_,activeLearning:A,memoryRetriever:I,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100}),this.reminderScheduler=new ar(n,async(C,U,fe)=>{let Ue=this.adapters.get(C);Ue?await Ue.sendMessage(U,fe):this.logger.warn({platform:C,chatId:U},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:u(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:u(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:u((C,U)=>t.findByPlatformAndUser(C,U),"findConversation")}),this.backgroundTaskRunner=new pr(L,P,d,this.adapters,s,this.logger.child({component:"background-tasks"})),this.proactiveScheduler=new hr(m,L,P,f,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,pe),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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";this.adapters.set("api",new t(s,r)),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.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(()=>(Ye(),Xe)),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.mcpManager&&await this.mcpManager.shutdown();for(let[e,t]of this.adapters)try{await t.disconnect(),this.logger.info({platform:e},"Adapter disconnected")}catch(s){this.logger.error({platform:e,err:s},"Failed to disconnect adapter")}this.database.close(),this.logger.info("Alfred stopped")}async reloadService(e){try{tn();let t=new se().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(te(),re));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(()=>(te(),re));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(()=>(te(),re));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(()=>(te(),re)),o=await r(t.contacts);this.skillRegistry.register(new s(o)),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(()=>(te(),re));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(()=>(te(),re));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(()=>(te(),re));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing 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}}}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 o=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,o),this.logger.info({apiUserId:t.id,masterUserId:o},"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,o="",n=u(async d=>{if(d!==o){o=d;try{r?await t.editMessage(s.chatId,r,d):r=await t.sendMessage(s.chatId,d)}catch(m){this.logger.debug({err:m,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,n),a=this.formatter.format(i.text,s.platform),l=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,l)}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,l)}else await t.sendMessage(s.chatId,a.text,l)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let m=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,m.text)}if(i.attachments)for(let d of i.attachments)try{let m=d.mimeType.startsWith("image/"),p=d.mimeType==="audio/ogg"||d.mimeType==="audio/opus";m?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(m){this.logger.warn({err:m,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(o){this.logger.error({err:o},"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")})}loadSecurityRules(){let e=yo.resolve(this.config.security.rulesPath),t=[];if(!go.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!go.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=go.readdirSync(e).filter(o=>o.endsWith(".yml")||o.endsWith(".yaml"));for(let o of r)try{let n=yo.join(e,o),i=go.readFileSync(n,"utf-8"),a=vm.load(i);a?.rules&&Array.isArray(a.rules)&&(t.push(...a.rules),this.logger.info({file:o,count:a.rules.length},"Loaded security rules"))}catch(n){this.logger.error({err:n,file:o},"Failed to load security rules file")}return t}}});var ml=E(()=>{"use strict"});var gi=E(()=>{"use strict";ul();Qn();Zn();ei();ti();si();ri();oi();ii();ai();nr();ni();ui();mi();di();ml();li()});import wo from"node:fs";import pl from"node:path";import Sm from"node:os";function hl(){try{let c=wo.readFileSync(yi,"utf-8"),e=JSON.parse(c);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function fl(c){try{let e=pl.dirname(yi);wo.existsSync(e)||wo.mkdirSync(e,{recursive:!0}),wo.writeFileSync(yi,JSON.stringify(c,null,2),"utf-8")}catch{}}async function Et(c,e){let t=new AbortController,s=setTimeout(()=>t.abort(),Am);try{return await fetch(c,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function gl(c,e,t){switch(c){case"anthropic":{let s=await Et("https://api.anthropic.com/v1/models",{headers:{"x-api-key":e??"","anthropic-version":"2023-06-01"}});return s.ok?((await s.json()).data??[]).map(o=>({id:o.id,name:o.display_name})):[]}case"openai":{let s=t?`${t.replace(/\/+$/,"")}/models`:"https://api.openai.com/v1/models",r=await Et(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(n=>({id:n.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await Et(s);return r.ok?((await r.json()).models??[]).map(n=>({id:n.name.replace(/^models\//,""),name:n.displayName})):[]}case"mistral":{let s=await Et("https://api.mistral.ai/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(o=>({id:o.id,name:o.name})):[]}case"openrouter":{let s=await Et("https://openrouter.ai/api/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(o=>({id:o.id,name:o.name})):[]}case"ollama":{let s=(t??"http://localhost:11434").replace(/\/+$/,""),r=await Et(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(n=>({id:n.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await Et(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(n=>({id:n.id})):[]}default:return[]}}async function wi(c,e,t){let s=hl(),r=s.providers[c];if(r&&Date.now()-r.fetchedAt<km)return r.models;try{let o=await gl(c,e,t);if(o.length>0)return s.providers[c]={fetchedAt:Date.now(),models:o},fl(s),o}catch{}return r?r.models:[]}function To(c,e,t){gl(c,e,t).then(s=>{if(s.length>0){let r=hl();r.providers[c]={fetchedAt:Date.now(),models:s},fl(r)}}).catch(()=>{})}function Ti(c,e){let t=new Set,s=[];for(let r of c)if(!t.has(r.id)){t.add(r.id);let o=e.find(n=>n.id===r.id);s.push({id:r.id,name:r.name,desc:o?.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 km,Am,yi,_i=E(()=>{"use strict";km=24*60*60*1e3,Am=5e3,yi=pl.join(Sm.homedir(),".alfred","model-cache.json");u(hl,"readCache");u(fl,"writeCache");u(Et,"fetchWithTimeout");u(gl,"fetchModelsFromAPI");u(wi,"getModels");u(To,"refreshCacheInBackground");u(Ti,"mergeModels")});var yl={};oe(yl,{startCommand:()=>Im});async function Im(){let c=new se,e;try{e=c.loadConfig()}catch(n){console.error("Failed to load configuration:",n.message),process.exit(1)}let t=Es("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new _t(e),r=!1,o=u(async n=>{if(!r){r=!0,t.info({signal:n},"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",()=>o("SIGINT")),process.on("SIGTERM",()=>o("SIGTERM")),process.on("uncaughtException",n=>{t.fatal({error:n},"Uncaught exception"),o("uncaughtException")}),process.on("unhandledRejection",n=>{t.fatal({reason:n},"Unhandled rejection"),o("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let n=e.llm;n?.default?.provider?To(n.default.provider,n.default.apiKey,n.default.baseUrl):n?.provider&&To(n.provider,void 0,n.baseUrl);for(let i of["strong","fast"]){let a=n?.[i];a?.provider&&To(a.provider,a.apiKey,a.baseUrl)}}catch(n){let i=n instanceof Error?n:new Error(String(n));t.fatal({err:i},"Failed to start Alfred"),process.exit(1)}}var wl=E(()=>{"use strict";Be();rn();gi();_i();u(Im,"startCommand")});var _l={};oe(_l,{chatCommand:()=>Cm});import Tl from"node:http";import wr from"node:readline";function xm(c,e){return new Promise(t=>{let s=Tl.get(`http://${c}:${e}/api/health`,{timeout:2e3},r=>{let o="";r.on("data",n=>{o+=n.toString()}),r.on("end",()=>{try{let n=JSON.parse(o);t(n.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function Rm(c,e){let t=wr.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
785
+ `)}}});var Xe={};oe(Xe,{CLIAdapter:()=>ho,DiscordAdapter:()=>lo,HttpAdapter:()=>fo,MatrixAdapter:()=>uo,MessagingAdapter:()=>ie,SignalAdapter:()=>po,TelegramAdapter:()=>ao,WhatsAppAdapter:()=>mo});var Ye=E(()=>{"use strict";qe();ol();nl();il();al();cl();ll();dl()});import go from"node:fs";import yo from"node:path";import vm from"js-yaml";var _t,ul=E(()=>{"use strict";rn();an();Be();wn();Pr();te();Zn();Qn();ei();ti();si();ri();oi();ni();ii();ai();ui();mi();_t=class{static{u(this,"Alfred")}config;logger;database;pipeline;reminderScheduler;backgroundTaskRunner;proactiveScheduler;adapters=new Map;formatter=new dr;userRepo;skillRegistry;mcpManager;calendarSkill;constructor(e){this.config=e,this.logger=Es("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new it(this.config.storage.path);let e=this.database.getDb(),t=new bs(e),s=new $s(e);this.userRepo=s;let r=new at(e),o=new vs(e),n=new Ss(e),i=new ks(e),a=new As(e),l=new Is(e),d=new xs(e),m=new Rs(e);this.logger.info("Storage initialized");let p=new Hs,w=this.loadSecurityRules();p.loadRules(w);let y=new qs(p,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:w.length},"Security engine initialized");let h=yn(this.config.llm,this.logger.child({component:"llm"}));await h.initialize();let T=new ur(h,a,this.logger.child({component:"embeddings"})),$=this.config.activeLearning?.enabled!==!1,A,I;$&&(A=new gr({llm:h,memoryRepo:o,logger:this.logger.child({component:"active-learning"}),embeddingService:T,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),I=new yr(o,this.logger.child({component:"memory-retriever"}),T),this.logger.info("Active learning & memory retriever initialized"));let P=new It(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new At;L.register(new xt),L.register(new Rt),L.register(new Ct(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new Lt(n)),L.register(new Nt(i));let X=new Ls(e);if(L.register(new Jt(X)),L.register(new Dt),L.register(new Mt),L.register(new Ot(o,T)),L.register(new Pt(h,L,P,y)),this.config.email?.accounts?.length){let C=new Map;for(let U of this.config.email.accounts)try{U.provider==="microsoft"&&!U.microsoft?.clientId&&this.config.calendar?.microsoft&&(U.microsoft={...this.config.calendar.microsoft});let fe=await zs(U);C.set(U.name,fe),this.logger.info({account:U.name,provider:U.provider??"imap-smtp"},"Email account initialized")}catch(fe){this.logger.warn({err:fe,account:U.name},"Email account initialization failed, skipping")}L.register(C.size>0?new Ge(C):new Ge)}else L.register(new Ge);L.register(new Ut),L.register(new Ft);let Oe=new Qt;Oe.setReloadCallback(C=>this.reloadService(C)),L.register(Oe),L.register(new Bt),L.register(new Ht),L.register(new qt),L.register(new zt(s)),L.register(new Wt(s,l,this.adapters,(C,U)=>t.findByPlatformAndUser(C,U))),L.register(new Vt(d)),L.register(new Gt(m));let ve=new Cs(e),Pe=new mr(ve,T,this.logger.child({component:"documents"}));L.register(new Xt(ve,Pe,T));let ae;if(this.config.calendar)try{let C=await Gs(this.config.calendar);ae=new mt(C),L.register(ae),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(C){this.logger.warn({err:C},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=ae,this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(te(),re));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let U of this.mcpManager.getSkills())L.register(U);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},h)),this.logger.info({agents:this.config.codeAgents.agents.map(U=>U.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:C,createContactsProvider:U}=await Promise.resolve().then(()=>(te(),re)),fe=await U(this.config.contacts);L.register(new C(fe)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(C){this.logger.warn({err:C},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:C}=await Promise.resolve().then(()=>(te(),re));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let V;if(this.config.speech?.apiKey&&(V=new cr(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let C=new lr(this.config.speech,this.logger.child({component:"tts"}));L.register(new Yt(C)),this.logger.info("Text-to-speech skill registered")}let pe=new or(t),he=yo.resolve(yo.dirname(this.config.storage.path),"inbox");this.pipeline=new ir({llm:h,conversationManager:pe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:P,securityManager:y,memoryRepo:o,speechTranscriber:V,inboxPath:he,embeddingService:T,activeLearning:A,memoryRetriever:I,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100}),this.reminderScheduler=new ar(n,async(C,U,fe)=>{let Ue=this.adapters.get(C);Ue?await Ue.sendMessage(U,fe):this.logger.warn({platform:C,chatId:U},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:u(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:u(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:u((C,U)=>t.findByPlatformAndUser(C,U),"findConversation")}),this.backgroundTaskRunner=new pr(L,P,d,this.adapters,s,this.logger.child({component:"background-tasks"})),this.proactiveScheduler=new hr(m,L,P,h,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,pe),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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe));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(()=>(Ye(),Xe)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";this.adapters.set("api",new t(s,r)),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.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(()=>(Ye(),Xe)),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.mcpManager&&await this.mcpManager.shutdown();for(let[e,t]of this.adapters)try{await t.disconnect(),this.logger.info({platform:e},"Adapter disconnected")}catch(s){this.logger.error({platform:e,err:s},"Failed to disconnect adapter")}this.database.close(),this.logger.info("Alfred stopped")}async reloadService(e){try{tn();let t=new se().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(te(),re));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(()=>(te(),re));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(()=>(te(),re));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(()=>(te(),re)),o=await r(t.contacts);this.skillRegistry.register(new s(o)),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(()=>(te(),re));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(()=>(te(),re));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(()=>(te(),re));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing 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}}}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 o=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,o),this.logger.info({apiUserId:t.id,masterUserId:o},"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,o="",n=u(async d=>{if(d!==o){o=d;try{r?await t.editMessage(s.chatId,r,d):r=await t.sendMessage(s.chatId,d)}catch(m){this.logger.debug({err:m,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,n),a=this.formatter.format(i.text,s.platform),l=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,l)}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,l)}else await t.sendMessage(s.chatId,a.text,l)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let m=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,m.text)}if(i.attachments)for(let d of i.attachments)try{let m=d.mimeType.startsWith("image/"),p=d.mimeType==="audio/ogg"||d.mimeType==="audio/opus";m?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(m){this.logger.warn({err:m,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(o){this.logger.error({err:o},"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")})}loadSecurityRules(){let e=yo.resolve(this.config.security.rulesPath),t=[];if(!go.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!go.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=go.readdirSync(e).filter(o=>o.endsWith(".yml")||o.endsWith(".yaml"));for(let o of r)try{let n=yo.join(e,o),i=go.readFileSync(n,"utf-8"),a=vm.load(i);a?.rules&&Array.isArray(a.rules)&&(t.push(...a.rules),this.logger.info({file:o,count:a.rules.length},"Loaded security rules"))}catch(n){this.logger.error({err:n,file:o},"Failed to load security rules file")}return t}}});var ml=E(()=>{"use strict"});var gi=E(()=>{"use strict";ul();Qn();Zn();ei();ti();si();ri();oi();ii();ai();nr();ni();ui();mi();di();ml();li()});import wo from"node:fs";import pl from"node:path";import Sm from"node:os";function hl(){try{let c=wo.readFileSync(yi,"utf-8"),e=JSON.parse(c);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function fl(c){try{let e=pl.dirname(yi);wo.existsSync(e)||wo.mkdirSync(e,{recursive:!0}),wo.writeFileSync(yi,JSON.stringify(c,null,2),"utf-8")}catch{}}async function Et(c,e){let t=new AbortController,s=setTimeout(()=>t.abort(),Am);try{return await fetch(c,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function gl(c,e,t){switch(c){case"anthropic":{let s=await Et("https://api.anthropic.com/v1/models",{headers:{"x-api-key":e??"","anthropic-version":"2023-06-01"}});return s.ok?((await s.json()).data??[]).map(o=>({id:o.id,name:o.display_name})):[]}case"openai":{let s=t?`${t.replace(/\/+$/,"")}/models`:"https://api.openai.com/v1/models",r=await Et(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(n=>({id:n.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await Et(s);return r.ok?((await r.json()).models??[]).map(n=>({id:n.name.replace(/^models\//,""),name:n.displayName})):[]}case"mistral":{let s=await Et("https://api.mistral.ai/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(o=>({id:o.id,name:o.name})):[]}case"openrouter":{let s=await Et("https://openrouter.ai/api/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(o=>({id:o.id,name:o.name})):[]}case"ollama":{let s=(t??"http://localhost:11434").replace(/\/+$/,""),r=await Et(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(n=>({id:n.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await Et(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(n=>({id:n.id})):[]}default:return[]}}async function wi(c,e,t){let s=hl(),r=s.providers[c];if(r&&Date.now()-r.fetchedAt<km)return r.models;try{let o=await gl(c,e,t);if(o.length>0)return s.providers[c]={fetchedAt:Date.now(),models:o},fl(s),o}catch{}return r?r.models:[]}function To(c,e,t){gl(c,e,t).then(s=>{if(s.length>0){let r=hl();r.providers[c]={fetchedAt:Date.now(),models:s},fl(r)}}).catch(()=>{})}function Ti(c,e){let t=new Set,s=[];for(let r of c)if(!t.has(r.id)){t.add(r.id);let o=e.find(n=>n.id===r.id);s.push({id:r.id,name:r.name,desc:o?.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 km,Am,yi,_i=E(()=>{"use strict";km=24*60*60*1e3,Am=5e3,yi=pl.join(Sm.homedir(),".alfred","model-cache.json");u(hl,"readCache");u(fl,"writeCache");u(Et,"fetchWithTimeout");u(gl,"fetchModelsFromAPI");u(wi,"getModels");u(To,"refreshCacheInBackground");u(Ti,"mergeModels")});var yl={};oe(yl,{startCommand:()=>Im});async function Im(){let c=new se,e;try{e=c.loadConfig()}catch(n){console.error("Failed to load configuration:",n.message),process.exit(1)}let t=Es("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new _t(e),r=!1,o=u(async n=>{if(!r){r=!0,t.info({signal:n},"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",()=>o("SIGINT")),process.on("SIGTERM",()=>o("SIGTERM")),process.on("uncaughtException",n=>{t.fatal({error:n},"Uncaught exception"),o("uncaughtException")}),process.on("unhandledRejection",n=>{t.fatal({reason:n},"Unhandled rejection"),o("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let n=e.llm;n?.default?.provider?To(n.default.provider,n.default.apiKey,n.default.baseUrl):n?.provider&&To(n.provider,void 0,n.baseUrl);for(let i of["strong","fast"]){let a=n?.[i];a?.provider&&To(a.provider,a.apiKey,a.baseUrl)}}catch(n){let i=n instanceof Error?n:new Error(String(n));t.fatal({err:i},"Failed to start Alfred"),process.exit(1)}}var wl=E(()=>{"use strict";Be();rn();gi();_i();u(Im,"startCommand")});var _l={};oe(_l,{chatCommand:()=>Cm});import Tl from"node:http";import wr from"node:readline";function xm(c,e){return new Promise(t=>{let s=Tl.get(`http://${c}:${e}/api/health`,{timeout:2e3},r=>{let o="";r.on("data",n=>{o+=n.toString()}),r.on("end",()=>{try{let n=JSON.parse(o);t(n.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function Rm(c,e){let t=wr.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
786
786
  Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
787
787
  `),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
788
788
  Goodbye!
789
789
  `),t.close(),process.exit(0));let o=JSON.stringify({text:r,chatId:"api-chat",userId:"api-user"}),n=Tl.request({hostname:c,port:e,path:"/api/message",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(o)}},i=>{let a="";i.on("data",l=>{a+=l.toString();let d=a.split(`
790
790
 
791
791
  `);a=d.pop()??"";for(let m of d){let p=m.split(`
792
- `).find(T=>T.startsWith("data: "));if(p)try{let T=JSON.parse(p.slice(6));switch(T.type){case"status":wr.clearLine(process.stdout,0),wr.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${T.text??""}`);break;case"response":wr.clearLine(process.stdout,0),wr.cursorTo(process.stdout,0),process.stdout.write(`
793
- Alfred: ${T.text??""}
794
- `);break;case"attachment":{let y=T.fileName??T.attachmentType??"file";process.stdout.write(`[Attachment: ${y}]
792
+ `).find(w=>w.startsWith("data: "));if(p)try{let w=JSON.parse(p.slice(6));switch(w.type){case"status":wr.clearLine(process.stdout,0),wr.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${w.text??""}`);break;case"response":wr.clearLine(process.stdout,0),wr.cursorTo(process.stdout,0),process.stdout.write(`
793
+ Alfred: ${w.text??""}
794
+ `);break;case"attachment":{let y=w.fileName??w.attachmentType??"file";process.stdout.write(`[Attachment: ${y}]
795
795
  `);break}case"done":t.prompt();break;case"error":process.stdout.write(`
796
- Error: ${T.text??"Unknown error"}
796
+ Error: ${w.text??"Unknown error"}
797
797
  `),t.prompt();break}}catch{}}}),i.on("end",()=>{if(a.length>0){let l=a.split(`
798
798
  `).find(d=>d.startsWith("data: "));if(l)try{let d=JSON.parse(l.slice(6));(d.type==="done"||d.type==="error")&&t.prompt()}catch{}}}),i.on("error",l=>{console.error(`
799
799
  Connection error: ${l.message}`),t.prompt()})});n.on("error",i=>{console.error(`
800
- Failed to send message: ${i.message}`),t.prompt()}),n.write(o),n.end()}),t.on("close",()=>{process.exit(0)})}async function Cm(c){let e=new se,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 xm(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),Rm(s,r);return}if(t.logger.level="warn",c.model&&(t.llm.default.model=c.model),c.tier){let i=t.llm[c.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${c.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let n=new _t(t);try{await n.initialize(),await n.startWithCLI()}catch(i){console.error("Failed to start chat:",i.message),process.exit(1)}}var El=E(()=>{"use strict";Be();gi();u(xm,"checkHealth");u(Rm,"startClientMode");u(Cm,"chatCommand")});var vl={};oe(vl,{setupCommand:()=>Hm});import{createInterface as Lm}from"node:readline/promises";import{stdin as Nm,stdout as Dm}from"node:process";import{execFileSync as Mm}from"node:child_process";import de from"node:fs";import Om from"node:os";import we from"node:path";import Ei from"js-yaml";function D(c){return`${_o}${c}${v}`}function Fm(c){return`${M}${c}${v}`}function le(c){return`${Eo}${c}${v}`}function $l(c){return`${Pm}${c}${v}`}function R(c){return`${q}${c}${v}`}function w(c){return`${Je}${c}${v}`}function me(c){return c.length<=4?"****":"*".repeat(c.length-4)+c.slice(-4)}function jm(c){let e=process.platform==="win32",t=e?"where":"which";try{let o=Mm(t,[c],{stdio:"pipe"}).toString().trim();if(o)return o.split(/\r?\n/)[0]}catch{}let s=Om.homedir(),r=e?[we.join(s,".local","bin",`${c}.exe`),we.join(s,"AppData","Roaming","npm",`${c}.cmd`),we.join(s,"AppData","Roaming","npm",`${c}`)]:[we.join(s,".local","bin",c),"/usr/local/bin/"+c,"/opt/homebrew/bin/"+c,we.join(s,".npm-global","bin",c)];for(let o of r)try{return de.accessSync(o,de.constants.X_OK),o}catch{}return null}function Bm(c){let e={},t={},s=!1,r=!1,o=30,n=we.join(c,"config","default.yml");if(de.existsSync(n))try{let p=Ei.load(de.readFileSync(n,"utf-8"));p&&typeof p=="object"&&Object.assign(e,p)}catch{}let i=we.join(c,".env");if(de.existsSync(i))try{let p=de.readFileSync(i,"utf-8").split(`
801
- `);for(let T of p){let y=T.trim();if(!y||y.startsWith("#"))continue;let f=y.indexOf("=");f>0&&(t[y.slice(0,f)]=y.slice(f+1))}}catch{}let a=we.join(c,"config","rules","default-rules.yml");if(de.existsSync(a))try{let p=Ei.load(de.readFileSync(a,"utf-8"));if(p?.rules){s=p.rules.some(f=>f.id==="allow-owner-admin"&&f.effect==="allow"),p.rules.find(f=>f.id==="allow-write-for-dm"||f.id==="allow-write-all")?.id==="allow-write-all"&&(r=!0);let y=p.rules.find(f=>f.id==="rate-limit-write");y?.rateLimit?.maxInvocations&&(o=y.rateLimit.maxInvocations)}}catch{}let l=!!e.codeSandbox?.enabled,d=e.llm,m={};if(d){for(let p of["strong","fast","embeddings","local"])d[p]?.provider&&d[p]?.model&&(m[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:o,codeSandboxEnabled:l,multiModelTiers:m}}async function Hm(){let c=Lm({input:Nm,output:Dm}),e=process.cwd(),t=Bm(e),s=Object.keys(t.config).length>0;try{qm(),console.log(s?`${Eo}Existing configuration found \u2014 press Enter to keep current values.${v}
802
- ${Je}Only change what you need to update.${v}
803
- `:`${Eo}Welcome to the Alfred setup wizard!${v}
804
- ${Je}This will walk you through configuring your AI assistant.${v}
805
- ${Je}Press Enter to accept defaults shown in [brackets].${v}
806
- `);let r=await O(c,"What should your bot be called?",t.config.name??"Alfred"),o=t.config.llm?.provider?ze.findIndex(h=>h.name===t.config.llm?.provider):-1,n=o>=0?o+1:1;console.log(`
807
- ${R("Which LLM provider would you like to use?")}`);for(let h=0;h<ze.length;h++){let b=h===o?` ${w("(current)")}`:"";console.log(` ${le(String(h+1)+")")} ${ze[h].label}${b}`)}let i=await Tr(c,"> ",1,ze.length,n),a=ze[i-1];console.log(` ${D(">")} Selected: ${R(a.label)}`);let l="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?l=await O(c,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):l=await $e(c,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${D(">")} API key set: ${w(me(l))}`));let m=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let b=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if(b){let $={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(""),m=await O(c,$[a.name]??"API Base URL",b.replace(/\/+$/,"")),m=m.replace(/\/+$/,""),console.log(` ${D(">")} URL: ${w(m)}`)}}let T=t.config.llm?.model??a.defaultModel;console.log("");let y,f=await wi(a.name,l,m),_=Ti(f,a.models??[]);if(_.length>0){console.log(`${R("Available models:")}`);for(let $=0;$<_.length;$++){let B=_[$],N=B.desc??B.name??"",j=B.id===T?` ${D("(current)")}`:"";console.log(` ${le(`${$+1})`)} ${B.id}${N?` ${w(`\u2014 ${N}`)}`:""}${j}`)}console.log(` ${le(`${_.length+1})`)} ${w("Other (enter manually)")}`);let h=await O(c,"Choose model","1"),b=parseInt(h,10)-1;b>=0&&b<_.length?y=_[b].id:y=await O(c,"Model ID",T)}else y=await O(c,"Which model?",T);let S=Object.keys(t.multiModelTiers).length>0,A=S?"Y/n":"y/N";console.log(`
808
- ${R("Configure additional model tiers for specialized tasks?")}`),console.log(`${w("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let I=(await c.question(`${M}> ${v}${w(`[${A}] `)}`)).trim().toLowerCase(),P=I===""?S:I==="y"||I==="yes",L={};if(P){let h=[{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 b of h){let $=t.multiModelTiers[b.key],B=!!$?.model;console.log(`
809
- ${R(`${b.label} model`)} ${w(`(${b.hint})`)}`),B&&console.log(` ${w(`Current: ${$.provider}/${$.model}`)}`);let N=$?.provider??a.name,j=ze.map(Ee=>Ee.name).join(", ");console.log(` ${w(`Providers: ${j}`)}`);let ge=(await c.question(` ${M}Provider: ${v}${w(`[${N}] `)}`)).trim()||N;if(!ge&&!B){console.log(` ${w("Skipped.")}`);continue}let z=ge,ye,Ae;if(z!==a.name){let Ee=$?.apiKey??t.env[`ALFRED_LLM_${b.key.toUpperCase()}_API_KEY`]??"";if(Ee?ye=await O(c,` API key for ${z}`,Ee):(ze.find(je=>je.name===z)?.needsApiKey??!0)&&(ye=await $e(c,` API key for ${z}`)),["ollama","openwebui"].includes(z)){let je=($?.baseUrl??"")||ze.find(Dr=>Dr.name===z)?.baseUrl||"";je&&(Ae=await O(c,` ${z} URL`,je))}}let ot=ye??(z===a.name?l:void 0),_s=Ae??(z===a.name?m:void 0),Xo=ze.find(Ee=>Ee.name===z),Yo=await wi(z,ot,_s),Ve=Ti(Yo,Xo?.models??[]),Fe;if(Ve.length>0){console.log(` ${R("Available models:")}`);for(let vt=0;vt<Ve.length;vt++){let je=Ve[vt],Dr=je.desc??je.name??"",ud=je.id===$?.model?` ${D("(current)")}`:"";console.log(` ${le(`${vt+1})`)} ${je.id}${Dr?` ${w(`\u2014 ${Dr}`)}`:""}${ud}`)}console.log(` ${le(`${Ve.length+1})`)} ${w("Other (enter manually)")}`),console.log(` ${le("0)")} ${w("Skip this tier")}`);let Ee=(await c.question(` ${M}> ${v}${B?w(`[${$.model}] `):""}`)).trim();if(Ee==="0"){console.log(` ${w("Skipped.")}`);continue}let Nr=parseInt(Ee,10)-1;Nr>=0&&Nr<Ve.length?Fe=Ve[Nr].id:!Ee&&B?Fe=$.model:Fe=await O(c," Model ID",B?$.model:b.defaultModel)}else if(console.log(` ${w("Press Enter to skip.")}`),Fe=(await c.question(` ${M}Model: ${v}${B?w(`[${$.model}] `):""}`)).trim()||(B?$.model:""),!Fe){console.log(` ${w("Skipped.")}`);continue}L[b.key]={provider:z,model:Fe,...ye?{apiKey:ye}:{},...Ae?{baseUrl:Ae}:{}},console.log(` ${D(">")} ${b.label}: ${R(z)}/${R(Fe)}`)}Object.keys(L).length===0&&console.log(`
810
- ${w("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${w("Using single model for all tasks.")}`);let X=["brave","tavily","duckduckgo","searxng"],Oe=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",ve=X.indexOf(Oe),Pe=ve>=0?ve+1:0;console.log(`
811
- ${R("Web Search provider (for searching the internet):")}`);let ae=["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"],V=u(h=>ve===h?` ${w("(current)")}`:"","mark");console.log(` ${le("0)")} None (disable web search)${ve===-1&&Oe===""?` ${w("(current)")}`:""}`);for(let h=0;h<ae.length;h++)console.log(` ${le(String(h+1)+")")} ${ae[h]}${V(h)}`);let pe=await Tr(c,"> ",0,X.length,Pe),he,C="",U="";if(pe>=1&&pe<=X.length&&(he=X[pe-1]),he==="brave"){let h=t.env.ALFRED_SEARCH_API_KEY??"";h?C=await O(c," Brave Search API key",h):(console.log(` ${w("Get your free API key at: https://brave.com/search/api/")}`),C=await $e(c," Brave Search API key")),console.log(` ${D(">")} Brave Search: ${w(me(C))}`)}else if(he==="tavily"){let h=t.env.ALFRED_SEARCH_API_KEY??"";h?C=await O(c," Tavily API key",h):(console.log(` ${w("Get your free API key at: https://tavily.com/")}`),C=await $e(c," Tavily API key")),console.log(` ${D(">")} Tavily: ${w(me(C))}`)}else if(he==="duckduckgo")console.log(` ${D(">")} DuckDuckGo: ${w("no API key needed")}`);else if(he==="searxng"){let h=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";U=await O(c," SearXNG URL",h),U=U.replace(/\/+$/,""),console.log(` ${D(">")} SearXNG: ${w(U)}`)}else console.log(` ${w("Web search disabled \u2014 you can configure it later.")}`);let fe=[];for(let h=0;h<rs.length;h++){let b=rs[h];t.config[b.configKey]?.enabled&&fe.push(h+1)}let Ue=fe.length>0?fe.join(","):"";console.log(`
812
- ${R("Which messaging platforms do you want to enable?")}`),console.log(`${w("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let h=0;h<rs.length;h++){let b=fe.includes(h+1)?` ${w("(enabled)")}`:"";console.log(` ${le(String(h+1)+")")} ${rs[h].label}${b}`)}console.log(` ${le("0)")} None (configure later)`);let os=(await c.question(`${M}> ${v}${Ue?w(`[${Ue}] `):""}`)).trim(),Q=[],ns=os||Ue;if(ns&&ns!=="0"){let h=ns.split(",").map(b=>parseInt(b.trim(),10));for(let b of h)if(b>=1&&b<=rs.length){let $=rs[b-1];Q.includes($)||Q.push($)}}Q.length>0?console.log(` ${D(">")} Enabling: ${Q.map(h=>R(h.label)).join(", ")}`):console.log(` ${w("No platforms selected \u2014 you can configure them later.")}`);let H={},Y={};for(let h of Q){if(h.credentials.length===0){h.name==="whatsapp"&&console.log(`
800
+ Failed to send message: ${i.message}`),t.prompt()}),n.write(o),n.end()}),t.on("close",()=>{process.exit(0)})}async function Cm(c){let e=new se,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 xm(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),Rm(s,r);return}if(t.logger.level="warn",c.model&&(t.llm.default.model=c.model),c.tier){let i=t.llm[c.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${c.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let n=new _t(t);try{await n.initialize(),await n.startWithCLI()}catch(i){console.error("Failed to start chat:",i.message),process.exit(1)}}var El=E(()=>{"use strict";Be();gi();u(xm,"checkHealth");u(Rm,"startClientMode");u(Cm,"chatCommand")});var vl={};oe(vl,{setupCommand:()=>Hm});import{createInterface as Lm}from"node:readline/promises";import{stdin as Nm,stdout as Dm}from"node:process";import{execFileSync as Mm}from"node:child_process";import de from"node:fs";import Om from"node:os";import we from"node:path";import Ei from"js-yaml";function D(c){return`${_o}${c}${S}`}function Fm(c){return`${M}${c}${S}`}function le(c){return`${Eo}${c}${S}`}function $l(c){return`${Pm}${c}${S}`}function R(c){return`${q}${c}${S}`}function _(c){return`${Je}${c}${S}`}function me(c){return c.length<=4?"****":"*".repeat(c.length-4)+c.slice(-4)}function jm(c){let e=process.platform==="win32",t=e?"where":"which";try{let o=Mm(t,[c],{stdio:"pipe"}).toString().trim();if(o)return o.split(/\r?\n/)[0]}catch{}let s=Om.homedir(),r=e?[we.join(s,".local","bin",`${c}.exe`),we.join(s,"AppData","Roaming","npm",`${c}.cmd`),we.join(s,"AppData","Roaming","npm",`${c}`)]:[we.join(s,".local","bin",c),"/usr/local/bin/"+c,"/opt/homebrew/bin/"+c,we.join(s,".npm-global","bin",c)];for(let o of r)try{return de.accessSync(o,de.constants.X_OK),o}catch{}return null}function Bm(c){let e={},t={},s=!1,r=!1,o=30,n=we.join(c,"config","default.yml");if(de.existsSync(n))try{let p=Ei.load(de.readFileSync(n,"utf-8"));p&&typeof p=="object"&&Object.assign(e,p)}catch{}let i=we.join(c,".env");if(de.existsSync(i))try{let p=de.readFileSync(i,"utf-8").split(`
801
+ `);for(let w of p){let y=w.trim();if(!y||y.startsWith("#"))continue;let h=y.indexOf("=");h>0&&(t[y.slice(0,h)]=y.slice(h+1))}}catch{}let a=we.join(c,"config","rules","default-rules.yml");if(de.existsSync(a))try{let p=Ei.load(de.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 y=p.rules.find(h=>h.id==="rate-limit-write");y?.rateLimit?.maxInvocations&&(o=y.rateLimit.maxInvocations)}}catch{}let l=!!e.codeSandbox?.enabled,d=e.llm,m={};if(d){for(let p of["strong","fast","embeddings","local"])d[p]?.provider&&d[p]?.model&&(m[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:o,codeSandboxEnabled:l,multiModelTiers:m}}async function Hm(){let c=Lm({input:Nm,output:Dm}),e=process.cwd(),t=Bm(e),s=Object.keys(t.config).length>0;try{qm(),console.log(s?`${Eo}Existing configuration found \u2014 press Enter to keep current values.${S}
802
+ ${Je}Only change what you need to update.${S}
803
+ `:`${Eo}Welcome to the Alfred setup wizard!${S}
804
+ ${Je}This will walk you through configuring your AI assistant.${S}
805
+ ${Je}Press Enter to accept defaults shown in [brackets].${S}
806
+ `);let r=await O(c,"What should your bot be called?",t.config.name??"Alfred"),o=t.config.llm?.provider?ze.findIndex(f=>f.name===t.config.llm?.provider):-1,n=o>=0?o+1:1;console.log(`
807
+ ${R("Which LLM provider would you like to use?")}`);for(let f=0;f<ze.length;f++){let b=f===o?` ${_("(current)")}`:"";console.log(` ${le(String(f+1)+")")} ${ze[f].label}${b}`)}let i=await Tr(c,"> ",1,ze.length,n),a=ze[i-1];console.log(` ${D(">")} Selected: ${R(a.label)}`);let l="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?l=await O(c,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):l=await $e(c,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${D(">")} API key set: ${_(me(l))}`));let m=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let b=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if(b){let v={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(""),m=await O(c,v[a.name]??"API Base URL",b.replace(/\/+$/,"")),m=m.replace(/\/+$/,""),console.log(` ${D(">")} URL: ${_(m)}`)}}let w=t.config.llm?.model??a.defaultModel;console.log("");let y,h=await wi(a.name,l,m),T=Ti(h,a.models??[]);if(T.length>0){console.log(`${R("Available models:")}`);for(let v=0;v<T.length;v++){let B=T[v],N=B.desc??B.name??"",j=B.id===w?` ${D("(current)")}`:"";console.log(` ${le(`${v+1})`)} ${B.id}${N?` ${_(`\u2014 ${N}`)}`:""}${j}`)}console.log(` ${le(`${T.length+1})`)} ${_("Other (enter manually)")}`);let f=await O(c,"Choose model","1"),b=parseInt(f,10)-1;b>=0&&b<T.length?y=T[b].id:y=await O(c,"Model ID",w)}else y=await O(c,"Which model?",w);let $=Object.keys(t.multiModelTiers).length>0,A=$?"Y/n":"y/N";console.log(`
808
+ ${R("Configure additional model tiers for specialized tasks?")}`),console.log(`${_("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let I=(await c.question(`${M}> ${S}${_(`[${A}] `)}`)).trim().toLowerCase(),P=I===""?$:I==="y"||I==="yes",L={};if(P){let f=[{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 b of f){let v=t.multiModelTiers[b.key],B=!!v?.model;console.log(`
809
+ ${R(`${b.label} model`)} ${_(`(${b.hint})`)}`),B&&console.log(` ${_(`Current: ${v.provider}/${v.model}`)}`);let N=v?.provider??a.name,j=ze.map(Ee=>Ee.name).join(", ");console.log(` ${_(`Providers: ${j}`)}`);let ge=(await c.question(` ${M}Provider: ${S}${_(`[${N}] `)}`)).trim()||N;if(!ge&&!B){console.log(` ${_("Skipped.")}`);continue}let z=ge,ye,Ae;if(z!==a.name){let Ee=v?.apiKey??t.env[`ALFRED_LLM_${b.key.toUpperCase()}_API_KEY`]??"";if(Ee?ye=await O(c,` API key for ${z}`,Ee):(ze.find(je=>je.name===z)?.needsApiKey??!0)&&(ye=await $e(c,` API key for ${z}`)),["ollama","openwebui"].includes(z)){let je=(v?.baseUrl??"")||ze.find(Dr=>Dr.name===z)?.baseUrl||"";je&&(Ae=await O(c,` ${z} URL`,je))}}let ot=ye??(z===a.name?l:void 0),_s=Ae??(z===a.name?m:void 0),Xo=ze.find(Ee=>Ee.name===z),Yo=await wi(z,ot,_s),Ve=Ti(Yo,Xo?.models??[]),Fe;if(Ve.length>0){console.log(` ${R("Available models:")}`);for(let vt=0;vt<Ve.length;vt++){let je=Ve[vt],Dr=je.desc??je.name??"",ud=je.id===v?.model?` ${D("(current)")}`:"";console.log(` ${le(`${vt+1})`)} ${je.id}${Dr?` ${_(`\u2014 ${Dr}`)}`:""}${ud}`)}console.log(` ${le(`${Ve.length+1})`)} ${_("Other (enter manually)")}`),console.log(` ${le("0)")} ${_("Skip this tier")}`);let Ee=(await c.question(` ${M}> ${S}${B?_(`[${v.model}] `):""}`)).trim();if(Ee==="0"){console.log(` ${_("Skipped.")}`);continue}let Nr=parseInt(Ee,10)-1;Nr>=0&&Nr<Ve.length?Fe=Ve[Nr].id:!Ee&&B?Fe=v.model:Fe=await O(c," Model ID",B?v.model:b.defaultModel)}else if(console.log(` ${_("Press Enter to skip.")}`),Fe=(await c.question(` ${M}Model: ${S}${B?_(`[${v.model}] `):""}`)).trim()||(B?v.model:""),!Fe){console.log(` ${_("Skipped.")}`);continue}L[b.key]={provider:z,model:Fe,...ye?{apiKey:ye}:{},...Ae?{baseUrl:Ae}:{}},console.log(` ${D(">")} ${b.label}: ${R(z)}/${R(Fe)}`)}Object.keys(L).length===0&&console.log(`
810
+ ${_("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${_("Using single model for all tasks.")}`);let X=["brave","tavily","duckduckgo","searxng"],Oe=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",ve=X.indexOf(Oe),Pe=ve>=0?ve+1:0;console.log(`
811
+ ${R("Web Search provider (for searching the internet):")}`);let ae=["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"],V=u(f=>ve===f?` ${_("(current)")}`:"","mark");console.log(` ${le("0)")} None (disable web search)${ve===-1&&Oe===""?` ${_("(current)")}`:""}`);for(let f=0;f<ae.length;f++)console.log(` ${le(String(f+1)+")")} ${ae[f]}${V(f)}`);let pe=await Tr(c,"> ",0,X.length,Pe),he,C="",U="";if(pe>=1&&pe<=X.length&&(he=X[pe-1]),he==="brave"){let f=t.env.ALFRED_SEARCH_API_KEY??"";f?C=await O(c," Brave Search API key",f):(console.log(` ${_("Get your free API key at: https://brave.com/search/api/")}`),C=await $e(c," Brave Search API key")),console.log(` ${D(">")} Brave Search: ${_(me(C))}`)}else if(he==="tavily"){let f=t.env.ALFRED_SEARCH_API_KEY??"";f?C=await O(c," Tavily API key",f):(console.log(` ${_("Get your free API key at: https://tavily.com/")}`),C=await $e(c," Tavily API key")),console.log(` ${D(">")} Tavily: ${_(me(C))}`)}else if(he==="duckduckgo")console.log(` ${D(">")} DuckDuckGo: ${_("no API key needed")}`);else if(he==="searxng"){let f=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";U=await O(c," SearXNG URL",f),U=U.replace(/\/+$/,""),console.log(` ${D(">")} SearXNG: ${_(U)}`)}else console.log(` ${_("Web search disabled \u2014 you can configure it later.")}`);let fe=[];for(let f=0;f<rs.length;f++){let b=rs[f];t.config[b.configKey]?.enabled&&fe.push(f+1)}let Ue=fe.length>0?fe.join(","):"";console.log(`
812
+ ${R("Which messaging platforms do you want to enable?")}`),console.log(`${_("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let f=0;f<rs.length;f++){let b=fe.includes(f+1)?` ${_("(enabled)")}`:"";console.log(` ${le(String(f+1)+")")} ${rs[f].label}${b}`)}console.log(` ${le("0)")} None (configure later)`);let os=(await c.question(`${M}> ${S}${Ue?_(`[${Ue}] `):""}`)).trim(),Q=[],ns=os||Ue;if(ns&&ns!=="0"){let f=ns.split(",").map(b=>parseInt(b.trim(),10));for(let b of f)if(b>=1&&b<=rs.length){let v=rs[b-1];Q.includes(v)||Q.push(v)}}Q.length>0?console.log(` ${D(">")} Enabling: ${Q.map(f=>R(f.label)).join(", ")}`):console.log(` ${_("No platforms selected \u2014 you can configure them later.")}`);let H={},Y={};for(let f of Q){if(f.credentials.length===0){f.name==="whatsapp"&&console.log(`
813
813
  ${Fm("i")} WhatsApp: a QR code will be displayed on first start.`);continue}console.log(`
814
- ${R(h.label+" configuration:")}`);let b={};for(let $ of h.credentials){let B=t.env[$.envKey]??"",N;B?N=await O(c,` ${$.prompt}`,B):$.defaultValue?N=await O(c,` ${$.prompt}`,$.defaultValue):$.required?N=await $e(c,` ${$.prompt}`):(N=(await c.question(` ${$.prompt}: ${M}`)).trim(),process.stdout.write(v)),b[$.configField]=N,Y[$.envKey]=N,$.configField==="token"||$.configField==="accessToken"?console.log(` ${D(">")} Set: ${w(me(N))}`):console.log(` ${D(">")} Set: ${w(N)}`)}H[h.configKey]=b}let ee=t.config.email?.accounts??[],J=ee[0],bt=J?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",Te=J?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",$o=ee.length>0||!!bt||Te==="microsoft",Bl=$o?"Y/n":"y/N";console.log(`
815
- ${R("Email access (read & send emails)?")}`),console.log(`${w("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let vo=(await c.question(`${M}> ${v}${w(`[${Bl}] `)}`)).trim().toLowerCase(),Er=vo===""?$o:vo==="y"||vo==="yes",Ne=[],Hl={"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"}},Si=u(async(h,b)=>{let $={name:h,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},B=b?.provider??"",N=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],j=B==="microsoft"?1:0;console.log("");for(let z=0;z<N.length;z++){let ye=z===j?` ${w("(current)")}`:"";console.log(` ${le(`${z+1})`)} ${N[z]}${ye}`)}let G=(await c.question(`${M}> ${v}${w(`[${j+1}] `)}`)).trim(),ge=G===""?j:parseInt(G,10)-1;if($.provider=ge===1?"microsoft":"imap-smtp",$.provider==="microsoft"){let z=t.config.calendar?.microsoft,ye=b?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Ae=b?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",ot=b?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(z&&!ye)console.log(` ${D(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${w("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${w("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${w("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),$.msClientId=await O(c," Client ID",ye),$.msClientId||($.msClientId=await $e(c," Client ID"));let _s=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";$.msClientSecret=await O(c," Client Secret",_s),$.msClientSecret||($.msClientSecret=await $e(c," Client Secret")),$.msTenantId=await O(c," Tenant ID",Ae),$.msTenantId||($.msTenantId=await $e(c," Tenant ID")),console.log(` ${w("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),$.msRefreshToken=await O(c," Refresh Token",ot),$.msRefreshToken||($.msRefreshToken=await $e(c," Refresh Token"))}console.log(` ${D(">")} Email [${h}]: Microsoft 365 (Graph API)`)}else{let z=b?.auth?.user??"";console.log(""),$.user=await O(c," Email address",z||""),$.user||($.user=await $e(c," Email address"));let ye=b?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";ye?$.pass=await O(c," Password / App password",ye):(console.log(` ${w("For Gmail: use an App Password (not your regular password)")}`),console.log(` ${w(" \u2192 Google Account \u2192 Security \u2192 2-Step \u2192 App passwords")}`),$.pass=await $e(c," Password / App password"));let Ae=$.user.split("@")[1]?.toLowerCase()??"",ot=Hl[Ae],_s=b?.imap?.host??ot?.imap??`imap.${Ae}`,Xo=b?.smtp?.host??ot?.smtp??`smtp.${Ae}`,Yo=b?.imap?.port??993,Ve=b?.smtp?.port??587;ot&&console.log(` ${D(">")} Detected ${Ae} \u2014 using preset server settings`),$.imapHost=await O(c," IMAP server",_s);let Fe=await O(c," IMAP port",String(Yo));$.imapPort=parseInt(Fe,10)||993,$.smtpHost=await O(c," SMTP server",Xo);let Ee=await O(c," SMTP port",String(Ve));$.smtpPort=parseInt(Ee,10)||587,console.log(` ${D(">")} Email [${h}]: ${w($.user)} via ${w($.imapHost)}`)}return $},"configureEmailAccount");if(Er){let h=J??(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);Ne.push(await Si("default",h));let b=!0;for(;b;){let $=(await c.question(`
816
- ${R("Add another email account?")} ${w("[y/N]")} `)).trim().toLowerCase();if($==="y"||$==="yes"){let N=(await c.question(` ${R("Account name:")} `)).trim()||`account${Ne.length+1}`,j=ee.find(G=>G.name===N);Ne.push(await Si(N,j))}else b=!1}}else console.log(` ${w("Email disabled \u2014 you can configure it later.")}`);let br=["openai","groq"],ql=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",$r=br.indexOf(ql),zl=$r>=0?$r+1:0;console.log(`
817
- ${R("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${w("Transcribes voice messages from Telegram, Discord, etc.")}`);let ki=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${le("0)")} None (disable voice transcription)${$r===-1?` ${w("(current)")}`:""}`);for(let h=0;h<ki.length;h++){let b=$r===h?` ${w("(current)")}`:"";console.log(` ${le(String(h+1)+")")} ${ki[h]}${b}`)}let So=await Tr(c,"> ",0,br.length,zl),De,We="",is="";if(So>=1&&So<=br.length&&(De=br[So-1]),De==="openai"){let h=t.env.ALFRED_SPEECH_API_KEY??"";h?We=await O(c," OpenAI API key (for Whisper)",h):(console.log(` ${w("Uses your OpenAI API key for Whisper transcription.")}`),We=await $e(c," OpenAI API key")),console.log(` ${D(">")} OpenAI Whisper: ${w(me(We))}`)}else if(De==="groq"){let h=t.env.ALFRED_SPEECH_API_KEY??"";h?We=await O(c," Groq API key",h):(console.log(` ${w("Get your free API key at: https://console.groq.com/")}`),We=await $e(c," Groq API key"));let b=t.env.ALFRED_SPEECH_BASE_URL??"";b&&(is=await O(c," Groq API URL",b)),console.log(` ${D(">")} Groq Whisper: ${w(me(We))}`)}else console.log(` ${w("Voice transcription disabled \u2014 you can configure it later.")}`);let as=!1,cs="alloy";if(De){let h=t.config.speech?.ttsEnabled??!1,b=h?"Y/n":"y/N";console.log(`
818
- ${R("Voice responses (Text-to-Speech)?")}`),console.log(`${w("Alfred can reply as a voice message when the user asks for it.")}`);let $=(await c.question(`${M}> ${v}${w(`[${b}] `)}`)).trim().toLowerCase();if(as=$===""?h:$==="y"||$==="yes",as){let B=["alloy","echo","fable","onyx","nova","shimmer"],N=t.config.speech?.ttsVoice??"alloy",j=B.indexOf(N),G=j>=0?j+1:1;console.log(`
819
- ${R("Which voice?")}`);for(let z=0;z<B.length;z++){let ye=j===z?` ${w("(current)")}`:"";console.log(` ${le(String(z+1)+")")} ${B[z]}${ye}`)}let ge=await Tr(c," > ",1,B.length,G);cs=B[ge-1],console.log(` ${D(">")} TTS voice: ${R(cs)}`)}else console.log(` ${w("Voice responses disabled.")}`)}let Wl=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
820
- ${R("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${w("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let ko=(await c.question(`${M}> ${v}${w(`[${Wl}] `)}`)).trim().toLowerCase(),Ao=ko===""?t.codeSandboxEnabled:ko==="y"||ko==="yes";console.log(Ao?` ${D(">")} Code Sandbox ${R("enabled")} (JavaScript + Python)`:` ${w("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
821
- ${R("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${w("Scanning for known coding agents on this system...")}`);let Io=[];for(let h of bl){let b=jm(h.whichCmd);b?(Io.push({...h,resolvedPath:b}),console.log(` ${D("\u2713")} ${R(h.label)} ${w(`(${b})`)}`)):console.log(` ${w("\xB7")} ${w(h.label)} ${w("\u2014 not found")}`)}let xo=(t.config.codeAgents?.agents??[]).filter(h=>!bl.some(b=>b.name===h.name));for(let h of xo)console.log(` ${D("\u2713")} ${R(h.name)} ${w(`(${h.command}) \u2014 from existing config`)}`);let Ze=[];if(Io.length===0&&xo.length===0)console.log(`
822
- ${w("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let h=[...Io.map(N=>({name:N.name,command:N.resolvedPath??N.command,argsTemplate:N.argsTemplate,promptVia:N.promptVia,label:N.label,detected:!0})),...xo.map(N=>({name:N.name,command:N.command,argsTemplate:N.argsTemplate,promptVia:N.promptVia??"arg",label:N.name,detected:!1}))];console.log(`
823
- ${R("Which agents should Alfred use?")} ${w("(comma-separated, e.g. 1,2)")}`);let b=new Set((t.config.codeAgents?.agents??[]).map(N=>N.name));for(let N=0;N<h.length;N++){let j=h[N],G=b.has(j.name)?` ${w("(current)")}`:"";console.log(` ${M}${N+1}${v}) ${j.label}${G}`)}console.log(` ${M}0${v}) None`);let $=h.map((N,j)=>b.size>0?b.has(N.name)?String(j+1):null:N.detected?String(j+1):null).filter(Boolean).join(",")||"0",B=(await c.question(` ${M}> ${v}${w(`[${$}] `)}`)).trim()||$;B!=="0"&&(Ze=B.split(",").map(j=>parseInt(j.trim(),10)).filter(j=>!isNaN(j)&&j>=1&&j<=h.length).map(j=>{let G=h[j-1];return{name:G.name,command:G.command,argsTemplate:G.argsTemplate,promptVia:G.promptVia}})),Ze.length>0?console.log(` ${D(">")} ${R(String(Ze.length))} agent(s) selected: ${Ze.map(N=>N.name).join(", ")}`):console.log(` ${w("No agents selected.")}`)}let Ro=t.config.codeAgents?.forge,Co=Ro?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
824
- ${R("Forge Integration (auto-create PRs/MRs after code agent orchestration)?")}`),console.log(`${w("Connects to GitHub or GitLab to push branches and create pull/merge requests.")}`),console.log(`${w("Owner/repo are detected automatically from the git remote at runtime.")}`);let Ai=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let h of Ai){let b=h.name===Co?` ${w("(current)")}`:"";console.log(` ${M}${h.num}${v}) ${h.label}${b}`)}let Ii=Co==="github"?"2":Co==="gitlab"?"3":"1",Vl=(await c.question(`${M}> ${v}${w(`[${Ii}] `)}`)).trim()||Ii,Qe=Ai.find(h=>h.num===Vl)?.name??"",ls="",ds="";if(Qe==="github"){console.log(` ${D(">")} Forge: ${R("GitHub")}`);let h=t.env.ALFRED_GITHUB_TOKEN??Ro?.github?.token??"";h&&console.log(` ${w(`Current token: ${me(h)}`)}`),console.log(` ${w("Create a token at https://github.com/settings/tokens (scope: repo)")}`),ls=(await c.question(` ${q}GitHub Token${v}: ${M}`)).trim(),process.stdout.write(v),!ls&&h&&(ls=h)}else if(Qe==="gitlab"){console.log(` ${D(">")} Forge: ${R("GitLab")}`);let h=t.env.ALFRED_GITLAB_TOKEN??Ro?.gitlab?.token??"";h&&console.log(` ${w(`Current token: ${me(h)}`)}`),console.log(` ${w("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),ds=(await c.question(` ${q}GitLab Token${v}: ${M}`)).trim(),process.stdout.write(v),!ds&&h&&(ds=h)}else console.log(` ${w("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);console.log(`
825
- ${R("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${w("Control VMs, containers, network devices, and smart home through Alfred.")}`);let us=t.config.proxmox,Lo=t.env.ALFRED_PROXMOX_BASE_URL??us?.baseUrl??"",Gl=Lo?"Y/n":"y/N",xi=(await c.question(` ${q}Enable Proxmox VE?${v} ${w(`[${Gl}]`)}: ${M}`)).trim().toLowerCase()||(Lo?"y":"n");process.stdout.write(v);let vr=xi==="y"||xi==="yes",ms="",No="",ps="",Do=!0;if(vr){ms=await O(c," Proxmox URL (e.g. https://pve.local:8006)",Lo||"https://pve.local:8006");let h=t.env.ALFRED_PROXMOX_TOKEN_ID??us?.tokenId??"";h&&console.log(` ${w(`Current token ID: ${h}`)}`),console.log(` ${w("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),No=await O(c," API Token ID (user@realm!name)",h);let b=t.env.ALFRED_PROXMOX_TOKEN_SECRET??us?.tokenSecret??"";b&&console.log(` ${w(`Current secret: ${me(b)}`)}`),ps=(await c.question(` ${q}API Token Secret${v}: ${M}`)).trim(),process.stdout.write(v),!ps&&b&&(ps=b);let $=us?.verifyTls===!1?"y/N":"Y/n",B=(await c.question(` ${q}Verify TLS?${v} ${w(`(self-signed? \u2192 no) [${$}]`)}: ${M}`)).trim().toLowerCase()||(us?.verifyTls===!1?"n":"y");process.stdout.write(v),Do=B==="y"||B==="yes",console.log(` ${D(">")} Proxmox: ${R(ms)} ${w(`(TLS verify: ${Do?"yes":"no"})`)}`)}else console.log(` ${w("Proxmox disabled.")}`);let et=t.config.unifi,Mo=t.env.ALFRED_UNIFI_BASE_URL??et?.baseUrl??"",Kl=Mo?"Y/n":"y/N",Ri=(await c.question(`
826
- ${q}Enable UniFi Network?${v} ${w(`[${Kl}]`)}: ${M}`)).trim().toLowerCase()||(Mo?"y":"n");process.stdout.write(v);let hs=Ri==="y"||Ri==="yes",$t="",tt="",Oo="",fs="",Po=!0;if(hs){$t=await O(c," UniFi URL (e.g. https://unifi.local)",Mo||"https://unifi.local"),console.log(` ${w("Auth: API Key (recommended) or Username/Password")}`);let h=t.env.ALFRED_UNIFI_API_KEY??et?.apiKey??"",b=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],$=h?"1":et?.username?"2":"1";for(let G of b)console.log(` ${M}${G.num}${v}) ${G.label}`);if(((await c.question(` ${M}> ${v}${w(`[${$}] `)}`)).trim()||$)==="1")h&&console.log(` ${w(`Current key: ${me(h)}`)}`),console.log(` ${w("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),tt=(await c.question(` ${q}API Key${v}: ${M}`)).trim(),process.stdout.write(v),!tt&&h&&(tt=h);else{let G=t.env.ALFRED_UNIFI_USERNAME??et?.username??"";Oo=await O(c," Username",G||"alfred");let ge=t.env.ALFRED_UNIFI_PASSWORD??et?.password??"";ge&&console.log(` ${w(`Current password: ${me(ge)}`)}`),fs=(await c.question(` ${q}Password${v}: ${M}`)).trim(),process.stdout.write(v),!fs&&ge&&(fs=ge)}let N=et?.verifyTls===!1?"y/N":"Y/n",j=(await c.question(` ${q}Verify TLS?${v} ${w(`(self-signed? \u2192 no) [${N}]`)}: ${M}`)).trim().toLowerCase()||(et?.verifyTls===!1?"n":"y");process.stdout.write(v),Po=j==="y"||j==="yes",console.log(` ${D(">")} UniFi: ${R($t)} ${w(`(TLS verify: ${Po?"yes":"no"})`)}`)}else console.log(` ${w("UniFi disabled.")}`);let Sr=t.config.homeassistant,Uo=t.env.ALFRED_HOMEASSISTANT_URL??Sr?.baseUrl??"",Xl=Uo?"Y/n":"y/N",Ci=(await c.question(`
827
- ${q}Enable Home Assistant?${v} ${w(`[${Xl}]`)}: ${M}`)).trim().toLowerCase()||(Uo?"y":"n");process.stdout.write(v);let kr=Ci==="y"||Ci==="yes",gs="",ys="",Fo=!0;if(kr){gs=await O(c," Home Assistant URL (e.g. http://homeassistant.local:8123)",Uo||"http://homeassistant.local:8123");let h=t.env.ALFRED_HOMEASSISTANT_TOKEN??Sr?.accessToken??"";h&&console.log(` ${w(`Current token: ${me(h)}`)}`),console.log(` ${w("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),ys=(await c.question(` ${q}Long-Lived Access Token${v}: ${M}`)).trim(),process.stdout.write(v),!ys&&h&&(ys=h);let b=Sr?.verifyTls===!1?"y/N":"Y/n",$=(await c.question(` ${q}Verify TLS?${v} ${w(`(self-signed? \u2192 no) [${b}]`)}: ${M}`)).trim().toLowerCase()||(Sr?.verifyTls===!1?"n":"y");process.stdout.write(v),Fo=$==="y"||$==="yes",console.log(` ${D(">")} Home Assistant: ${R(gs)} ${w(`(TLS verify: ${Fo?"yes":"no"})`)}`)}else console.log(` ${w("Home Assistant disabled.")}`);let Se=t.config.contacts,jo=t.env.ALFRED_CONTACTS_PROVIDER??Se?.provider??"",Yl=jo?"Y/n":"y/N",Li=(await c.question(`
828
- ${q}Enable Contacts management?${v} ${w(`[${Yl}]`)}: ${M}`)).trim().toLowerCase()||(jo?"y":"n");process.stdout.write(v);let Ar=Li==="y"||Li==="yes",ke="",ce={};if(Ar){let h=["carddav","google","microsoft"],b=h.indexOf(jo),$=b>=0?b+1:1;console.log(` ${le("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${le("2)")} Google Contacts`),console.log(` ${le("3)")} Microsoft 365`);let B=await Tr(c," > ",1,3,$);if(ke=h[B-1],ce.ALFRED_CONTACTS_PROVIDER=ke,ke==="carddav"){let N=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Se?.carddav?.serverUrl??"";ce.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await O(c," CardDAV Server URL",N||"https://cloud.example.com/remote.php/dav");let j=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Se?.carddav?.username??"";ce.ALFRED_CARDDAV_CONTACTS_USERNAME=await O(c," Username",j);let G=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Se?.carddav?.password??"";G&&console.log(` ${w(`Current password: ${me(G)}`)}`);let ge=(await c.question(` ${q}Password${v}: ${M}`)).trim();process.stdout.write(v),ce.ALFRED_CARDDAV_CONTACTS_PASSWORD=ge||G}else if(ke==="google"){let N=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Se?.google?.clientId??"";N&&console.log(` ${w(`Current client ID: ${me(N)}`)}`),ce.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await c.question(` ${q}Google Client ID${v}: ${M}`)).trim()||N,process.stdout.write(v);let j=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Se?.google?.clientSecret??"";ce.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await c.question(` ${q}Google Client Secret${v}: ${M}`)).trim()||j,process.stdout.write(v);let G=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Se?.google?.refreshToken??"";ce.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await c.question(` ${q}Refresh Token${v}: ${M}`)).trim()||G,process.stdout.write(v)}else if(ke==="microsoft"){let N=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Se?.microsoft?.clientId??"";N&&console.log(` ${w(`Current client ID: ${me(N)}`)}`),ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await c.question(` ${q}Microsoft Client ID${v}: ${M}`)).trim()||N,process.stdout.write(v);let j=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Se?.microsoft?.clientSecret??"";ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await c.question(` ${q}Microsoft Client Secret${v}: ${M}`)).trim()||j,process.stdout.write(v);let G=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Se?.microsoft?.tenantId??"";ce.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await O(c," Tenant ID",G||"common");let ge=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Se?.microsoft?.refreshToken??"";console.log(` ${w("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),ce.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await c.question(` ${q}Refresh Token${v}: ${M}`)).trim()||ge,process.stdout.write(v)}console.log(` ${D(">")} Contacts: ${R(ke)}`)}else console.log(` ${w("Contacts disabled.")}`);let Ni=t.config.docker,Bo=t.env.ALFRED_DOCKER_SOCKET_PATH??Ni?.socketPath??"",Ho=t.env.ALFRED_DOCKER_HOST??Ni?.host??"",Jl=Bo||Ho?"Y/n":"y/N",Di=(await c.question(`
829
- ${q}Enable Docker management?${v} ${w(`[${Jl}]`)}: ${M}`)).trim().toLowerCase()||(Bo||Ho?"y":"n");process.stdout.write(v);let Ir=Di==="y"||Di==="yes",st="",rt="";if(Ir){let h=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${w("Use socket path for local Docker, or host URL for remote.")}`),st=await O(c," Docker socket path",Bo||h);let b=(await c.question(` ${q}Docker host URL (optional, for remote)${v}: ${M}`)).trim();process.stdout.write(v),rt=b||Ho,console.log(` ${D(">")} Docker: ${R(rt||st)}`)}else console.log(` ${w("Docker disabled.")}`);let Zl=t.config.bmw,qo=t.env.ALFRED_BMW_CLIENT_ID??Zl?.clientId??"",Ql=qo?"Y/n":"y/N",Mi=(await c.question(`
830
- ${q}Enable BMW CarData (vehicle status, charging)?${v} ${w(`[${Ql}]`)}: ${M}`)).trim().toLowerCase()||(qo?"y":"n");process.stdout.write(v);let xr=Mi==="y"||Mi==="yes",zo="";xr?(console.log(` ${w("Setup:")}`),console.log(` ${w(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${w(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${w(" 3. Client-ID generieren")}`),console.log(` ${w(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),zo=await O(c," BMW CarData Client ID",qo),console.log(` ${D(">")} BMW CarData: ${R("enabled")}`)):console.log(` ${w("BMW CarData disabled.")}`);let ed=t.config.routing,Wo=t.env.ALFRED_ROUTING_API_KEY??ed?.apiKey??"",td=Wo?"Y/n":"y/N",Oi=(await c.question(`
831
- ${q}Enable route planning with live traffic (Google Routes)?${v} ${w(`[${td}]`)}: ${M}`)).trim().toLowerCase()||(Wo?"y":"n");process.stdout.write(v);let Rr=Oi==="y"||Oi==="yes",Vo="";Rr?(console.log(` ${w("Setup:")}`),console.log(` ${w(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${w(" 2. Routes API aktivieren")}`),console.log(` ${w(" 3. API Key erstellen")}`),Vo=await O(c," Google Maps API Key",Wo),console.log(` ${D(">")} Routing: ${R("enabled")}`)):console.log(` ${w("Routing disabled.")}`),console.log(`
832
- ${R("Security configuration:")}`);let Pi=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",_e;if(Pi)_e=await O(c,"Owner user ID (for elevated permissions)",Pi);else{let h=(await c.question(`${q}Owner user ID${v} ${w("(optional, for elevated permissions)")}: ${M}`)).trim();process.stdout.write(v),_e=h}let ws=!1;if(_e){let h=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${R("Enable shell access (admin commands) for the owner?")}`),console.log(` ${w("Allows Alfred to execute shell commands. Only for the owner.")}`);let b=(await c.question(` ${M}> ${v}${w(`[${h}] `)}`)).trim().toLowerCase();b===""?ws=t.shellEnabled:ws=b==="y"||b==="yes",console.log(ws?` ${D(">")} Shell access ${R("enabled")} for owner ${w(_e)}`:` ${w("Shell access disabled.")}`)}let sd=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${R("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${w("By default, write actions are only allowed in DMs.")}`);let Go=(await c.question(` ${M}> ${v}${w(`[${sd}] `)}`)).trim().toLowerCase(),Ts;Go===""?Ts=t.writeInGroups:Ts=Go==="y"||Go==="yes",console.log(Ts?` ${D(">")} Write actions ${R("enabled")} in groups`:` ${w("Write actions only in DMs (default).")}`);let rd=t.rateLimit??30;console.log("");let od=await O(c," Rate limit (max write actions per hour per user)",String(rd)),Cr=Math.max(1,parseInt(od,10)||30);console.log(` ${D(">")} Rate limit: ${R(String(Cr))} per hour`),console.log(`
833
- ${R("Writing configuration files...")}`);let k=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(l){let h=a.envKeyName||"ALFRED_OLLAMA_API_KEY";k.push(`${h}=${l}`)}if(y!==a.defaultModel&&k.push(`ALFRED_LLM_MODEL=${y}`),m&&k.push(`ALFRED_LLM_BASE_URL=${m}`),Object.keys(L).length>0){k.push("","# === Additional Model Tiers ===");for(let[h,b]of Object.entries(L)){let $=`ALFRED_LLM_${h.toUpperCase()}`;k.push(""),k.push(`${$}_PROVIDER=${b.provider}`),k.push(`${$}_MODEL=${b.model}`),b.apiKey&&k.push(`${$}_API_KEY=${b.apiKey}`),b.baseUrl&&k.push(`${$}_BASE_URL=${b.baseUrl}`)}}k.push("","# === Messaging Platforms ===","");for(let[h,b]of Object.entries(Y))k.push(`${h}=${b}`);if(k.push("","# === Web Search ===",""),he?(k.push(`ALFRED_SEARCH_PROVIDER=${he}`),C&&k.push(`ALFRED_SEARCH_API_KEY=${C}`),U&&k.push(`ALFRED_SEARCH_BASE_URL=${U}`)):(k.push("# ALFRED_SEARCH_PROVIDER=brave"),k.push("# ALFRED_SEARCH_API_KEY=")),k.push("","# === Email ===",""),Er&&Ne.length>0){let h=Ne[0];h.provider==="microsoft"?(k.push("ALFRED_EMAIL_PROVIDER=microsoft"),h.msClientId?(k.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${h.msClientId}`),k.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${h.msClientSecret}`),k.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${h.msTenantId}`),k.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${h.msRefreshToken}`)):k.push("# Microsoft email credentials shared from calendar config")):(k.push(`ALFRED_EMAIL_USER=${h.user}`),k.push(`ALFRED_EMAIL_PASS=${h.pass}`)),Ne.length>1&&k.push("# Additional email accounts configured in config/default.yml")}else k.push("# ALFRED_EMAIL_USER="),k.push("# ALFRED_EMAIL_PASS=");if(k.push("","# === Speech ===",""),De?(k.push(`ALFRED_SPEECH_PROVIDER=${De}`),k.push(`ALFRED_SPEECH_API_KEY=${We}`),is&&k.push(`ALFRED_SPEECH_BASE_URL=${is}`),as&&(k.push("ALFRED_TTS_ENABLED=true"),k.push(`ALFRED_TTS_VOICE=${cs}`))):(k.push("# ALFRED_SPEECH_PROVIDER=groq"),k.push("# ALFRED_SPEECH_API_KEY=")),k.push("","# === Forge (GitHub / GitLab) ===",""),Qe==="github"?(k.push("ALFRED_FORGE_PROVIDER=github"),k.push(`ALFRED_GITHUB_TOKEN=${ls}`)):Qe==="gitlab"?(k.push("ALFRED_FORGE_PROVIDER=gitlab"),k.push(`ALFRED_GITLAB_TOKEN=${ds}`)):(k.push("# ALFRED_FORGE_PROVIDER=github"),k.push("# ALFRED_GITHUB_TOKEN=")),k.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),vr?(k.push(`ALFRED_PROXMOX_BASE_URL=${ms}`),k.push(`ALFRED_PROXMOX_TOKEN_ID=${No}`),k.push(`ALFRED_PROXMOX_TOKEN_SECRET=${ps}`)):(k.push("# ALFRED_PROXMOX_BASE_URL="),k.push("# ALFRED_PROXMOX_TOKEN_ID="),k.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),hs&&tt?(k.push(`ALFRED_UNIFI_BASE_URL=${$t}`),k.push(`ALFRED_UNIFI_API_KEY=${tt}`)):hs?(k.push(`ALFRED_UNIFI_BASE_URL=${$t}`),k.push(`ALFRED_UNIFI_USERNAME=${Oo}`),k.push(`ALFRED_UNIFI_PASSWORD=${fs}`)):(k.push("# ALFRED_UNIFI_BASE_URL="),k.push("# ALFRED_UNIFI_API_KEY=")),kr?(k.push(`ALFRED_HOMEASSISTANT_URL=${gs}`),k.push(`ALFRED_HOMEASSISTANT_TOKEN=${ys}`)):(k.push("# ALFRED_HOMEASSISTANT_URL="),k.push("# ALFRED_HOMEASSISTANT_TOKEN=")),k.push("","# === Contacts ===",""),Ar)for(let[h,b]of Object.entries(ce))k.push(`${h}=${b}`);else k.push("# ALFRED_CONTACTS_PROVIDER=carddav");k.push("","# === Docker ===",""),Ir?(st&&k.push(`ALFRED_DOCKER_SOCKET_PATH=${st}`),rt&&k.push(`ALFRED_DOCKER_HOST=${rt}`)):(k.push("# ALFRED_DOCKER_SOCKET_PATH="),k.push("# ALFRED_DOCKER_HOST=")),k.push("","# === BMW CarData ===",""),xr?k.push(`ALFRED_BMW_CLIENT_ID=${zo}`):k.push("# ALFRED_BMW_CLIENT_ID="),k.push("","# === Routing ===",""),Rr?k.push(`ALFRED_ROUTING_API_KEY=${Vo}`):k.push("# ALFRED_ROUTING_API_KEY="),k.push("","# === Security ===",""),_e?k.push(`ALFRED_OWNER_USER_ID=${_e}`):k.push("# ALFRED_OWNER_USER_ID="),k.push("");let nd=we.join(e,".env");de.writeFileSync(nd,k.join(`
834
- `),"utf-8"),console.log(` ${D("+")} ${w(".env")} written`);let Lr=we.join(e,"config");de.existsSync(Lr)||de.mkdirSync(Lr,{recursive:!0});let Ui={name:r,telegram:{token:H.telegram?.token??"",enabled:Q.some(h=>h.name==="telegram")},discord:{token:H.discord?.token??"",enabled:Q.some(h=>h.name==="discord")},whatsapp:{enabled:Q.some(h=>h.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:H.matrix?.homeserverUrl??"https://matrix.org",accessToken:H.matrix?.accessToken??"",userId:H.matrix?.userId??"",enabled:Q.some(h=>h.name==="matrix")},signal:{apiUrl:H.signal?.apiUrl??"http://localhost:8080",phoneNumber:H.signal?.phoneNumber??"",enabled:Q.some(h=>h.name==="signal")},llm:Object.keys(L).length>0?{default:{provider:a.name,model:y,...m?{baseUrl:m}:{},temperature:.7,maxTokens:4096},...L}:{provider:a.name,model:y,...m?{baseUrl:m}:{},temperature:.7,maxTokens:4096},...he?{search:{provider:he,...C?{apiKey:C}:{},...U?{baseUrl:U}:{}}}:{},...Er&&Ne.length>0?{email:{accounts:Ne.map(h=>h.provider==="microsoft"?{name:h.name,provider:"microsoft",...h.msClientId?{microsoft:{clientId:h.msClientId,clientSecret:h.msClientSecret,tenantId:h.msTenantId,refreshToken:h.msRefreshToken}}:{}}:{name:h.name,imap:{host:h.imapHost,port:h.imapPort,secure:h.imapPort===993},smtp:{host:h.smtpHost,port:h.smtpPort,secure:h.smtpPort===465},auth:{user:h.user,pass:h.pass}})}}:{},...De?{speech:{provider:De,apiKey:We,...is?{baseUrl:is}:{},...as?{ttsEnabled:!0,ttsVoice:cs}:{}}}:{},...Ao?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Ze.length>0||Qe?{codeAgents:{enabled:Ze.length>0,agents:Ze,...Qe==="github"?{forge:{provider:"github",github:{token:ls}}}:Qe==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:ds}}}:{}}}:{},...vr?{proxmox:{baseUrl:ms,tokenId:No,tokenSecret:ps,verifyTls:Do}}:{},...hs?{unifi:{baseUrl:$t,...tt?{apiKey:tt}:{username:Oo,password:fs},site:"default",verifyTls:Po}}:{},...kr?{homeassistant:{baseUrl:gs,accessToken:ys,verifyTls:Fo}}:{},...Ar?{contacts:{provider:ke,...ke==="carddav"?{carddav:{serverUrl:ce.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:ce.ALFRED_CARDDAV_CONTACTS_USERNAME}}:ke==="google"?{google:{clientId:ce.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:ke==="microsoft"?{microsoft:{clientId:ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:ce.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Ir?{docker:{...st?{socketPath:st}:{},...rt?{host:rt}:{}}}:{},...xr?{bmw:{clientId:zo}}:{},...Rr?{routing:{apiKey:Vo}}:{},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};_e&&(Ui.security.ownerUserId=_e);let id="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Ei.dump(Ui,{lineWidth:120,noRefs:!0,sortKeys:!1}),ad=we.join(Lr,"default.yml");de.writeFileSync(ad,id,"utf-8"),console.log(` ${D("+")} ${w("config/default.yml")} written`);let Ko=we.join(Lr,"rules");de.existsSync(Ko)||de.mkdirSync(Ko,{recursive:!0});let cd=ws&&_e?`
814
+ ${R(f.label+" configuration:")}`);let b={};for(let v of f.credentials){let B=t.env[v.envKey]??"",N;B?N=await O(c,` ${v.prompt}`,B):v.defaultValue?N=await O(c,` ${v.prompt}`,v.defaultValue):v.required?N=await $e(c,` ${v.prompt}`):(N=(await c.question(` ${v.prompt}: ${M}`)).trim(),process.stdout.write(S)),b[v.configField]=N,Y[v.envKey]=N,v.configField==="token"||v.configField==="accessToken"?console.log(` ${D(">")} Set: ${_(me(N))}`):console.log(` ${D(">")} Set: ${_(N)}`)}H[f.configKey]=b}let ee=t.config.email?.accounts??[],J=ee[0],bt=J?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",Te=J?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",$o=ee.length>0||!!bt||Te==="microsoft",Bl=$o?"Y/n":"y/N";console.log(`
815
+ ${R("Email access (read & send emails)?")}`),console.log(`${_("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let vo=(await c.question(`${M}> ${S}${_(`[${Bl}] `)}`)).trim().toLowerCase(),Er=vo===""?$o:vo==="y"||vo==="yes",Ne=[],Hl={"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"}},Si=u(async(f,b)=>{let v={name:f,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},B=b?.provider??"",N=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],j=B==="microsoft"?1:0;console.log("");for(let z=0;z<N.length;z++){let ye=z===j?` ${_("(current)")}`:"";console.log(` ${le(`${z+1})`)} ${N[z]}${ye}`)}let G=(await c.question(`${M}> ${S}${_(`[${j+1}] `)}`)).trim(),ge=G===""?j:parseInt(G,10)-1;if(v.provider=ge===1?"microsoft":"imap-smtp",v.provider==="microsoft"){let z=t.config.calendar?.microsoft,ye=b?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Ae=b?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",ot=b?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(z&&!ye)console.log(` ${D(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${_("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${_("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${_("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),v.msClientId=await O(c," Client ID",ye),v.msClientId||(v.msClientId=await $e(c," Client ID"));let _s=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";v.msClientSecret=await O(c," Client Secret",_s),v.msClientSecret||(v.msClientSecret=await $e(c," Client Secret")),v.msTenantId=await O(c," Tenant ID",Ae),v.msTenantId||(v.msTenantId=await $e(c," Tenant ID")),console.log(` ${_("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),v.msRefreshToken=await O(c," Refresh Token",ot),v.msRefreshToken||(v.msRefreshToken=await $e(c," Refresh Token"))}console.log(` ${D(">")} Email [${f}]: Microsoft 365 (Graph API)`)}else{let z=b?.auth?.user??"";console.log(""),v.user=await O(c," Email address",z||""),v.user||(v.user=await $e(c," Email address"));let ye=b?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";ye?v.pass=await O(c," Password / App password",ye):(console.log(` ${_("For Gmail: use an App Password (not your regular password)")}`),console.log(` ${_(" \u2192 Google Account \u2192 Security \u2192 2-Step \u2192 App passwords")}`),v.pass=await $e(c," Password / App password"));let Ae=v.user.split("@")[1]?.toLowerCase()??"",ot=Hl[Ae],_s=b?.imap?.host??ot?.imap??`imap.${Ae}`,Xo=b?.smtp?.host??ot?.smtp??`smtp.${Ae}`,Yo=b?.imap?.port??993,Ve=b?.smtp?.port??587;ot&&console.log(` ${D(">")} Detected ${Ae} \u2014 using preset server settings`),v.imapHost=await O(c," IMAP server",_s);let Fe=await O(c," IMAP port",String(Yo));v.imapPort=parseInt(Fe,10)||993,v.smtpHost=await O(c," SMTP server",Xo);let Ee=await O(c," SMTP port",String(Ve));v.smtpPort=parseInt(Ee,10)||587,console.log(` ${D(">")} Email [${f}]: ${_(v.user)} via ${_(v.imapHost)}`)}return v},"configureEmailAccount");if(Er){let f=J??(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);Ne.push(await Si("default",f));let b=!0;for(;b;){let v=(await c.question(`
816
+ ${R("Add another email account?")} ${_("[y/N]")} `)).trim().toLowerCase();if(v==="y"||v==="yes"){let N=(await c.question(` ${R("Account name:")} `)).trim()||`account${Ne.length+1}`,j=ee.find(G=>G.name===N);Ne.push(await Si(N,j))}else b=!1}}else console.log(` ${_("Email disabled \u2014 you can configure it later.")}`);let br=["openai","groq"],ql=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",$r=br.indexOf(ql),zl=$r>=0?$r+1:0;console.log(`
817
+ ${R("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${_("Transcribes voice messages from Telegram, Discord, etc.")}`);let ki=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${le("0)")} None (disable voice transcription)${$r===-1?` ${_("(current)")}`:""}`);for(let f=0;f<ki.length;f++){let b=$r===f?` ${_("(current)")}`:"";console.log(` ${le(String(f+1)+")")} ${ki[f]}${b}`)}let So=await Tr(c,"> ",0,br.length,zl),De,We="",is="";if(So>=1&&So<=br.length&&(De=br[So-1]),De==="openai"){let f=t.env.ALFRED_SPEECH_API_KEY??"";f?We=await O(c," OpenAI API key (for Whisper)",f):(console.log(` ${_("Uses your OpenAI API key for Whisper transcription.")}`),We=await $e(c," OpenAI API key")),console.log(` ${D(">")} OpenAI Whisper: ${_(me(We))}`)}else if(De==="groq"){let f=t.env.ALFRED_SPEECH_API_KEY??"";f?We=await O(c," Groq API key",f):(console.log(` ${_("Get your free API key at: https://console.groq.com/")}`),We=await $e(c," Groq API key"));let b=t.env.ALFRED_SPEECH_BASE_URL??"";b&&(is=await O(c," Groq API URL",b)),console.log(` ${D(">")} Groq Whisper: ${_(me(We))}`)}else console.log(` ${_("Voice transcription disabled \u2014 you can configure it later.")}`);let as=!1,cs="alloy";if(De){let f=t.config.speech?.ttsEnabled??!1,b=f?"Y/n":"y/N";console.log(`
818
+ ${R("Voice responses (Text-to-Speech)?")}`),console.log(`${_("Alfred can reply as a voice message when the user asks for it.")}`);let v=(await c.question(`${M}> ${S}${_(`[${b}] `)}`)).trim().toLowerCase();if(as=v===""?f:v==="y"||v==="yes",as){let B=["alloy","echo","fable","onyx","nova","shimmer"],N=t.config.speech?.ttsVoice??"alloy",j=B.indexOf(N),G=j>=0?j+1:1;console.log(`
819
+ ${R("Which voice?")}`);for(let z=0;z<B.length;z++){let ye=j===z?` ${_("(current)")}`:"";console.log(` ${le(String(z+1)+")")} ${B[z]}${ye}`)}let ge=await Tr(c," > ",1,B.length,G);cs=B[ge-1],console.log(` ${D(">")} TTS voice: ${R(cs)}`)}else console.log(` ${_("Voice responses disabled.")}`)}let Wl=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
820
+ ${R("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${_("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let ko=(await c.question(`${M}> ${S}${_(`[${Wl}] `)}`)).trim().toLowerCase(),Ao=ko===""?t.codeSandboxEnabled:ko==="y"||ko==="yes";console.log(Ao?` ${D(">")} Code Sandbox ${R("enabled")} (JavaScript + Python)`:` ${_("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
821
+ ${R("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${_("Scanning for known coding agents on this system...")}`);let Io=[];for(let f of bl){let b=jm(f.whichCmd);b?(Io.push({...f,resolvedPath:b}),console.log(` ${D("\u2713")} ${R(f.label)} ${_(`(${b})`)}`)):console.log(` ${_("\xB7")} ${_(f.label)} ${_("\u2014 not found")}`)}let xo=(t.config.codeAgents?.agents??[]).filter(f=>!bl.some(b=>b.name===f.name));for(let f of xo)console.log(` ${D("\u2713")} ${R(f.name)} ${_(`(${f.command}) \u2014 from existing config`)}`);let Ze=[];if(Io.length===0&&xo.length===0)console.log(`
822
+ ${_("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let f=[...Io.map(N=>({name:N.name,command:N.resolvedPath??N.command,argsTemplate:N.argsTemplate,promptVia:N.promptVia,label:N.label,detected:!0})),...xo.map(N=>({name:N.name,command:N.command,argsTemplate:N.argsTemplate,promptVia:N.promptVia??"arg",label:N.name,detected:!1}))];console.log(`
823
+ ${R("Which agents should Alfred use?")} ${_("(comma-separated, e.g. 1,2)")}`);let b=new Set((t.config.codeAgents?.agents??[]).map(N=>N.name));for(let N=0;N<f.length;N++){let j=f[N],G=b.has(j.name)?` ${_("(current)")}`:"";console.log(` ${M}${N+1}${S}) ${j.label}${G}`)}console.log(` ${M}0${S}) None`);let v=f.map((N,j)=>b.size>0?b.has(N.name)?String(j+1):null:N.detected?String(j+1):null).filter(Boolean).join(",")||"0",B=(await c.question(` ${M}> ${S}${_(`[${v}] `)}`)).trim()||v;B!=="0"&&(Ze=B.split(",").map(j=>parseInt(j.trim(),10)).filter(j=>!isNaN(j)&&j>=1&&j<=f.length).map(j=>{let G=f[j-1];return{name:G.name,command:G.command,argsTemplate:G.argsTemplate,promptVia:G.promptVia}})),Ze.length>0?console.log(` ${D(">")} ${R(String(Ze.length))} agent(s) selected: ${Ze.map(N=>N.name).join(", ")}`):console.log(` ${_("No agents selected.")}`)}let Ro=t.config.codeAgents?.forge,Co=Ro?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
824
+ ${R("Forge Integration (auto-create PRs/MRs after code agent orchestration)?")}`),console.log(`${_("Connects to GitHub or GitLab to push branches and create pull/merge requests.")}`),console.log(`${_("Owner/repo are detected automatically from the git remote at runtime.")}`);let Ai=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let f of Ai){let b=f.name===Co?` ${_("(current)")}`:"";console.log(` ${M}${f.num}${S}) ${f.label}${b}`)}let Ii=Co==="github"?"2":Co==="gitlab"?"3":"1",Vl=(await c.question(`${M}> ${S}${_(`[${Ii}] `)}`)).trim()||Ii,Qe=Ai.find(f=>f.num===Vl)?.name??"",ls="",ds="";if(Qe==="github"){console.log(` ${D(">")} Forge: ${R("GitHub")}`);let f=t.env.ALFRED_GITHUB_TOKEN??Ro?.github?.token??"";f&&console.log(` ${_(`Current token: ${me(f)}`)}`),console.log(` ${_("Create a token at https://github.com/settings/tokens (scope: repo)")}`),ls=(await c.question(` ${q}GitHub Token${S}: ${M}`)).trim(),process.stdout.write(S),!ls&&f&&(ls=f)}else if(Qe==="gitlab"){console.log(` ${D(">")} Forge: ${R("GitLab")}`);let f=t.env.ALFRED_GITLAB_TOKEN??Ro?.gitlab?.token??"";f&&console.log(` ${_(`Current token: ${me(f)}`)}`),console.log(` ${_("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),ds=(await c.question(` ${q}GitLab Token${S}: ${M}`)).trim(),process.stdout.write(S),!ds&&f&&(ds=f)}else console.log(` ${_("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);console.log(`
825
+ ${R("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${_("Control VMs, containers, network devices, and smart home through Alfred.")}`);let us=t.config.proxmox,Lo=t.env.ALFRED_PROXMOX_BASE_URL??us?.baseUrl??"",Gl=Lo?"Y/n":"y/N",xi=(await c.question(` ${q}Enable Proxmox VE?${S} ${_(`[${Gl}]`)}: ${M}`)).trim().toLowerCase()||(Lo?"y":"n");process.stdout.write(S);let vr=xi==="y"||xi==="yes",ms="",No="",ps="",Do=!0;if(vr){ms=await O(c," Proxmox URL (e.g. https://pve.local:8006)",Lo||"https://pve.local:8006");let f=t.env.ALFRED_PROXMOX_TOKEN_ID??us?.tokenId??"";f&&console.log(` ${_(`Current token ID: ${f}`)}`),console.log(` ${_("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),No=await O(c," API Token ID (user@realm!name)",f);let b=t.env.ALFRED_PROXMOX_TOKEN_SECRET??us?.tokenSecret??"";b&&console.log(` ${_(`Current secret: ${me(b)}`)}`),ps=(await c.question(` ${q}API Token Secret${S}: ${M}`)).trim(),process.stdout.write(S),!ps&&b&&(ps=b);let v=us?.verifyTls===!1?"y/N":"Y/n",B=(await c.question(` ${q}Verify TLS?${S} ${_(`(self-signed? \u2192 no) [${v}]`)}: ${M}`)).trim().toLowerCase()||(us?.verifyTls===!1?"n":"y");process.stdout.write(S),Do=B==="y"||B==="yes",console.log(` ${D(">")} Proxmox: ${R(ms)} ${_(`(TLS verify: ${Do?"yes":"no"})`)}`)}else console.log(` ${_("Proxmox disabled.")}`);let et=t.config.unifi,Mo=t.env.ALFRED_UNIFI_BASE_URL??et?.baseUrl??"",Kl=Mo?"Y/n":"y/N",Ri=(await c.question(`
826
+ ${q}Enable UniFi Network?${S} ${_(`[${Kl}]`)}: ${M}`)).trim().toLowerCase()||(Mo?"y":"n");process.stdout.write(S);let hs=Ri==="y"||Ri==="yes",$t="",tt="",Oo="",fs="",Po=!0;if(hs){$t=await O(c," UniFi URL (e.g. https://unifi.local)",Mo||"https://unifi.local"),console.log(` ${_("Auth: API Key (recommended) or Username/Password")}`);let f=t.env.ALFRED_UNIFI_API_KEY??et?.apiKey??"",b=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],v=f?"1":et?.username?"2":"1";for(let G of b)console.log(` ${M}${G.num}${S}) ${G.label}`);if(((await c.question(` ${M}> ${S}${_(`[${v}] `)}`)).trim()||v)==="1")f&&console.log(` ${_(`Current key: ${me(f)}`)}`),console.log(` ${_("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),tt=(await c.question(` ${q}API Key${S}: ${M}`)).trim(),process.stdout.write(S),!tt&&f&&(tt=f);else{let G=t.env.ALFRED_UNIFI_USERNAME??et?.username??"";Oo=await O(c," Username",G||"alfred");let ge=t.env.ALFRED_UNIFI_PASSWORD??et?.password??"";ge&&console.log(` ${_(`Current password: ${me(ge)}`)}`),fs=(await c.question(` ${q}Password${S}: ${M}`)).trim(),process.stdout.write(S),!fs&&ge&&(fs=ge)}let N=et?.verifyTls===!1?"y/N":"Y/n",j=(await c.question(` ${q}Verify TLS?${S} ${_(`(self-signed? \u2192 no) [${N}]`)}: ${M}`)).trim().toLowerCase()||(et?.verifyTls===!1?"n":"y");process.stdout.write(S),Po=j==="y"||j==="yes",console.log(` ${D(">")} UniFi: ${R($t)} ${_(`(TLS verify: ${Po?"yes":"no"})`)}`)}else console.log(` ${_("UniFi disabled.")}`);let Sr=t.config.homeassistant,Uo=t.env.ALFRED_HOMEASSISTANT_URL??Sr?.baseUrl??"",Xl=Uo?"Y/n":"y/N",Ci=(await c.question(`
827
+ ${q}Enable Home Assistant?${S} ${_(`[${Xl}]`)}: ${M}`)).trim().toLowerCase()||(Uo?"y":"n");process.stdout.write(S);let kr=Ci==="y"||Ci==="yes",gs="",ys="",Fo=!0;if(kr){gs=await O(c," Home Assistant URL (e.g. http://homeassistant.local:8123)",Uo||"http://homeassistant.local:8123");let f=t.env.ALFRED_HOMEASSISTANT_TOKEN??Sr?.accessToken??"";f&&console.log(` ${_(`Current token: ${me(f)}`)}`),console.log(` ${_("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),ys=(await c.question(` ${q}Long-Lived Access Token${S}: ${M}`)).trim(),process.stdout.write(S),!ys&&f&&(ys=f);let b=Sr?.verifyTls===!1?"y/N":"Y/n",v=(await c.question(` ${q}Verify TLS?${S} ${_(`(self-signed? \u2192 no) [${b}]`)}: ${M}`)).trim().toLowerCase()||(Sr?.verifyTls===!1?"n":"y");process.stdout.write(S),Fo=v==="y"||v==="yes",console.log(` ${D(">")} Home Assistant: ${R(gs)} ${_(`(TLS verify: ${Fo?"yes":"no"})`)}`)}else console.log(` ${_("Home Assistant disabled.")}`);let Se=t.config.contacts,jo=t.env.ALFRED_CONTACTS_PROVIDER??Se?.provider??"",Yl=jo?"Y/n":"y/N",Li=(await c.question(`
828
+ ${q}Enable Contacts management?${S} ${_(`[${Yl}]`)}: ${M}`)).trim().toLowerCase()||(jo?"y":"n");process.stdout.write(S);let Ar=Li==="y"||Li==="yes",ke="",ce={};if(Ar){let f=["carddav","google","microsoft"],b=f.indexOf(jo),v=b>=0?b+1:1;console.log(` ${le("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${le("2)")} Google Contacts`),console.log(` ${le("3)")} Microsoft 365`);let B=await Tr(c," > ",1,3,v);if(ke=f[B-1],ce.ALFRED_CONTACTS_PROVIDER=ke,ke==="carddav"){let N=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Se?.carddav?.serverUrl??"";ce.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await O(c," CardDAV Server URL",N||"https://cloud.example.com/remote.php/dav");let j=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Se?.carddav?.username??"";ce.ALFRED_CARDDAV_CONTACTS_USERNAME=await O(c," Username",j);let G=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Se?.carddav?.password??"";G&&console.log(` ${_(`Current password: ${me(G)}`)}`);let ge=(await c.question(` ${q}Password${S}: ${M}`)).trim();process.stdout.write(S),ce.ALFRED_CARDDAV_CONTACTS_PASSWORD=ge||G}else if(ke==="google"){let N=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Se?.google?.clientId??"";N&&console.log(` ${_(`Current client ID: ${me(N)}`)}`),ce.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await c.question(` ${q}Google Client ID${S}: ${M}`)).trim()||N,process.stdout.write(S);let j=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Se?.google?.clientSecret??"";ce.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await c.question(` ${q}Google Client Secret${S}: ${M}`)).trim()||j,process.stdout.write(S);let G=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Se?.google?.refreshToken??"";ce.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await c.question(` ${q}Refresh Token${S}: ${M}`)).trim()||G,process.stdout.write(S)}else if(ke==="microsoft"){let N=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Se?.microsoft?.clientId??"";N&&console.log(` ${_(`Current client ID: ${me(N)}`)}`),ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await c.question(` ${q}Microsoft Client ID${S}: ${M}`)).trim()||N,process.stdout.write(S);let j=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Se?.microsoft?.clientSecret??"";ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await c.question(` ${q}Microsoft Client Secret${S}: ${M}`)).trim()||j,process.stdout.write(S);let G=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Se?.microsoft?.tenantId??"";ce.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await O(c," Tenant ID",G||"common");let ge=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Se?.microsoft?.refreshToken??"";console.log(` ${_("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),ce.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await c.question(` ${q}Refresh Token${S}: ${M}`)).trim()||ge,process.stdout.write(S)}console.log(` ${D(">")} Contacts: ${R(ke)}`)}else console.log(` ${_("Contacts disabled.")}`);let Ni=t.config.docker,Bo=t.env.ALFRED_DOCKER_SOCKET_PATH??Ni?.socketPath??"",Ho=t.env.ALFRED_DOCKER_HOST??Ni?.host??"",Jl=Bo||Ho?"Y/n":"y/N",Di=(await c.question(`
829
+ ${q}Enable Docker management?${S} ${_(`[${Jl}]`)}: ${M}`)).trim().toLowerCase()||(Bo||Ho?"y":"n");process.stdout.write(S);let Ir=Di==="y"||Di==="yes",st="",rt="";if(Ir){let f=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${_("Use socket path for local Docker, or host URL for remote.")}`),st=await O(c," Docker socket path",Bo||f);let b=(await c.question(` ${q}Docker host URL (optional, for remote)${S}: ${M}`)).trim();process.stdout.write(S),rt=b||Ho,console.log(` ${D(">")} Docker: ${R(rt||st)}`)}else console.log(` ${_("Docker disabled.")}`);let Zl=t.config.bmw,qo=t.env.ALFRED_BMW_CLIENT_ID??Zl?.clientId??"",Ql=qo?"Y/n":"y/N",Mi=(await c.question(`
830
+ ${q}Enable BMW CarData (vehicle status, charging)?${S} ${_(`[${Ql}]`)}: ${M}`)).trim().toLowerCase()||(qo?"y":"n");process.stdout.write(S);let xr=Mi==="y"||Mi==="yes",zo="";xr?(console.log(` ${_("Setup:")}`),console.log(` ${_(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${_(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${_(" 3. Client-ID generieren")}`),console.log(` ${_(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),zo=await O(c," BMW CarData Client ID",qo),console.log(` ${D(">")} BMW CarData: ${R("enabled")}`)):console.log(` ${_("BMW CarData disabled.")}`);let ed=t.config.routing,Wo=t.env.ALFRED_ROUTING_API_KEY??ed?.apiKey??"",td=Wo?"Y/n":"y/N",Oi=(await c.question(`
831
+ ${q}Enable route planning with live traffic (Google Routes)?${S} ${_(`[${td}]`)}: ${M}`)).trim().toLowerCase()||(Wo?"y":"n");process.stdout.write(S);let Rr=Oi==="y"||Oi==="yes",Vo="";Rr?(console.log(` ${_("Setup:")}`),console.log(` ${_(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${_(" 2. Routes API aktivieren")}`),console.log(` ${_(" 3. API Key erstellen")}`),Vo=await O(c," Google Maps API Key",Wo),console.log(` ${D(">")} Routing: ${R("enabled")}`)):console.log(` ${_("Routing disabled.")}`),console.log(`
832
+ ${R("Security configuration:")}`);let Pi=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",_e;if(Pi)_e=await O(c,"Owner user ID (for elevated permissions)",Pi);else{let f=(await c.question(`${q}Owner user ID${S} ${_("(optional, for elevated permissions)")}: ${M}`)).trim();process.stdout.write(S),_e=f}let ws=!1;if(_e){let f=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${R("Enable shell access (admin commands) for the owner?")}`),console.log(` ${_("Allows Alfred to execute shell commands. Only for the owner.")}`);let b=(await c.question(` ${M}> ${S}${_(`[${f}] `)}`)).trim().toLowerCase();b===""?ws=t.shellEnabled:ws=b==="y"||b==="yes",console.log(ws?` ${D(">")} Shell access ${R("enabled")} for owner ${_(_e)}`:` ${_("Shell access disabled.")}`)}let sd=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${R("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${_("By default, write actions are only allowed in DMs.")}`);let Go=(await c.question(` ${M}> ${S}${_(`[${sd}] `)}`)).trim().toLowerCase(),Ts;Go===""?Ts=t.writeInGroups:Ts=Go==="y"||Go==="yes",console.log(Ts?` ${D(">")} Write actions ${R("enabled")} in groups`:` ${_("Write actions only in DMs (default).")}`);let rd=t.rateLimit??30;console.log("");let od=await O(c," Rate limit (max write actions per hour per user)",String(rd)),Cr=Math.max(1,parseInt(od,10)||30);console.log(` ${D(">")} Rate limit: ${R(String(Cr))} per hour`),console.log(`
833
+ ${R("Writing configuration files...")}`);let k=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(l){let f=a.envKeyName||"ALFRED_OLLAMA_API_KEY";k.push(`${f}=${l}`)}if(y!==a.defaultModel&&k.push(`ALFRED_LLM_MODEL=${y}`),m&&k.push(`ALFRED_LLM_BASE_URL=${m}`),Object.keys(L).length>0){k.push("","# === Additional Model Tiers ===");for(let[f,b]of Object.entries(L)){let v=`ALFRED_LLM_${f.toUpperCase()}`;k.push(""),k.push(`${v}_PROVIDER=${b.provider}`),k.push(`${v}_MODEL=${b.model}`),b.apiKey&&k.push(`${v}_API_KEY=${b.apiKey}`),b.baseUrl&&k.push(`${v}_BASE_URL=${b.baseUrl}`)}}k.push("","# === Messaging Platforms ===","");for(let[f,b]of Object.entries(Y))k.push(`${f}=${b}`);if(k.push("","# === Web Search ===",""),he?(k.push(`ALFRED_SEARCH_PROVIDER=${he}`),C&&k.push(`ALFRED_SEARCH_API_KEY=${C}`),U&&k.push(`ALFRED_SEARCH_BASE_URL=${U}`)):(k.push("# ALFRED_SEARCH_PROVIDER=brave"),k.push("# ALFRED_SEARCH_API_KEY=")),k.push("","# === Email ===",""),Er&&Ne.length>0){let f=Ne[0];f.provider==="microsoft"?(k.push("ALFRED_EMAIL_PROVIDER=microsoft"),f.msClientId?(k.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${f.msClientId}`),k.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${f.msClientSecret}`),k.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${f.msTenantId}`),k.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${f.msRefreshToken}`)):k.push("# Microsoft email credentials shared from calendar config")):(k.push(`ALFRED_EMAIL_USER=${f.user}`),k.push(`ALFRED_EMAIL_PASS=${f.pass}`)),Ne.length>1&&k.push("# Additional email accounts configured in config/default.yml")}else k.push("# ALFRED_EMAIL_USER="),k.push("# ALFRED_EMAIL_PASS=");if(k.push("","# === Speech ===",""),De?(k.push(`ALFRED_SPEECH_PROVIDER=${De}`),k.push(`ALFRED_SPEECH_API_KEY=${We}`),is&&k.push(`ALFRED_SPEECH_BASE_URL=${is}`),as&&(k.push("ALFRED_TTS_ENABLED=true"),k.push(`ALFRED_TTS_VOICE=${cs}`))):(k.push("# ALFRED_SPEECH_PROVIDER=groq"),k.push("# ALFRED_SPEECH_API_KEY=")),k.push("","# === Forge (GitHub / GitLab) ===",""),Qe==="github"?(k.push("ALFRED_FORGE_PROVIDER=github"),k.push(`ALFRED_GITHUB_TOKEN=${ls}`)):Qe==="gitlab"?(k.push("ALFRED_FORGE_PROVIDER=gitlab"),k.push(`ALFRED_GITLAB_TOKEN=${ds}`)):(k.push("# ALFRED_FORGE_PROVIDER=github"),k.push("# ALFRED_GITHUB_TOKEN=")),k.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),vr?(k.push(`ALFRED_PROXMOX_BASE_URL=${ms}`),k.push(`ALFRED_PROXMOX_TOKEN_ID=${No}`),k.push(`ALFRED_PROXMOX_TOKEN_SECRET=${ps}`)):(k.push("# ALFRED_PROXMOX_BASE_URL="),k.push("# ALFRED_PROXMOX_TOKEN_ID="),k.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),hs&&tt?(k.push(`ALFRED_UNIFI_BASE_URL=${$t}`),k.push(`ALFRED_UNIFI_API_KEY=${tt}`)):hs?(k.push(`ALFRED_UNIFI_BASE_URL=${$t}`),k.push(`ALFRED_UNIFI_USERNAME=${Oo}`),k.push(`ALFRED_UNIFI_PASSWORD=${fs}`)):(k.push("# ALFRED_UNIFI_BASE_URL="),k.push("# ALFRED_UNIFI_API_KEY=")),kr?(k.push(`ALFRED_HOMEASSISTANT_URL=${gs}`),k.push(`ALFRED_HOMEASSISTANT_TOKEN=${ys}`)):(k.push("# ALFRED_HOMEASSISTANT_URL="),k.push("# ALFRED_HOMEASSISTANT_TOKEN=")),k.push("","# === Contacts ===",""),Ar)for(let[f,b]of Object.entries(ce))k.push(`${f}=${b}`);else k.push("# ALFRED_CONTACTS_PROVIDER=carddav");k.push("","# === Docker ===",""),Ir?(st&&k.push(`ALFRED_DOCKER_SOCKET_PATH=${st}`),rt&&k.push(`ALFRED_DOCKER_HOST=${rt}`)):(k.push("# ALFRED_DOCKER_SOCKET_PATH="),k.push("# ALFRED_DOCKER_HOST=")),k.push("","# === BMW CarData ===",""),xr?k.push(`ALFRED_BMW_CLIENT_ID=${zo}`):k.push("# ALFRED_BMW_CLIENT_ID="),k.push("","# === Routing ===",""),Rr?k.push(`ALFRED_ROUTING_API_KEY=${Vo}`):k.push("# ALFRED_ROUTING_API_KEY="),k.push("","# === Security ===",""),_e?k.push(`ALFRED_OWNER_USER_ID=${_e}`):k.push("# ALFRED_OWNER_USER_ID="),k.push("");let nd=we.join(e,".env");de.writeFileSync(nd,k.join(`
834
+ `),"utf-8"),console.log(` ${D("+")} ${_(".env")} written`);let Lr=we.join(e,"config");de.existsSync(Lr)||de.mkdirSync(Lr,{recursive:!0});let Ui={name:r,telegram:{token:H.telegram?.token??"",enabled:Q.some(f=>f.name==="telegram")},discord:{token:H.discord?.token??"",enabled:Q.some(f=>f.name==="discord")},whatsapp:{enabled:Q.some(f=>f.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:H.matrix?.homeserverUrl??"https://matrix.org",accessToken:H.matrix?.accessToken??"",userId:H.matrix?.userId??"",enabled:Q.some(f=>f.name==="matrix")},signal:{apiUrl:H.signal?.apiUrl??"http://localhost:8080",phoneNumber:H.signal?.phoneNumber??"",enabled:Q.some(f=>f.name==="signal")},llm:Object.keys(L).length>0?{default:{provider:a.name,model:y,...m?{baseUrl:m}:{},temperature:.7,maxTokens:4096},...L}:{provider:a.name,model:y,...m?{baseUrl:m}:{},temperature:.7,maxTokens:4096},...he?{search:{provider:he,...C?{apiKey:C}:{},...U?{baseUrl:U}:{}}}:{},...Er&&Ne.length>0?{email:{accounts:Ne.map(f=>f.provider==="microsoft"?{name:f.name,provider:"microsoft",...f.msClientId?{microsoft:{clientId:f.msClientId,clientSecret:f.msClientSecret,tenantId:f.msTenantId,refreshToken:f.msRefreshToken}}:{}}:{name:f.name,imap:{host:f.imapHost,port:f.imapPort,secure:f.imapPort===993},smtp:{host:f.smtpHost,port:f.smtpPort,secure:f.smtpPort===465},auth:{user:f.user,pass:f.pass}})}}:{},...De?{speech:{provider:De,apiKey:We,...is?{baseUrl:is}:{},...as?{ttsEnabled:!0,ttsVoice:cs}:{}}}:{},...Ao?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Ze.length>0||Qe?{codeAgents:{enabled:Ze.length>0,agents:Ze,...Qe==="github"?{forge:{provider:"github",github:{token:ls}}}:Qe==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:ds}}}:{}}}:{},...vr?{proxmox:{baseUrl:ms,tokenId:No,tokenSecret:ps,verifyTls:Do}}:{},...hs?{unifi:{baseUrl:$t,...tt?{apiKey:tt}:{username:Oo,password:fs},site:"default",verifyTls:Po}}:{},...kr?{homeassistant:{baseUrl:gs,accessToken:ys,verifyTls:Fo}}:{},...Ar?{contacts:{provider:ke,...ke==="carddav"?{carddav:{serverUrl:ce.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:ce.ALFRED_CARDDAV_CONTACTS_USERNAME}}:ke==="google"?{google:{clientId:ce.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:ke==="microsoft"?{microsoft:{clientId:ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:ce.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Ir?{docker:{...st?{socketPath:st}:{},...rt?{host:rt}:{}}}:{},...xr?{bmw:{clientId:zo}}:{},...Rr?{routing:{apiKey:Vo}}:{},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};_e&&(Ui.security.ownerUserId=_e);let id="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Ei.dump(Ui,{lineWidth:120,noRefs:!0,sortKeys:!1}),ad=we.join(Lr,"default.yml");de.writeFileSync(ad,id,"utf-8"),console.log(` ${D("+")} ${_("config/default.yml")} written`);let Ko=we.join(Lr,"rules");de.existsSync(Ko)||de.mkdirSync(Ko,{recursive:!0});let cd=ws&&_e?`
835
835
  # Allow admin actions (shell, etc.) for the owner only
836
836
  - id: allow-owner-admin
837
837
  effect: allow
@@ -907,14 +907,14 @@ ${cd}
907
907
  scope: global
908
908
  actions: ["*"]
909
909
  riskLevels: [read, write, destructive, admin]
910
- `,dd=we.join(Ko,"default-rules.yml");de.writeFileSync(dd,ld,"utf-8"),console.log(` ${D("+")} ${w("config/rules/default-rules.yml")} written`);let Fi=we.join(e,"data");de.existsSync(Fi)||(de.mkdirSync(Fi,{recursive:!0}),console.log(` ${D("+")} ${w("data/")} directory created`)),console.log(""),console.log(`${_o}${"=".repeat(52)}${v}`),console.log(`${_o}${q} Setup complete!${v}`),console.log(`${_o}${"=".repeat(52)}${v}`),console.log(""),console.log(` ${R("Bot name:")} ${r}`),console.log(` ${R("LLM default:")} ${a.name} (${y})`),l&&console.log(` ${R("API key:")} ${me(l)}`);for(let[h,b]of Object.entries(L)){let $=h.charAt(0).toUpperCase()+h.slice(1);console.log(` ${R(`LLM ${$}:`)}${" ".repeat(Math.max(1,10-$.length))}${b.provider} (${b.model})`)}if(Q.length>0?console.log(` ${R("Platforms:")} ${Q.map(h=>h.label).join(", ")}`):console.log(` ${R("Platforms:")} none (configure later)`),he){let h={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${U})`};console.log(` ${R("Web search:")} ${h[he]}`)}else console.log(` ${R("Web search:")} ${w("disabled")}`);if(Er&&Ne.length>0){let h=Ne.map(b=>b.provider==="microsoft"?`${b.name} (Microsoft 365)${b.msClientId?"":" \u2014 shared from Calendar"}`:`${b.name} (${b.imapHost})`);console.log(` ${R("Email:")} ${h.join(", ")}`)}else console.log(` ${R("Email:")} ${w("disabled")}`);if(De){let h={openai:"OpenAI Whisper",groq:"Groq Whisper"},b=as?`, TTS: ${cs}`:"";console.log(` ${R("Voice:")} ${h[De]}${b}`)}else console.log(` ${R("Voice:")} ${w("disabled")}`);console.log(` ${R("Code Sandbox:")} ${Ao?D("enabled"):w("disabled")}`),vr&&console.log(` ${R("Proxmox:")} ${D(ms)}`),hs&&console.log(` ${R("UniFi:")} ${D($t)}`),kr&&console.log(` ${R("Home Assist.:")} ${D(gs)}`),Ar&&console.log(` ${R("Contacts:")} ${D(ke)}`),Ir&&console.log(` ${R("Docker:")} ${D(rt||st)}`),xr&&console.log(` ${R("BMW CarData:")} ${D("enabled")}`),Rr&&console.log(` ${R("Routing:")} ${D("enabled")}`),_e&&(console.log(` ${R("Owner ID:")} ${_e}`),console.log(` ${R("Shell access:")} ${ws?D("enabled"):w("disabled")}`)),console.log(` ${R("Write scope:")} ${Ts?"DMs + Groups":"DMs only"}`),console.log(` ${R("Rate limit:")} ${Cr}/hour per user`),console.log(""),console.log(`${Eo}Next steps:${v}`),console.log(` ${R("alfred start")} Start Alfred`),console.log(` ${R("alfred status")} Check configuration`),console.log(` ${R("alfred --help")} Show all commands`),console.log(""),console.log(`${Je}Edit ${R(".env")}${Je} or ${R("config/default.yml")}${Je} for manual configuration.${v}`),console.log("")}finally{c.close()}}async function O(c,e,t){let s=(await c.question(`${q}${e}${v} ${w(`[${t}]`)}: ${M}`)).trim();return process.stdout.write(v),s||t}async function $e(c,e){for(;;){let t=(await c.question(`${q}${e}${v}: ${M}`)).trim();if(process.stdout.write(v),t)return t;console.log(` ${$l("!")} This field is required. Please enter a value.`)}}async function Tr(c,e,t,s,r){for(;;){let o=(await c.question(`${M}${e}${v}`)).trim();if(!o)return r;let n=parseInt(o,10);if(!Number.isNaN(n)&&n>=t&&n<=s)return n;console.log(` ${$l("!")} Please enter a number between ${t} and ${s}.`)}}function qm(){console.log(`
910
+ `,dd=we.join(Ko,"default-rules.yml");de.writeFileSync(dd,ld,"utf-8"),console.log(` ${D("+")} ${_("config/rules/default-rules.yml")} written`);let Fi=we.join(e,"data");de.existsSync(Fi)||(de.mkdirSync(Fi,{recursive:!0}),console.log(` ${D("+")} ${_("data/")} directory created`)),console.log(""),console.log(`${_o}${"=".repeat(52)}${S}`),console.log(`${_o}${q} Setup complete!${S}`),console.log(`${_o}${"=".repeat(52)}${S}`),console.log(""),console.log(` ${R("Bot name:")} ${r}`),console.log(` ${R("LLM default:")} ${a.name} (${y})`),l&&console.log(` ${R("API key:")} ${me(l)}`);for(let[f,b]of Object.entries(L)){let v=f.charAt(0).toUpperCase()+f.slice(1);console.log(` ${R(`LLM ${v}:`)}${" ".repeat(Math.max(1,10-v.length))}${b.provider} (${b.model})`)}if(Q.length>0?console.log(` ${R("Platforms:")} ${Q.map(f=>f.label).join(", ")}`):console.log(` ${R("Platforms:")} none (configure later)`),he){let f={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${U})`};console.log(` ${R("Web search:")} ${f[he]}`)}else console.log(` ${R("Web search:")} ${_("disabled")}`);if(Er&&Ne.length>0){let f=Ne.map(b=>b.provider==="microsoft"?`${b.name} (Microsoft 365)${b.msClientId?"":" \u2014 shared from Calendar"}`:`${b.name} (${b.imapHost})`);console.log(` ${R("Email:")} ${f.join(", ")}`)}else console.log(` ${R("Email:")} ${_("disabled")}`);if(De){let f={openai:"OpenAI Whisper",groq:"Groq Whisper"},b=as?`, TTS: ${cs}`:"";console.log(` ${R("Voice:")} ${f[De]}${b}`)}else console.log(` ${R("Voice:")} ${_("disabled")}`);console.log(` ${R("Code Sandbox:")} ${Ao?D("enabled"):_("disabled")}`),vr&&console.log(` ${R("Proxmox:")} ${D(ms)}`),hs&&console.log(` ${R("UniFi:")} ${D($t)}`),kr&&console.log(` ${R("Home Assist.:")} ${D(gs)}`),Ar&&console.log(` ${R("Contacts:")} ${D(ke)}`),Ir&&console.log(` ${R("Docker:")} ${D(rt||st)}`),xr&&console.log(` ${R("BMW CarData:")} ${D("enabled")}`),Rr&&console.log(` ${R("Routing:")} ${D("enabled")}`),_e&&(console.log(` ${R("Owner ID:")} ${_e}`),console.log(` ${R("Shell access:")} ${ws?D("enabled"):_("disabled")}`)),console.log(` ${R("Write scope:")} ${Ts?"DMs + Groups":"DMs only"}`),console.log(` ${R("Rate limit:")} ${Cr}/hour per user`),console.log(""),console.log(`${Eo}Next steps:${S}`),console.log(` ${R("alfred start")} Start Alfred`),console.log(` ${R("alfred status")} Check configuration`),console.log(` ${R("alfred --help")} Show all commands`),console.log(""),console.log(`${Je}Edit ${R(".env")}${Je} or ${R("config/default.yml")}${Je} for manual configuration.${S}`),console.log("")}finally{c.close()}}async function O(c,e,t){let s=(await c.question(`${q}${e}${S} ${_(`[${t}]`)}: ${M}`)).trim();return process.stdout.write(S),s||t}async function $e(c,e){for(;;){let t=(await c.question(`${q}${e}${S}: ${M}`)).trim();if(process.stdout.write(S),t)return t;console.log(` ${$l("!")} This field is required. Please enter a value.`)}}async function Tr(c,e,t,s,r){for(;;){let o=(await c.question(`${M}${e}${S}`)).trim();if(!o)return r;let n=parseInt(o,10);if(!Number.isNaN(n)&&n>=t&&n<=s)return n;console.log(` ${$l("!")} Please enter a number between ${t} and ${s}.`)}}function qm(){console.log(`
911
911
  ${Um}${q} _ _ _____ ____ _____ ____
912
912
  / \\ | | | ___| _ \\| ____| _ \\
913
913
  / _ \\ | | | |_ | |_) | _| | | | |
914
914
  / ___ \\| |___| _| | _ <| |___| |_| |
915
- /_/ \\_\\_____|_| |_| \\_\\_____|____/ ${v}
916
- ${Je} Personal AI Assistant \u2014 Setup Wizard${v}
917
- `)}var v,q,Je,_o,M,Eo,Pm,Um,ze,rs,bl,Sl=E(()=>{"use strict";_i();v="\x1B[0m",q="\x1B[1m",Je="\x1B[2m",_o="\x1B[32m",M="\x1B[33m",Eo="\x1B[36m",Pm="\x1B[31m",Um="\x1B[35m";u(D,"green");u(Fm,"yellow");u(le,"cyan");u($l,"red");u(R,"bold");u(w,"dim");u(me,"maskKey");ze=[{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"}]}],rs=[{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}]}];u(jm,"findCommand");bl=[{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"}];u(Bm,"loadExistingConfig");u(Hm,"setupCommand");u(O,"askWithDefault");u($e,"askRequired");u(Tr,"askNumber");u(qm,"printBanner")});var Al={};oe(Al,{configCommand:()=>Gm});function Wm(c){let e=c.toLowerCase();return zm.some(t=>e.includes(t))}function Vm(c){return typeof c!="string"||c.length===0?"(empty)":c.length<=8?"***":c.slice(0,4)+"..."+c.slice(-4)}function kl(c){let e={};for(let[t,s]of Object.entries(c))Wm(t)?e[t]=Vm(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=kl(s):e[t]=s;return e}async function Gm(){let c=new se,e;try{e=c.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=kl(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var zm,Il=E(()=>{"use strict";Be();zm=["token","apikey","api_key","accesstoken","secret","password"];u(Wm,"isSensitiveKey");u(Vm,"redactValue");u(kl,"redactObject");u(Gm,"configCommand")});var Rl={};oe(Rl,{rulesCommand:()=>Xm});import bo from"node:fs";import xl from"node:path";import Km from"js-yaml";async function Xm(){let c=new se,e;try{e=c.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=xl.resolve(e.security.rulesPath);if(!bo.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}bo.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=bo.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 o=new dt,n=[],i=[];for(let a of r){let l=xl.join(t,a);try{let d=bo.readFileSync(l,"utf-8"),m=Km.load(d),p=o.loadFromObject(m);n.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: ${n.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(n.length!==0){n.sort((a,l)=>a.priority-l.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of n){let l=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(", ")}${l}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var Cl=E(()=>{"use strict";Be();Pr();u(Xm,"rulesCommand")});var Ll={};oe(Ll,{statusCommand:()=>Jm});import _r from"node:fs";import bi from"node:path";import Ym from"js-yaml";async function Jm(){let c=new se,e;try{e=c.loadConfig()}catch(l){console.error("Failed to load configuration:",l.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 l of t){let d=l.enabled?"enabled":l.configured?"configured (disabled)":"not configured",m=l.enabled?"+":"-";console.log(` [${m}] ${l.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 l of["strong","fast","embeddings","local"]){let d=e.llm[l];d&&console.log(` ${l}: ${d.provider}/${d.model}`)}console.log(""),console.log("Storage:");let r=bi.resolve(e.storage.path),o=_r.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${o?"exists":"not yet created"}`),console.log("");let n=bi.resolve(e.security.rulesPath),i=0,a=0;if(_r.existsSync(n)&&_r.statSync(n).isDirectory()){let l=_r.readdirSync(n).filter(m=>m.endsWith(".yml")||m.endsWith(".yaml"));a=l.length;let d=new dt;for(let m of l){let p=bi.join(n,m);try{let T=_r.readFileSync(p,"utf-8"),y=Ym.load(T),f=d.loadFromObject(y);i+=f.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${n}`),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 Nl=E(()=>{"use strict";Be();Pr();u(Jm,"statusCommand")});var Ol={};oe(Ol,{authCommand:()=>pp});import{createServer as Zm}from"node:http";import{exec as Qm}from"node:child_process";import{readFileSync as ep,writeFileSync as tp,existsSync as sp}from"node:fs";import{createInterface as rp}from"node:readline";import{resolve as op}from"node:path";async function $i(c){let e=rp({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(c,s=>{e.close(),t(s.trim())})})}function ip(){let c={};try{let s=new se().loadConfig();for(let o of["email","calendar","contacts"]){let n=s[o];if(!n)continue;let i=n.microsoft;i&&(!c.clientId&&i.clientId&&(c.clientId=i.clientId),!c.clientSecret&&i.clientSecret&&(c.clientSecret=i.clientSecret),!c.tenantId&&i.tenantId&&(c.tenantId=i.tenantId))}let r=s.email;if(r?.accounts&&Array.isArray(r.accounts))for(let o of r.accounts){let n=o.microsoft;n&&(!c.clientId&&n.clientId&&(c.clientId=n.clientId),!c.clientSecret&&n.clientSecret&&(c.clientSecret=n.clientSecret),!c.tenantId&&n.tenantId&&(c.tenantId=n.tenantId))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS"];for(let t of e)c.clientId||(c.clientId=process.env[`${t}_CLIENT_ID`]),c.clientSecret||(c.clientSecret=process.env[`${t}_CLIENT_SECRET`]),c.tenantId||(c.tenantId=process.env[`${t}_TENANT_ID`]);return c}async function ap(){let c=ip(),e=c.clientId||await $i(" Client ID: "),t=c.clientSecret||await $i(" Client Secret: "),s=c.tenantId||await $i(' 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 cp(c){let e=new URLSearchParams({client_id:c.clientId,response_type:"code",redirect_uri:Dl,response_mode:"query",scope:Ml,prompt:"consent"});return`https://login.microsoftonline.com/${c.tenantId}/oauth2/v2.0/authorize?${e}`}async function lp(c,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:c,redirect_uri:Dl,grant_type:"authorization_code",scope:Ml}),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 o=await s.text();throw new Error(`Token-Austausch fehlgeschlagen (${s.status}): ${o}`)}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 dp(c){let t={win32:`start "" "${c}"`,darwin:`open "${c}"`,linux:`xdg-open "${c}"`}[process.platform];t&&Qm(t,()=>{})}function up(c,e){let t=op(process.cwd(),".env"),s=[];sp(t)&&(s=ep(t,"utf-8").split(`
915
+ /_/ \\_\\_____|_| |_| \\_\\_____|____/ ${S}
916
+ ${Je} Personal AI Assistant \u2014 Setup Wizard${S}
917
+ `)}var S,q,Je,_o,M,Eo,Pm,Um,ze,rs,bl,Sl=E(()=>{"use strict";_i();S="\x1B[0m",q="\x1B[1m",Je="\x1B[2m",_o="\x1B[32m",M="\x1B[33m",Eo="\x1B[36m",Pm="\x1B[31m",Um="\x1B[35m";u(D,"green");u(Fm,"yellow");u(le,"cyan");u($l,"red");u(R,"bold");u(_,"dim");u(me,"maskKey");ze=[{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"}]}],rs=[{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}]}];u(jm,"findCommand");bl=[{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"}];u(Bm,"loadExistingConfig");u(Hm,"setupCommand");u(O,"askWithDefault");u($e,"askRequired");u(Tr,"askNumber");u(qm,"printBanner")});var Al={};oe(Al,{configCommand:()=>Gm});function Wm(c){let e=c.toLowerCase();return zm.some(t=>e.includes(t))}function Vm(c){return typeof c!="string"||c.length===0?"(empty)":c.length<=8?"***":c.slice(0,4)+"..."+c.slice(-4)}function kl(c){let e={};for(let[t,s]of Object.entries(c))Wm(t)?e[t]=Vm(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=kl(s):e[t]=s;return e}async function Gm(){let c=new se,e;try{e=c.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=kl(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var zm,Il=E(()=>{"use strict";Be();zm=["token","apikey","api_key","accesstoken","secret","password"];u(Wm,"isSensitiveKey");u(Vm,"redactValue");u(kl,"redactObject");u(Gm,"configCommand")});var Rl={};oe(Rl,{rulesCommand:()=>Xm});import bo from"node:fs";import xl from"node:path";import Km from"js-yaml";async function Xm(){let c=new se,e;try{e=c.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=xl.resolve(e.security.rulesPath);if(!bo.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}bo.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=bo.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 o=new dt,n=[],i=[];for(let a of r){let l=xl.join(t,a);try{let d=bo.readFileSync(l,"utf-8"),m=Km.load(d),p=o.loadFromObject(m);n.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: ${n.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(n.length!==0){n.sort((a,l)=>a.priority-l.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of n){let l=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(", ")}${l}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var Cl=E(()=>{"use strict";Be();Pr();u(Xm,"rulesCommand")});var Ll={};oe(Ll,{statusCommand:()=>Jm});import _r from"node:fs";import bi from"node:path";import Ym from"js-yaml";async function Jm(){let c=new se,e;try{e=c.loadConfig()}catch(l){console.error("Failed to load configuration:",l.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 l of t){let d=l.enabled?"enabled":l.configured?"configured (disabled)":"not configured",m=l.enabled?"+":"-";console.log(` [${m}] ${l.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 l of["strong","fast","embeddings","local"]){let d=e.llm[l];d&&console.log(` ${l}: ${d.provider}/${d.model}`)}console.log(""),console.log("Storage:");let r=bi.resolve(e.storage.path),o=_r.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${o?"exists":"not yet created"}`),console.log("");let n=bi.resolve(e.security.rulesPath),i=0,a=0;if(_r.existsSync(n)&&_r.statSync(n).isDirectory()){let l=_r.readdirSync(n).filter(m=>m.endsWith(".yml")||m.endsWith(".yaml"));a=l.length;let d=new dt;for(let m of l){let p=bi.join(n,m);try{let w=_r.readFileSync(p,"utf-8"),y=Ym.load(w),h=d.loadFromObject(y);i+=h.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${n}`),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 Nl=E(()=>{"use strict";Be();Pr();u(Jm,"statusCommand")});var Ol={};oe(Ol,{authCommand:()=>pp});import{createServer as Zm}from"node:http";import{exec as Qm}from"node:child_process";import{readFileSync as ep,writeFileSync as tp,existsSync as sp}from"node:fs";import{createInterface as rp}from"node:readline";import{resolve as op}from"node:path";async function $i(c){let e=rp({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(c,s=>{e.close(),t(s.trim())})})}function ip(){let c={};try{let s=new se().loadConfig();for(let o of["email","calendar","contacts"]){let n=s[o];if(!n)continue;let i=n.microsoft;i&&(!c.clientId&&i.clientId&&(c.clientId=i.clientId),!c.clientSecret&&i.clientSecret&&(c.clientSecret=i.clientSecret),!c.tenantId&&i.tenantId&&(c.tenantId=i.tenantId))}let r=s.email;if(r?.accounts&&Array.isArray(r.accounts))for(let o of r.accounts){let n=o.microsoft;n&&(!c.clientId&&n.clientId&&(c.clientId=n.clientId),!c.clientSecret&&n.clientSecret&&(c.clientSecret=n.clientSecret),!c.tenantId&&n.tenantId&&(c.tenantId=n.tenantId))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS"];for(let t of e)c.clientId||(c.clientId=process.env[`${t}_CLIENT_ID`]),c.clientSecret||(c.clientSecret=process.env[`${t}_CLIENT_SECRET`]),c.tenantId||(c.tenantId=process.env[`${t}_TENANT_ID`]);return c}async function ap(){let c=ip(),e=c.clientId||await $i(" Client ID: "),t=c.clientSecret||await $i(" Client Secret: "),s=c.tenantId||await $i(' 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 cp(c){let e=new URLSearchParams({client_id:c.clientId,response_type:"code",redirect_uri:Dl,response_mode:"query",scope:Ml,prompt:"consent"});return`https://login.microsoftonline.com/${c.tenantId}/oauth2/v2.0/authorize?${e}`}async function lp(c,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:c,redirect_uri:Dl,grant_type:"authorization_code",scope:Ml}),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 o=await s.text();throw new Error(`Token-Austausch fehlgeschlagen (${s.status}): ${o}`)}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 dp(c){let t={win32:`start "" "${c}"`,darwin:`open "${c}"`,linux:`xdg-open "${c}"`}[process.platform];t&&Qm(t,()=>{})}function up(c,e){let t=op(process.cwd(),".env"),s=[];sp(t)&&(s=ep(t,"utf-8").split(`
918
918
  `));let r={ALFRED_EMAIL_PROVIDER:"microsoft",ALFRED_CALENDAR_PROVIDER:"microsoft",ALFRED_CONTACTS_PROVIDER:"microsoft",ALFRED_MICROSOFT_EMAIL_CLIENT_ID:c.clientId,ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:c.clientSecret,ALFRED_MICROSOFT_EMAIL_TENANT_ID:c.tenantId,ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:e,ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:c.clientId,ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:c.clientSecret,ALFRED_MICROSOFT_CALENDAR_TENANT_ID:c.tenantId,ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:e,ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:c.clientId,ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:c.clientSecret,ALFRED_MICROSOFT_CONTACTS_TENANT_ID:c.tenantId,ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:e},o=new Set(Object.keys(r));for(let i=0;i<s.length;i++){let a=s[i].match(/^#?\s*([A-Z_]+)=/);a&&o.has(a[1])&&(s[i]=`${a[1]}=${r[a[1]]}`,o.delete(a[1]))}if(o.size>0){s.length>0&&s[s.length-1]!==""&&s.push("");for(let i of o)s.push(`${i}=${r[i]}`)}let n=s.join(`
919
919
  `).replace(/\n*$/,`
920
920
  `);tp(t,n)}function mp(c){return new Promise((e,t)=>{let s=Zm(async(r,o)=>{let n=new URL(r.url??"/","http://localhost:3000");if(n.pathname!=="/callback"){o.writeHead(404),o.end("Not found");return}let i=n.searchParams.get("code"),a=n.searchParams.get("error");if(a){o.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),o.end(`<h1>Fehler: ${a}</h1><p>${n.searchParams.get("error_description")??""}</p>`),s.close(),t(new Error(`OAuth-Fehler: ${a}`));return}if(!i){o.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),o.end("<h1>Fehler: Kein Auth-Code erhalten</h1>");return}try{let l=await lp(i,c);o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(np),s.close(),e(l)}catch(l){o.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),o.end(`<h1>Fehler beim Token-Austausch</h1><p>${l.message}</p>`),s.close(),t(l)}});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 pp(c){c||(console.error("Usage: alfred auth <provider>"),console.error(" Unterst\xFCtzte Provider: microsoft"),process.exit(1)),c!=="microsoft"&&(console.error(`Unbekannter Provider: ${c}`),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 ap(),t=cp(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),dp(t);try{let s=await mp(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),up(e,s),console.log(" .env aktualisiert (Email, Calendar, Contacts)."),console.log(""),console.log(" Fertig! Du kannst Alfred jetzt mit Microsoft 365 nutzen."),console.log("")}catch(s){console.error(`