@madh-io/alfred-ai 0.9.99 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/index.js +144 -144
- package/package.json +1 -1
package/bundle/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var Hi=Object.defineProperty;var u=(c,e)=>Hi(c,"name",{value:e,configurable:!0});var b=(c,e)=>()=>(c&&(e=c(c=0)),e);var oe=(c,e)=>{for(var t in e)Hi(c,t,{get:e[t],enumerable:!0})};import{z as f}from"zod";var zi,Wi,Vi,Ki,Gi,Xi,Yi,Ji,it,gd,yd,wd,qi,Td,_d,bd,Ed,$d,vd,kd,Sd,Ad,Id,xd,Rd,Cd,Ld,Nd,Dd,Md,Od,Pd,Ud,Fd,jd,Bd,Hd,qd,zd,Wd,Vd,Qo,en=b(()=>{"use strict";zi=f.object({token:f.string().optional(),enabled:f.boolean()}),Wi=f.object({token:f.string().optional(),enabled:f.boolean()}),Vi=f.object({enabled:f.boolean(),dataPath:f.string()}),Ki=f.object({homeserverUrl:f.string(),accessToken:f.string().optional(),userId:f.string().optional(),enabled:f.boolean()}),Gi=f.object({apiUrl:f.string(),phoneNumber:f.string().optional(),enabled:f.boolean()}),Xi=f.object({path:f.string()}),Yi=f.object({level:f.enum(["trace","debug","info","warn","error","fatal"]),pretty:f.boolean(),auditLogPath:f.string().optional()}),Ji=f.object({rulesPath:f.string(),defaultEffect:f.enum(["allow","deny"]),ownerUserId:f.string().optional()}),it=f.object({provider:f.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:f.string().optional(),baseUrl:f.string().optional(),model:f.string(),temperature:f.number().optional(),maxTokens:f.number().optional()}),gd=f.object({default:it,strong:it.optional(),fast:it.optional(),embeddings:it.optional(),local:it.optional()}).passthrough(),yd=f.union([it,gd]),wd=f.object({provider:f.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:f.string().optional(),baseUrl:f.string().optional()}),qi=f.object({name:f.string().optional(),provider:f.enum(["imap-smtp","microsoft"]).optional(),imap:f.object({host:f.string(),port:f.number(),secure:f.boolean()}).optional(),smtp:f.object({host:f.string(),port:f.number(),secure:f.boolean()}).optional(),auth:f.object({user:f.string(),pass:f.string()}).optional(),microsoft:f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}).optional()}),Td=f.union([f.object({accounts:f.array(qi)}),qi]),_d=f.object({provider:f.enum(["openai","groq","google"]),apiKey:f.string(),baseUrl:f.string().optional(),ttsEnabled:f.boolean().optional(),ttsModel:f.string().optional(),ttsVoice:f.string().optional()}),bd=f.object({serverUrl:f.string(),username:f.string(),password:f.string()}),Ed=f.object({clientId:f.string(),clientSecret:f.string(),refreshToken:f.string()}),$d=f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}),vd=f.object({provider:f.enum(["caldav","google","microsoft"]),caldav:bd.optional(),google:Ed.optional(),microsoft:$d.optional()}),kd=f.object({name:f.string(),command:f.string().optional(),args:f.array(f.string()).optional(),env:f.record(f.string()).optional(),url:f.string().optional()}),Sd=f.object({servers:f.array(kd)}),Ad=f.object({enabled:f.boolean(),allowedLanguages:f.array(f.enum(["javascript","python"])).optional(),maxTimeoutMs:f.number().optional(),allowNetwork:f.boolean().optional()}),Id=f.object({enabled:f.boolean().optional(),minMessageLength:f.number().optional(),minConfidence:f.number().min(0).max(1).optional(),maxExtractionsPerMinute:f.number().optional()}),xd=f.object({enabled:f.boolean(),port:f.coerce.number().int().min(1).max(65535),host:f.string()}),Rd=f.object({name:f.string(),command:f.string(),argsTemplate:f.array(f.string()),promptVia:f.enum(["arg","stdin"]).default("arg"),env:f.record(f.string()).optional(),cwd:f.string().optional(),timeoutMs:f.number().max(9e5).optional()}),Cd=f.object({token:f.string(),baseUrl:f.string().optional()}),Ld=f.object({token:f.string(),baseUrl:f.string().optional()}),Nd=f.object({provider:f.enum(["github","gitlab"]),baseBranch:f.string().optional(),github:Cd.optional(),gitlab:Ld.optional()}),Dd=f.object({enabled:f.boolean(),agents:f.array(Rd),forge:Nd.optional()}),Md=f.object({baseUrl:f.string(),tokenId:f.string(),tokenSecret:f.string(),verifyTls:f.boolean().optional(),defaultNode:f.string().optional()}),Od=f.object({baseUrl:f.string(),apiKey:f.string().optional(),username:f.string().optional(),password:f.string().optional(),site:f.string().optional(),verifyTls:f.boolean().optional()}),Pd=f.object({baseUrl:f.string(),accessToken:f.string(),verifyTls:f.boolean().optional()}),Ud=f.object({serverUrl:f.string(),username:f.string(),password:f.string(),addressBookPath:f.string().optional()}),Fd=f.object({clientId:f.string(),clientSecret:f.string(),refreshToken:f.string()}),jd=f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}),Bd=f.object({provider:f.enum(["carddav","google","microsoft"]),carddav:Ud.optional(),google:Fd.optional(),microsoft:jd.optional()}),Hd=f.object({socketPath:f.string().optional(),host:f.string().optional(),verifyTls:f.boolean().optional()}),qd=f.object({clientId:f.string()}),zd=f.object({apiKey:f.string()}),Wd=f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}),Vd=f.object({maxHistoryMessages:f.number().min(10).max(500).optional()}).optional(),Qo=f.object({name:f.string(),telegram:zi,discord:Wi.optional(),whatsapp:Vi.optional(),matrix:Ki.optional(),signal:Gi.optional(),llm:yd,storage:Xi,logger:Yi,security:Ji,search:wd.optional(),email:Td.optional(),speech:_d.optional(),calendar:vd.optional(),mcp:Sd.optional(),codeSandbox:Ad.optional(),activeLearning:Id.optional(),api:xd.optional(),codeAgents:Dd.optional(),proxmox:Md.optional(),unifi:Od.optional(),homeassistant:Pd.optional(),contacts:Bd.optional(),docker:Hd.optional(),bmw:qd.optional(),routing:zd.optional(),todo:Wd.optional(),conversation:Vd})});var tn,sn=b(()=>{"use strict";tn={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 Zi from"node:fs";import Kd from"node:path";import{config as Qi}from"dotenv";import Gd from"js-yaml";function ea(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]=ea(o,r):t[s]=r}return t}function Yd(c){let e={...c};for(let[t,s]of Object.entries(Xd)){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 rn(){Qi({override:!0})}var Xd,re,ta=b(()=>{"use strict";en();sn();u(ea,"deepMerge");Xd={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],ALFRED_ANTHROPIC_API_KEY:["llm","apiKey"],ALFRED_OPENAI_API_KEY:["llm","apiKey"],ALFRED_GOOGLE_API_KEY:["llm","apiKey"],ALFRED_OPENROUTER_API_KEY:["llm","apiKey"],ALFRED_OPENWEBUI_API_KEY:["llm","apiKey"],ALFRED_LLM_PROVIDER:["llm","provider"],ALFRED_LLM_MODEL:["llm","model"],ALFRED_LLM_BASE_URL:["llm","baseUrl"],ALFRED_LLM_STRONG_PROVIDER:["llm","strong","provider"],ALFRED_LLM_STRONG_MODEL:["llm","strong","model"],ALFRED_LLM_STRONG_API_KEY:["llm","strong","apiKey"],ALFRED_LLM_FAST_PROVIDER:["llm","fast","provider"],ALFRED_LLM_FAST_MODEL:["llm","fast","model"],ALFRED_LLM_FAST_API_KEY:["llm","fast","apiKey"],ALFRED_LLM_EMBEDDINGS_PROVIDER:["llm","embeddings","provider"],ALFRED_LLM_EMBEDDINGS_MODEL:["llm","embeddings","model"],ALFRED_LLM_EMBEDDINGS_API_KEY:["llm","embeddings","apiKey"],ALFRED_LLM_LOCAL_PROVIDER:["llm","local","provider"],ALFRED_LLM_LOCAL_MODEL:["llm","local","model"],ALFRED_LLM_LOCAL_BASE_URL:["llm","local","baseUrl"],ALFRED_STORAGE_PATH:["storage","path"],ALFRED_LOG_LEVEL:["logger","level"],ALFRED_OWNER_USER_ID:["security","ownerUserId"],ALFRED_SEARCH_PROVIDER:["search","provider"],ALFRED_SEARCH_API_KEY:["search","apiKey"],ALFRED_SEARCH_BASE_URL:["search","baseUrl"],ALFRED_EMAIL_PROVIDER:["email","provider"],ALFRED_EMAIL_USER:["email","auth","user"],ALFRED_EMAIL_PASS:["email","auth","pass"],ALFRED_MICROSOFT_EMAIL_CLIENT_ID:["email","microsoft","clientId"],ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:["email","microsoft","clientSecret"],ALFRED_MICROSOFT_EMAIL_TENANT_ID:["email","microsoft","tenantId"],ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:["email","microsoft","refreshToken"],ALFRED_SPEECH_PROVIDER:["speech","provider"],ALFRED_SPEECH_API_KEY:["speech","apiKey"],ALFRED_SPEECH_BASE_URL:["speech","baseUrl"],ALFRED_CALENDAR_PROVIDER:["calendar","provider"],ALFRED_CALDAV_SERVER_URL:["calendar","caldav","serverUrl"],ALFRED_CALDAV_USERNAME:["calendar","caldav","username"],ALFRED_CALDAV_PASSWORD:["calendar","caldav","password"],ALFRED_GOOGLE_CALENDAR_CLIENT_ID:["calendar","google","clientId"],ALFRED_GOOGLE_CALENDAR_CLIENT_SECRET:["calendar","google","clientSecret"],ALFRED_GOOGLE_CALENDAR_REFRESH_TOKEN:["calendar","google","refreshToken"],ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:["calendar","microsoft","clientId"],ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:["calendar","microsoft","clientSecret"],ALFRED_MICROSOFT_CALENDAR_TENANT_ID:["calendar","microsoft","tenantId"],ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:["calendar","microsoft","refreshToken"],ALFRED_FORGE_PROVIDER:["codeAgents","forge","provider"],ALFRED_FORGE_BASE_BRANCH:["codeAgents","forge","baseBranch"],ALFRED_GITHUB_TOKEN:["codeAgents","forge","github","token"],ALFRED_GITHUB_BASE_URL:["codeAgents","forge","github","baseUrl"],ALFRED_GITLAB_TOKEN:["codeAgents","forge","gitlab","token"],ALFRED_GITLAB_BASE_URL:["codeAgents","forge","gitlab","baseUrl"],ALFRED_PROXMOX_BASE_URL:["proxmox","baseUrl"],ALFRED_PROXMOX_TOKEN_ID:["proxmox","tokenId"],ALFRED_PROXMOX_TOKEN_SECRET:["proxmox","tokenSecret"],ALFRED_UNIFI_BASE_URL:["unifi","baseUrl"],ALFRED_UNIFI_API_KEY:["unifi","apiKey"],ALFRED_UNIFI_USERNAME:["unifi","username"],ALFRED_UNIFI_PASSWORD:["unifi","password"],ALFRED_UNIFI_SITE:["unifi","site"],ALFRED_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],ALFRED_CONTACTS_PROVIDER:["contacts","provider"],ALFRED_CARDDAV_CONTACTS_SERVER_URL:["contacts","carddav","serverUrl"],ALFRED_CARDDAV_CONTACTS_USERNAME:["contacts","carddav","username"],ALFRED_CARDDAV_CONTACTS_PASSWORD:["contacts","carddav","password"],ALFRED_GOOGLE_CONTACTS_CLIENT_ID:["contacts","google","clientId"],ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET:["contacts","google","clientSecret"],ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN:["contacts","google","refreshToken"],ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:["contacts","microsoft","clientId"],ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:["contacts","microsoft","clientSecret"],ALFRED_MICROSOFT_CONTACTS_TENANT_ID:["contacts","microsoft","tenantId"],ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:["contacts","microsoft","refreshToken"],ALFRED_DOCKER_SOCKET_PATH:["docker","socketPath"],ALFRED_DOCKER_HOST:["docker","host"],ALFRED_BMW_CLIENT_ID:["bmw","clientId"],ALFRED_ROUTING_API_KEY:["routing","apiKey"],ALFRED_MICROSOFT_TODO_CLIENT_ID:["todo","clientId"],ALFRED_MICROSOFT_TODO_CLIENT_SECRET:["todo","clientSecret"],ALFRED_MICROSOFT_TODO_TENANT_ID:["todo","tenantId"],ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:["todo","refreshToken"]};u(Yd,"applyEnvOverrides");u(rn,"reloadDotenv");re=class{static{u(this,"ConfigLoader")}loadConfig(e){Qi();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Kd.resolve(t);if(Zi.existsSync(r)){let w=Zi.readFileSync(r,"utf-8"),y=Gd.load(w);y&&typeof y=="object"&&(s=y)}let o=ea(tn,s),n=Yd(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=Qo.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=b(()=>{"use strict";en();sn();ta()});import on from"pino";function bs(c,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=on.transport({target:"pino-pretty",options:{colorize:!0}});return on({name:c,level:t},r)}return on({name:c,level:t})}var sa=b(()=>{"use strict";u(bs,"createLogger")});import Zp from"pino";var ra=b(()=>{"use strict"});var nn=b(()=>{"use strict";sa();ra()});var kt,Mr=b(()=>{"use strict";kt=class{static{u(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
|
|
2
|
+
var Hi=Object.defineProperty;var u=(c,e)=>Hi(c,"name",{value:e,configurable:!0}),qi=(c=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(c,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):c)(function(c){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+c+'" is not supported')});var b=(c,e)=>()=>(c&&(e=c(c=0)),e);var oe=(c,e)=>{for(var t in e)Hi(c,t,{get:e[t],enumerable:!0})};import{z as f}from"zod";var Wi,Vi,Ki,Gi,Xi,Yi,Ji,Zi,it,yd,wd,Td,zi,_d,bd,Ed,$d,vd,kd,Sd,Ad,Id,xd,Rd,Cd,Ld,Nd,Dd,Md,Od,Pd,Ud,Fd,jd,Bd,Hd,qd,zd,Wd,Vd,Kd,en,tn=b(()=>{"use strict";Wi=f.object({token:f.string().optional(),enabled:f.boolean()}),Vi=f.object({token:f.string().optional(),enabled:f.boolean()}),Ki=f.object({enabled:f.boolean(),dataPath:f.string()}),Gi=f.object({homeserverUrl:f.string(),accessToken:f.string().optional(),userId:f.string().optional(),enabled:f.boolean()}),Xi=f.object({apiUrl:f.string(),phoneNumber:f.string().optional(),enabled:f.boolean()}),Yi=f.object({path:f.string()}),Ji=f.object({level:f.enum(["trace","debug","info","warn","error","fatal"]),pretty:f.boolean(),auditLogPath:f.string().optional()}),Zi=f.object({rulesPath:f.string(),defaultEffect:f.enum(["allow","deny"]),ownerUserId:f.string().optional()}),it=f.object({provider:f.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:f.string().optional(),baseUrl:f.string().optional(),model:f.string(),temperature:f.number().optional(),maxTokens:f.number().optional()}),yd=f.object({default:it,strong:it.optional(),fast:it.optional(),embeddings:it.optional(),local:it.optional()}).passthrough(),wd=f.union([it,yd]),Td=f.object({provider:f.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:f.string().optional(),baseUrl:f.string().optional()}),zi=f.object({name:f.string().optional(),provider:f.enum(["imap-smtp","microsoft"]).optional(),imap:f.object({host:f.string(),port:f.number(),secure:f.boolean()}).optional(),smtp:f.object({host:f.string(),port:f.number(),secure:f.boolean()}).optional(),auth:f.object({user:f.string(),pass:f.string()}).optional(),microsoft:f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}).optional()}),_d=f.union([f.object({accounts:f.array(zi)}),zi]),bd=f.object({provider:f.enum(["openai","groq","google"]),apiKey:f.string(),baseUrl:f.string().optional(),ttsEnabled:f.boolean().optional(),ttsModel:f.string().optional(),ttsVoice:f.string().optional()}),Ed=f.object({serverUrl:f.string(),username:f.string(),password:f.string()}),$d=f.object({clientId:f.string(),clientSecret:f.string(),refreshToken:f.string()}),vd=f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}),kd=f.object({provider:f.enum(["caldav","google","microsoft"]),caldav:Ed.optional(),google:$d.optional(),microsoft:vd.optional()}),Sd=f.object({name:f.string(),command:f.string().optional(),args:f.array(f.string()).optional(),env:f.record(f.string()).optional(),url:f.string().optional()}),Ad=f.object({servers:f.array(Sd)}),Id=f.object({enabled:f.boolean(),allowedLanguages:f.array(f.enum(["javascript","python"])).optional(),maxTimeoutMs:f.number().optional(),allowNetwork:f.boolean().optional()}),xd=f.object({enabled:f.boolean().optional(),minMessageLength:f.number().optional(),minConfidence:f.number().min(0).max(1).optional(),maxExtractionsPerMinute:f.number().optional()}),Rd=f.object({enabled:f.boolean(),port:f.coerce.number().int().min(1).max(65535),host:f.string()}),Cd=f.object({name:f.string(),command:f.string(),argsTemplate:f.array(f.string()),promptVia:f.enum(["arg","stdin"]).default("arg"),env:f.record(f.string()).optional(),cwd:f.string().optional(),timeoutMs:f.number().max(9e5).optional()}),Ld=f.object({token:f.string(),baseUrl:f.string().optional()}),Nd=f.object({token:f.string(),baseUrl:f.string().optional()}),Dd=f.object({provider:f.enum(["github","gitlab"]),baseBranch:f.string().optional(),github:Ld.optional(),gitlab:Nd.optional()}),Md=f.object({enabled:f.boolean(),agents:f.array(Cd),forge:Dd.optional()}),Od=f.object({baseUrl:f.string(),tokenId:f.string(),tokenSecret:f.string(),verifyTls:f.boolean().optional(),defaultNode:f.string().optional()}),Pd=f.object({baseUrl:f.string(),apiKey:f.string().optional(),username:f.string().optional(),password:f.string().optional(),site:f.string().optional(),verifyTls:f.boolean().optional()}),Ud=f.object({baseUrl:f.string(),accessToken:f.string(),verifyTls:f.boolean().optional()}),Fd=f.object({serverUrl:f.string(),username:f.string(),password:f.string(),addressBookPath:f.string().optional()}),jd=f.object({clientId:f.string(),clientSecret:f.string(),refreshToken:f.string()}),Bd=f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}),Hd=f.object({provider:f.enum(["carddav","google","microsoft"]),carddav:Fd.optional(),google:jd.optional(),microsoft:Bd.optional()}),qd=f.object({socketPath:f.string().optional(),host:f.string().optional(),verifyTls:f.boolean().optional()}),zd=f.object({clientId:f.string()}),Wd=f.object({apiKey:f.string()}),Vd=f.object({clientId:f.string(),clientSecret:f.string(),tenantId:f.string(),refreshToken:f.string()}),Kd=f.object({maxHistoryMessages:f.number().min(10).max(500).optional()}).optional(),en=f.object({name:f.string(),telegram:Wi,discord:Vi.optional(),whatsapp:Ki.optional(),matrix:Gi.optional(),signal:Xi.optional(),llm:wd,storage:Yi,logger:Ji,security:Zi,search:Td.optional(),email:_d.optional(),speech:bd.optional(),calendar:kd.optional(),mcp:Ad.optional(),codeSandbox:Id.optional(),activeLearning:xd.optional(),api:Rd.optional(),codeAgents:Md.optional(),proxmox:Od.optional(),unifi:Pd.optional(),homeassistant:Ud.optional(),contacts:Hd.optional(),docker:qd.optional(),bmw:zd.optional(),routing:Wd.optional(),todo:Vd.optional(),conversation:Kd})});var sn,rn=b(()=>{"use strict";sn={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 Qi from"node:fs";import Gd from"node:path";import{config as ea}from"dotenv";import Xd from"js-yaml";function ta(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]=ta(o,r):t[s]=r}return t}function Jd(c){let e={...c};for(let[t,s]of Object.entries(Yd)){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 on(){ea({override:!0})}var Yd,re,sa=b(()=>{"use strict";tn();rn();u(ta,"deepMerge");Yd={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],ALFRED_ANTHROPIC_API_KEY:["llm","apiKey"],ALFRED_OPENAI_API_KEY:["llm","apiKey"],ALFRED_GOOGLE_API_KEY:["llm","apiKey"],ALFRED_OPENROUTER_API_KEY:["llm","apiKey"],ALFRED_OPENWEBUI_API_KEY:["llm","apiKey"],ALFRED_LLM_PROVIDER:["llm","provider"],ALFRED_LLM_MODEL:["llm","model"],ALFRED_LLM_BASE_URL:["llm","baseUrl"],ALFRED_LLM_STRONG_PROVIDER:["llm","strong","provider"],ALFRED_LLM_STRONG_MODEL:["llm","strong","model"],ALFRED_LLM_STRONG_API_KEY:["llm","strong","apiKey"],ALFRED_LLM_FAST_PROVIDER:["llm","fast","provider"],ALFRED_LLM_FAST_MODEL:["llm","fast","model"],ALFRED_LLM_FAST_API_KEY:["llm","fast","apiKey"],ALFRED_LLM_EMBEDDINGS_PROVIDER:["llm","embeddings","provider"],ALFRED_LLM_EMBEDDINGS_MODEL:["llm","embeddings","model"],ALFRED_LLM_EMBEDDINGS_API_KEY:["llm","embeddings","apiKey"],ALFRED_LLM_LOCAL_PROVIDER:["llm","local","provider"],ALFRED_LLM_LOCAL_MODEL:["llm","local","model"],ALFRED_LLM_LOCAL_BASE_URL:["llm","local","baseUrl"],ALFRED_STORAGE_PATH:["storage","path"],ALFRED_LOG_LEVEL:["logger","level"],ALFRED_OWNER_USER_ID:["security","ownerUserId"],ALFRED_SEARCH_PROVIDER:["search","provider"],ALFRED_SEARCH_API_KEY:["search","apiKey"],ALFRED_SEARCH_BASE_URL:["search","baseUrl"],ALFRED_EMAIL_PROVIDER:["email","provider"],ALFRED_EMAIL_USER:["email","auth","user"],ALFRED_EMAIL_PASS:["email","auth","pass"],ALFRED_MICROSOFT_EMAIL_CLIENT_ID:["email","microsoft","clientId"],ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:["email","microsoft","clientSecret"],ALFRED_MICROSOFT_EMAIL_TENANT_ID:["email","microsoft","tenantId"],ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:["email","microsoft","refreshToken"],ALFRED_SPEECH_PROVIDER:["speech","provider"],ALFRED_SPEECH_API_KEY:["speech","apiKey"],ALFRED_SPEECH_BASE_URL:["speech","baseUrl"],ALFRED_CALENDAR_PROVIDER:["calendar","provider"],ALFRED_CALDAV_SERVER_URL:["calendar","caldav","serverUrl"],ALFRED_CALDAV_USERNAME:["calendar","caldav","username"],ALFRED_CALDAV_PASSWORD:["calendar","caldav","password"],ALFRED_GOOGLE_CALENDAR_CLIENT_ID:["calendar","google","clientId"],ALFRED_GOOGLE_CALENDAR_CLIENT_SECRET:["calendar","google","clientSecret"],ALFRED_GOOGLE_CALENDAR_REFRESH_TOKEN:["calendar","google","refreshToken"],ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:["calendar","microsoft","clientId"],ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:["calendar","microsoft","clientSecret"],ALFRED_MICROSOFT_CALENDAR_TENANT_ID:["calendar","microsoft","tenantId"],ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:["calendar","microsoft","refreshToken"],ALFRED_FORGE_PROVIDER:["codeAgents","forge","provider"],ALFRED_FORGE_BASE_BRANCH:["codeAgents","forge","baseBranch"],ALFRED_GITHUB_TOKEN:["codeAgents","forge","github","token"],ALFRED_GITHUB_BASE_URL:["codeAgents","forge","github","baseUrl"],ALFRED_GITLAB_TOKEN:["codeAgents","forge","gitlab","token"],ALFRED_GITLAB_BASE_URL:["codeAgents","forge","gitlab","baseUrl"],ALFRED_PROXMOX_BASE_URL:["proxmox","baseUrl"],ALFRED_PROXMOX_TOKEN_ID:["proxmox","tokenId"],ALFRED_PROXMOX_TOKEN_SECRET:["proxmox","tokenSecret"],ALFRED_UNIFI_BASE_URL:["unifi","baseUrl"],ALFRED_UNIFI_API_KEY:["unifi","apiKey"],ALFRED_UNIFI_USERNAME:["unifi","username"],ALFRED_UNIFI_PASSWORD:["unifi","password"],ALFRED_UNIFI_SITE:["unifi","site"],ALFRED_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],ALFRED_CONTACTS_PROVIDER:["contacts","provider"],ALFRED_CARDDAV_CONTACTS_SERVER_URL:["contacts","carddav","serverUrl"],ALFRED_CARDDAV_CONTACTS_USERNAME:["contacts","carddav","username"],ALFRED_CARDDAV_CONTACTS_PASSWORD:["contacts","carddav","password"],ALFRED_GOOGLE_CONTACTS_CLIENT_ID:["contacts","google","clientId"],ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET:["contacts","google","clientSecret"],ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN:["contacts","google","refreshToken"],ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:["contacts","microsoft","clientId"],ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:["contacts","microsoft","clientSecret"],ALFRED_MICROSOFT_CONTACTS_TENANT_ID:["contacts","microsoft","tenantId"],ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:["contacts","microsoft","refreshToken"],ALFRED_DOCKER_SOCKET_PATH:["docker","socketPath"],ALFRED_DOCKER_HOST:["docker","host"],ALFRED_BMW_CLIENT_ID:["bmw","clientId"],ALFRED_ROUTING_API_KEY:["routing","apiKey"],ALFRED_MICROSOFT_TODO_CLIENT_ID:["todo","clientId"],ALFRED_MICROSOFT_TODO_CLIENT_SECRET:["todo","clientSecret"],ALFRED_MICROSOFT_TODO_TENANT_ID:["todo","tenantId"],ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:["todo","refreshToken"]};u(Jd,"applyEnvOverrides");u(on,"reloadDotenv");re=class{static{u(this,"ConfigLoader")}loadConfig(e){ea();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Gd.resolve(t);if(Qi.existsSync(r)){let w=Qi.readFileSync(r,"utf-8"),y=Xd.load(w);y&&typeof y=="object"&&(s=y)}let o=ta(sn,s),n=Jd(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=en.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=b(()=>{"use strict";tn();rn();sa()});import nn 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=nn.transport({target:"pino-pretty",options:{colorize:!0}});return nn({name:c,level:t},r)}return nn({name:c,level:t})}var ra=b(()=>{"use strict";u(Es,"createLogger")});import Qp from"pino";var oa=b(()=>{"use strict"});var an=b(()=>{"use strict";ra();oa()});var kt,Or=b(()=>{"use strict";kt=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,
|
|
6
6
|
applied_at TEXT NOT NULL
|
|
7
7
|
)
|
|
8
|
-
`)}getCurrentVersion(){return this.db.prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}migrate(e){let t=[...e].sort((r,o)=>r.version-o.version),s=this.getCurrentVersion();for(let r of t){if(r.version<=s)continue;this.db.transaction(()=>{r.up(this.db),this.db.prepare("INSERT INTO _migrations (version, description, applied_at) VALUES (?, ?, ?)").run(r.version,r.description,new Date().toISOString())})()}}getAppliedMigrations(){return this.db.prepare("SELECT version, applied_at FROM _migrations ORDER BY version ASC").all().map(t=>({version:t.version,appliedAt:t.applied_at}))}}});var
|
|
8
|
+
`)}getCurrentVersion(){return this.db.prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}migrate(e){let t=[...e].sort((r,o)=>r.version-o.version),s=this.getCurrentVersion();for(let r of t){if(r.version<=s)continue;this.db.transaction(()=>{r.up(this.db),this.db.prepare("INSERT INTO _migrations (version, description, applied_at) VALUES (?, ?, ?)").run(r.version,r.description,new Date().toISOString())})()}}getAppliedMigrations(){return this.db.prepare("SELECT version, applied_at FROM _migrations ORDER BY version ASC").all().map(t=>({version:t.version,appliedAt:t.applied_at}))}}});var cn,ln=b(()=>{"use strict";Or();cn=[{version:1,description:"Initial schema \u2014 conversations, messages, users, audit_log",up(c){}},{version:2,description:"Add plugin_skills table for tracking loaded external plugins",up(c){c.exec(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS plugin_skills (
|
|
10
10
|
name TEXT PRIMARY KEY,
|
|
11
11
|
file_path TEXT NOT NULL,
|
|
@@ -209,7 +209,7 @@ var Hi=Object.defineProperty;var u=(c,e)=>Hi(c,"name",{value:e,configurable:!0})
|
|
|
209
209
|
|
|
210
210
|
CREATE INDEX IF NOT EXISTS idx_todos_user_due
|
|
211
211
|
ON todos(user_id, completed, due_date);
|
|
212
|
-
`)}}]});import
|
|
212
|
+
`)}}]});import Zd from"better-sqlite3";import Qd from"node:fs";import eu from"node:path";var at,na=b(()=>{"use strict";Or();ln();at=class{static{u(this,"Database")}db;constructor(e){let t=eu.dirname(e);Qd.mkdirSync(t,{recursive:!0}),this.db=new Zd(e),this.db.pragma("journal_mode = WAL"),this.db.pragma("foreign_keys = ON"),this.db.pragma("busy_timeout = 5000"),this.initTables(),this.runMigrations()}initTables(){this.db.exec(`
|
|
213
213
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
214
214
|
id TEXT PRIMARY KEY,
|
|
215
215
|
platform TEXT NOT NULL,
|
|
@@ -259,23 +259,23 @@ var Hi=Object.defineProperty;var u=(c,e)=>Hi(c,"name",{value:e,configurable:!0})
|
|
|
259
259
|
|
|
260
260
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_platform
|
|
261
261
|
ON users(platform, platform_user_id);
|
|
262
|
-
`)}runMigrations(){new kt(this.db).migrate(
|
|
262
|
+
`)}runMigrations(){new kt(this.db).migrate(cn)}getDb(){return this.db}close(){this.db.close()}}});import ia from"node:crypto";var $s,aa=b(()=>{"use strict";$s=class{static{u(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),o={id:ia.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
|
|
263
263
|
INSERT INTO conversations (id, platform, chat_id, user_id, created_at, updated_at)
|
|
264
264
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
265
|
-
`).run(o.id,o.platform,o.chatId,o.userId,o.createdAt,o.updatedAt),o}findById(e){let t=this.db.prepare("SELECT * FROM conversations WHERE id = ?").get(e);if(t)return this.mapRow(t)}findByPlatformChat(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND chat_id = ?").get(e,t);if(s)return this.mapRow(s)}findByPlatformAndUser(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND user_id = ? ORDER BY updated_at DESC LIMIT 1").get(e,t);if(s)return this.mapRow(s)}addMessage(e,t,s,r){let o={id:
|
|
265
|
+
`).run(o.id,o.platform,o.chatId,o.userId,o.createdAt,o.updatedAt),o}findById(e){let t=this.db.prepare("SELECT * FROM conversations WHERE id = ?").get(e);if(t)return this.mapRow(t)}findByPlatformChat(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND chat_id = ?").get(e,t);if(s)return this.mapRow(s)}findByPlatformAndUser(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND user_id = ? ORDER BY updated_at DESC LIMIT 1").get(e,t);if(s)return this.mapRow(s)}addMessage(e,t,s,r){let o={id:ia.randomUUID(),conversationId:e,role:t,content:s,toolCalls:r,createdAt:new Date().toISOString()};return this.db.prepare(`
|
|
266
266
|
INSERT INTO messages (id, conversation_id, role, content, tool_calls, created_at)
|
|
267
267
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
268
268
|
`).run(o.id,o.conversationId,o.role,o.content,o.toolCalls??null,o.createdAt),o}getMessages(e,t=50){return this.db.prepare("SELECT * FROM (SELECT *, rowid AS _rn FROM messages WHERE conversation_id = ? ORDER BY created_at DESC, _rn DESC LIMIT ?) ORDER BY created_at ASC, _rn ASC").all(e,t).map(r=>({id:r.id,conversationId:r.conversation_id,role:r.role,content:r.content,toolCalls:r.tool_calls??void 0,createdAt:r.created_at}))}updateTimestamp(e){this.db.prepare("UPDATE conversations SET updated_at = ? WHERE id = ?").run(new Date().toISOString(),e)}pruneMessages(e,t){return this.db.prepare(`
|
|
269
269
|
DELETE FROM messages WHERE conversation_id = ? AND id NOT IN (
|
|
270
270
|
SELECT id FROM messages WHERE conversation_id = ? ORDER BY created_at DESC LIMIT ?
|
|
271
271
|
)
|
|
272
|
-
`).run(e,e,t).changes}mapRow(e){return{id:e.id,platform:e.platform,chatId:e.chat_id,userId:e.user_id,createdAt:e.created_at,updatedAt:e.updated_at}}}});import
|
|
272
|
+
`).run(e,e,t).changes}mapRow(e){return{id:e.id,platform:e.platform,chatId:e.chat_id,userId:e.user_id,createdAt:e.created_at,updatedAt:e.updated_at}}}});import tu from"node:crypto";var vs,ca=b(()=>{"use strict";vs=class{static{u(this,"UserRepository")}db;constructor(e){this.db=e}findOrCreate(e,t,s,r){let o=this.db.prepare("SELECT * FROM users WHERE platform = ? AND platform_user_id = ?").get(e,t);if(o)return this.mapRow(o);let n=new Date().toISOString(),i={id:tu.randomUUID(),platform:e,platformUserId:t,username:s,displayName:r,createdAt:n,updatedAt:n};return this.db.prepare(`
|
|
273
273
|
INSERT INTO users (id, platform, platform_user_id, username, display_name, created_at, updated_at)
|
|
274
274
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
275
|
-
`).run(i.id,i.platform,i.platformUserId,i.username??null,i.displayName??null,i.createdAt,i.updatedAt),i}findById(e){let t=this.db.prepare("SELECT * FROM users WHERE id = ?").get(e);if(t)return this.mapRow(t)}update(e,t){let s=[],r=[];t.username!==void 0&&(s.push("username = ?"),r.push(t.username??null)),t.displayName!==void 0&&(s.push("display_name = ?"),r.push(t.displayName??null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}updateProfile(e,t){let s=[],r=[];t.timezone!==void 0&&(s.push("timezone = ?"),r.push(t.timezone??null)),t.language!==void 0&&(s.push("language = ?"),r.push(t.language??null)),t.bio!==void 0&&(s.push("bio = ?"),r.push(t.bio??null)),t.preferences!==void 0&&(s.push("preferences = ?"),r.push(t.preferences?JSON.stringify(t.preferences):null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}getProfile(e){let t=this.db.prepare("SELECT display_name, timezone, language, bio, preferences FROM users WHERE id = ?").get(e);if(t)return{displayName:t.display_name??void 0,timezone:t.timezone??void 0,language:t.language??void 0,bio:t.bio??void 0,preferences:t.preferences?JSON.parse(t.preferences):void 0}}setMasterUser(e,t){this.db.prepare("UPDATE users SET master_user_id = ?, updated_at = ? WHERE id = ?").run(t,new Date().toISOString(),e)}getLinkedUsers(e){return this.db.prepare("SELECT DISTINCT * FROM users WHERE master_user_id = ? OR id = ?").all(e,e).map(s=>this.mapRow(s))}findFirstByPlatformNotIn(e){let t=e.map(()=>"?").join(", "),s=this.db.prepare(`SELECT * FROM users WHERE platform NOT IN (${t}) LIMIT 1`).get(...e);if(s)return this.mapRow(s)}getMasterUserId(e){return this.db.prepare("SELECT master_user_id FROM users WHERE id = ?").get(e)?.master_user_id??e}mapRow(e){return{id:e.id,platform:e.platform,platformUserId:e.platform_user_id,username:e.username??void 0,displayName:e.display_name??void 0,timezone:e.timezone??void 0,language:e.language??void 0,bio:e.bio??void 0,preferences:e.preferences?JSON.parse(e.preferences):void 0,masterUserId:e.master_user_id??void 0,createdAt:e.created_at,updatedAt:e.updated_at}}}});var ct,
|
|
275
|
+
`).run(i.id,i.platform,i.platformUserId,i.username??null,i.displayName??null,i.createdAt,i.updatedAt),i}findById(e){let t=this.db.prepare("SELECT * FROM users WHERE id = ?").get(e);if(t)return this.mapRow(t)}update(e,t){let s=[],r=[];t.username!==void 0&&(s.push("username = ?"),r.push(t.username??null)),t.displayName!==void 0&&(s.push("display_name = ?"),r.push(t.displayName??null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}updateProfile(e,t){let s=[],r=[];t.timezone!==void 0&&(s.push("timezone = ?"),r.push(t.timezone??null)),t.language!==void 0&&(s.push("language = ?"),r.push(t.language??null)),t.bio!==void 0&&(s.push("bio = ?"),r.push(t.bio??null)),t.preferences!==void 0&&(s.push("preferences = ?"),r.push(t.preferences?JSON.stringify(t.preferences):null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}getProfile(e){let t=this.db.prepare("SELECT display_name, timezone, language, bio, preferences FROM users WHERE id = ?").get(e);if(t)return{displayName:t.display_name??void 0,timezone:t.timezone??void 0,language:t.language??void 0,bio:t.bio??void 0,preferences:t.preferences?JSON.parse(t.preferences):void 0}}setMasterUser(e,t){this.db.prepare("UPDATE users SET master_user_id = ?, updated_at = ? WHERE id = ?").run(t,new Date().toISOString(),e)}getLinkedUsers(e){return this.db.prepare("SELECT DISTINCT * FROM users WHERE master_user_id = ? OR id = ?").all(e,e).map(s=>this.mapRow(s))}findFirstByPlatformNotIn(e){let t=e.map(()=>"?").join(", "),s=this.db.prepare(`SELECT * FROM users WHERE platform NOT IN (${t}) LIMIT 1`).get(...e);if(s)return this.mapRow(s)}getMasterUserId(e){return this.db.prepare("SELECT master_user_id FROM users WHERE id = ?").get(e)?.master_user_id??e}mapRow(e){return{id:e.id,platform:e.platform,platformUserId:e.platform_user_id,username:e.username??void 0,displayName:e.display_name??void 0,timezone:e.timezone??void 0,language:e.language??void 0,bio:e.bio??void 0,preferences:e.preferences?JSON.parse(e.preferences):void 0,masterUserId:e.master_user_id??void 0,createdAt:e.created_at,updatedAt:e.updated_at}}}});var ct,la=b(()=>{"use strict";ct=class{static{u(this,"AuditRepository")}db;constructor(e){this.db=e}log(e){this.db.prepare(`
|
|
276
276
|
INSERT INTO audit_log (id, timestamp, user_id, action, risk_level, rule_id, effect, platform, chat_id, context)
|
|
277
277
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
278
|
-
`).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",o=e.limit??100;return s.push(o),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}mapRow(e){return{id:e.id,timestamp:new Date(e.timestamp),userId:e.user_id,action:e.action,riskLevel:e.risk_level,ruleId:e.rule_id??void 0,effect:e.effect,platform:e.platform,chatId:e.chat_id??void 0,context:e.context?JSON.parse(e.context):void 0}}}});import{randomUUID as
|
|
278
|
+
`).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",o=e.limit??100;return s.push(o),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}mapRow(e){return{id:e.id,timestamp:new Date(e.timestamp),userId:e.user_id,action:e.action,riskLevel:e.risk_level,ruleId:e.rule_id??void 0,effect:e.effect,platform:e.platform,chatId:e.chat_id??void 0,context:e.context?JSON.parse(e.context):void 0}}}});import{randomUUID as su}from"node:crypto";var ks,da=b(()=>{"use strict";ks=class{static{u(this,"MemoryRepository")}db;constructor(e){this.db=e}save(e,t,s,r="general"){return this.saveWithMetadata(e,t,s,r,"general",1,"manual")}saveWithMetadata(e,t,s,r,o,n,i){let a=new Date().toISOString(),l=su();this.db.prepare(`INSERT INTO memories (id, user_id, key, value, category, type, confidence, source, created_at, updated_at)
|
|
279
279
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
280
280
|
ON CONFLICT(user_id, key) DO UPDATE SET
|
|
281
281
|
value = excluded.value,
|
|
@@ -283,13 +283,13 @@ var Hi=Object.defineProperty;var u=(c,e)=>Hi(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 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
|
|
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 ru}from"node:crypto";var Ss,ua=b(()=>{"use strict";Ss=class{static{u(this,"ReminderRepository")}db;constructor(e){this.db=e}create(e,t,s,r,o){let n={id:ru(),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
|
-
`).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
|
|
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 ou}from"node:crypto";var As,ma=b(()=>{"use strict";As=class{static{u(this,"NoteRepository")}db;constructor(e){this.db=e}save(e,t,s){let r=new Date().toISOString(),o=ou();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 nu}from"node:crypto";var Is,pa=b(()=>{"use strict";Is=class{static{u(this,"EmbeddingRepository")}db;constructor(e){this.db=e}store(e){let t=nu(),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 iu from"node:crypto";var xs,ha=b(()=>{"use strict";xs=class{static{u(this,"LinkTokenRepository")}db;constructor(e){this.db=e}create(e,t){for(let s=0;s<5;s++){let r={id:iu.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(`
|
|
290
290
|
INSERT INTO link_tokens (id, code, user_id, platform, created_at, expires_at)
|
|
291
291
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
292
|
-
`).run(r.id,r.code,r.userId,r.platform,r.createdAt,r.expiresAt),r}catch(o){if(!(o instanceof Error?o.message:"").includes("UNIQUE")||s===4)throw o}}throw new Error("Failed to generate unique link code after retries")}findByCode(e){let t=this.db.prepare("SELECT * FROM link_tokens WHERE code = ? AND expires_at > ?").get(e,new Date().toISOString());if(t)return{id:t.id,code:t.code,userId:t.user_id,platform:t.platform,createdAt:t.created_at,expiresAt:t.expires_at}}consume(e){this.db.prepare("DELETE FROM link_tokens WHERE id = ?").run(e)}countRecentByUser(e,t=10){let s=new Date(Date.now()-t*6e4).toISOString();return this.db.prepare("SELECT COUNT(*) as cnt FROM link_tokens WHERE user_id = ? AND created_at > ?").get(e,s).cnt}cleanup(){this.db.prepare("DELETE FROM link_tokens WHERE expires_at <= ?").run(new Date().toISOString())}}});import{randomUUID as
|
|
292
|
+
`).run(r.id,r.code,r.userId,r.platform,r.createdAt,r.expiresAt),r}catch(o){if(!(o instanceof Error?o.message:"").includes("UNIQUE")||s===4)throw o}}throw new Error("Failed to generate unique link code after retries")}findByCode(e){let t=this.db.prepare("SELECT * FROM link_tokens WHERE code = ? AND expires_at > ?").get(e,new Date().toISOString());if(t)return{id:t.id,code:t.code,userId:t.user_id,platform:t.platform,createdAt:t.created_at,expiresAt:t.expires_at}}consume(e){this.db.prepare("DELETE FROM link_tokens WHERE id = ?").run(e)}countRecentByUser(e,t=10){let s=new Date(Date.now()-t*6e4).toISOString();return this.db.prepare("SELECT COUNT(*) as cnt FROM link_tokens WHERE user_id = ? AND created_at > ?").get(e,s).cnt}cleanup(){this.db.prepare("DELETE FROM link_tokens WHERE expires_at <= ?").run(new Date().toISOString())}}});import{randomUUID as au}from"node:crypto";var Rs,fa=b(()=>{"use strict";Rs=class{static{u(this,"BackgroundTaskRepository")}db;constructor(e){this.db=e}create(e,t,s,r,o,n){let i={id:au(),userId:e,platform:t,chatId:s,description:r,skillName:o,skillInput:n,status:"pending",createdAt:new Date().toISOString()};return this.db.prepare(`
|
|
293
293
|
INSERT INTO background_tasks (id, user_id, platform, chat_id, description, skill_name, skill_input, status, created_at)
|
|
294
294
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
295
295
|
`).run(i.id,i.userId,i.platform,i.chatId,i.description,i.skillName,i.skillInput,i.status,i.createdAt),i}updateStatus(e,t,s,r){let o=new Date().toISOString(),n=null,i=null;t==="running"&&(n=o),(t==="completed"||t==="failed")&&(i=o),this.db.prepare(`
|
|
@@ -305,7 +305,7 @@ var Hi=Object.defineProperty;var u=(c,e)=>Hi(c,"name",{value:e,configurable:!0})
|
|
|
305
305
|
AND (status IN ('pending', 'running') OR completed_at > datetime('now', '-1 day'))
|
|
306
306
|
ORDER BY created_at DESC`).all(e).map(s=>this.mapRow(s))}cancel(e){return this.db.prepare("DELETE FROM background_tasks WHERE id = ? AND status IN ('pending', 'running')").run(e).changes>0}cleanup(e=7){return this.db.prepare(`DELETE FROM background_tasks
|
|
307
307
|
WHERE status IN ('completed', 'failed')
|
|
308
|
-
AND completed_at < datetime('now', '-' || ? || ' days')`).run(e).changes}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at}}}});import{randomUUID as
|
|
308
|
+
AND completed_at < datetime('now', '-' || ? || ' days')`).run(e).changes}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at}}}});import{randomUUID as cu}from"node:crypto";var Cs,ga=b(()=>{"use strict";Cs=class{static{u(this,"ScheduledActionRepository")}db;constructor(e){this.db=e}create(e){let t=new Date().toISOString(),s=cu(),r=this.calculateInitialNextRun(e.scheduleType,e.scheduleValue);return this.db.prepare(`
|
|
309
309
|
INSERT INTO scheduled_actions
|
|
310
310
|
(id, user_id, platform, chat_id, name, description, schedule_type, schedule_value,
|
|
311
311
|
skill_name, skill_input, prompt_template, enabled, next_run_at, created_at)
|
|
@@ -316,13 +316,13 @@ var Hi=Object.defineProperty;var u=(c,e)=>Hi(c,"name",{value:e,configurable:!0})
|
|
|
316
316
|
UPDATE scheduled_actions
|
|
317
317
|
SET last_run_at = ?, next_run_at = ?
|
|
318
318
|
WHERE id = ?
|
|
319
|
-
`).run(t,s,e)}setEnabled(e,t){return this.db.prepare("UPDATE scheduled_actions SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM scheduled_actions WHERE id = ?").run(e).changes>0}calculateInitialNextRun(e,t){let s=new Date;switch(e){case"interval":{let r=parseInt(t,10);return isNaN(r)||r<=0?null:new Date(s.getTime()+r*6e4).toISOString()}case"once":return new Date(t).toISOString();case"cron":return this.getNextCronDate(t,s)?.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}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as
|
|
319
|
+
`).run(t,s,e)}setEnabled(e,t){return this.db.prepare("UPDATE scheduled_actions SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM scheduled_actions WHERE id = ?").run(e).changes>0}calculateInitialNextRun(e,t){let s=new Date;switch(e){case"interval":{let r=parseInt(t,10);return isNaN(r)||r<=0?null:new Date(s.getTime()+r*6e4).toISOString()}case"once":return new Date(t).toISOString();case"cron":return this.getNextCronDate(t,s)?.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}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as ya}from"node:crypto";var Ls,wa=b(()=>{"use strict";Ls=class{static{u(this,"DocumentRepository")}db;constructor(e){this.db=e}createDocument(e,t,s,r){let o=ya(),n=new Date().toISOString();return this.db.prepare("INSERT INTO documents (id, user_id, filename, mime_type, size_bytes, chunk_count, created_at) VALUES (?, ?, ?, ?, ?, 0, ?)").run(o,e,t,s,r,n),{id:o,userId:e,filename:t,mimeType:s,sizeBytes:r,chunkCount:0,createdAt:n}}updateChunkCount(e,t){this.db.prepare("UPDATE documents SET chunk_count = ? WHERE id = ?").run(t,e)}addChunk(e,t,s,r){let o=ya(),n=new Date().toISOString();return this.db.prepare("INSERT INTO document_chunks (id, document_id, chunk_index, content, embedding_id, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(o,e,t,s,r??null,n),{id:o,documentId:e,chunkIndex:t,content:s,embeddingId:r,createdAt:n}}getDocument(e){let t=this.db.prepare("SELECT * FROM documents WHERE id = ?").get(e);return t?this.mapDocumentRow(t):void 0}getChunks(e){return this.db.prepare("SELECT * FROM document_chunks WHERE document_id = ? ORDER BY chunk_index ASC").all(e).map(s=>this.mapChunkRow(s))}listByUser(e){return this.db.prepare("SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapDocumentRow(s))}deleteDocument(e){this.db.transaction(()=>{let s=this.db.prepare("SELECT embedding_id FROM document_chunks WHERE document_id = ? AND embedding_id IS NOT NULL").all(e);if(s.length>0){let r=s.map(n=>n.embedding_id),o=r.map(()=>"?").join(", ");this.db.prepare(`DELETE FROM embeddings WHERE id IN (${o})`).run(...r)}this.db.prepare("DELETE FROM document_chunks WHERE document_id = ?").run(e),this.db.prepare("DELETE FROM documents WHERE id = ?").run(e)})()}getChunksByEmbeddingIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(", ");return this.db.prepare(`SELECT * FROM document_chunks WHERE embedding_id IN (${t}) ORDER BY chunk_index ASC`).all(...e).map(r=>this.mapChunkRow(r))}mapDocumentRow(e){return{id:e.id,userId:e.user_id,filename:e.filename,mimeType:e.mime_type,sizeBytes:e.size_bytes,chunkCount:e.chunk_count,createdAt:e.created_at}}mapChunkRow(e){return{id:e.id,documentId:e.document_id,chunkIndex:e.chunk_index,content:e.content,embeddingId:e.embedding_id||void 0,createdAt:e.created_at}}}});import{randomUUID as lu}from"node:crypto";var Ns,Ta=b(()=>{"use strict";Ns=class{static{u(this,"TodoRepository")}db;constructor(e){this.db=e}add(e,t,s){let r=new Date().toISOString(),o=lu(),n=s?.list??"default",i=s?.priority??"normal";return this.db.prepare("INSERT INTO todos (id, user_id, list, title, description, priority, due_date, completed, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)").run(o,e,n,t,s?.description??null,i,s?.dueDate??null,r,r),{id:o,userId:e,list:n,title:t,description:s?.description,priority:i,dueDate:s?.dueDate,completed:!1,createdAt:r,updatedAt:r}}list(e,t,s=!1){let r="SELECT * FROM todos WHERE user_id = ?",o=[e];return t&&(r+=" AND list = ?",o.push(t)),s||(r+=" AND completed = 0"),r+=" ORDER BY CASE priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'normal' THEN 2 WHEN 'low' THEN 3 END, created_at DESC",this.db.prepare(r).all(...o).map(i=>this.mapRow(i))}getById(e){let t=this.db.prepare("SELECT * FROM todos WHERE id = ?").get(e);return t?this.mapRow(t):void 0}complete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 1, updated_at = ? WHERE id = ? AND completed = 0").run(t,e).changes>0}uncomplete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 0, updated_at = ? WHERE id = ? AND completed = 1").run(t,e).changes>0}delete(e){return this.db.prepare("DELETE FROM todos WHERE id = ?").run(e).changes>0}clearCompleted(e,t){let s="DELETE FROM todos WHERE user_id = ? AND completed = 1",r=[e];return t&&(s+=" AND list = ?",r.push(t)),this.db.prepare(s).run(...r).changes}getLists(e){return this.db.prepare(`SELECT list,
|
|
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 ln=b(()=>{"use strict";oa();ia();aa();ca();la();Mr();cn();da();ua();ma();pa();ha();fa();ya();wa()});function He(c){if(dn[c])return dn[c];let e=Object.entries(dn).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(c.startsWith(t))return s}var dn,lu,Ee,lt=b(()=>{"use strict";dn={"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}},lu={maxInputTokens:128e3,maxOutputTokens:8192};u(He,"lookupContextWindow");Ee=class{static{u(this,"LLMProvider")}config;contextWindow=lu;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import du from"@anthropic-ai/sdk";var Ns,un=b(()=>{"use strict";lt();Ns=class extends Ee{static{u(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new du({apiKey:this.config.apiKey,maxRetries:5});let e=He(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 uu from"openai";var Ie,St=b(()=>{"use strict";lt();Ie=class extends Ee{static{u(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new uu({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=He(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},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,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.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}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let 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,mn=b(()=>{"use strict";St();Ds=class extends Ie{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,pn=b(()=>{"use strict";lt();Ms=class extends Ee{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=He(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(`
|
|
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 dn=b(()=>{"use strict";na();aa();ca();la();da();Or();ln();ua();ma();pa();ha();fa();ga();wa();Ta()});function He(c){if(un[c])return un[c];let e=Object.entries(un).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(c.startsWith(t))return s}var un,du,Ee,lt=b(()=>{"use strict";un={"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}},du={maxInputTokens:128e3,maxOutputTokens:8192};u(He,"lookupContextWindow");Ee=class{static{u(this,"LLMProvider")}config;contextWindow=du;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import uu from"@anthropic-ai/sdk";var Ds,mn=b(()=>{"use strict";lt();Ds=class extends Ee{static{u(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new uu({apiKey:this.config.apiKey,maxRetries:5});let e=He(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 mu from"openai";var Ie,St=b(()=>{"use strict";lt();Ie=class extends Ee{static{u(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new mu({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=He(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},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,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.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}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let 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 Ms,pn=b(()=>{"use strict";St();Ms=class extends Ie{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 Os,hn=b(()=>{"use strict";lt();Os=class extends Ee{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=He(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
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 x of A.message.tool_calls){let U={id:`ollama_tool_${p.length}`,name:x.function.name,input:x.function.arguments};p.push(U),yield{type:"tool_use_start",toolCall:{id:U.id,name:U.name}},yield{type:"tool_use_delta",toolCall:{input:U.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
|
-
`)};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
|
|
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 Ps,fn=b(()=>{"use strict";St();Ps=class extends Ie{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}}});import{GoogleGenAI as pu}from"@google/genai";var Us,gn=b(()=>{"use strict";lt();Us=class extends Ee{static{u(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new pu({apiKey:this.config.apiKey});let e=He(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),o="",n=[],i=0,a=0,l;for await(let d of r){l=d;let m=d.text;if(m&&(o+=m,yield{type:"text_delta",text:m}),d.functionCalls)for(let p of d.functionCalls){let w={id:p.id??`google_tool_${n.length}`,name:p.name,input:p.args??{}};n.push(w),yield{type:"tool_use_start",toolCall:{id:w.id,name:w.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}l&&this.cacheRawContent(l),yield{type:"message_complete",response:{content:o,toolCalls:n.length>0?n:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:n.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(o=>o.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let o=this.rawContentCache.keys().next().value;o&&this.rawContentCache.delete(o)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let o of r.content)o.type==="tool_use"&&t.set(o.id,o.name);let s=[];for(let r of e){let o=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:o,parts:[{text:r.content}]});continue}let n=[],i=[],a=[];for(let l of r.content)switch(l.type){case"text":i.push({text:l.text});break;case"image":i.push({inlineData:{mimeType:l.source.media_type,data:l.source.data}});break;case"tool_use":n.push({id:l.id,name:l.name,input:l.input});break;case"tool_result":{let d=t.get(l.tool_use_id)??l.tool_use_id,m;try{let p=JSON.parse(l.content);m=typeof p=="object"&&p!==null?p:{result:p}}catch{m={result:l.content}}a.push({functionResponse:{id:l.tool_use_id,name:d,response:m}});break}}if(r.role==="assistant"&&n.length>0){let l=this.buildCacheKeyFromBlocks(n),d=this.rawContentCache.get(l);if(d)s.push(d);else{let m=[...i];for(let p=0;p<n.length;p++){let w=n[p];m.push({functionCall:{id:w.id,name:w.name,args:w.input},...p===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:m})}}else i.length>0&&s.push({role:o,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let l=a.functionCall.id??a.functionCall.name??"";l&&t.add(l)}s.push(i)}else{let a=(i.parts??[]).filter(l=>{if(l.functionResponse){let d=l.functionResponse.id??l.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let l=a.functionResponse.id??a.functionResponse.name??"";l&&r.add(l)}}let o=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(l=>{if(l.functionCall){let d=l.functionCall.id??l.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&o.push({role:i.role,parts:a})}else o.push(i);if(o.length<=1)return o;let n=[o[0]];for(let i=1;i<o.length;i++){let a=n[n.length-1],l=o[i];a.role===l.role?a.parts=[...a.parts??[],...l.parts??[]]:n.push(l)}return n}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((o,n)=>({id:o.id??`google_tool_${n}`,name:o.name,input:o.args??{}}));return{content:t,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var Fs,yn=b(()=>{"use strict";St();Fs=class extends Ie{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 wn(c){switch(c.provider){case"anthropic":return new Ds(c);case"openai":return new Ie(c);case"openrouter":return new Ms(c);case"ollama":return new Os(c);case"openwebui":return new Ps(c);case"google":return new Us(c);case"mistral":return new Fs(c);default:throw new Error(`Unknown LLM provider: ${c.provider}`)}}var Tn=b(()=>{"use strict";mn();St();pn();hn();fn();gn();yn();u(wn,"createLLMProvider")});function _n(c,e){return new Pr(c,e)}var hu,Pr,_a=b(()=>{"use strict";lt();Tn();hu=["default","strong","fast","embeddings","local"],Pr=class extends Ee{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 hu){let t=this.multiConfig[e];if(t){let s=wn(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(_n,"createModelRouter")});function xe(c){return Math.ceil(c.length/3.5)}function Bs(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 js,ba=b(()=>{"use strict";u(xe,"estimateTokens");u(Bs,"estimateMessageTokens");js=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
|
|
328
328
|
- **When the user's intent is clear**, ACT immediately using your tools. Don't explain what you'll do \u2014 just do it.
|
|
@@ -380,40 +380,40 @@ For complex tasks, work through multiple steps:
|
|
|
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 _n=b(()=>{"use strict";lt();un();St();mn();pn();hn();fn();gn();wn();Ta();_a()});var Bs,bn=b(()=>{"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,ba=b(()=>{"use strict";bn();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 Ea,$a,va,dt,ka=b(()=>{"use strict";Ea=["allow","deny"],$a=["global","user","conversation","platform"],va=["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"||!Ea.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Ea.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"||!$a.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${$a.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(!va.includes(o))throw new Error(`Rule "${s.id}" has invalid risk level "${o}": expected one of ${va.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 hu from"node:crypto";var qs,Sa=b(()=>{"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:hu.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=b(()=>{"use strict";ba();bn();ka();Sa()});var I,P=b(()=>{"use strict";I=class{static{u(this,"Skill")}}});function ee(c){return c.masterUserId??c.userId}function W(c){let e=new Set;if(e.add(ee(c)),e.add(c.userId),c.linkedPlatformUserIds)for(let t of c.linkedPlatformUserIds)e.add(t);return[...e]}var Me=b(()=>{"use strict";u(ee,"effectiveUserId");u(W,"allUserIds")});var At,Aa=b(()=>{"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,Ia=b(()=>{"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,...y.success?{}:{error:y.error}},"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,...n.success?{}:{error:n.error}},"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,En=b(()=>{"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 fu from"node:fs";import $n from"node:path";var Ur,xa=b(()=>{"use strict";P();Ur=class{static{u(this,"PluginLoader")}async loadFromDirectory(e){let t=$n.resolve(e),s;try{s=await fu.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=$n.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=$n.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 I))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 gu,yu,xt,Ra=b(()=>{"use strict";P();gu=/Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)/g,yu=/^[\d+\-*/().,\s%]*(Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)[\d+\-*/().,\s(%)]*)*$/,xt=class extends I{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(!yu.test(r))return{success:!1,error:`Invalid expression: "${r}" contains disallowed constructs`};let o=r.replace(gu,"");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,Ca=b(()=>{"use strict";P();Rt=class extends I{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,La=b(()=>{"use strict";P();Ct=class extends I{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 bn=b(()=>{"use strict";lt();mn();St();pn();hn();fn();gn();yn();Tn();_a();ba()});var Hs,En=b(()=>{"use strict";Hs=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 qs,Ea=b(()=>{"use strict";En();qs=class{static{u(this,"RuleEngine")}rules=[];rateLimiter=new Hs;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,va,ka,dt,Sa=b(()=>{"use strict";$a=["allow","deny"],va=["global","user","conversation","platform"],ka=["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"||!va.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${va.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(!ka.includes(o))throw new Error(`Rule "${s.id}" has invalid risk level "${o}": expected one of ${ka.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 fu from"node:crypto";var zs,Aa=b(()=>{"use strict";zs=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:fu.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 Ur=b(()=>{"use strict";Ea();En();Sa();Aa()});var I,P=b(()=>{"use strict";I=class{static{u(this,"Skill")}}});function ee(c){return c.masterUserId??c.userId}function W(c){let e=new Set;if(e.add(ee(c)),e.add(c.userId),c.linkedPlatformUserIds)for(let t of c.linkedPlatformUserIds)e.add(t);return[...e]}var Me=b(()=>{"use strict";u(ee,"effectiveUserId");u(W,"allUserIds")});var At,Ia=b(()=>{"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,xa=b(()=>{"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,...y.success?{}:{error:y.error}},"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,...n.success?{}:{error:n.error}},"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=b(()=>{"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 gu from"node:fs";import vn from"node:path";var Fr,Ra=b(()=>{"use strict";P();Fr=class{static{u(this,"PluginLoader")}async loadFromDirectory(e){let t=vn.resolve(e),s;try{s=await gu.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=vn.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=vn.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 I))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 yu,wu,xt,Ca=b(()=>{"use strict";P();yu=/Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)/g,wu=/^[\d+\-*/().,\s%]*(Math\.(sin|cos|tan|sqrt|pow|abs|floor|ceil|round|log|log2|log10|PI|E)[\d+\-*/().,\s(%)]*)*$/,xt=class extends I{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(!wu.test(r))return{success:!1,error:`Invalid expression: "${r}" contains disallowed constructs`};let o=r.replace(yu,"");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,La=b(()=>{"use strict";P();Rt=class extends I{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,Na=b(()=>{"use strict";P();Ct=class extends I{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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ")}}});var Lt,
|
|
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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ")}}});var Lt,Da=b(()=>{"use strict";P();Me();Lt=class extends I{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(ee(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(Y=>Y.type==="year").value,10),h=parseInt(w.find(Y=>Y.type==="month").value,10)-1,T=parseInt(w.find(Y=>Y.type==="day").value,10),$=new Date(Date.UTC(y,h,T,e,t,0)),A=i.formatToParts($),x=parseInt(A.find(Y=>Y.type==="hour").value,10),U=parseInt(A.find(Y=>Y.type==="minute").value,10),L=(e-x)*60+(t-U);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
|
-
`)}`}}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,
|
|
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,Ma=b(()=>{"use strict";P();Me();Nt=class extends I{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(ee(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(`
|
|
393
393
|
`);return{success:!0,data:s,display:`${s.length} note(s):
|
|
394
394
|
${r}`}}searchNotes(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for search action'};let r=new Set,o=[];for(let i of W(t))for(let a of this.noteRepo.search(i,s))r.has(a.id)||(r.add(a.id),o.push(a));if(o.length===0)return{success:!0,data:[],display:`No notes matching "${s}".`};let n=o.map(i=>`- **${i.title}** (${i.id.slice(0,8)}\u2026)
|
|
395
395
|
${i.content.slice(0,100)}${i.content.length>100?"\u2026":""}`).join(`
|
|
396
396
|
`);return{success:!0,data:o,display:`Found ${o.length} note(s):
|
|
397
|
-
${n}`}}deleteNote(e,t){let s=e.noteId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "noteId" for delete action'};let r=this.noteRepo.getById(s);return r?W(t).includes(r.userId)?this.noteRepo.delete(s)?{success:!0,data:{noteId:s},display:"Note deleted."}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}}}});var
|
|
398
|
-
Wind: ${o.windspeed} km/h`;return{success:!0,data:a,display:l}}catch(r){return{success:!1,error:`Weather fetch failed: ${r instanceof Error?r.message:String(r)}`}}}async geocode(e){let t=`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(e)}&count=1&language=en&format=json`,s=await fetch(t);if(!s.ok)throw new Error(`Geocoding API returned ${s.status}`);return(await s.json()).results?.[0]}async fetchWeather(e,t){let s=`https://api.open-meteo.com/v1/forecast?latitude=${e}&longitude=${t}¤t_weather=true&timezone=auto`,r=await fetch(s);if(!r.ok)throw new Error(`Weather API returned ${r.status}`);return(await r.json()).current_weather}}});import{exec as
|
|
399
|
-
[output truncated]`:c}var
|
|
400
|
-
${
|
|
401
|
-
${
|
|
397
|
+
${n}`}}deleteNote(e,t){let s=e.noteId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "noteId" for delete action'};let r=this.noteRepo.getById(s);return r?W(t).includes(r.userId)?this.noteRepo.delete(s)?{success:!0,data:{noteId:s},display:"Note deleted."}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}}}});var Tu,Dt,Oa=b(()=>{"use strict";P();Tu={0:"Clear sky",1:"Mainly clear",2:"Partly cloudy",3:"Overcast",45:"Foggy",48:"Depositing rime fog",51:"Light drizzle",53:"Moderate drizzle",55:"Dense drizzle",61:"Slight rain",63:"Moderate rain",65:"Heavy rain",71:"Slight snow",73:"Moderate snow",75:"Heavy snow",77:"Snow grains",80:"Slight rain showers",81:"Moderate rain showers",82:"Violent rain showers",85:"Slight snow showers",86:"Heavy snow showers",95:"Thunderstorm",96:"Thunderstorm with slight hail",99:"Thunderstorm with heavy hail"},Dt=class extends I{static{u(this,"WeatherSkill")}metadata={name:"weather",category:"information",description:"Get current weather for any location. Uses Open-Meteo (free, no API key). Use when the user asks about weather, temperature, or conditions somewhere.",riskLevel:"read",version:"2.0.0",inputSchema:{type:"object",properties:{location:{type:"string",description:'City or place name (e.g. "Vienna", "New York", "Tokyo")'}},required:["location"]}};async execute(e,t){let s=e.location;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "location"'};try{let r=await this.geocode(s);if(!r)return{success:!1,error:`Location "${s}" not found`};let o=await this.fetchWeather(r.latitude,r.longitude),n=Tu[o.weathercode]??`Code ${o.weathercode}`,i=r.admin1?`${r.name}, ${r.admin1}, ${r.country}`:`${r.name}, ${r.country}`,a={location:i,temperature:o.temperature,unit:"\xB0C",condition:n,windSpeed:o.windspeed,windDirection:o.winddirection,isDay:o.is_day===1},l=`${i}: ${o.temperature}\xB0C, ${n}
|
|
398
|
+
Wind: ${o.windspeed} km/h`;return{success:!0,data:a,display:l}}catch(r){return{success:!1,error:`Weather fetch failed: ${r instanceof Error?r.message:String(r)}`}}}async geocode(e){let t=`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(e)}&count=1&language=en&format=json`,s=await fetch(t);if(!s.ok)throw new Error(`Geocoding API returned ${s.status}`);return(await s.json()).results?.[0]}async fetchWeather(e,t){let s=`https://api.open-meteo.com/v1/forecast?latitude=${e}&longitude=${t}¤t_weather=true&timezone=auto`,r=await fetch(s);if(!r.ok)throw new Error(`Weather API returned ${r.status}`);return(await r.json()).current_weather}}});import{exec as _u}from"node:child_process";function Ua(c){return c.length>Pa?c.slice(0,Pa)+`
|
|
399
|
+
[output truncated]`:c}var bu,Pa,Mt,Fa=b(()=>{"use strict";P();bu=3e4,Pa=1e4;u(Ua,"truncate");Mt=class extends I{static{u(this,"ShellSkill")}metadata={name:"shell",category:"automation",description:"Execute shell commands on the host system. Use this for ANY task involving files, folders, system operations, or running programs: ls, cat, find, file, du, mkdir, cp, mv, grep, etc. When the user asks about their documents, files, or anything on disk \u2014 use this tool.",riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute"},timeout:{type:"number",description:"Timeout in milliseconds (default: 30000)"},cwd:{type:"string",description:"Working directory for the command"}},required:["command"]}};async execute(e,t){let s=e.command;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "command"'};let r=[/\brm\s+-rf\s+\/(?:\s|$)/,/\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+-[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*\s+-[a-zA-Z]*r)[a-zA-Z]*\s+\/(?:\s|$)/,/\brm\s+-rf\s+\/\*/,/:(){ :|:& };:/,/:\(\)\s*\{.*\|.*&\s*\}\s*;/,/>\s*\/dev\/sd[a-z]/,/\bmkfs\b/,/\bdd\s+.*\bif=/,/\bchmod\s+777\b/,/\bcurl\b.*\|\s*\bbash\b/,/\bwget\b.*\|\s*\bsh\b/,/\bpython[23]?\s+-c\b/,/\bnode\s+-e\b/,/\b(bash|sh)\s+-i\b.*\/dev\/tcp/,/\bnc\s+.*-e\b/];for(let i of r)if(i.test(s))return{success:!1,error:"Command blocked: potentially destructive system operation"};let o=typeof e.timeout=="number"&&e.timeout>0?e.timeout:bu,n=typeof e.cwd=="string"&&e.cwd.length>0?e.cwd:void 0;try{let{stdout:i,stderr:a,exitCode:l}=await this.run(s,o,n),d=[];return i&&d.push(`stdout:
|
|
400
|
+
${Ua(i)}`),a&&d.push(`stderr:
|
|
401
|
+
${Ua(a)}`),d.length===0&&d.push("(no output)"),d.push(`exit code: ${l}`),{success:l===0,data:{stdout:i,stderr:a,exitCode:l},display:d.join(`
|
|
402
402
|
|
|
403
|
-
`),...l!==0&&{error:`Command exited with code ${l}`}}}catch(i){return{success:!1,error:`Shell execution failed: ${i instanceof Error?i.message:String(i)}`}}}run(e,t,s){return new Promise(r=>{
|
|
403
|
+
`),...l!==0&&{error:`Command exited with code ${l}`}}}catch(i){return{success:!1,error:`Shell execution failed: ${i instanceof Error?i.message:String(i)}`}}}run(e,t,s){return new Promise(r=>{_u(e,{timeout:t,cwd:s},(o,n,i)=>{let a=o&&"code"in o&&typeof o.code=="number"?o.code:o?1:0;r({stdout:typeof n=="string"?n:"",stderr:typeof i=="string"?i:"",exitCode:a})})})}}});var Ot,ja=b(()=>{"use strict";P();Me();Ot=class extends I{static{u(this,"MemorySkill")}memoryRepo;embeddingService;metadata={name:"memory",category:"core",description:"Store and retrieve persistent memories. Use this to remember user preferences, facts, and important information across conversations.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","recall","search","list","delete","semantic_search"],description:"The memory action to perform"},key:{type:"string",description:"The memory key/label"},value:{type:"string",description:"The value to remember (for save)"},category:{type:"string",description:"Optional category (for save/list)"},query:{type:"string",description:"Search query (for search)"}},required:["action"]}};constructor(e,t){super(),this.memoryRepo=e,this.embeddingService=t}async execute(e,t){let s=e.action;switch(s){case"save":return this.saveMemory(e,t);case"recall":return this.recallMemory(e,t);case"search":return this.searchMemories(e,t);case"list":return this.listMemories(e,t);case"delete":return this.deleteMemory(e,t);case"semantic_search":return this.semanticSearchMemories(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: save, recall, search, list, delete, semantic_search`}}}saveMemory(e,t){let s=e.key,r=e.value,o=e.category;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for save action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "value" for save action'};let n=this.memoryRepo.save(ee(t),s,r,o??"general");return this.embeddingService&&this.embeddingService.embedAndStore(ee(t),`${s}: ${r}`,"memory",s).catch(()=>{}),{success:!0,data:n,display:`Remembered "${s}" = "${r}" (category: ${n.category})`}}recallMemory(e,t){let s=e.key;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for recall action'};let r;for(let o of W(t))if(r=this.memoryRepo.recall(o,s),r)break;return r?{success:!0,data:r,display:`${s} = "${r.value}" (category: ${r.category}, updated: ${r.updatedAt})`}:{success:!0,data:null,display:`No memory found for key "${s}".`}}searchMemories(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for search action'};let r=new Set,o=[];for(let n of W(t))for(let i of this.memoryRepo.search(n,s))r.has(i.id)||(r.add(i.id),o.push(i));return{success:!0,data:o,display:o.length===0?`No memories matching "${s}".`:`Found ${o.length} memory(ies):
|
|
404
404
|
${o.map(n=>`- ${n.key}: "${n.value}"`).join(`
|
|
405
405
|
`)}`}}listMemories(e,t){let s=e.category,r=new Set,o=[];for(let i of W(t)){let a=s&&typeof s=="string"?this.memoryRepo.listByCategory(i,s):this.memoryRepo.listAll(i);for(let l of a)r.has(l.id)||(r.add(l.id),o.push(l))}let n=s?`in category "${s}"`:"total";return{success:!0,data:o,display:o.length===0?`No memories found${s?` in category "${s}"`:""}.`:`${o.length} memory(ies) ${n}:
|
|
406
406
|
${o.map(i=>`- [${i.category}] ${i.key}: "${i.value}"`).join(`
|
|
407
407
|
`)}`}}deleteMemory(e,t){let s=e.key;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for delete action'};let r=!1;for(let o of W(t))if(this.memoryRepo.delete(o,s)){r=!0;break}return{success:!0,data:{key:s,deleted:r},display:r?`Memory "${s}" deleted.`:`No memory found for key "${s}".`}}async semanticSearchMemories(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for semantic_search action'};if(!this.embeddingService)return this.searchMemories(e,t);let r=new Set,o=[];for(let n of W(t))for(let i of await this.embeddingService.semanticSearch(n,s,10))r.has(i.key)||(r.add(i.key),o.push(i));return o.length===0?this.searchMemories(e,t):{success:!0,data:o,display:`Found ${o.length} semantically related memory(ies):
|
|
408
408
|
${o.map(n=>`- ${n.key}: "${n.value}" (score: ${n.score.toFixed(2)})`).join(`
|
|
409
|
-
`)}`}}}});var
|
|
409
|
+
`)}`}}}});var Eu,$u,vu,Pt,Ba=b(()=>{"use strict";P();$n();Eu=5,$u=15,vu=12e4,Pt=class extends I{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:vu,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($u,Math.round(o))):Eu,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 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 x of T.toolCalls)$.push({type:"tool_use",id:x.id,name:x.name,input:x.input});p.push({role:"assistant",content:$});let A=[];for(let x of T.toolCalls){a.ping("tool_call",{iteration:w,maxIterations:n,tool:x.name});let U=await this.executeSubAgentTool(x,t);A.push({type:"tool_result",tool_use_id:x.id,content:U.content,is_error:U.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 qe,
|
|
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 x of T.toolCalls)$.push({type:"tool_use",id:x.id,name:x.name,input:x.input});p.push({role:"assistant",content:$});let A=[];for(let x of T.toolCalls){a.ping("tool_call",{iteration:w,maxIterations:n,tool:x.name});let U=await this.executeSubAgentTool(x,t);A.push({type:"tool_result",tool_use_id:x.id,content:U.content,is_error:U.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 qe,jr=b(()=>{"use strict";qe=class{static{u(this,"EmailProvider")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var Ha={};oe(Ha,{MicrosoftGraphEmailProvider:()=>Br});var Br,kn=b(()=>{"use strict";jr();Br=class extends qe{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 this.parseJsonOrUndefined(o)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=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 createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`/me/messages/${e.replyTo}/createReply`,{method:"POST",body:JSON.stringify({comment:e.body})}))?.id??e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(r=>({emailAddress:{address:r.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(r=>({emailAddress:{address:r.trim()}}))),{messageId:(await this.graphRequest("/me/messages",{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest("/me/mailFolders?$select=displayName&$top=100")).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest("/me/mailFolders?$select=id,displayName&$top=100")).value??[]).find(i=>i.displayName.toLowerCase()===e.toLowerCase());if(!r)throw new Error(`Folder "${e}" not found. Use the 'folders' action to list available folders.`);let 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`)}async forwardMessage(e,t,s){return await this.graphRequest(`/me/messages/${e}/forward`,{method:"POST",body:JSON.stringify({comment:s??"",toRecipients:t.split(",").map(r=>({emailAddress:{address:r.trim()}}))})}),{messageId:`fwd-${Date.now()}`}}mapMessage(e){return{id:e.id,from:this.formatGraphAddress(e.from),to:(e.toRecipients??[]).map(t=>this.formatGraphAddress(t)),subject:e.subject??"(no subject)",date:new Date(e.receivedDateTime),read:e.isRead??!1,preview:e.bodyPreview??void 0,hasAttachments:e.hasAttachments??!1}}formatGraphAddress(e){if(!e)return"unknown";let t=e.emailAddress??e;return t?.address?t.name?`${t.name} <${t.address}>`:t.address:"unknown"}stripHtml(e){return e.replace(/<br\s*\/?>/gi,`
|
|
412
412
|
`).replace(/<\/p>/gi,`
|
|
413
413
|
|
|
414
414
|
`).replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/\n{3,}/g,`
|
|
415
415
|
|
|
416
|
-
`).trim()}}});var
|
|
416
|
+
`).trim()}}});var qa={};oe(qa,{StandardEmailProvider:()=>Hr});var Hr,Sn=b(()=>{"use strict";jr();Hr=class extends qe{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
|
|
|
@@ -423,7 +423,7 @@ Additional context: ${r}`);let p=[{role:"user",content:m}];try{let w=0,y=0,h=0;f
|
|
|
423
423
|
\r
|
|
424
424
|
`);if(d>=0)return this.decodeBody(i.slice(d+4))}}return this.decodeBody(t.slice(1).join(`
|
|
425
425
|
|
|
426
|
-
`).slice(0,5e3))}decodeBody(e){return e.replace(/=\r?\n/g,"").replace(/=([0-9A-Fa-f]{2})/g,(t,s)=>String.fromCharCode(parseInt(s,16))).trim()}}});async function
|
|
426
|
+
`).slice(0,5e3))}decodeBody(e){return e.replace(/=\r?\n/g,"").replace(/=([0-9A-Fa-f]{2})/g,(t,s)=>String.fromCharCode(parseInt(s,16))).trim()}}});async function Ws(c){if(c.provider==="microsoft"){if(!c.microsoft)throw new Error("Microsoft email config missing");let{MicrosoftGraphEmailProvider:s}=await Promise.resolve().then(()=>(kn(),Ha)),r=new s(c.microsoft);return await r.initialize(),r}if(!c.imap||!c.smtp||!c.auth)throw new Error("IMAP/SMTP email config missing (imap, smtp, auth required)");let{StandardEmailProvider:e}=await Promise.resolve().then(()=>(Sn(),qa)),t=new e(c);return await t.initialize(),t}var za=b(()=>{"use strict";u(Ws,"createEmailProvider")});var Ge,Wa=b(()=>{"use strict";jr();za();Sn();kn();P();Ge=class extends I{static{u(this,"EmailSkill")}metadata;providers;accountNames;defaultAccount;multiAccount;constructor(e){super(),e instanceof Map?this.providers=e:e?this.providers=new Map([["default",e]]):this.providers=new Map,this.accountNames=[...this.providers.keys()],this.defaultAccount=this.accountNames[0]??"default",this.multiAccount=this.providers.size>1;let t=this.multiAccount?{account:{type:"string",enum:this.accountNames,description:`Email account to use (available: ${this.accountNames.join(", ")})`}}:{},s=this.multiAccount?`Access the user's email accounts (${this.accountNames.join(", ")}): check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments.`:`Access the user's email: check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments. Use "draft" instead of "send" when the user asks to prepare/draft an email without sending it.`;this.metadata={name:"email",category:"productivity",description:s,riskLevel:"write",version:"3.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["inbox","read","search","send","draft","folders","folder","reply","forward","attachment"],description:"The email action to perform"},...t,count:{type:"number",description:"Number of emails to fetch (for inbox/search/folder, default: 10)"},messageId:{type:"string",description:"Message ID to read or reply to"},query:{type:"string",description:"Search query (for search action)"},to:{type:"string",description:"Recipient email address (for send action)"},subject:{type:"string",description:"Email subject (for send action)"},body:{type:"string",description:"Email body text (for send/reply action)"},cc:{type:"string",description:"CC recipients, comma-separated (for send action)"},folder:{type:"string",description:"Folder name (for folder action)"},attachmentId:{type:"string",description:"Attachment ID or filename (for attachment action)"},save:{type:"string",description:"Directory path to save the attachment to disk instead of reading its content (for attachment action)"},isHtml:{type:"boolean",description:"Whether the body is HTML (for send action)"}},required:["action"]}}}async execute(e,t){if(this.providers.size===0)return{success:!1,error:"Email is not configured. Run `alfred setup` to configure email access."};let s=e.action;try{switch(s){case"inbox":return await this.handleInbox(e);case"read":return await this.handleRead(e);case"search":return await this.handleSearch(e);case"send":return await this.handleSend(e);case"draft":return await this.handleDraft(e);case"folders":return await this.handleFolders(e);case"folder":return await this.handleFolder(e);case"reply":return await this.handleReply(e);case"forward":return await this.handleForward(e);case"attachment":return await this.handleAttachment(e);default:return{success:!1,error:`Unknown action: ${s}. Use: inbox, read, search, send, draft, folders, folder, reply, forward, attachment`}}}catch(r){return{success:!1,error:`Email error: ${r instanceof Error?r.message:String(r)}`}}}resolveProvider(e){let t=e.account??this.defaultAccount,s=this.providers.get(t);return s?{provider:s,account:t}:{success:!1,error:`Unknown email account "${t}". Available: ${this.accountNames.join(", ")}`}}encodeId(e,t){return this.multiAccount?`${e}::${t}`:t}decodeId(e){if(this.multiAccount){let t=e.indexOf("::");if(t>=0)return{account:e.slice(0,t),rawId:e.slice(t+2)}}return{account:this.defaultAccount,rawId:e}}accountLabel(e,t){return this.multiAccount?`[${e}] ${t}`:t}async handleInbox(e){let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,o=Math.min(Math.max(1,e.count??10),50),n=await s.fetchInbox(o);if(n.length===0)return{success:!0,data:{messages:[]},display:this.accountLabel(r,"Inbox is empty.")};let i=n.filter(l=>!l.read).length,a=n.map((l,d)=>{let m=l.read?"":" [UNREAD]",p=l.hasAttachments?" [ATT]":"";return`${d+1}. [${this.encodeId(r,l.id)}]${m}${p} ${l.subject}
|
|
427
427
|
From: ${l.from}
|
|
428
428
|
Date: ${l.date.toISOString()}`}).join(`
|
|
429
429
|
|
|
@@ -463,34 +463,34 @@ ${a}`)}}async handleReply(e){let t=e.messageId,s=e.body;if(!t)return{success:!1,
|
|
|
463
463
|
... (truncated)`:w;return{success:!0,data:{messageId:t,attachmentId:l.id,fileName:m,size:d.length,hasContent:!0},display:this.accountLabel(o,`Attachment: ${m} (${this.formatSize(d.length)})
|
|
464
464
|
|
|
465
465
|
Content:
|
|
466
|
-
${y}`),attachments:[{fileName:m,data:d,mimeType:p}]}}return{success:!0,data:{messageId:t,attachmentId:l.id,fileName:m,size:d.length},display:this.accountLabel(o,`Downloaded attachment: ${m} (${this.formatSize(d.length)})`),attachments:[{fileName:m,data:d,mimeType:p}]}}async extractText(e,t,s){try{if(t==="application/pdf"){let r=(await import("pdf-parse")).default;return(await r(e)).text?.trim()||null}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")return(await(await import("mammoth")).extractRawText({buffer:e})).value?.trim()||null;if(t.startsWith("text/")||s.endsWith(".csv")||s.endsWith(".json")||s.endsWith(".md"))return e.toString("utf-8")}catch{}return null}formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var
|
|
466
|
+
${y}`),attachments:[{fileName:m,data:d,mimeType:p}]}}return{success:!0,data:{messageId:t,attachmentId:l.id,fileName:m,size:d.length},display:this.accountLabel(o,`Downloaded attachment: ${m} (${this.formatSize(d.length)})`),attachments:[{fileName:m,data:d,mimeType:p}]}}async extractText(e,t,s){try{if(t==="application/pdf"){let r=(await import("pdf-parse")).default;return(await r(e)).text?.trim()||null}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")return(await(await import("mammoth")).extractRawText({buffer:e})).value?.trim()||null;if(t.startsWith("text/")||s.endsWith(".csv")||s.endsWith(".json")||s.endsWith(".md"))return e.toString("utf-8")}catch{}return null}formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var Va,Ut,Ka=b(()=>{"use strict";P();Va=1e5,Ut=class extends I{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>Va,w=p?m.slice(0,Va)+`
|
|
467
467
|
|
|
468
468
|
[... 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)
|
|
469
469
|
|
|
470
470
|
${y.slice(0,5e3)}`}:{success:!0,data:h,display:`HTTP ${l.status} ${l.statusText}
|
|
471
471
|
|
|
472
|
-
${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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ").trim()}}});import G from"node:fs";import Xe from"node:path";var
|
|
472
|
+
${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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ").trim()}}});import G from"node:fs";import Xe from"node:path";var An,Ga,ku,Ft,Xa=b(()=>{"use strict";P();An=5e5,Ga=5e7,ku={".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 I{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(G.existsSync(i)&&G.lstatSync(i).isSymbolicLink()){let l=G.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 Xe.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=Xe.basename(e);return n.includes(i.toLowerCase())?{success:!1,error:"Access to sensitive files is blocked for security"}:null}readFile(e){try{let t=G.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file. Use action "list" instead.`};if(t.size>An){let r=G.readFileSync(e,"utf-8").slice(0,An);return{success:!0,data:{path:e,size:t.size,truncated:!0},display:`${e} (${t.size} bytes, truncated to ${An}):
|
|
473
473
|
|
|
474
474
|
${r}`}}let s=G.readFileSync(e,"utf-8");return{success:!0,data:{path:e,size:t.size,content:s},display:s}}catch(t){return{success:!1,error:`Cannot read "${e}": ${t.message}`}}}writeFile(e,t){if(t==null)return{success:!1,error:'Missing "content" for write action'};try{let s=Xe.dirname(e);return G.mkdirSync(s,{recursive:!0}),G.writeFileSync(e,t,"utf-8"),{success:!0,data:{path:e,bytes:Buffer.byteLength(t)},display:`Written ${Buffer.byteLength(t)} bytes to ${e}`}}catch(s){return{success:!1,error:`Cannot write "${e}": ${s.message}`}}}appendFile(e,t){if(t==null)return{success:!1,error:'Missing "content" for append action'};try{return G.appendFileSync(e,t,"utf-8"),{success:!0,data:{path:e,appendedBytes:Buffer.byteLength(t)},display:`Appended ${Buffer.byteLength(t)} bytes to ${e}`}}catch(s){return{success:!1,error:`Cannot append to "${e}": ${s.message}`}}}listDir(e){try{let s=G.readdirSync(e,{withFileTypes:!0}).map(o=>({name:o.name,type:o.isDirectory()?"dir":o.isSymbolicLink()?"symlink":"file"})),r=s.length===0?`${e}: (empty)`:s.map(o=>`${o.type==="dir"?"\u{1F4C1}":"\u{1F4C4}"} ${o.name}`).join(`
|
|
475
475
|
`);return{success:!0,data:{path:e,entries:s},display:r}}catch(t){return{success:!1,error:`Cannot list "${e}": ${t.message}`}}}fileInfo(e){try{let t=G.statSync(e),s={path:e,type:t.isDirectory()?"directory":t.isFile()?"file":"other",size:t.size,created:t.birthtime.toISOString(),modified:t.mtime.toISOString(),permissions:t.mode.toString(8)};return{success:!0,data:s,display:`${s.type}: ${e}
|
|
476
476
|
Size: ${t.size} bytes
|
|
477
|
-
Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=G.existsSync(e);return{success:!0,data:{path:e,exists:t},display:t?`Yes, "${e}" exists`:`No, "${e}" does not exist`}}writeBinaryFile(e,t){if(!t)return{success:!1,error:'Missing "content" (base64-encoded) for write_binary action'};try{let s=Xe.dirname(e);G.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return G.writeFileSync(e,r),{success:!0,data:{path:e,bytes:r.length},display:`Written ${r.length} bytes (binary) to ${e}`}}catch(s){return{success:!1,error:`Cannot write "${e}": ${s.message}`}}}moveFile(e,t){if(!t)return{success:!1,error:'Missing "destination" for move action'};let s=this.resolvePath(t),r=this.checkBlocked(s);if(r)return r;try{let o=Xe.dirname(s);return G.mkdirSync(o,{recursive:!0}),G.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return G.copyFileSync(e,s),G.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(n){return{success:!1,error:`Cannot move "${e}" to "${s}": ${n.message}`}}}}copyFile(e,t){if(!t)return{success:!1,error:'Missing "destination" for copy action'};let s=this.resolvePath(t),r=this.checkBlocked(s);if(r)return r;try{let o=Xe.dirname(s);return G.mkdirSync(o,{recursive:!0}),G.copyFileSync(e,s),{success:!0,data:{from:e,to:s},display:`Copied ${e} \u2192 ${s}`}}catch(o){return{success:!1,error:`Cannot copy "${e}" to "${s}": ${o.message}`}}}sendFile(e){try{if(!G.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=G.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file`};if(t.size>
|
|
477
|
+
Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=G.existsSync(e);return{success:!0,data:{path:e,exists:t},display:t?`Yes, "${e}" exists`:`No, "${e}" does not exist`}}writeBinaryFile(e,t){if(!t)return{success:!1,error:'Missing "content" (base64-encoded) for write_binary action'};try{let s=Xe.dirname(e);G.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return G.writeFileSync(e,r),{success:!0,data:{path:e,bytes:r.length},display:`Written ${r.length} bytes (binary) to ${e}`}}catch(s){return{success:!1,error:`Cannot write "${e}": ${s.message}`}}}moveFile(e,t){if(!t)return{success:!1,error:'Missing "destination" for move action'};let s=this.resolvePath(t),r=this.checkBlocked(s);if(r)return r;try{let o=Xe.dirname(s);return G.mkdirSync(o,{recursive:!0}),G.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return G.copyFileSync(e,s),G.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(n){return{success:!1,error:`Cannot move "${e}" to "${s}": ${n.message}`}}}}copyFile(e,t){if(!t)return{success:!1,error:'Missing "destination" for copy action'};let s=this.resolvePath(t),r=this.checkBlocked(s);if(r)return r;try{let o=Xe.dirname(s);return G.mkdirSync(o,{recursive:!0}),G.copyFileSync(e,s),{success:!0,data:{from:e,to:s},display:`Copied ${e} \u2192 ${s}`}}catch(o){return{success:!1,error:`Cannot copy "${e}" to "${s}": ${o.message}`}}}sendFile(e){try{if(!G.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=G.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file`};if(t.size>Ga)return{success:!1,error:`File too large to send (${t.size} bytes, max ${Ga})`};let s=G.readFileSync(e),r=Xe.basename(e),o=Xe.extname(e).toLowerCase(),n=ku[o]||"application/octet-stream",i={fileName:r,data:s,mimeType:n};return{success:!0,data:{path:e,size:t.size,fileName:r,mimeType:n},display:`Sending ${r} (${t.size} bytes)`,attachments:[i]}}catch(t){return{success:!1,error:`Cannot send "${e}": ${t.message}`}}}deleteFile(e){try{return G.existsSync(e)?G.statSync(e).isDirectory()?{success:!1,error:`"${e}" is a directory. Use shell for directory deletion.`}:(G.unlinkSync(e),{success:!0,data:{path:e},display:`Deleted ${e}`}):{success:!1,error:`"${e}" does not exist`}}catch(t){return{success:!1,error:`Cannot delete "${e}": ${t.message}`}}}}});import{execSync as jt}from"node:child_process";var Bt,Ya=b(()=>{"use strict";P();Bt=class extends I{static{u(this,"ClipboardSkill")}metadata={name:"clipboard",category:"media",description:"Read or write the system clipboard. Use when the user asks to copy something, paste from clipboard, or check what is in their clipboard.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["read","write"],description:'"read" to get clipboard contents, "write" to set clipboard contents'},text:{type:"string",description:"Text to copy to clipboard (required for write)"}},required:["action"]}};async execute(e,t){let s=e.action;switch(s){case"read":return this.readClipboard();case"write":return this.writeClipboard(e.text);default:return{success:!1,error:`Unknown action "${s}". Valid: read, write`}}}readClipboard(){try{let e;switch(process.platform){case"darwin":e=jt("pbpaste",{encoding:"utf-8",timeout:5e3});break;case"win32":e=jt("powershell -NoProfile -Command Get-Clipboard",{encoding:"utf-8",timeout:5e3}).replace(/\r\n$/,"");break;default:e=jt("xclip -selection clipboard -o 2>/dev/null || xsel --clipboard --output",{encoding:"utf-8",timeout:5e3});break}return!e||e.trim().length===0?{success:!0,data:{content:""},display:"Clipboard is empty."}:{success:!0,data:{content:e},display:e.length>2e3?e.slice(0,2e3)+`
|
|
478
478
|
|
|
479
|
-
[... truncated]`:e}}catch(e){return{success:!1,error:`Failed to read clipboard: ${e.message}`}}}writeClipboard(e){if(!e||typeof e!="string")return{success:!1,error:'Missing "text" for write action'};try{switch(process.platform){case"darwin":jt("pbcopy",{input:e,timeout:5e3});break;case"win32":jt('powershell -NoProfile -Command "$input | Set-Clipboard"',{input:e,timeout:5e3});break;default:jt("xclip -selection clipboard 2>/dev/null || xsel --clipboard --input",{input:e,timeout:5e3});break}return{success:!0,data:{copiedLength:e.length},display:`Copied ${e.length} characters to clipboard.`}}catch(t){return{success:!1,error:`Failed to write clipboard: ${t.message}`}}}}});import{execSync as
|
|
479
|
+
[... truncated]`:e}}catch(e){return{success:!1,error:`Failed to read clipboard: ${e.message}`}}}writeClipboard(e){if(!e||typeof e!="string")return{success:!1,error:'Missing "text" for write action'};try{switch(process.platform){case"darwin":jt("pbcopy",{input:e,timeout:5e3});break;case"win32":jt('powershell -NoProfile -Command "$input | Set-Clipboard"',{input:e,timeout:5e3});break;default:jt("xclip -selection clipboard 2>/dev/null || xsel --clipboard --input",{input:e,timeout:5e3});break}return{success:!0,data:{copiedLength:e.length},display:`Copied ${e.length} characters to clipboard.`}}catch(t){return{success:!1,error:`Failed to write clipboard: ${t.message}`}}}}});import{execSync as Vs}from"node:child_process";import Ja from"node:path";import Su from"node:os";var Ht,Za=b(()=>{"use strict";P();Ht=class extends I{static{u(this,"ScreenshotSkill")}metadata={name:"screenshot",category:"media",description:"Take a screenshot of the current screen and save it to a file. Use when the user asks to capture their screen or take a screenshot.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{path:{type:"string",description:"Output file path (optional, defaults to ~/Desktop/screenshot-<timestamp>.png)"}}}};async execute(e,t){let s=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),r=Ja.join(Su.homedir(),"Desktop"),o=e.path||Ja.join(r,`screenshot-${s}.png`);try{switch(process.platform){case"darwin":Vs(`screencapture -x "${o}"`,{timeout:1e4});break;case"win32":Vs(`powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; $screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds; $bitmap = New-Object System.Drawing.Bitmap($screen.Width, $screen.Height); $graphics = [System.Drawing.Graphics]::FromImage($bitmap); $graphics.CopyFromScreen($screen.Location, [System.Drawing.Point]::Empty, $screen.Size); $bitmap.Save('${o.replace(/'/g,"''")}'); $graphics.Dispose(); $bitmap.Dispose()"`,{timeout:1e4});break;default:try{Vs(`scrot "${o}"`,{timeout:1e4})}catch{try{Vs(`import -window root "${o}"`,{timeout:1e4})}catch{Vs(`gnome-screenshot -f "${o}"`,{timeout:1e4})}}break}return{success:!0,data:{path:o},display:`Screenshot saved to ${o}`}}catch(n){return{success:!1,error:`Screenshot failed: ${n.message}`}}}}});import Au from"node:path";import Iu from"node:os";var Qa,qt,ec=b(()=>{"use strict";P();Qa=5e4,qt=class extends I{static{u(this,"BrowserSkill")}browser=null;page=null;metadata={name:"browser",category:"media",description:"Open web pages in a real browser (Puppeteer/Chromium). Renders JavaScript, so it works with SPAs and dynamic sites. Can also interact with pages: click buttons, fill forms, take screenshots. Use when http skill returns empty/broken content, or when you need to interact with a web page.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["open","screenshot","click","type","evaluate","close"],description:"open = navigate to URL and return page text. screenshot = save screenshot of current page. click = click element by CSS selector. type = type text into input by CSS selector. evaluate = run JavaScript on the page. close = close the browser."},url:{type:"string",description:'URL to open (required for "open", optional for "screenshot")'},selector:{type:"string",description:'CSS selector for the element (required for "click" and "type")'},text:{type:"string",description:'Text to type (required for "type")'},script:{type:"string",description:'JavaScript code to evaluate (required for "evaluate")'},path:{type:"string",description:"File path to save screenshot (optional, defaults to Desktop)"}},required:["action"]}};async execute(e,t){let s=e.action;if(s==="close")return this.closeBrowser();let r=await this.loadPuppeteer();if(!r)return{success:!1,error:`Puppeteer is not installed. Run: npm install -g puppeteer
|
|
480
480
|
Or add it to Alfred: npm install puppeteer`};switch(s){case"open":return this.openPage(r,e);case"screenshot":return this.screenshotPage(r,e);case"click":return this.clickElement(e);case"type":return this.typeText(e);case"evaluate":return this.evaluateScript(e);default:return{success:!1,error:`Unknown action "${s}". Valid: open, screenshot, click, type, evaluate, close`}}}async loadPuppeteer(){try{let e=await Function('return import("puppeteer")')();return this.resolvePuppeteerModule(e)}catch{try{let e=await Function('return import("puppeteer-core")')();return this.resolvePuppeteerModule(e)}catch{return null}}}resolvePuppeteerModule(e){let t=e;return typeof t.launch=="function"?t:t.default}async ensureBrowser(e){return this.browser&&this.browser.connected?this.browser:(this.browser=await e.launch({headless:!0,args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage"]}),this.browser)}async ensurePage(e){let t=await this.ensureBrowser(e);return this.page||(this.page=await t.newPage(),await this.page.setViewport({width:1280,height:900})),this.page}async openPage(e,t){let s=t.url;if(!s)return{success:!1,error:'Missing "url" for open action'};let r=this.validateUrl(s);if(r)return{success:!1,error:r};try{let o=await this.ensurePage(e);await o.goto(s,{waitUntil:"networkidle2",timeout:3e4});let n=await o.title(),i=await o.evaluate(`
|
|
481
481
|
(() => {
|
|
482
482
|
document.querySelectorAll('script, style, noscript').forEach(el => el.remove());
|
|
483
483
|
return document.body?.innerText ?? '';
|
|
484
484
|
})()
|
|
485
|
-
`),l=(i.length>
|
|
485
|
+
`),l=(i.length>Qa?i.slice(0,Qa)+`
|
|
486
486
|
|
|
487
487
|
[... truncated]`:i).replace(/\n{3,}/g,`
|
|
488
488
|
|
|
489
489
|
`).trim();return{success:!0,data:{url:o.url(),title:n,length:i.length},display:`**${n}** (${o.url()})
|
|
490
490
|
|
|
491
|
-
${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||
|
|
491
|
+
${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||Au.join(Iu.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,tc=b(()=>{"use strict";P();Me();zt=class extends I{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=ee(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:
|
|
492
492
|
${s.map(r=>`- ${r}`).join(`
|
|
493
|
-
`)}`:"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,
|
|
493
|
+
`)}`:"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,Ks=b(()=>{"use strict";Re=class{static{u(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var sc={};oe(sc,{CalDAVProvider:()=>qr});var qr,In=b(()=>{"use strict";Ks();qr=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(`
|
|
494
494
|
`).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
|
|
495
495
|
VERSION:2.0\r
|
|
496
496
|
PRODID:-//Alfred//EN\r
|
|
@@ -506,11 +506,11 @@ BEGIN:VEVENT\r
|
|
|
506
506
|
`),r+=`DTSTAMP:${s(new Date)}\r
|
|
507
507
|
`,r+=`END:VEVENT\r
|
|
508
508
|
END:VCALENDAR\r
|
|
509
|
-
`,r}}});var
|
|
509
|
+
`,r}}});var rc={};oe(rc,{GoogleCalendarProvider:()=>zr});var zr,xn=b(()=>{"use strict";Ks();zr=class extends Re{static{u(this,"GoogleCalendarProvider")}config;calendar;constructor(e){super(),this.config=e}async initialize(){try{let{google:e}=await import("googleapis"),t=new e.auth.OAuth2(this.config.clientId,this.config.clientSecret);t.setCredentials({refresh_token:this.config.refreshToken}),this.calendar=e.calendar({version:"v3",auth:t})}catch(e){throw new Error(`Google Calendar initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){return((await this.calendar.events.list({calendarId:"primary",timeMin:e.toISOString(),timeMax:t.toISOString(),singleEvents:!0,orderBy:"startTime"})).data.items??[]).map(r=>this.mapEvent(r))}async createEvent(e){let t={summary:e.title,location:e.location,description:e.description};e.allDay?(t.start={date:e.start.toISOString().slice(0,10)},t.end={date:e.end.toISOString().slice(0,10)}):(t.start={dateTime:e.start.toISOString()},t.end={dateTime:e.end.toISOString()});let s=await this.calendar.events.insert({calendarId:"primary",requestBody:t});return this.mapEvent(s.data)}async updateEvent(e,t){let s={};t.title&&(s.summary=t.title),t.location&&(s.location=t.location),t.description&&(s.description=t.description),t.start&&(s.start=t.allDay?{date:t.start.toISOString().slice(0,10)}:{dateTime:t.start.toISOString()}),t.end&&(s.end=t.allDay?{date:t.end.toISOString().slice(0,10)}:{dateTime:t.end.toISOString()});let r=await this.calendar.events.patch({calendarId:"primary",eventId:e,requestBody:s});return this.mapEvent(r.data)}async deleteEvent(e){await this.calendar.events.delete({calendarId:"primary",eventId:e})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(o=>!o.allDay&&o.start<t&&o.end>e);return{available:r.length===0,conflicts:r}}mapEvent(e){let t=!!e.start?.date;return{id:e.id,title:e.summary??"(No title)",start:new Date(e.start?.dateTime??e.start?.date),end:new Date(e.end?.dateTime??e.end?.date),location:e.location??void 0,description:e.description??void 0,allDay:t}}}});var oc={};oe(oc,{MicrosoftCalendarProvider:()=>Wr});var Wr,Rn=b(()=>{"use strict";Ks();Wr=class extends Re{static{u(this,"MicrosoftCalendarProvider")}config;client;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Calendars.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async listEvents(e,t){let s=new URLSearchParams({startDateTime:e.toISOString(),endDateTime:t.toISOString(),$orderby:"start/dateTime",$top:"50"});return((await this.graphRequest(`/me/calendarView?${s}`)).value??[]).map(o=>this.mapEvent(o))}async createEvent(e){let t=this.timezone,s={subject:e.title,body:e.description?{contentType:"text",content:e.description}:void 0,location:e.location?{displayName:e.location}:void 0,isAllDay:e.allDay??!1};e.allDay?(s.start={dateTime:this.formatDateInTz(e.start,t).slice(0,10)+"T00:00:00",timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t).slice(0,10)+"T00:00:00",timeZone:t}):(s.start={dateTime:this.formatDateInTz(e.start,t),timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t),timeZone:t});let r=await this.graphRequest("/me/events",{method:"POST",body:JSON.stringify(s)});return this.mapEvent(r)}async updateEvent(e,t){let s={};t.title&&(s.subject=t.title),t.description&&(s.body={contentType:"text",content:t.description}),t.location&&(s.location={displayName:t.location}),t.start&&(s.start={dateTime:this.formatDateInTz(t.start,this.timezone),timeZone:this.timezone}),t.end&&(s.end={dateTime:this.formatDateInTz(t.end,this.timezone),timeZone:this.timezone});let r=await this.graphRequest(`/me/events/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapEvent(r)}async deleteEvent(e){await this.graphRequest(`/me/events/${e}`,{method:"DELETE"})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(o=>!o.allDay&&o.start<t&&o.end>e);return{available:r.length===0,conflicts:r}}formatDateInTz(e,t){let s=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),r=u(o=>s.find(n=>n.type===o)?.value??"00","g");return`${r("year")}-${r("month")}-${r("day")}T${r("hour")}:${r("minute")}:${r("second")}`}mapEvent(e){return{id:e.id,title:e.subject??"(No title)",start:new Date(e.start?.dateTime),end:new Date(e.end?.dateTime),location:e.location?.displayName??void 0,description:e.body?.content??void 0,allDay:e.isAllDay??!1}}}});async function Gs(c){switch(c.provider){case"caldav":{if(!c.caldav)throw new Error("CalDAV config missing");let{CalDAVProvider:e}=await Promise.resolve().then(()=>(In(),sc)),t=new e(c.caldav);return await t.initialize(),t}case"google":{if(!c.google)throw new Error("Google Calendar config missing");let{GoogleCalendarProvider:e}=await Promise.resolve().then(()=>(xn(),rc)),t=new e(c.google);return await t.initialize(),t}case"microsoft":{if(!c.microsoft)throw new Error("Microsoft Calendar config missing");let{MicrosoftCalendarProvider:e}=await Promise.resolve().then(()=>(Rn(),oc)),t=new e(c.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown calendar provider: ${c.provider}`)}}var nc=b(()=>{"use strict";u(Gs,"createCalendarProvider")});var mt,ic=b(()=>{"use strict";P();mt=class extends I{static{u(this,"CalendarSkill")}calendarProvider;timezone;metadata={name:"calendar",category:"productivity",description:"Manage calendar events. List upcoming events, create new events, update or delete existing ones, and check availability.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_events","create_event","update_event","delete_event","check_availability"],description:"The calendar action to perform"},start:{type:"string",description:"Start date/time in ISO 8601 format"},end:{type:"string",description:"End date/time in ISO 8601 format"},title:{type:"string",description:"Event title (for create/update)"},location:{type:"string",description:"Event location (for create/update)"},description:{type:"string",description:"Event description (for create/update)"},event_id:{type:"string",description:"Event ID (for update/delete)"},all_day:{type:"boolean",description:"Whether this is an all-day event"}},required:["action"]}};constructor(e,t){super(),this.calendarProvider=e,this.timezone=t}async execute(e,t){t.timezone&&(this.calendarProvider.timezone=t.timezone);let s=e.action;switch(s){case"list_events":return this.listEvents(e);case"create_event":return this.createEvent(e);case"update_event":return this.updateEvent(e);case"delete_event":return this.deleteEvent(e);case"check_availability":return this.checkAvailability(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async getTodayEvents(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate()),s=new Date(e.getFullYear(),e.getMonth(),e.getDate()+1);try{return await this.calendarProvider.listEvents(t,s)}catch(r){return console.error("[calendar] Failed to fetch today events",r),[]}}async listEvents(e){let t=e.start?new Date(e.start):new Date,s=e.end?new Date(e.end):new Date(t.getTime()+7*24*60*60*1e3);try{let r=await this.calendarProvider.listEvents(t,s);if(r.length===0)return{success:!0,data:[],display:"No events found in this time range."};let o=r.map(n=>this.formatEvent(n)).join(`
|
|
510
510
|
`);return{success:!0,data:r,display:`${r.length} event(s):
|
|
511
511
|
${o}`}}catch(r){return{success:!1,error:`Failed to list events: ${r instanceof Error?r.message:String(r)}`}}}async createEvent(e){let t=e.title,s=e.start,r=e.end;if(!t)return{success:!1,error:'Missing required field "title"'};if(!s)return{success:!1,error:'Missing required field "start"'};if(!r)return{success:!1,error:'Missing required field "end"'};try{let o=await this.calendarProvider.createEvent({title:t,start:new Date(s),end:new Date(r),location:e.location,description:e.description,allDay:e.all_day});return{success:!0,data:o,display:`Event created: ${this.formatEvent(o)}`}}catch(o){return{success:!1,error:`Failed to create event: ${o instanceof Error?o.message:String(o)}`}}}async updateEvent(e){let t=e.event_id;if(!t)return{success:!1,error:'Missing required field "event_id"'};try{let s=await this.calendarProvider.updateEvent(t,{title:e.title,start:e.start?new Date(e.start):void 0,end:e.end?new Date(e.end):void 0,location:e.location,description:e.description,allDay:e.all_day});return{success:!0,data:s,display:`Event updated: ${this.formatEvent(s)}`}}catch(s){return{success:!1,error:`Failed to update event: ${s instanceof Error?s.message:String(s)}`}}}async deleteEvent(e){let t=e.event_id;if(!t)return{success:!1,error:'Missing required field "event_id"'};try{return await this.calendarProvider.deleteEvent(t),{success:!0,data:{deleted:t},display:`Event "${t}" deleted.`}}catch(s){return{success:!1,error:`Failed to delete event: ${s instanceof Error?s.message:String(s)}`}}}async checkAvailability(e){let t=e.start,s=e.end;if(!t||!s)return{success:!1,error:'Missing required fields "start" and "end"'};try{let r=await this.calendarProvider.checkAvailability(new Date(t),new Date(s)),o=r.available?"Time slot is available.":`Time slot has ${r.conflicts.length} conflict(s):
|
|
512
512
|
${r.conflicts.map(n=>this.formatEvent(n)).join(`
|
|
513
|
-
`)}`;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
|
|
513
|
+
`)}`;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 ac=b(()=>{"use strict";Ks();In();xn();Rn();nc();ic()});var Wt,cc=b(()=>{"use strict";P();Wt=class extends I{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}**
|
|
514
514
|
|
|
515
515
|
Enter this code on your other platform within 10 minutes using:
|
|
516
516
|
"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.
|
|
@@ -518,18 +518,18 @@ Enter this code on your other platform within 10 minutes using:
|
|
|
518
518
|
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:
|
|
519
519
|
"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:
|
|
520
520
|
${o.join(`
|
|
521
|
-
`)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=this.resolveInternalId(t),o=this.users.getMasterUserId(r),i=this.users.getLinkedUsers(o).find(a=>a.platform===s&&a.id!==r);return i?(this.users.setMasterUser(i.id,i.id),{success:!0,data:{unlinkedPlatform:s,unlinkedUserId:i.id},display:`Unlinked ${s} account (${i.displayName??i.username??i.platformUserId}).`}):{success:!1,error:`No linked account found on platform "${s}".`}}}});var Vt,
|
|
521
|
+
`)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=this.resolveInternalId(t),o=this.users.getMasterUserId(r),i=this.users.getLinkedUsers(o).find(a=>a.platform===s&&a.id!==r);return i?(this.users.setMasterUser(i.id,i.id),{success:!0,data:{unlinkedPlatform:s,unlinkedUserId:i.id},display:`Unlinked ${s} account (${i.displayName??i.username??i.platformUserId}).`}):{success:!1,error:`No linked account found on platform "${s}".`}}}});var Vt,lc=b(()=>{"use strict";P();Me();Vt=class extends I{static{u(this,"BackgroundTaskSkill")}taskRepo;metadata={name:"background_task",category:"automation",description:'Schedule, list, or cancel background tasks that run independently. Use "schedule" to queue a skill to execute in the background (user will be notified when done). Use "list" to see active/recent tasks. Use "cancel" to stop a pending or running task.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["schedule","list","cancel"],description:"The background task action to perform"},description:{type:"string",description:"Human-readable description of what the task does (for schedule)"},skill_name:{type:"string",description:"The skill to run in the background (for schedule)"},skill_input:{type:"object",description:"Input to pass to the skill (for schedule)"},task_id:{type:"string",description:"Task ID (for cancel)"}},required:["action"]}};constructor(e){super(),this.taskRepo=e}getAllTasks(e){let t=new Set,s=[];for(let r of W(e))for(let o of this.taskRepo.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"schedule":return this.scheduleTask(e,t);case"list":return this.listTasks(t);case"cancel":return this.cancelTask(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: schedule, list, cancel`}}}scheduleTask(e,t){let s=e.description,r=e.skill_name,o=e.skill_input;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "description" for schedule action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "skill_name" for schedule action'};let n=this.taskRepo.create(ee(t),t.platform,t.chatId,s,r,JSON.stringify(o??{}));return{success:!0,data:{taskId:n.id,description:s,skillName:r,status:n.status},display:`Background task scheduled (${n.id}): "${s}" using skill "${r}". You'll be notified when it completes.`}}listTasks(e){let t=this.getAllTasks(e);if(t.length===0)return{success:!0,data:[],display:"No active or recent background tasks."};let s={pending:"\u23F3",running:"\u25B6\uFE0F",completed:"\u2705",failed:"\u274C"},r=t.map(o=>`- ${s[o.status]??"?"} ${o.id}: "${o.description}" [${o.status}] (${o.skillName})`);return{success:!0,data:t.map(o=>({taskId:o.id,description:o.description,status:o.status,skillName:o.skillName,createdAt:o.createdAt,completedAt:o.completedAt})),display:`Background tasks:
|
|
522
522
|
${r.join(`
|
|
523
|
-
`)}`}}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 Kt,
|
|
523
|
+
`)}`}}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 Kt,dc=b(()=>{"use strict";P();Me();Kt=class extends I{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:ee(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:
|
|
524
524
|
${s.join(`
|
|
525
|
-
`)}`}}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,
|
|
526
|
-
`),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
|
|
525
|
+
`)}`}}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,Cn=b(()=>{"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(`
|
|
526
|
+
`),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 xu,ht,Ln=b(()=>{"use strict";P();xu=["read","write","destructive","admin"],ht=class extends I{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&&xu.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 Xs,uc=b(()=>{"use strict";Cn();Ln();Xs=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 mc=b(()=>{"use strict";Cn();Ln();uc()});import{spawn as Ru}from"node:child_process";import Gt from"node:fs";import Xt from"node:path";import Cu from"node:os";import Lu from"node:crypto";var ft,Nn=b(()=>{"use strict";ft=class{static{u(this,"CodeExecutor")}resolveNodePath(){let e=[];try{let t=qi.resolve("pdf-parse/package.json");e.push(Xt.dirname(Xt.dirname(t)))}catch{}return process.env.NODE_PATH&&e.push(process.env.NODE_PATH),e.filter(Boolean).join(Xt.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),o=Xt.join(Cu.tmpdir(),`alfred-sandbox-${Lu.randomUUID()}`);Gt.mkdirSync(o,{recursive:!0});try{let n=t==="javascript"?"js":"py",i=Xt.join(o,`script.${n}`);Gt.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=Ru(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,NODE_PATH:this.resolveNodePath()},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=Gt.readdirSync(o).filter(x=>!x.startsWith("script."));for(let x of A){let U=Xt.join(o,x),L=Gt.statSync(U);if(L.isFile()&&L.size<1e7){let Y=Gt.readFileSync(U),Oe=x.endsWith(".png")?"image/png":x.endsWith(".jpg")||x.endsWith(".jpeg")?"image/jpeg":x.endsWith(".svg")?"image/svg+xml":x.endsWith(".csv")?"text/csv":x.endsWith(".json")?"application/json":x.endsWith(".html")||x.endsWith(".htm")?"text/html":x.endsWith(".txt")?"text/plain":x.endsWith(".md")?"text/markdown":x.endsWith(".xml")?"application/xml":x.endsWith(".pdf")?"application/pdf":"application/octet-stream";$.push({name:x,data:Y,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{Gt.rmSync(o,{recursive:!0,force:!0})}catch{}}}}});var Ys,pc=b(()=>{"use strict";P();Nn();Ys=class extends I{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)};
|
|
527
527
|
${r}`:a=`INPUT_DATA = ${JSON.stringify(n)}
|
|
528
528
|
${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:
|
|
529
529
|
${l.stdout}`:"",l.stderr?`Errors:
|
|
530
530
|
${l.stderr}`:"",`Exit code: ${l.exitCode}`,`Duration: ${l.durationMs}ms`,d&&d.length>0?`Files generated: ${d.map(p=>p.fileName).join(", ")}`:""].filter(Boolean).join(`
|
|
531
531
|
|
|
532
|
-
`);return{success:l.exitCode===0,data:{stdout:l.stdout,stderr:l.stderr,exitCode:l.exitCode,durationMs:l.durationMs,fileCount:l.files?.length??0},display:m,error:l.exitCode!==0?`Code execution failed with exit code ${l.exitCode}`:void 0,attachments:d}}}});var
|
|
532
|
+
`);return{success:l.exitCode===0,data:{stdout:l.stdout,stderr:l.stderr,exitCode:l.exitCode,durationMs:l.durationMs,fileCount:l.files?.length??0},display:m,error:l.exitCode!==0?`Code execution failed with exit code ${l.exitCode}`:void 0,attachments:d}}}});var hc=b(()=>{"use strict";Nn();pc()});var Yt,fc=b(()=>{"use strict";P();Me();Yt=class extends I{static{u(this,"DocumentSkill")}docRepo;processor;embeddingService;metadata={name:"document",category:"files",description:"Ingest, search, summarize, list, or delete documents. Supports PDF, DOCX, TXT, CSV, and Markdown files. Documents are chunked and embedded for semantic search.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["ingest","search","summarize","list","delete"],description:"Action to perform"},file_path:{type:"string",description:"Path to the file (for ingest)"},filename:{type:"string",description:"Original filename (for ingest)"},mime_type:{type:"string",description:"MIME type of the file (for ingest)"},query:{type:"string",description:"Search query (for search)"},document_id:{type:"string",description:"Document ID (for summarize, delete)"},limit:{type:"number",description:"Max results (for search, list)"}},required:["action"]}};constructor(e,t,s){super(),this.docRepo=e,this.processor=t,this.embeddingService=s}async execute(e,t){let s=e.action;switch(s){case"ingest":return this.ingest(e,t);case"search":return this.search(e,t);case"summarize":return this.summarize(e);case"list":return this.list(e,t);case"delete":return this.deleteDoc(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: ingest, search, summarize, list, delete`}}}async ingest(e,t){let s=e.file_path,r=e.filename,o=e.mime_type;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "file_path" for ingest action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "filename" for ingest action'};if(!o||typeof o!="string")return{success:!1,error:'Missing required field "mime_type" for ingest action'};let n=await import("node:path"),i=n.resolve(s);if(i!==n.normalize(s)&&s.includes(".."))return{success:!1,error:"Invalid file path: path traversal not allowed"};let a=i.toLowerCase();if(a.startsWith("/etc/")||a.startsWith("/proc/")||a.startsWith("/sys/")||a.startsWith("c:\\windows\\")||a.startsWith("/root/"))return{success:!1,error:"Access to system directories is not allowed"};try{let l=await this.processor.ingest(ee(t),s,r,o);return{success:!0,data:l,display:`Document "${r}" ingested successfully (${l.chunkCount} chunks). ID: ${l.documentId.slice(0,8)}...`}}catch(l){return{success:!1,error:`Failed to ingest document: ${l instanceof Error?l.message:String(l)}`}}}async search(e,t){let s=e.query,r=e.limit||5;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for search action'};if(!this.embeddingService)return{success:!1,error:"Embedding service not available for document search"};let o=W(t),n=new Set,i=[];for(let d of o)for(let m of await this.embeddingService.semanticSearch(d,s,r))n.has(m.key)||(n.add(m.key),i.push(m));let a=i.filter(d=>d.category==="document");if(a.length===0)return{success:!0,data:[],display:`No document matches found for "${s}".`};let l=a.map((d,m)=>`${m+1}. (score: ${d.score.toFixed(3)}) ${d.value.slice(0,200)}${d.value.length>200?"...":""}`).join(`
|
|
533
533
|
|
|
534
534
|
`);return{success:!0,data:a,display:`Found ${a.length} relevant chunk(s):
|
|
535
535
|
|
|
@@ -541,11 +541,11 @@ ${l}`}}summarize(e){let t=e.document_id;if(!t||typeof t!="string")return{success
|
|
|
541
541
|
|
|
542
542
|
${a}`}}list(e,t){let s=e.limit||50,r=W(t),o=new Set,n=[];for(let l of r)for(let d of this.docRepo.listByUser(l))o.has(d.id)||(o.add(d.id),n.push(d));let i=n.slice(0,s);if(i.length===0)return{success:!0,data:[],display:"No documents found."};let a=i.map(l=>`- **${l.filename}** (${l.id.slice(0,8)}...) \u2014 ${l.mimeType}, ${l.chunkCount} chunks, ${l.sizeBytes} bytes`).join(`
|
|
543
543
|
`);return{success:!0,data:i,display:`${i.length} document(s):
|
|
544
|
-
${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success:!1,error:'Missing required field "document_id" for delete action'};let s=this.docRepo.getDocument(t);return s?(this.docRepo.deleteDocument(t),{success:!0,data:{documentId:t},display:`Document "${s.filename}" deleted.`}):{success:!1,error:`Document "${t}" not found`}}}});var
|
|
545
|
-
`)}}async listNodes(){let e=await this.get("/nodes"),t=["## Nodes","","| Node | Status | CPU | RAM Used / Total | Uptime |"];t.push("|------|--------|-----|------------------|--------|");for(let s of e){let r=typeof s.cpu=="number"?
|
|
546
|
-
`)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,o=s.memory,n=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${
|
|
547
|
-
`)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let o=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let n of o)s.push({...n,node:e,type:"qemu"})}if(!t||t==="lxc"){let o=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let n of o)s.push({...n,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(o=>o.type===t));s.sort((o,n)=>o.vmid-n.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let o of s)r.push(`| ${o.vmid} | ${o.name??"-"} | ${o.type} | ${o.node} | ${o.status??"-"} | ${
|
|
548
|
-
`)}}async vmStatus(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/status/current`),o=[`## VM ${e} (${s.type}) on ${s.node}`,"",`**Name:** ${r.name??"-"}`,`**Status:** ${r.status}`,`**CPU:** ${
|
|
544
|
+
${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success:!1,error:'Missing required field "document_id" for delete action'};let s=this.docRepo.getDocument(t);return s?(this.docRepo.deleteDocument(t),{success:!0,data:{documentId:t},display:`Document "${s.filename}" deleted.`}):{success:!1,error:`Document "${t}" not found`}}}});var Jt,gc=b(()=>{"use strict";P();Jt=class extends I{static{u(this,"TTSSkill")}synthesizer;metadata={name:"text_to_speech",category:"media",description:"Send a voice/audio message to the user. You MUST use this tool whenever the user asks you to respond as a voice message, speak, or reply with audio. Pass the full response text \u2014 it will be converted to speech and delivered as a playable voice message.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{text:{type:"string",description:"The text to convert to speech"}},required:["text"]}};constructor(e){super(),this.synthesizer=e}async execute(e,t){let s=e.text;if(!s)return{success:!1,error:"No text provided for speech synthesis."};try{return{success:!0,display:"Voice message sent.",attachments:[{fileName:"voice.ogg",data:await this.synthesizer.synthesize(s),mimeType:"audio/ogg"}]}}catch(r){return{success:!1,error:`Speech synthesis failed: ${r instanceof Error?r.message:String(r)}`}}}}});function ne(c){return c==null?"-":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 Js(c){return c==null?"-":`${(c*100).toFixed(1)}%`}function Vr(c){if(!c)return"-";let e=Math.floor(c/86400),t=Math.floor(c%86400/3600),s=Math.floor(c%3600/60),r=[];return e&&r.push(`${e}d`),t&&r.push(`${t}h`),r.push(`${s}m`),r.join(" ")}var Kr,yc=b(()=>{"use strict";P();u(ne,"bytes");u(Js,"pct");u(Vr,"uptimeStr");Kr=class c extends I{static{u(this,"ProxmoxSkill")}metadata={name:"proxmox",category:"infrastructure",description:'Manage Proxmox VE virtual machines, containers, and cluster. Use action "list_vms" to see VMs, "start_vm"/"shutdown_vm" to control them, "cluster_status" for health, "create_snapshot" for backups.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["cluster_status","list_nodes","node_stats","list_vms","vm_status","list_snapshots","list_storage","list_tasks","task_status","start_vm","shutdown_vm","reboot_vm","suspend_vm","resume_vm","create_snapshot","backup_vm","migrate_vm","stop_vm","delete_snapshot","rollback_snapshot"],description:"The Proxmox action to perform"},vmid:{type:"number",description:"Virtual machine / container ID"},node:{type:"string",description:"Proxmox node name (optional \u2014 resolved automatically when omitted)"},type:{type:"string",enum:["qemu","lxc"],description:"VM type filter for list_vms (default: both)"},name:{type:"string",description:"Snapshot name (for create/delete/rollback_snapshot)"},description:{type:"string",description:"Snapshot description (optional)"},target:{type:"string",description:"Target node for migration"},storage:{type:"string",description:"Storage target for backup_vm"},upid:{type:"string",description:"Task UPID for task_status"}},required:["action"]}};config;vmCache=null;static VM_CACHE_TTL=3e4;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"cluster_status":return await this.clusterStatus();case"list_nodes":return await this.listNodes();case"node_stats":return await this.nodeStats(e.node);case"list_vms":return await this.listVms(e.node,e.type);case"vm_status":return await this.vmStatus(e.vmid,e.node);case"list_snapshots":return await this.listSnapshots(e.vmid,e.node);case"list_storage":return await this.listStorage(e.node);case"list_tasks":return await this.listTasks(e.node);case"task_status":return await this.taskStatus(e.upid);case"start_vm":return await this.vmPowerAction("start",e);case"shutdown_vm":return await this.vmPowerAction("shutdown",e);case"reboot_vm":return await this.vmPowerAction("reboot",e);case"suspend_vm":return await this.vmPowerAction("suspend",e);case"resume_vm":return await this.vmPowerAction("resume",e);case"stop_vm":return await this.vmPowerAction("stop",e);case"create_snapshot":return await this.createSnapshot(e);case"backup_vm":return await this.backupVm(e);case"migrate_vm":return await this.migrateVm(e);case"delete_snapshot":return await this.deleteSnapshot(e);case"rollback_snapshot":return await this.rollbackSnapshot(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Proxmox API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl}/api2/json${t}`,o={Authorization:`PVEAPIToken=${this.config.tokenId}=${this.config.tokenSecret}`},n={method:e,headers:o};s&&e!=="GET"&&(o["Content-Type"]="application/json",n.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let l;try{l=await fetch(r,n)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!l.ok){let m="";try{m=(await l.text()).slice(0,500)}catch{}throw new Error(`HTTP ${l.status} ${l.statusText} \u2014 ${m}`)}return(await l.json()).data}async get(e){return this.api("GET",e)}async post(e,t){return this.api("POST",e,t)}async del(e){return this.api("DELETE",e)}async resolveVm(e,t){if(t)try{return await this.get(`/nodes/${t}/qemu/${e}/status/current`),{node:t,type:"qemu"}}catch{try{return await this.get(`/nodes/${t}/lxc/${e}/status/current`),{node:t,type:"lxc"}}catch{throw new Error(`VM ${e} not found on node "${t}"`)}}let r=(await this.getAllVms()).find(o=>o.vmid===e);if(!r)throw new Error(`VM ${e} not found on any node. Use "list_vms" to see available VMs.`);return{node:r.node,type:r.type}}async getAllVms(){let e=Date.now();if(this.vmCache&&e-this.vmCache.ts<c.VM_CACHE_TTL)return this.vmCache.entries;let t=await this.get("/nodes"),s=[];for(let r of t){let[o,n]=await Promise.all([this.get(`/nodes/${r.node}/qemu`).catch(()=>[]),this.get(`/nodes/${r.node}/lxc`).catch(()=>[])]);for(let i of o)s.push({...i,node:r.node,type:"qemu"});for(let i of n)s.push({...i,node:r.node,type:"lxc"})}return this.vmCache={entries:s,ts:e},s}async clusterStatus(){let e=await this.get("/cluster/status"),t=["## Cluster Status",""],s=e.find(o=>o.type==="cluster");s&&(t.push(`**Cluster:** ${s.name}`),t.push(`**Quorum:** ${s.quorate?"Yes":"No"}`),t.push(`**Nodes:** ${s.nodes??"-"}`),t.push(`**Version:** ${s.version??"-"}`),t.push(""));let r=e.filter(o=>o.type==="node");if(r.length){t.push("| Node | Online | Level | ID |"),t.push("|------|--------|-------|----|");for(let o of r)t.push(`| ${o.name} | ${o.online?"Yes":"**No**"} | ${o.level??"-"} | ${o.nodeid??"-"} |`)}return{success:!0,data:e,display:t.join(`
|
|
545
|
+
`)}}async listNodes(){let e=await this.get("/nodes"),t=["## Nodes","","| Node | Status | CPU | RAM Used / Total | Uptime |"];t.push("|------|--------|-----|------------------|--------|");for(let s of e){let r=typeof s.cpu=="number"?Js(s.cpu):"-",o=ne(s.mem),n=ne(s.maxmem);t.push(`| ${s.node} | ${s.status} | ${r} | ${o} / ${n} | ${Vr(s.uptime)} |`)}return{success:!0,data:e,display:t.join(`
|
|
546
|
+
`)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,o=s.memory,n=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${Vr(s.uptime)}`,`**Kernel:** ${s.kversion??"-"}`,`**PVE Version:** ${s.pveversion??"-"}`,""];return r&&(a.push(`**CPU:** ${r.model??"-"} (${r.cpus??"-"} cores)`),a.push(`**CPU Usage:** ${Js(r.cpu)}`),a.push(`**Load:** ${Array.isArray(s.loadavg)?s.loadavg.join(", "):"-"}`)),o&&a.push(`**RAM:** ${ne(o.used)} / ${ne(o.total)} (${Js(o.used/o.total)})`),i&&a.push(`**Swap:** ${ne(i.used)} / ${ne(i.total)}`),n&&a.push(`**Root FS:** ${ne(n.used)} / ${ne(n.total)}`),{success:!0,data:s,display:a.join(`
|
|
547
|
+
`)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let o=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let n of o)s.push({...n,node:e,type:"qemu"})}if(!t||t==="lxc"){let o=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let n of o)s.push({...n,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(o=>o.type===t));s.sort((o,n)=>o.vmid-n.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let o of s)r.push(`| ${o.vmid} | ${o.name??"-"} | ${o.type} | ${o.node} | ${o.status??"-"} | ${Js(o.cpu)} | ${ne(o.mem)} / ${ne(o.maxmem)} | ${Vr(o.uptime)} |`);return s.length===0&&r.push("| - | No VMs found | - | - | - | - | - | - |"),{success:!0,data:s,display:r.join(`
|
|
548
|
+
`)}}async vmStatus(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/status/current`),o=[`## VM ${e} (${s.type}) on ${s.node}`,"",`**Name:** ${r.name??"-"}`,`**Status:** ${r.status}`,`**CPU:** ${Js(r.cpu)} (${r.cpus??"-"} cores)`,`**RAM:** ${ne(r.mem)} / ${ne(r.maxmem)}`,`**Disk:** ${ne(r.disk)} / ${ne(r.maxdisk)}`,`**Uptime:** ${Vr(r.uptime)}`,`**PID:** ${r.pid??"-"}`,`**Net In / Out:** ${ne(r.netin)} / ${ne(r.netout)}`];return r.lock&&o.push(`**Lock:** ${r.lock}`),{success:!0,data:r,display:o.join(`
|
|
549
549
|
`)}}async listSnapshots(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/snapshot`),o=[`## Snapshots for VM ${e}`,"","| Name | Description | Date | Parent |","|------|-------------|------|--------|"];for(let n of r){let i=n.snaptime?new Date(n.snaptime*1e3).toISOString():"-";o.push(`| ${n.name} | ${n.description??"-"} | ${i} | ${n.parent??"-"} |`)}return{success:!0,data:r,display:o.join(`
|
|
550
550
|
`)}}async listStorage(e){let t=e??this.config.defaultNode,s=t?`/nodes/${t}/storage`:"/storage",r=await this.get(s),o=[`## Storage${t?` (Node: ${t})`:""}`,"","| Storage | Type | Content | Used / Total | Status |","|---------|------|---------|--------------|--------|"];for(let n of r){let i=ne(n.used),a=ne(n.total);o.push(`| ${n.storage} | ${n.type} | ${n.content??"-"} | ${i} / ${a} | ${n.active?"active":n.enabled?"enabled":"disabled"} |`)}return{success:!0,data:r,display:o.join(`
|
|
551
551
|
`)}}async listTasks(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/tasks?limit=20`),r=[`## Recent Tasks (Node: ${t})`,"","| UPID | Type | Status | Start | User |","|------|------|--------|-------|------|"];for(let o of s){let n=o.starttime?new Date(o.starttime*1e3).toISOString():"-";r.push(`| \`${o.upid?.slice(-16)??"-"}\` | ${o.type??"-"} | ${o.status??"running"} | ${n} | ${o.user??"-"} |`)}return{success:!0,data:s,display:r.join(`
|
|
@@ -556,7 +556,7 @@ ${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success
|
|
|
556
556
|
`)}}async migrateVm(e){let t=e.vmid,s=e.target;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "target" parameter (target node)'};let r=await this.resolveVm(t,e.node),o=await this.post(`/nodes/${r.node}/${r.type}/${t}/migrate`,{target:s,online:1});return{success:!0,data:{vmid:t,from:r.node,target:s,type:r.type,upid:o},display:[`Live migration of VM ${t} from **${r.node}** to **${s}** started.`,"",`UPID: \`${o}\``].join(`
|
|
557
557
|
`)}}async deleteSnapshot(e){let t=e.vmid,s=e.name;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "name" parameter (snapshot name)'};let r=await this.resolveVm(t,e.node),o=await this.del(`/nodes/${r.node}/${r.type}/${t}/snapshot/${encodeURIComponent(s)}`);return{success:!0,data:{vmid:t,node:r.node,type:r.type,snapname:s,upid:o},display:[`Snapshot **"${s}"** deletion started for VM ${t} on **${r.node}**.`,"",`UPID: \`${o}\``].join(`
|
|
558
558
|
`)}}async rollbackSnapshot(e){let t=e.vmid,s=e.name;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "name" parameter (snapshot name)'};let r=await this.resolveVm(t,e.node),o=await this.post(`/nodes/${r.node}/${r.type}/${t}/snapshot/${encodeURIComponent(s)}/rollback`);return{success:!0,data:{vmid:t,node:r.node,type:r.type,snapname:s,upid:o},display:[`Rollback to snapshot **"${s}"** started for VM ${t} on **${r.node}**.`,"",`UPID: \`${o}\``,"","**Warning:** The VM will be stopped during rollback."].join(`
|
|
559
|
-
`)}}}});var
|
|
559
|
+
`)}}}});var Gr,wc=b(()=>{"use strict";P();Gr=class extends I{static{u(this,"UniFiSkill")}metadata={name:"unifi",category:"infrastructure",description:'Manage UniFi network devices, clients, and WLANs. Use "list_devices" to see APs/switches, "list_clients" for connected clients, "restart_device" to reboot a device, "block_client"/"unblock_client" for access control.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_devices","device_info","list_clients","client_info","list_networks","list_wlans","site_stats","dpi_stats","list_alerts","list_events","list_vouchers","restart_device","locate_device","reconnect_client","create_voucher","enable_wlan","disable_wlan","archive_alerts","block_client","unblock_client","forget_client","adopt_device"],description:"The UniFi action to perform"},mac:{type:"string",description:"MAC address of device or client (for device_info, client_info, restart_device, locate_device, reconnect_client, block_client, unblock_client, forget_client, adopt_device)"},active:{type:"boolean",description:"If true list only active clients, if false list all known clients (for list_clients, default: true)"},enabled:{type:"boolean",description:"Enable or disable device locate LED (for locate_device, default: true)"},id:{type:"string",description:"WLAN config ID (for enable_wlan, disable_wlan)"},limit:{type:"number",description:"Maximum number of items to return (for list_alerts, list_events)"},count:{type:"number",description:"Number of vouchers to create (for create_voucher, default: 1)"},duration:{type:"number",description:"Voucher validity in minutes (for create_voucher)"},bandwidth_down:{type:"number",description:"Download bandwidth limit in Kbps (for create_voucher, optional)"},bandwidth_up:{type:"number",description:"Upload bandwidth limit in Kbps (for create_voucher, optional)"},quota:{type:"number",description:"Number of uses per voucher (for create_voucher, 0 = unlimited, default: 1)"}},required:["action"]}};config;site;controllerMode;cookies=[];csrfToken;constructor(e){if(super(),!e.apiKey&&!(e.username&&e.password))throw new Error('UniFi config requires either "apiKey" or both "username" and "password".');this.config=e,this.site=e.site??"default",e.apiKey&&(this.controllerMode="unifi-os")}async execute(e,t){let s=e.action;try{switch(s){case"list_devices":return await this.listDevices();case"device_info":return await this.deviceInfo(e.mac);case"list_clients":return await this.listClients(e.active);case"client_info":return await this.clientInfo(e.mac);case"list_networks":return await this.listNetworks();case"list_wlans":return await this.listWlans();case"site_stats":return await this.siteStats();case"dpi_stats":return await this.dpiStats(e.mac);case"list_alerts":return await this.listAlerts(e.limit);case"list_events":return await this.listEvents(e.limit);case"list_vouchers":return await this.listVouchers();case"restart_device":return await this.restartDevice(e.mac);case"locate_device":return await this.locateDevice(e.mac,e.enabled);case"reconnect_client":return await this.reconnectClient(e.mac);case"create_voucher":return await this.createVoucher(e.count,e.duration,e.bandwidth_down,e.bandwidth_up,e.quota);case"enable_wlan":return await this.enableWlan(e.id);case"disable_wlan":return await this.disableWlan(e.id);case"archive_alerts":return await this.archiveAlerts();case"block_client":return await this.blockClient(e.mac);case"unblock_client":return await this.unblockClient(e.mac);case"forget_client":return await this.forgetClient(e.mac);case"adopt_device":return await this.adoptDevice(e.mac);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:`UniFi error: ${r instanceof Error?r.message:String(r)}`}}}apiUrl(e){let t=this.config.baseUrl.replace(/\/+$/,"");return this.controllerMode==="unifi-os"?`${t}/proxy/network/api/s/${this.site}/${e}`:`${t}/api/s/${this.site}/${e}`}async ensureAuth(){this.config.apiKey||this.cookies.length>0||await this.login()}async login(){let e=this.config.baseUrl.replace(/\/+$/,""),t=JSON.stringify({username:this.config.username,password:this.config.password}),s=await this.rawFetch(`${e}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(s.status===200){this.controllerMode="unifi-os",this.storeCookies(s);return}if(s.status===404){let r=await this.rawFetch(`${e}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(r.ok){this.controllerMode="classic",this.storeCookies(r);return}throw new Error(`UniFi Classic login failed (HTTP ${r.status}): ${await r.text()}`)}throw new Error(`UniFi OS login failed (HTTP ${s.status}): ${await s.text()}`)}storeCookies(e){let t=e.headers.getSetCookie?.()??[];t.length>0&&(this.cookies=t.map(r=>r.split(";")[0]));let s=e.headers.get("x-csrf-token");s&&(this.csrfToken=s)}clearSession(){this.cookies=[],this.csrfToken=void 0}async rawFetch(e,t){let s=process.env.NODE_TLS_REJECT_UNAUTHORIZED;this.config.verifyTls===!1&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{this.config.verifyTls===!1&&(s===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=s)}}async request(e,t,s){await this.ensureAuth();let r=await this.doFetch(e,t,s);if(r.status===401&&!this.config.apiKey){this.clearSession(),await this.login();let o=await this.doFetch(e,t,s);if(!o.ok)throw new Error(`UniFi API error after relogin: HTTP ${o.status} ${await o.text()}`);return this.parseResponse(o)}if(!r.ok)throw new Error(`UniFi API error: HTTP ${r.status} ${await r.text()}`);return this.parseResponse(r)}async doFetch(e,t,s){let r=this.apiUrl(t),o={"Content-Type":"application/json"};return this.config.apiKey?o["X-API-Key"]=this.config.apiKey:(this.cookies.length>0&&(o.Cookie=this.cookies.join("; ")),this.csrfToken&&(o["X-CSRF-Token"]=this.csrfToken)),this.rawFetch(r,{method:e,headers:o,body:s!==void 0?JSON.stringify(s):void 0,signal:AbortSignal.timeout(3e4)})}async parseResponse(e){let t=await e.json(),s=e.headers.get("x-csrf-token");if(s&&(this.csrfToken=s),t.meta?.rc==="error")throw new Error(`UniFi: ${t.meta.msg??"unknown error"}`);return t.data}async listDevices(){let e=await this.request("GET","stat/device"),t=(e??[]).map(r=>({name:r.name??r.hostname??r.mac,model:r.model??"unknown",ip:r.ip??"-",mac:r.mac,status:r.state===1?"online":"offline",clients:r.num_sta??0,load:r["system-stats"]?.cpu!=null?`${r["system-stats"].cpu}%`:"-"})),s=t.length===0?"No devices found.":["| Name | Model | IP | MAC | Status | Clients | CPU |","|------|-------|----|-----|--------|---------|-----|",...t.map(r=>`| ${r.name} | ${r.model} | ${r.ip} | ${r.mac} | ${r.status} | ${r.clients} | ${r.load} |`)].join(`
|
|
560
560
|
`);return{success:!0,data:e,display:s}}async deviceInfo(e){if(!e)return{success:!1,error:"mac is required for device_info."};let s=(await this.request("GET",`stat/device/${e}`))?.[0];if(!s)return{success:!1,error:`Device ${e} not found.`};let r=[`**${s.name??s.hostname??e}**`,`- Model: ${s.model??"unknown"} (${s.model_in_lts?"LTS":s.model_in_eol?"EOL":"supported"})`,`- IP: ${s.ip??"-"}`,`- MAC: ${s.mac}`,`- Status: ${s.state===1?"online":"offline"}`,`- Version: ${s.version??"-"}`,`- Uptime: ${s.uptime?this.formatUptime(s.uptime):"-"}`,`- Clients: ${s.num_sta??0}`,`- CPU: ${s["system-stats"]?.cpu??"-"}%`,`- Memory: ${s["system-stats"]?.mem??"-"}%`,`- TX bytes: ${this.formatBytes(s.tx_bytes??0)}`,`- RX bytes: ${this.formatBytes(s.rx_bytes??0)}`];return{success:!0,data:s,display:r.join(`
|
|
561
561
|
`)}}async listClients(e){let t=e!==!1,s=t?"stat/sta":"rest/user",r=await this.request("GET",s),o=(r??[]).map(i=>({name:i.name??i.hostname??i.mac,ip:i.ip??i.fixed_ip??"-",mac:i.mac,network:i.essid??i.network??"-",signal:i.signal!=null?`${i.signal} dBm`:"-",tx:this.formatBytes(i.tx_bytes??0),rx:this.formatBytes(i.rx_bytes??0)})),n=o.length===0?"No clients found.":["| Name | IP | MAC | Network | Signal | TX | RX |","|------|----|-----|---------|--------|----|----|",...o.map(i=>`| ${i.name} | ${i.ip} | ${i.mac} | ${i.network} | ${i.signal} | ${i.tx} | ${i.rx} |`)].join(`
|
|
562
562
|
`);return{success:!0,data:r,display:`${t?"Active":"All known"} clients (${o.length}):
|
|
@@ -572,15 +572,15 @@ ${n}`}}async clientInfo(e){if(!e)return{success:!1,error:"mac is required for cl
|
|
|
572
572
|
`);return{success:!0,data:s,display:o}}async listEvents(e){let t=Math.min(Math.max(1,e??20),200),s=await this.request("GET",`stat/event?_limit=${t}`),r=(s??[]).slice(0,t).map(n=>({time:n.datetime??n.time??"-",type:n.key??"-",message:n.msg??"-"})),o=r.length===0?"No events.":["| Time | Type | Message |","|------|------|---------|",...r.map(n=>`| ${n.time} | ${n.type} | ${n.message} |`)].join(`
|
|
573
573
|
`);return{success:!0,data:s,display:o}}async listVouchers(){let e=await this.request("GET","stat/voucher"),t=(e??[]).map(r=>({code:r.code??"-",duration:r.duration!=null?`${r.duration} min`:"-",quota:r.quota??0,used:r.used??0,created:r.create_time?new Date(r.create_time*1e3).toISOString():"-",note:r.note??"-"})),s=t.length===0?"No vouchers.":["| Code | Duration | Quota | Used | Created | Note |","|------|----------|-------|------|---------|------|",...t.map(r=>`| ${r.code} | ${r.duration} | ${r.quota} | ${r.used} | ${r.created} | ${r.note} |`)].join(`
|
|
574
574
|
`);return{success:!0,data:e,display:s}}async restartDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"restart",mac:e}),{success:!0,data:{mac:e},display:`Restart command sent to device ${e}.`}):{success:!1,error:"mac is required for restart_device."}}async locateDevice(e,t){if(!e)return{success:!1,error:"mac is required for locate_device."};let s=t!==!1,r=s?"set-locate":"unset-locate";return await this.request("POST","cmd/devmgr",{cmd:r,mac:e}),{success:!0,data:{mac:e,enabled:s},display:`Device ${e} locate LED ${s?"enabled":"disabled"}.`}}async reconnectClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"kick-sta",mac:e}),{success:!0,data:{mac:e},display:`Reconnect (kick) command sent to client ${e}.`}):{success:!1,error:"mac is required for reconnect_client."}}async createVoucher(e,t,s,r,o){if(!t)return{success:!1,error:"duration (minutes) is required for create_voucher."};let n={cmd:"create-voucher",n:e??1,expire:t,quota:o??1};s!=null&&(n.down=s),r!=null&&(n.up=r);let i=await this.request("POST","cmd/hotspot",n),a=i?.[0]?.create_time;return{success:!0,data:i,display:`Created ${e??1} voucher(s), duration ${t} min.${a?` Batch: ${a}`:""}
|
|
575
|
-
Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!0}),{success:!0,data:{id:e,enabled:!0},display:`WLAN ${e} enabled.`}):{success:!1,error:"id is required for enable_wlan."}}async disableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!1}),{success:!0,data:{id:e,enabled:!1},display:`WLAN ${e} disabled.`}):{success:!1,error:"id is required for disable_wlan."}}async archiveAlerts(){return await this.request("POST","cmd/evtmgr",{cmd:"archive-all-alarms"}),{success:!0,data:{},display:"All alerts archived."}}async blockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"block-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} blocked.`}):{success:!1,error:"mac is required for block_client."}}async unblockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"unblock-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} unblocked.`}):{success:!1,error:"mac is required for unblock_client."}}async forgetClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"forget-sta",macs:[e]}),{success:!0,data:{mac:e},display:`Client ${e} forgotten (removed from known clients).`}):{success:!1,error:"mac is required for forget_client."}}async adoptDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"adopt",mac:e}),{success:!0,data:{mac:e},display:`Adopt command sent to device ${e}.`}):{success:!1,error:"mac is required for adopt_device."}}formatBytes(e){if(e===0)return"0 B";let t=["B","KB","MB","GB","TB"],s=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/Math.pow(1024,s)).toFixed(s===0?0:1)} ${t[s]}`}formatUptime(e){let t=Math.floor(e/86400),s=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),o=[];return t>0&&o.push(`${t}d`),s>0&&o.push(`${s}h`),o.push(`${r}m`),o.join(" ")}}});function
|
|
575
|
+
Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!0}),{success:!0,data:{id:e,enabled:!0},display:`WLAN ${e} enabled.`}):{success:!1,error:"id is required for enable_wlan."}}async disableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!1}),{success:!0,data:{id:e,enabled:!1},display:`WLAN ${e} disabled.`}):{success:!1,error:"id is required for disable_wlan."}}async archiveAlerts(){return await this.request("POST","cmd/evtmgr",{cmd:"archive-all-alarms"}),{success:!0,data:{},display:"All alerts archived."}}async blockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"block-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} blocked.`}):{success:!1,error:"mac is required for block_client."}}async unblockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"unblock-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} unblocked.`}):{success:!1,error:"mac is required for unblock_client."}}async forgetClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"forget-sta",macs:[e]}),{success:!0,data:{mac:e},display:`Client ${e} forgotten (removed from known clients).`}):{success:!1,error:"mac is required for forget_client."}}async adoptDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"adopt",mac:e}),{success:!0,data:{mac:e},display:`Adopt command sent to device ${e}.`}):{success:!1,error:"mac is required for adopt_device."}}formatBytes(e){if(e===0)return"0 B";let t=["B","KB","MB","GB","TB"],s=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/Math.pow(1024,s)).toFixed(s===0?0:1)} ${t[s]}`}formatUptime(e){let t=Math.floor(e/86400),s=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),o=[];return t>0&&o.push(`${t}d`),s>0&&o.push(`${s}h`),o.push(`${r}m`),o.join(" ")}}});function Tc(c){let e=c.match(/^(\d+)\s*(h|d|m|w)$/i);if(!e)return new Date(Date.now()-36e5).toISOString();let t=parseInt(e[1],10),s=e[2].toLowerCase(),r={m:6e4,h:36e5,d:864e5,w:6048e5}[s]??36e5;return new Date(Date.now()-t*r).toISOString()}function Nu(c){let e=c.indexOf(".");if(e<1)throw new Error(`Invalid entity_id "${c}" \u2014 expected format "domain.name"`);return c.slice(0,e)}var Xr,_c=b(()=>{"use strict";P();u(Tc,"parsePeriod");u(Nu,"extractDomain");Xr=class extends I{static{u(this,"HomeAssistantSkill")}metadata={name:"homeassistant",category:"infrastructure",description:'Control Home Assistant smart home devices. Use "states" to list entities, "turn_on"/"turn_off"/"toggle" to control devices, "call_service" for advanced service calls, "history" for entity state history. Also: "areas" for rooms/zones, "presence" for who is home, "activate_scene"/"trigger_automation"/"run_script" for automations, "notify" for notifications, "calendar_events" for calendars, "template" for Jinja2 queries, "error_log" for HA logs.',riskLevel:"write",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["states","state","turn_on","turn_off","toggle","call_service","services","history","logbook","config","areas","template","presence","notify","activate_scene","trigger_automation","run_script","calendar_events","error_log"],description:"The Home Assistant action to perform"},entityId:{type:"string",description:"Entity ID, e.g. light.wohnzimmer, switch.garage, sensor.temperature"},domain:{type:"string",description:'Domain filter for "states" (e.g. light, sensor, switch) or domain for "call_service"'},service:{type:"string",description:'Service name for "call_service", e.g. set_temperature, set_hvac_mode'},serviceData:{type:"string",description:'JSON string with service parameters, e.g. {"brightness": 200, "color_name": "red"}'},period:{type:"string",description:"Time period for history/logbook, e.g. 1h, 24h, 7d (default: 1h)"},area:{type:"string",description:"Area name or ID (for areas action)"},template:{type:"string",description:"Jinja2 template string (for template action)"},target:{type:"string",description:"Notification target (for notify action, e.g. mobile_app_pixel)"},message:{type:"string",description:"Notification message (for notify action)"},title:{type:"string",description:"Optional title (for notify action)"},startTime:{type:"string",description:"ISO datetime start (for calendar_events, default: now)"},endTime:{type:"string",description:"ISO datetime end (for calendar_events, default: +24h)"},subAction:{type:"string",enum:["trigger","enable","disable"],description:"Sub-action for trigger_automation"},variables:{type:"string",description:"JSON string with script variables (for run_script)"}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"states":return await this.getStates(e.domain);case"state":return await this.getState(e.entityId);case"turn_on":return await this.switchAction("turn_on",e.entityId,e.serviceData);case"turn_off":return await this.switchAction("turn_off",e.entityId,e.serviceData);case"toggle":return await this.switchAction("toggle",e.entityId,e.serviceData);case"call_service":return await this.callService(e.domain,e.service,e.entityId,e.serviceData);case"services":return await this.getServices();case"history":return await this.getHistory(e.entityId,e.period);case"logbook":return await this.getLogbook(e.entityId,e.period);case"config":return await this.getConfig();case"areas":return await this.getAreas(e.area);case"template":return await this.renderTemplate(e.template);case"presence":return await this.getPresence();case"notify":return await this.sendNotification(e.message,e.title,e.target);case"activate_scene":return await this.activateScene(e.entityId);case"trigger_automation":return await this.triggerAutomation(e.entityId,e.subAction);case"run_script":return await this.runScript(e.entityId,e.variables);case"calendar_events":return await this.getCalendarEvents(e.entityId,e.startTime,e.endTime);case"error_log":return await this.getErrorLog();default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Home Assistant API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,o={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},n={method:e,headers:o,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(n.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let l;try{l=await fetch(r,n)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!l.ok){let d="";try{d=(await l.text()).slice(0,500)}catch{}throw new Error(`HTTP ${l.status} ${l.statusText} \u2014 ${d}`)}return await l.json()}async apiText(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,o={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},n={method:e,headers:o,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(n.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let l;try{l=await fetch(r,n)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!l.ok){let d="";try{d=(await l.text()).slice(0,500)}catch{}throw new Error(`HTTP ${l.status} ${l.statusText} \u2014 ${d}`)}return await l.text()}async getStates(e){let t=await this.api("GET","/api/states");e&&(t=t.filter(r=>r.entity_id.startsWith(`${e}.`)));let s=[`## Entities${e?` (${e})`:""}`,"","| Entity ID | State | Name | Unit |","|-----------|-------|------|------|"];for(let r of t){let o=r.attributes?.friendly_name??"-",n=r.attributes?.unit_of_measurement??"-";s.push(`| ${r.entity_id} | ${r.state} | ${o} | ${n} |`)}return t.length===0&&s.push(`| - | No entities found${e?` for domain "${e}"`:""} | - | - |`),{success:!0,data:t,display:s.join(`
|
|
576
576
|
`)}}async getState(e){if(!e)return{success:!1,error:'Missing required "entityId" parameter'};let t=await this.api("GET",`/api/states/${e}`),s=t.attributes??{},r=[`## ${s.friendly_name??e}`,"",`**Entity ID:** ${t.entity_id}`,`**State:** ${t.state}`,`**Last Changed:** ${t.last_changed??"-"}`,`**Last Updated:** ${t.last_updated??"-"}`,"","### Attributes"];for(let[o,n]of Object.entries(s)){let i=typeof n=="object"?JSON.stringify(n):String(n);r.push(`- **${o}:** ${i}`)}return{success:!0,data:t,display:r.join(`
|
|
577
577
|
`)}}async getServices(){let e=await this.api("GET","/api/services"),t=["## Available Services",""];for(let s of e){let r=s.domain??"unknown",o=Object.keys(s.services??{});if(o.length!==0){t.push(`### ${r}`);for(let n of o){let i=s.services[n]?.description??"";t.push(`- **${n}**${i?`: ${i}`:""}`)}t.push("")}}return{success:!0,data:e,display:t.join(`
|
|
578
|
-
`)}}async getHistory(e,t){let s=
|
|
578
|
+
`)}}async getHistory(e,t){let s=Tc(t??"1h"),r=e?`?filter_entity_id=${e}`:"",o=await this.api("GET",`/api/history/period/${s}${r}`),n=["## History",""];if(!o||o.length===0||o.every(i=>i.length===0))return n.push("No history entries found for the given period."),{success:!0,data:[],display:n.join(`
|
|
579
579
|
`)};for(let i of o){if(i.length===0)continue;let a=i[0]?.entity_id??"unknown",l=i[0]?.attributes?.friendly_name??a;n.push(`### ${l} (\`${a}\`)`),n.push(""),n.push("| Time | State |"),n.push("|------|-------|");for(let d of i){let m=d.last_changed?new Date(d.last_changed).toLocaleString():"-";n.push(`| ${m} | ${d.state} |`)}n.push("")}return{success:!0,data:o,display:n.join(`
|
|
580
|
-
`)}}async getLogbook(e,t){let s=
|
|
580
|
+
`)}}async getLogbook(e,t){let s=Tc(t??"1h"),r=e?`?entity=${e}`:"",o=await this.api("GET",`/api/logbook/${s}${r}`),n=["## Logbook",""];if(!o||o.length===0)return n.push("No logbook entries found for the given period."),{success:!0,data:[],display:n.join(`
|
|
581
581
|
`)};n.push("| Time | Entity | Message |"),n.push("|------|--------|---------|");for(let i of o){let a=i.when?new Date(i.when).toLocaleString():"-",l=i.name??i.entity_id??"-",d=i.message??i.state??"-";n.push(`| ${a} | ${l} | ${d} |`)}return{success:!0,data:o,display:n.join(`
|
|
582
582
|
`)}}async getConfig(){let e=await this.api("GET","/api/config"),t=["## Home Assistant Configuration","",`**Name:** ${e.location_name??"-"}`,`**Version:** ${e.version??"-"}`,`**Time Zone:** ${e.time_zone??"-"}`,`**Latitude:** ${e.latitude??"-"}`,`**Longitude:** ${e.longitude??"-"}`,`**Elevation:** ${e.elevation??"-"} m`,`**Unit System:** ${e.unit_system?.length?JSON.stringify(e.unit_system):"-"}`,`**Currency:** ${e.currency??"-"}`,`**Internal URL:** ${e.internal_url??"-"}`,`**External URL:** ${e.external_url??"-"}`];return e.components&&Array.isArray(e.components)&&t.push("",`**Components:** ${e.components.length} loaded`),{success:!0,data:e,display:t.join(`
|
|
583
|
-
`)}}async switchAction(e,t,s){if(!t)return{success:!1,error:'Missing required "entityId" parameter'};let r=
|
|
583
|
+
`)}}async switchAction(e,t,s){if(!t)return{success:!1,error:'Missing required "entityId" parameter'};let r=Nu(t),o={entity_id:t};if(s)try{let l=JSON.parse(s);Object.assign(o,l)}catch{return{success:!1,error:'Invalid "serviceData" \u2014 must be valid JSON'}}let n=await this.api("POST",`/api/services/${r}/${e}`,o),i=n?.[0]?.state??"unknown",a=n?.[0]?.attributes?.friendly_name??t;return{success:!0,data:n,display:[`**${e.replace("_"," ")}** \u2192 **${a}**`,"",`New state: **${i}**`].join(`
|
|
584
584
|
`)}}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(`
|
|
585
585
|
`)}}async getAreas(e){if(e){let n=`{% for eid in area_entities('${e.replace(/'/g,"\\'")}') %}{{ eid }}||{{ states(eid) }}||{{ state_attr(eid, 'friendly_name') }}
|
|
586
586
|
{% endfor %}`,a=(await this.apiText("POST","/api/template",{template:n})).trim().split(`
|
|
@@ -597,7 +597,7 @@ Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this
|
|
|
597
597
|
`)}}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(`
|
|
598
598
|
`)}}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(`
|
|
599
599
|
`)}}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(`
|
|
600
|
-
`)}}}});var Ce,
|
|
600
|
+
`)}}}});var Ce,Zs=b(()=>{"use strict";Ce=class{static{u(this,"ContactsProvider")}}});var bc={};oe(bc,{CardDAVContactsProvider:()=>Yr});var Yr,Dn=b(()=>{"use strict";Zs();Yr=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],x=/TYPE=pref/i.test(T);a.push({address:$,label:A,primary:x})}let l=[];for(let h of e.matchAll(/^TEL[^:]*:(.+)$/gmi)){let T=h[0],$=h[1].trim(),A=T.match(/TYPE=([^;:,]+)/i)?.[1],x=/TYPE=pref/i.test(T);l.push({number:$,label:A,primary:x})}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
|
|
601
601
|
VERSION:3.0\r
|
|
602
602
|
`;r+=`UID:${e}\r
|
|
603
603
|
`,r+=`FN:${s}\r
|
|
@@ -609,13 +609,13 @@ VERSION:3.0\r
|
|
|
609
609
|
`),t.birthday&&(r+=`BDAY:${t.birthday}\r
|
|
610
610
|
`),t.notes&&(r+=`NOTE:${t.notes}\r
|
|
611
611
|
`),r+=`END:VCARD\r
|
|
612
|
-
`,r}}});var bc={};oe(bc,{GoogleContactsProvider:()=>Jr});var Yr,gt,Jr,Mn=b(()=>{"use strict";Js();Yr="names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies",gt="https://people.googleapis.com/v1",Jr=class extends Ce{static{u(this,"GoogleContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),t=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!t.ok)throw new Error(`Google token refresh failed: ${t.status}`);let s=await t.json();this.accessToken=s.access_token}async apiRequest(e,t,s){let r={method:e,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}};s&&(r.body=JSON.stringify(s));let o=await fetch(t,r);if(o.status===401){await this.refreshAccessToken();let n=await fetch(t,{...r,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}});if(!n.ok)throw new Error(`People API error: ${n.status}`);return n.status===204?void 0:n.json()}if(!o.ok)throw new Error(`People API error: ${o.status}`);if(o.status!==204)return o.json()}async list(e=50){let t=`${gt}/people/me/connections?personFields=${Yr}&pageSize=${e}`;return((await this.apiRequest("GET",t)).connections??[]).map(r=>this.mapPerson(r))}async search(e){let t=`${gt}/people:searchContacts?query=${encodeURIComponent(e)}&readMask=${Yr}&pageSize=30`;return((await this.apiRequest("GET",t)).results??[]).map(r=>this.mapPerson(r.person))}async get(e){try{let t=`${gt}/${e}?personFields=${Yr}`,s=await this.apiRequest("GET",t);return this.mapPerson(s)}catch{return}}async create(e){let t=this.buildPersonBody(e),s=await this.apiRequest("POST",`${gt}/people:createContact`,t);return this.mapPerson(s)}async update(e,t){let s=await this.apiRequest("GET",`${gt}/${e}?personFields=${Yr}`),r=this.buildPersonBody(t);r.etag=s.etag;let n=`${gt}/${e}:updateContact?updatePersonFields=names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies`,i=await this.apiRequest("PATCH",n,r);return this.mapPerson(i)}async delete(e){await this.apiRequest("DELETE",`${gt}/${e}:deleteContact`)}mapPerson(e){let t=e.names?.[0],s=(e.emailAddresses??[]).map(l=>({address:l.value,label:l.type,primary:l.metadata?.primary??!1})),r=(e.phoneNumbers??[]).map(l=>({number:l.value,label:l.type,primary:l.metadata?.primary??!1})),o=(e.addresses??[]).map(l=>({street:l.streetAddress??void 0,city:l.city??void 0,region:l.region??void 0,postalCode:l.postalCode??void 0,country:l.country??void 0,label:l.type??void 0})),n=e.organizations?.[0]?.name,i=e.birthdays?.[0]?.date?`${e.birthdays[0].date.year??"????"}-${String(e.birthdays[0].date.month).padStart(2,"0")}-${String(e.birthdays[0].date.day).padStart(2,"0")}`:void 0,a=e.biographies?.[0]?.value;return{id:e.resourceName??e.etag??"",displayName:t?.displayName??"(No name)",firstName:t?.givenName,lastName:t?.familyName,emails:s,phones:r,addresses:o,organization:n,birthday:i,notes:a}}buildPersonBody(e){let t={};if((e.firstName!==void 0||e.lastName!==void 0||e.displayName!==void 0)&&(t.names=[{givenName:e.firstName,familyName:e.lastName,displayName:e.displayName}]),e.emails&&(t.emailAddresses=e.emails.map(s=>({value:s.address,type:s.label??"home"}))),e.phones&&(t.phoneNumbers=e.phones.map(s=>({value:s.number,type:s.label??"mobile"}))),e.addresses&&(t.addresses=e.addresses.map(s=>({streetAddress:s.street,city:s.city,region:s.region,postalCode:s.postalCode,country:s.country,type:s.label??"home"}))),e.organization&&(t.organizations=[{name:e.organization}]),e.birthday){let s=e.birthday.split("-");t.birthdays=[{date:{year:s[0]!=="????"?parseInt(s[0],10):void 0,month:parseInt(s[1],10),day:parseInt(s[2],10)}}]}return e.notes&&(t.biographies=[{value:e.notes,contentType:"TEXT_PLAIN"}]),t}}});var Ec={};oe(Ec,{MicrosoftContactsProvider:()=>Zr});var Zr,On=b(()=>{"use strict";Js();Zr=class extends Ce{static{u(this,"MicrosoftContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Contacts.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.status===204?void 0:r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async list(e=50){return((await this.graphRequest(`/me/contacts?$top=${e}&$orderby=displayName`)).value??[]).map(s=>this.mapContact(s))}async search(e){try{return((await this.graphRequest(`/me/contacts?$search="${encodeURIComponent(e)}"`,{headers:{ConsistencyLevel:"eventual"}})).value??[]).map(s=>this.mapContact(s))}catch{return((await this.graphRequest(`/me/contacts?$filter=contains(displayName, '${encodeURIComponent(e)}')`)).value??[]).map(s=>this.mapContact(s))}}async get(e){try{let t=await this.graphRequest(`/me/contacts/${e}`);return this.mapContact(t)}catch{return}}async create(e){let t=this.buildContactBody(e),s=await this.graphRequest("/me/contacts",{method:"POST",body:JSON.stringify(t)});return this.mapContact(s)}async update(e,t){let s=this.buildContactBody(t),r=await this.graphRequest(`/me/contacts/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapContact(r)}async delete(e){await this.graphRequest(`/me/contacts/${e}`,{method:"DELETE"})}mapContact(e){let t=(e.emailAddresses??[]).map(n=>({address:n.address,label:n.name??void 0,primary:!1})),s=[];if(e.mobilePhone&&s.push({number:e.mobilePhone,label:"mobile"}),e.businessPhones)for(let n of e.businessPhones)s.push({number:n,label:"work"});if(e.homePhones)for(let n of e.homePhones)s.push({number:n,label:"home"});let r=[];e.homeAddress&&Object.values(e.homeAddress).some(Boolean)&&r.push({street:e.homeAddress.street??void 0,city:e.homeAddress.city??void 0,region:e.homeAddress.state??void 0,postalCode:e.homeAddress.postalCode??void 0,country:e.homeAddress.countryOrRegion??void 0,label:"home"}),e.businessAddress&&Object.values(e.businessAddress).some(Boolean)&&r.push({street:e.businessAddress.street??void 0,city:e.businessAddress.city??void 0,region:e.businessAddress.state??void 0,postalCode:e.businessAddress.postalCode??void 0,country:e.businessAddress.countryOrRegion??void 0,label:"work"});let o=e.birthday?e.birthday.slice(0,10):void 0;return{id:e.id,displayName:e.displayName??"(No name)",firstName:e.givenName??void 0,lastName:e.surname??void 0,emails:t,phones:s,addresses:r,organization:e.companyName??void 0,birthday:o,notes:e.personalNotes??void 0}}buildContactBody(e){let t={};if(e.firstName!==void 0&&(t.givenName=e.firstName),e.lastName!==void 0&&(t.surname=e.lastName),e.displayName!==void 0&&(t.displayName=e.displayName),e.emails&&(t.emailAddresses=e.emails.map(s=>({address:s.address,name:s.label??s.address}))),e.phones){let s=e.phones.find(i=>i.label==="mobile"),r=e.phones.filter(i=>i.label==="work"),o=e.phones.filter(i=>i.label==="home"),n=e.phones.filter(i=>!["mobile","work","home"].includes(i.label??""));s&&(t.mobilePhone=s.number),r.length>0&&(t.businessPhones=r.map(i=>i.number)),o.length>0&&(t.homePhones=o.map(i=>i.number)),n.length>0&&!r.length&&(t.businessPhones=n.map(i=>i.number))}if(e.addresses)for(let s of e.addresses){let r={street:s.street,city:s.city,state:s.region,postalCode:s.postalCode,countryOrRegion:s.country};s.label==="work"?t.businessAddress=r:t.homeAddress=r}return e.organization!==void 0&&(t.companyName=e.organization),e.birthday!==void 0&&(t.birthday=e.birthday),e.notes!==void 0&&(t.personalNotes=e.notes),t}}});async function Pn(c){switch(c.provider){case"carddav":{if(!c.carddav)throw new Error("CardDAV contacts config missing");let{CardDAVContactsProvider:e}=await Promise.resolve().then(()=>(Dn(),_c)),t=new e(c.carddav);return await t.initialize(),t}case"google":{if(!c.google)throw new Error("Google contacts config missing");let{GoogleContactsProvider:e}=await Promise.resolve().then(()=>(Mn(),bc)),t=new e(c.google);return await t.initialize(),t}case"microsoft":{if(!c.microsoft)throw new Error("Microsoft contacts config missing");let{MicrosoftContactsProvider:e}=await Promise.resolve().then(()=>(On(),Ec)),t=new e(c.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown contacts provider: ${c.provider}`)}}var $c=b(()=>{"use strict";u(Pn,"createContactsProvider")});var Zs,vc=b(()=>{"use strict";P();Zs=class extends I{static{u(this,"ContactsSkill")}contactsProvider;metadata={name:"contacts",category:"productivity",description:"Manage contacts. Search, view, create, update, or delete contacts.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","get","list","create","update","delete"],description:"The contacts action to perform"},query:{type:"string",description:"Search query (for search action)"},contactId:{type:"string",description:"Contact ID (for get/update/delete)"},firstName:{type:"string",description:"First name (for create/update)"},lastName:{type:"string",description:"Last name (for create/update)"},displayName:{type:"string",description:"Display name (for create/update)"},email:{type:"string",description:"Single email address (for create/update, shorthand)"},phone:{type:"string",description:"Single phone number (for create/update, shorthand)"},organization:{type:"string",description:"Organization / company (for create/update)"},birthday:{type:"string",description:"Birthday in YYYY-MM-DD format (for create/update)"},notes:{type:"string",description:"Notes (for create/update)"},emailAddresses:{type:"string",description:"JSON array of {address, label?, primary?} for multiple emails"},phoneNumbers:{type:"string",description:"JSON array of {number, label?, primary?} for multiple phones"},addresses:{type:"string",description:"JSON array of {street?, city?, region?, postalCode?, country?, label?}"},limit:{type:"number",description:"Maximum number of contacts to return (for list, default 50)"}},required:["action"]}};constructor(e){super(),this.contactsProvider=e}async execute(e,t){let s=e.action;switch(s){case"search":return this.searchContacts(e);case"get":return this.getContact(e);case"list":return this.listContacts(e);case"create":return this.createContact(e);case"update":return this.updateContact(e);case"delete":return this.deleteContact(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async searchContacts(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query"'};try{let s=await this.contactsProvider.search(t);if(s.length===0)return{success:!0,data:[],display:`No contacts found for "${t}".`};let r=this.formatTable(s);return{success:!0,data:s,display:`${s.length} contact(s) found:
|
|
612
|
+
`,r}}});var Ec={};oe(Ec,{GoogleContactsProvider:()=>Zr});var Jr,gt,Zr,Mn=b(()=>{"use strict";Zs();Jr="names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies",gt="https://people.googleapis.com/v1",Zr=class extends Ce{static{u(this,"GoogleContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),t=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!t.ok)throw new Error(`Google token refresh failed: ${t.status}`);let s=await t.json();this.accessToken=s.access_token}async apiRequest(e,t,s){let r={method:e,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}};s&&(r.body=JSON.stringify(s));let o=await fetch(t,r);if(o.status===401){await this.refreshAccessToken();let n=await fetch(t,{...r,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}});if(!n.ok)throw new Error(`People API error: ${n.status}`);return n.status===204?void 0:n.json()}if(!o.ok)throw new Error(`People API error: ${o.status}`);if(o.status!==204)return o.json()}async list(e=50){let t=`${gt}/people/me/connections?personFields=${Jr}&pageSize=${e}`;return((await this.apiRequest("GET",t)).connections??[]).map(r=>this.mapPerson(r))}async search(e){let t=`${gt}/people:searchContacts?query=${encodeURIComponent(e)}&readMask=${Jr}&pageSize=30`;return((await this.apiRequest("GET",t)).results??[]).map(r=>this.mapPerson(r.person))}async get(e){try{let t=`${gt}/${e}?personFields=${Jr}`,s=await this.apiRequest("GET",t);return this.mapPerson(s)}catch{return}}async create(e){let t=this.buildPersonBody(e),s=await this.apiRequest("POST",`${gt}/people:createContact`,t);return this.mapPerson(s)}async update(e,t){let s=await this.apiRequest("GET",`${gt}/${e}?personFields=${Jr}`),r=this.buildPersonBody(t);r.etag=s.etag;let n=`${gt}/${e}:updateContact?updatePersonFields=names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies`,i=await this.apiRequest("PATCH",n,r);return this.mapPerson(i)}async delete(e){await this.apiRequest("DELETE",`${gt}/${e}:deleteContact`)}mapPerson(e){let t=e.names?.[0],s=(e.emailAddresses??[]).map(l=>({address:l.value,label:l.type,primary:l.metadata?.primary??!1})),r=(e.phoneNumbers??[]).map(l=>({number:l.value,label:l.type,primary:l.metadata?.primary??!1})),o=(e.addresses??[]).map(l=>({street:l.streetAddress??void 0,city:l.city??void 0,region:l.region??void 0,postalCode:l.postalCode??void 0,country:l.country??void 0,label:l.type??void 0})),n=e.organizations?.[0]?.name,i=e.birthdays?.[0]?.date?`${e.birthdays[0].date.year??"????"}-${String(e.birthdays[0].date.month).padStart(2,"0")}-${String(e.birthdays[0].date.day).padStart(2,"0")}`:void 0,a=e.biographies?.[0]?.value;return{id:e.resourceName??e.etag??"",displayName:t?.displayName??"(No name)",firstName:t?.givenName,lastName:t?.familyName,emails:s,phones:r,addresses:o,organization:n,birthday:i,notes:a}}buildPersonBody(e){let t={};if((e.firstName!==void 0||e.lastName!==void 0||e.displayName!==void 0)&&(t.names=[{givenName:e.firstName,familyName:e.lastName,displayName:e.displayName}]),e.emails&&(t.emailAddresses=e.emails.map(s=>({value:s.address,type:s.label??"home"}))),e.phones&&(t.phoneNumbers=e.phones.map(s=>({value:s.number,type:s.label??"mobile"}))),e.addresses&&(t.addresses=e.addresses.map(s=>({streetAddress:s.street,city:s.city,region:s.region,postalCode:s.postalCode,country:s.country,type:s.label??"home"}))),e.organization&&(t.organizations=[{name:e.organization}]),e.birthday){let s=e.birthday.split("-");t.birthdays=[{date:{year:s[0]!=="????"?parseInt(s[0],10):void 0,month:parseInt(s[1],10),day:parseInt(s[2],10)}}]}return e.notes&&(t.biographies=[{value:e.notes,contentType:"TEXT_PLAIN"}]),t}}});var $c={};oe($c,{MicrosoftContactsProvider:()=>Qr});var Qr,On=b(()=>{"use strict";Zs();Qr=class extends Ce{static{u(this,"MicrosoftContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Contacts.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.status===204?void 0:r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async list(e=50){return((await this.graphRequest(`/me/contacts?$top=${e}&$orderby=displayName`)).value??[]).map(s=>this.mapContact(s))}async search(e){try{return((await this.graphRequest(`/me/contacts?$search="${encodeURIComponent(e)}"`,{headers:{ConsistencyLevel:"eventual"}})).value??[]).map(s=>this.mapContact(s))}catch{return((await this.graphRequest(`/me/contacts?$filter=contains(displayName, '${encodeURIComponent(e)}')`)).value??[]).map(s=>this.mapContact(s))}}async get(e){try{let t=await this.graphRequest(`/me/contacts/${e}`);return this.mapContact(t)}catch{return}}async create(e){let t=this.buildContactBody(e),s=await this.graphRequest("/me/contacts",{method:"POST",body:JSON.stringify(t)});return this.mapContact(s)}async update(e,t){let s=this.buildContactBody(t),r=await this.graphRequest(`/me/contacts/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapContact(r)}async delete(e){await this.graphRequest(`/me/contacts/${e}`,{method:"DELETE"})}mapContact(e){let t=(e.emailAddresses??[]).map(n=>({address:n.address,label:n.name??void 0,primary:!1})),s=[];if(e.mobilePhone&&s.push({number:e.mobilePhone,label:"mobile"}),e.businessPhones)for(let n of e.businessPhones)s.push({number:n,label:"work"});if(e.homePhones)for(let n of e.homePhones)s.push({number:n,label:"home"});let r=[];e.homeAddress&&Object.values(e.homeAddress).some(Boolean)&&r.push({street:e.homeAddress.street??void 0,city:e.homeAddress.city??void 0,region:e.homeAddress.state??void 0,postalCode:e.homeAddress.postalCode??void 0,country:e.homeAddress.countryOrRegion??void 0,label:"home"}),e.businessAddress&&Object.values(e.businessAddress).some(Boolean)&&r.push({street:e.businessAddress.street??void 0,city:e.businessAddress.city??void 0,region:e.businessAddress.state??void 0,postalCode:e.businessAddress.postalCode??void 0,country:e.businessAddress.countryOrRegion??void 0,label:"work"});let o=e.birthday?e.birthday.slice(0,10):void 0;return{id:e.id,displayName:e.displayName??"(No name)",firstName:e.givenName??void 0,lastName:e.surname??void 0,emails:t,phones:s,addresses:r,organization:e.companyName??void 0,birthday:o,notes:e.personalNotes??void 0}}buildContactBody(e){let t={};if(e.firstName!==void 0&&(t.givenName=e.firstName),e.lastName!==void 0&&(t.surname=e.lastName),e.displayName!==void 0&&(t.displayName=e.displayName),e.emails&&(t.emailAddresses=e.emails.map(s=>({address:s.address,name:s.label??s.address}))),e.phones){let s=e.phones.find(i=>i.label==="mobile"),r=e.phones.filter(i=>i.label==="work"),o=e.phones.filter(i=>i.label==="home"),n=e.phones.filter(i=>!["mobile","work","home"].includes(i.label??""));s&&(t.mobilePhone=s.number),r.length>0&&(t.businessPhones=r.map(i=>i.number)),o.length>0&&(t.homePhones=o.map(i=>i.number)),n.length>0&&!r.length&&(t.businessPhones=n.map(i=>i.number))}if(e.addresses)for(let s of e.addresses){let r={street:s.street,city:s.city,state:s.region,postalCode:s.postalCode,countryOrRegion:s.country};s.label==="work"?t.businessAddress=r:t.homeAddress=r}return e.organization!==void 0&&(t.companyName=e.organization),e.birthday!==void 0&&(t.birthday=e.birthday),e.notes!==void 0&&(t.personalNotes=e.notes),t}}});async function Pn(c){switch(c.provider){case"carddav":{if(!c.carddav)throw new Error("CardDAV contacts config missing");let{CardDAVContactsProvider:e}=await Promise.resolve().then(()=>(Dn(),bc)),t=new e(c.carddav);return await t.initialize(),t}case"google":{if(!c.google)throw new Error("Google contacts config missing");let{GoogleContactsProvider:e}=await Promise.resolve().then(()=>(Mn(),Ec)),t=new e(c.google);return await t.initialize(),t}case"microsoft":{if(!c.microsoft)throw new Error("Microsoft contacts config missing");let{MicrosoftContactsProvider:e}=await Promise.resolve().then(()=>(On(),$c)),t=new e(c.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown contacts provider: ${c.provider}`)}}var vc=b(()=>{"use strict";u(Pn,"createContactsProvider")});var Qs,kc=b(()=>{"use strict";P();Qs=class extends I{static{u(this,"ContactsSkill")}contactsProvider;metadata={name:"contacts",category:"productivity",description:"Manage contacts. Search, view, create, update, or delete contacts.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","get","list","create","update","delete"],description:"The contacts action to perform"},query:{type:"string",description:"Search query (for search action)"},contactId:{type:"string",description:"Contact ID (for get/update/delete)"},firstName:{type:"string",description:"First name (for create/update)"},lastName:{type:"string",description:"Last name (for create/update)"},displayName:{type:"string",description:"Display name (for create/update)"},email:{type:"string",description:"Single email address (for create/update, shorthand)"},phone:{type:"string",description:"Single phone number (for create/update, shorthand)"},organization:{type:"string",description:"Organization / company (for create/update)"},birthday:{type:"string",description:"Birthday in YYYY-MM-DD format (for create/update)"},notes:{type:"string",description:"Notes (for create/update)"},emailAddresses:{type:"string",description:"JSON array of {address, label?, primary?} for multiple emails"},phoneNumbers:{type:"string",description:"JSON array of {number, label?, primary?} for multiple phones"},addresses:{type:"string",description:"JSON array of {street?, city?, region?, postalCode?, country?, label?}"},limit:{type:"number",description:"Maximum number of contacts to return (for list, default 50)"}},required:["action"]}};constructor(e){super(),this.contactsProvider=e}async execute(e,t){let s=e.action;switch(s){case"search":return this.searchContacts(e);case"get":return this.getContact(e);case"list":return this.listContacts(e);case"create":return this.createContact(e);case"update":return this.updateContact(e);case"delete":return this.deleteContact(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async searchContacts(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query"'};try{let s=await this.contactsProvider.search(t);if(s.length===0)return{success:!0,data:[],display:`No contacts found for "${t}".`};let r=this.formatTable(s);return{success:!0,data:s,display:`${s.length} contact(s) found:
|
|
613
613
|
${r}`}}catch(s){return{success:!1,error:`Failed to search contacts: ${s instanceof Error?s.message:String(s)}`}}}async getContact(e){let t=e.contactId;if(!t)return{success:!1,error:'Missing required field "contactId"'};try{let s=await this.contactsProvider.get(t);if(!s)return{success:!1,error:`Contact "${t}" not found.`};let r=this.formatDetail(s);return{success:!0,data:s,display:r}}catch(s){return{success:!1,error:`Failed to get contact: ${s instanceof Error?s.message:String(s)}`}}}async listContacts(e){let t=e.limit??50;try{let s=await this.contactsProvider.list(t);if(s.length===0)return{success:!0,data:[],display:"No contacts found."};let r=this.formatTable(s);return{success:!0,data:s,display:`${s.length} contact(s):
|
|
614
614
|
${r}`}}catch(s){return{success:!1,error:`Failed to list contacts: ${s instanceof Error?s.message:String(s)}`}}}async createContact(e){try{let t=this.buildContactInput(e),s=await this.contactsProvider.create(t);return{success:!0,data:s,display:`Contact created: ${s.displayName}`}}catch(t){return{success:!1,error:`Failed to create contact: ${t instanceof Error?t.message:String(t)}`}}}async updateContact(e){let t=e.contactId;if(!t)return{success:!1,error:'Missing required field "contactId"'};try{let s=this.buildContactInput(e),r=await this.contactsProvider.update(t,s);return{success:!0,data:r,display:`Contact updated: ${r.displayName}`}}catch(s){return{success:!1,error:`Failed to update contact: ${s instanceof Error?s.message:String(s)}`}}}async deleteContact(e){let t=e.contactId;if(!t)return{success:!1,error:'Missing required field "contactId"'};try{return await this.contactsProvider.delete(t),{success:!0,data:{deleted:t},display:`Contact "${t}" deleted.`}}catch(s){return{success:!1,error:`Failed to delete contact: ${s instanceof Error?s.message:String(s)}`}}}buildContactInput(e){let t={};if(e.firstName&&(t.firstName=e.firstName),e.lastName&&(t.lastName=e.lastName),e.displayName&&(t.displayName=e.displayName),e.organization&&(t.organization=e.organization),e.birthday&&(t.birthday=e.birthday),e.notes&&(t.notes=e.notes),e.emailAddresses)try{t.emails=JSON.parse(e.emailAddresses)}catch{t.emails=[{address:e.emailAddresses}]}else e.email&&(t.emails=[{address:e.email,primary:!0}]);if(e.phoneNumbers)try{t.phones=JSON.parse(e.phoneNumbers)}catch{t.phones=[{number:e.phoneNumbers}]}else e.phone&&(t.phones=[{number:e.phone,primary:!0}]);if(e.addresses)try{t.addresses=JSON.parse(e.addresses)}catch{}return t}formatTable(e){let t=`| Name | Email | Phone |
|
|
615
615
|
|------|-------|-------|`,s=e.map(r=>{let o=r.emails[0]?.address??"-",n=r.phones[0]?.number??"-";return`| ${r.displayName} | ${o} | ${n} |`});return`${t}
|
|
616
616
|
${s.join(`
|
|
617
617
|
`)}`}formatDetail(e){let t=[];if(t.push(`**Name:** ${e.displayName}`),e.firstName&&t.push(`**First name:** ${e.firstName}`),e.lastName&&t.push(`**Last name:** ${e.lastName}`),e.emails.length>0&&t.push(`**Email(s):** ${e.emails.map(s=>`${s.address}${s.label?` (${s.label})`:""}`).join(", ")}`),e.phones.length>0&&t.push(`**Phone(s):** ${e.phones.map(s=>`${s.number}${s.label?` (${s.label})`:""}`).join(", ")}`),e.addresses.length>0)for(let s of e.addresses){let r=[s.street,s.city,s.region,s.postalCode,s.country].filter(Boolean);t.push(`**Address${s.label?` (${s.label})`:""}:** ${r.join(", ")}`)}return e.organization&&t.push(`**Organization:** ${e.organization}`),e.birthday&&t.push(`**Birthday:** ${e.birthday}`),e.notes&&t.push(`**Notes:** ${e.notes}`),t.push(`**ID:** ${e.id}`),t.join(`
|
|
618
|
-
`)}}});var
|
|
618
|
+
`)}}});var Sc=b(()=>{"use strict";Zs();Dn();Mn();On();vc();kc()});var Zt,Ac=b(()=>{"use strict";P();Me();Zt=class extends I{static{u(this,"TodoSkill")}todoRepo;metadata={name:"todo",category:"productivity",description:"Manage todo lists with multiple named lists. Actions: add, list, complete, uncomplete, delete, lists, clear.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["add","list","complete","uncomplete","delete","lists","clear"],description:"The todo action to perform"},title:{type:"string",description:"The todo title (required for add)"},list:{type:"string",description:'The list name (default: "default")'},description:{type:"string",description:"Optional description for the todo"},priority:{type:"string",enum:["low","normal","high","urgent"],description:'Priority level (default: "normal")'},dueDate:{type:"string",description:"Due date for the todo (ISO string)"},todoId:{type:"string",description:"The ID of the todo (required for complete, uncomplete, delete)"},includeCompleted:{type:"boolean",description:"Include completed todos in list output (default: false)"}},required:["action"]}};constructor(e){super(),this.todoRepo=e}async execute(e,t){let s=e.action;switch(s){case"add":return this.addTodo(e,t);case"list":return this.listTodos(e,t);case"complete":return this.completeTodo(e,t);case"uncomplete":return this.uncompleteTodo(e,t);case"delete":return this.deleteTodo(e,t);case"lists":return this.showLists(t);case"clear":return this.clearCompleted(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: add, list, complete, uncomplete, delete, lists, clear`}}}addTodo(e,t){let s=e.title;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "title" for add action'};let r=e.list??"default",o=e.description,n=e.priority,i=e.dueDate,a=this.todoRepo.add(ee(t),s,{list:r,description:o,priority:n,dueDate:i});return{success:!0,data:{todoId:a.id,title:a.title,list:a.list},display:`Todo added: "${s}"`}}listTodos(e,t){let s=e.list,r=e.includeCompleted??!1,o=new Set,n=[];for(let l of W(t))for(let d of this.todoRepo.list(l,s,r))o.has(d.id)||(o.add(d.id),n.push(d));if(n.length===0)return{success:!0,data:[],display:"No todos found."};let i=`| | Priority | Title | Due | ID |
|
|
619
619
|
|---|---|---|---|---|`,a=n.map(l=>{let d=l.completed?"\u2611":"\u2610",m=l.dueDate??"",p=l.id.slice(0,8);return`| ${d} | ${l.priority} | ${l.title} | ${m} | ${p} |`}).join(`
|
|
620
620
|
`);return{success:!0,data:n,display:`${n.length} todo(s):
|
|
621
621
|
${i}
|
|
@@ -623,59 +623,59 @@ ${a}`}}completeTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success
|
|
|
623
623
|
|---|---|---|---|`,o=s.map(n=>`| ${n.list} | ${n.open} | ${n.completed} | ${n.total} |`).join(`
|
|
624
624
|
`);return{success:!0,data:s,display:`${s.length} list(s):
|
|
625
625
|
${r}
|
|
626
|
-
${o}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(ee(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import
|
|
626
|
+
${o}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(ee(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import Ic from"node:http";import xc from"node:https";import{execFile as Du}from"node:child_process";import{promisify as Mu}from"node:util";function Un(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 Cc(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 Fn(c){return!c||c.length===0?"-":c.map(e=>e.replace(/^\//,"")).join(", ")}function Ou(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 Pu(c){return c?new Date(c*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var Rc,eo,Lc=b(()=>{"use strict";P();Rc=Mu(Du);u(Un,"formatBytes");u(Cc,"formatPorts");u(Fn,"containerName");u(Ou,"stripDockerStreamHeaders");u(Pu,"relativeTime");eo=class extends I{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")?xc:Ic).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")?xc:Ic).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(`| ${Fn(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${Cc(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
|
|
627
627
|
`)}}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: ${Fn(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(`
|
|
628
628
|
`):"- No port bindings","","### Mounts",l.length>0?l.join(`
|
|
629
629
|
`):"- No mounts"];return{success:!0,data:t,display:m.join(`
|
|
630
|
-
`)}}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=
|
|
631
|
-
`)}}async startContainer(e){return e?(await this.api("POST",`/containers/${encodeURIComponent(e)}/start`),{success:!0,data:{containerId:e,action:"start"},display:`**Container started:** \`${e}\``}):{success:!1,error:'Missing required "containerId" parameter'}}async stopContainer(e){return e?(await this.api("POST",`/containers/${encodeURIComponent(e)}/stop`),{success:!0,data:{containerId:e,action:"stop"},display:`**Container stopped:** \`${e}\``}):{success:!1,error:'Missing required "containerId" parameter'}}async restartContainer(e){return e?(await this.api("POST",`/containers/${encodeURIComponent(e)}/restart`),{success:!0,data:{containerId:e,action:"restart"},display:`**Container restarted:** \`${e}\``}):{success:!1,error:'Missing required "containerId" parameter'}}async listImages(){let e=await this.api("GET","/images/json"),t=["## Docker Images","","| Repo:Tag | Size | Created |","|----------|------|---------|"];for(let s of e){let o=(s.RepoTags??["<none>:<none>"]).join(", "),n=Un(s.Size),i=
|
|
630
|
+
`)}}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=Ou(r),n=[`## Logs: ${e} (last ${s} lines)`,"","```",o.trimEnd(),"```"];return{success:!0,data:o,display:n.join(`
|
|
631
|
+
`)}}async startContainer(e){return e?(await this.api("POST",`/containers/${encodeURIComponent(e)}/start`),{success:!0,data:{containerId:e,action:"start"},display:`**Container started:** \`${e}\``}):{success:!1,error:'Missing required "containerId" parameter'}}async stopContainer(e){return e?(await this.api("POST",`/containers/${encodeURIComponent(e)}/stop`),{success:!0,data:{containerId:e,action:"stop"},display:`**Container stopped:** \`${e}\``}):{success:!1,error:'Missing required "containerId" parameter'}}async restartContainer(e){return e?(await this.api("POST",`/containers/${encodeURIComponent(e)}/restart`),{success:!0,data:{containerId:e,action:"restart"},display:`**Container restarted:** \`${e}\``}):{success:!1,error:'Missing required "containerId" parameter'}}async listImages(){let e=await this.api("GET","/images/json"),t=["## Docker Images","","| Repo:Tag | Size | Created |","|----------|------|---------|"];for(let s of e){let o=(s.RepoTags??["<none>:<none>"]).join(", "),n=Un(s.Size),i=Pu(s.Created);t.push(`| ${o} | ${n} | ${i} |`)}return e.length===0&&t.push("| - | No images found | - |"),{success:!0,data:e,display:t.join(`
|
|
632
632
|
`)}}async pullImage(e,t){if(!e)return{success:!1,error:'Missing required "imageName" parameter'};let s=t??"latest",r=await this.apiRaw("POST",`/images/create?fromImage=${encodeURIComponent(e)}&tag=${encodeURIComponent(s)}`);return{success:!0,data:{imageName:e,tag:s,raw:r.slice(0,500)},display:`**Image pulled:** \`${e}:${s}\``}}async removeImage(e){if(!e)return{success:!1,error:'Missing required "imageName" parameter'};let t=await this.api("DELETE",`/images/${encodeURIComponent(e)}`),s=(t??[]).filter(n=>n.Deleted).map(n=>n.Deleted),r=(t??[]).filter(n=>n.Untagged).map(n=>n.Untagged),o=[`**Image removed:** \`${e}\``,"",`**Untagged:** ${r.length>0?r.join(", "):"-"}`,`**Deleted layers:** ${s.length}`];return{success:!0,data:t,display:o.join(`
|
|
633
633
|
`)}}async listNetworks(){let e=await this.api("GET","/networks"),t=["## Docker Networks","","| Name | Driver | Scope | Subnet |","|------|--------|-------|--------|"];for(let s of e){let o=(s.IPAM?.Config??[]).map(n=>n.Subnet).filter(Boolean).join(", ")||"-";t.push(`| ${s.Name??"-"} | ${s.Driver??"-"} | ${s.Scope??"-"} | ${o} |`)}return e.length===0&&t.push("| - | No networks found | - | - |"),{success:!0,data:e,display:t.join(`
|
|
634
634
|
`)}}async listVolumes(){let t=(await this.api("GET","/volumes")).Volumes??[],s=["## Docker Volumes","","| Name | Driver | Mountpoint |","|------|--------|------------|"];for(let r of t)s.push(`| ${r.Name??"-"} | ${r.Driver??"-"} | ${r.Mountpoint??"-"} |`);return t.length===0&&s.push("| - | No volumes found | - |"),{success:!0,data:t,display:s.join(`
|
|
635
635
|
`)}}async getSystemInfo(){let e=await this.api("GET","/info"),t=["## Docker System Info","",`**Docker Version:** ${e.ServerVersion??"-"}`,`**OS:** ${e.OperatingSystem??"-"} (${e.Architecture??"-"})`,`**Kernel:** ${e.KernelVersion??"-"}`,`**CPUs:** ${e.NCPU??"-"}`,`**Memory:** ${Un(e.MemTotal)}`,`**Containers:** ${e.Containers??"-"} (running: ${e.ContainersRunning??"-"}, paused: ${e.ContainersPaused??"-"}, stopped: ${e.ContainersStopped??"-"})`,`**Images:** ${e.Images??"-"}`,`**Storage Driver:** ${e.Driver??"-"}`,`**Docker Root Dir:** ${e.DockerRootDir??"-"}`];return{success:!0,data:e,display:t.join(`
|
|
636
636
|
`)}}async pruneAll(){let[e,t,s,r]=await Promise.all([this.api("POST","/containers/prune"),this.api("POST","/images/prune"),this.api("POST","/volumes/prune"),this.api("POST","/networks/prune")]),o=e.ContainersDeleted?.length??0,n=t.ImagesDeleted?.length??0,i=s.VolumesDeleted?.length??0,a=r.NetworksDeleted?.length??0,l=(e.SpaceReclaimed??0)+(t.SpaceReclaimed??0)+(s.SpaceReclaimed??0),d=["## Docker Prune Results","",`**Containers removed:** ${o}`,`**Images removed:** ${n}`,`**Volumes removed:** ${i}`,`**Networks removed:** ${a}`,"",`**Total space reclaimed:** ${Un(l)}`];return{success:!0,data:{containers:e,images:t,volumes:s,networks:r},display:d.join(`
|
|
637
637
|
`)}}async composePs(e){let s=(await this.api("GET","/containers/json?all=true")).filter(n=>n.Labels?.["com.docker.compose.project"]),r=new Map;for(let n of s){let i=n.Labels["com.docker.compose.project"];e&&i!==e||(r.has(i)||r.set(i,[]),r.get(i).push(n))}let o=["## Docker Compose Projects",""];if(r.size===0)return o.push(e?`No containers found for project "${e}".`:"No Compose-managed containers found."),{success:!0,data:[],display:o.join(`
|
|
638
|
-
`)};for(let[n,i]of r){o.push(`### ${n}`),o.push(""),o.push("| Service | Name | Status | Ports |"),o.push("|---------|------|--------|-------|");for(let a of i){let l=a.Labels?.["com.docker.compose.service"]??"-";o.push(`| ${l} | ${Fn(a.Names)} | ${a.Status??a.State??"-"} | ${
|
|
639
|
-
`)}}async composeUp(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await
|
|
638
|
+
`)};for(let[n,i]of r){o.push(`### ${n}`),o.push(""),o.push("| Service | Name | Status | Ports |"),o.push("|---------|------|--------|-------|");for(let a of i){let l=a.Labels?.["com.docker.compose.service"]??"-";o.push(`| ${l} | ${Fn(a.Names)} | ${a.Status??a.State??"-"} | ${Cc(a.Ports)} |`)}o.push("")}return{success:!0,data:[...r.entries()],display:o.join(`
|
|
639
|
+
`)}}async composeUp(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await Rc("docker",["compose","-p",e,"up","-d"],{timeout:12e4}),r=(t+`
|
|
640
640
|
`+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose up:** \`${e}\``,"","```",r,"```"].join(`
|
|
641
|
-
`)}}async composeDown(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await
|
|
641
|
+
`)}}async composeDown(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await Rc("docker",["compose","-p",e,"down"],{timeout:12e4}),r=(t+`
|
|
642
642
|
`+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose down:** \`${e}\``,"","```",r,"```"].join(`
|
|
643
|
-
`)}}}});import{readFile as
|
|
644
|
-
`)}}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(
|
|
645
|
-
`)}}async fetchVin(e){let t=await fetch(`${
|
|
643
|
+
`)}}}});import{readFile as Nc,writeFile as Dc,mkdir as Mc}from"node:fs/promises";import{homedir as jn}from"node:os";import{join as Bn}from"node:path";import Uc from"node:crypto";function Hu(){let c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=Uc.randomBytes(86);return Array.from(e).map(t=>c[t%c.length]).join("")}function qu(c){return Uc.createHash("sha256").update(c).digest("base64url")}function ue(c,e){return c[e]?.value??"?"}var Uu,Oc,to,Fu,ju,Bu,Pc,so,zu,ro,Fc=b(()=>{"use strict";P();Uu="https://customer.bmwgroup.com/gcdm/oauth/device/code",Oc="https://customer.bmwgroup.com/gcdm/oauth/token",to="https://api-cardata.bmwgroup.com",Fu="v1",ju="authenticate_user openid cardata:api:read cardata:streaming:read",Bu=5*6e4,Pc="Alfred",so=Bn(jn(),".alfred","bmw-tokens.json");u(Hu,"generateCodeVerifier");u(qu,"generateCodeChallenge");zu=["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");ro=class extends I{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=Hu(),s=qu(t),r=await fetch(Uu,{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:ju}),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(`
|
|
644
|
+
`)}}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(Oc,{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(`
|
|
645
|
+
`)}}async fetchVin(e){let t=await fetch(`${to}/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(`${to}/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===Pc);if(i)return i.containerId}let s=await fetch(`${to}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:Pc,purpose:"Alfred AI Assistant",technicalDescriptors:zu}),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":Fu,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<Bu)return s.data;let r=await this.ensureToken(),o=`${to}${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 Nc(so,"utf-8");return this.tokens=JSON.parse(e),this.tokens}catch{return null}}async saveTokens(e){await Mc(Bn(jn(),".alfred"),{recursive:!0}),await Dc(so,JSON.stringify(e,null,2),"utf-8")}async savePartialTokens(e){await Mc(Bn(jn(),".alfred"),{recursive:!0});let t={};try{let s=await Nc(so,"utf-8");t=JSON.parse(s)}catch{}await Dc(so,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(Oc,{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(`
|
|
646
646
|
`)}}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(`
|
|
647
647
|
`)}}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(`
|
|
648
|
-
`)}}}});var
|
|
648
|
+
`)}}}});var Wu,oo,jc=b(()=>{"use strict";P();Wu="https://routes.googleapis.com/directions/v2:computeRoutes",oo=class extends I{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(`
|
|
649
649
|
`)}}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(`
|
|
650
|
-
`)}}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(
|
|
651
|
-
`)}}showService(e){let t=
|
|
652
|
-
`],r={};for(let o of t.fields){let n=process.env[o.env];r[o.env]=n;let i=n?o.secret?
|
|
653
|
-
`)}}async setService(e,t){let s=
|
|
650
|
+
`)}}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(Wu,{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 Hn from"node:fs";import Bc from"node:path";function Hc(c){return c.length<=4?"****":"*".repeat(c.length-4)+c.slice(-4)}function Vu(){let c=process.cwd();for(let e=0;e<10;e++){let t=Bc.join(c,".env");if(Hn.existsSync(t))return t;let s=Bc.dirname(c);if(s===c)break;c=s}return null}var Qt,es,qc=b(()=>{"use strict";P();Qt={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)"}]}},es=class extends I{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(Qt)){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(Qt),display:e.join(`
|
|
651
|
+
`)}}showService(e){let t=Qt[e];if(!t)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Qt).join(", ")}`};let s=[`**${t.label}** configuration:
|
|
652
|
+
`],r={};for(let o of t.fields){let n=process.env[o.env];r[o.env]=n;let i=n?o.secret?Hc(n):n:"_not set_",a=o.required?" (required)":"";s.push(`- \`${o.env}\`: ${i}${a}`)}return{success:!0,data:r,display:s.join(`
|
|
653
|
+
`)}}async setService(e,t){let s=Qt[e];if(!s)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Qt).join(", ")}`};if(!t||Object.keys(t).length===0)return{success:!1,error:`No values provided. Pass an object with ENV variable names as keys.
|
|
654
654
|
|
|
655
655
|
Available keys for ${s.label}:
|
|
656
656
|
${s.fields.map(d=>`- \`${d.env}\`: ${d.label}${d.required?" (required)":""}`).join(`
|
|
657
|
-
`)}`};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=
|
|
657
|
+
`)}`};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=Vu();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=Hn.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()+`
|
|
658
658
|
${d}=${p}
|
|
659
659
|
`,i.push(d)}Hn.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}\`:
|
|
660
|
-
`,...i.map(d=>`- \`${d}\` = ${s.fields.find(m=>m.env===d)?.secret?
|
|
660
|
+
`,...i.map(d=>`- \`${d}\` = ${s.fields.find(m=>m.env===d)?.secret?Hc(t[d]):t[d]}`)];if(a.length>0)l.push(`
|
|
661
661
|
**Still missing:** ${a.join(", ")}`);else if(this.reloadCallback){let d=await this.reloadCallback(e);d.success?l.push(`
|
|
662
662
|
**${s.label} wurde aktiviert.** Du kannst es jetzt sofort nutzen.`):l.push(`
|
|
663
663
|
**${s.label} is fully configured.** Hot-Reload fehlgeschlagen: ${d.error??"unbekannter Fehler"}. Restart Alfred: \`alfred start\``)}else l.push(`
|
|
664
664
|
**${s.label} is fully configured.** Restart Alfred to activate: \`alfred start\``);return{success:!0,data:{envPath:o,written:i},display:l.join(`
|
|
665
|
-
`)}}};u(
|
|
666
|
-
`)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let o of s)o.type==="node"&&!o.online&&t.push({source:"proxmox",message:`Node "${o.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let o of r){let n=o.name??`VMID ${o.vmid}`,i=o.status,a=o.maxdisk,l=o.disk;if(a&&a>0&&l!=null){let d=l/a*100;d>90&&t.push({source:"proxmox",message:`${n} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=o.maxmem,m=o.mem;if(d&&d>0&&m!=null){let p=m/d*100;p>95&&t.push({source:"proxmox",message:`${n} RAM usage ${p.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},o=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)throw new Error(`Proxmox HTTP ${o.status}: ${(await o.text()).slice(0,200)}`);return(await o.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,o=[],n;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let l=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),m=await this.apiFetch(`${l}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),p;if(m.status===200)p="unifi-os",o=(m.headers.getSetCookie?.()??[]).map(w=>w.split(";")[0]),n=m.headers.get("x-csrf-token")??void 0;else if(m.status===404){let w=await this.apiFetch(`${l}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!w.ok)throw new Error(`UniFi login failed: HTTP ${w.status}`);p="classic",o=(w.headers.getSetCookie?.()??[]).map(y=>y.split(";")[0])}else throw new Error(`UniFi login failed: HTTP ${m.status}`);r={"Content-Type":"application/json"},o.length>0&&(r.Cookie=o.join("; ")),n&&(r["X-CSRF-Token"]=n)}let i=u(l=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${l}`,"apiUrl"),a=u(async l=>{let d=await this.apiFetch(i(l),{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!d.ok)throw new Error(`UniFi HTTP ${d.status}`);return(await d.json()).data},"unifiGet");try{let l=await a("stat/health");for(let d of l??[])d.status&&d.status!=="ok"&&t.push({source:"unifi",message:`Subsystem "${d.subsystem}" status: ${d.status}`})}catch{}try{let l=await a("stat/device");for(let d of l??[])if(d.state!==1){let m=d.name??d.hostname??d.mac??"unknown";t.push({source:"unifi",message:`Device "${m}" is not connected (state: ${d.state})`})}}catch{}try{let l=await a("rest/alarm?archived=false");l&&l.length>0&&t.push({source:"unifi",message:`${l.length} open alert(s): ${l.slice(0,3).map(d=>d.key??d.msg??"unknown").join(", ")}`})}catch{}return t}async checkHomeAssistant(){let e=this.config.homeassistant,t=[],s=await this.haGet(e,"/api/states"),r=0,o=[];for(let n of s){let i=n.entity_id;if(!i.startsWith("update.")){if(n.state==="unavailable"&&(r++,o.length<5)){let a=n.attributes?.friendly_name??i;o.push(a)}if(i.startsWith("sensor.")&&i.includes("battery")){let a=parseFloat(n.state);if(!isNaN(a)&&a<20){let l=n.attributes?.friendly_name??i;t.push({source:"homeassistant",message:`Low battery: ${l} at ${a}%`})}}}}if(r>0){let n=o.join(", "),i=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${n}${i}`})}return t}async haGet(e,t){let s=`${e.baseUrl.replace(/\/+$/,"")}${t}`,r={Authorization:`Bearer ${e.accessToken}`,"Content-Type":"application/json"},o=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)throw new Error(`HA HTTP ${o.status}: ${(await o.text()).slice(0,200)}`);return await o.json()}async apiFetch(e,t,s){let r=s===!1,o=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{r&&(o===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}}}});var
|
|
665
|
+
`)}}};u(Hc,"maskValue");u(Vu,"findEnvFile")});var no,zc=b(()=>{"use strict";P();no=class extends I{static{u(this,"MonitorSkill")}metadata={name:"monitor",category:"infrastructure",description:"Deterministic infrastructure health checks without LLM. Checks Proxmox cluster, UniFi network, and Home Assistant for issues. Returns alerts only when problems are detected \u2014 empty display means all OK.",riskLevel:"read",version:"1.0.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{checks:{type:"array",items:{type:"string",enum:["proxmox","unifi","homeassistant"]},description:"Which checks to run (default: all configured)"}}}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.checks,r=[],o=u(l=>!s||s.length===0||s.includes(l),"shouldRun");if(this.config.proxmox&&o("proxmox")&&r.push(this.checkProxmox()),this.config.unifi&&o("unifi")&&r.push(this.checkUnifi()),this.config.homeassistant&&o("homeassistant")&&r.push(this.checkHomeAssistant()),r.length===0)return{success:!0,display:""};let n=await Promise.allSettled(r),i=[];for(let l of n)if(l.status==="fulfilled")i.push(...l.value);else{let d=l.reason instanceof Error?l.reason.message:String(l.reason);i.push({source:"proxmox",message:`Health check failed: ${d}`})}if(i.length===0)return{success:!0,display:""};let a=["\u26A0 Infrastructure Alerts:",""];for(let l of i)a.push(`- [${l.source}] ${l.message}`);return{success:!0,display:a.join(`
|
|
666
|
+
`)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let o of s)o.type==="node"&&!o.online&&t.push({source:"proxmox",message:`Node "${o.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let o of r){let n=o.name??`VMID ${o.vmid}`,i=o.status,a=o.maxdisk,l=o.disk;if(a&&a>0&&l!=null){let d=l/a*100;d>90&&t.push({source:"proxmox",message:`${n} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=o.maxmem,m=o.mem;if(d&&d>0&&m!=null){let p=m/d*100;p>95&&t.push({source:"proxmox",message:`${n} RAM usage ${p.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},o=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)throw new Error(`Proxmox HTTP ${o.status}: ${(await o.text()).slice(0,200)}`);return(await o.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,o=[],n;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let l=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),m=await this.apiFetch(`${l}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),p;if(m.status===200)p="unifi-os",o=(m.headers.getSetCookie?.()??[]).map(w=>w.split(";")[0]),n=m.headers.get("x-csrf-token")??void 0;else if(m.status===404){let w=await this.apiFetch(`${l}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!w.ok)throw new Error(`UniFi login failed: HTTP ${w.status}`);p="classic",o=(w.headers.getSetCookie?.()??[]).map(y=>y.split(";")[0])}else throw new Error(`UniFi login failed: HTTP ${m.status}`);r={"Content-Type":"application/json"},o.length>0&&(r.Cookie=o.join("; ")),n&&(r["X-CSRF-Token"]=n)}let i=u(l=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${l}`,"apiUrl"),a=u(async l=>{let d=await this.apiFetch(i(l),{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!d.ok)throw new Error(`UniFi HTTP ${d.status}`);return(await d.json()).data},"unifiGet");try{let l=await a("stat/health");for(let d of l??[])d.status&&d.status!=="ok"&&t.push({source:"unifi",message:`Subsystem "${d.subsystem}" status: ${d.status}`})}catch{}try{let l=await a("stat/device");for(let d of l??[])if(d.state!==1){let m=d.name??d.hostname??d.mac??"unknown";t.push({source:"unifi",message:`Device "${m}" is not connected (state: ${d.state})`})}}catch{}try{let l=await a("rest/alarm?archived=false");l&&l.length>0&&t.push({source:"unifi",message:`${l.length} open alert(s): ${l.slice(0,3).map(d=>d.key??d.msg??"unknown").join(", ")}`})}catch{}return t}async checkHomeAssistant(){let e=this.config.homeassistant,t=[],s=await this.haGet(e,"/api/states"),r=0,o=[];for(let n of s){let i=n.entity_id;if(!i.startsWith("update.")){if(n.state==="unavailable"&&(r++,o.length<5)){let a=n.attributes?.friendly_name??i;o.push(a)}if(i.startsWith("sensor.")&&i.includes("battery")){let a=parseFloat(n.state);if(!isNaN(a)&&a<20){let l=n.attributes?.friendly_name??i;t.push({source:"homeassistant",message:`Low battery: ${l} at ${a}%`})}}}}if(r>0){let n=o.join(", "),i=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${n}${i}`})}return t}async haGet(e,t){let s=`${e.baseUrl.replace(/\/+$/,"")}${t}`,r={Authorization:`Bearer ${e.accessToken}`,"Content-Type":"application/json"},o=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)throw new Error(`HA HTTP ${o.status}: ${(await o.text()).slice(0,200)}`);return await o.json()}async apiFetch(e,t,s){let r=s===!1,o=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{r&&(o===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}}}});var io,Wc=b(()=>{"use strict";P();io=class extends I{static{u(this,"MicrosoftTodoSkill")}config;accessToken="";metadata={name:"microsoft_todo",description:"Manage Microsoft To Do lists and tasks \u2014 list, create, complete, update and delete tasks across all lists.",version:"1.0.0",riskLevel:"write",category:"productivity",inputSchema:{type:"object",required:["action"],properties:{action:{type:"string",enum:["list_lists","list_tasks","add_task","complete_task","uncomplete_task","delete_task","update_task","create_list"],description:"Action to perform."},listId:{type:"string",description:"To Do list ID. Either listId or list (display name) is required for task actions."},list:{type:"string",description:'To Do list display name (resolved to listId automatically). E.g. "Einkaufsliste".'},taskId:{type:"string",description:"Task ID (required for complete/uncomplete/delete/update)."},title:{type:"string",description:"Task or list title (required for add_task, create_list; optional for update_task)."},body:{type:"string",description:"Task body/notes."},dueDate:{type:"string",description:"Due date in YYYY-MM-DD format."},importance:{type:"string",enum:["low","normal","high"],description:"Task importance."},includeCompleted:{type:"boolean",description:"Include completed tasks in list_tasks (default: false)."}}}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;try{switch(s){case"list_lists":return await this.listLists();case"list_tasks":return await this.listTasks(e);case"add_task":return await this.addTask(e);case"complete_task":return await this.completeTask(e);case"uncomplete_task":return await this.uncompleteTask(e);case"delete_task":return await this.deleteTask(e);case"update_task":return await this.updateTask(e);case"create_list":return await this.createList(e);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Tasks.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=u(()=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s();if(r.status===401){if(await this.refreshAccessToken(),r=await s(),!r.ok)throw new Error(`Graph API error: ${r.status}`)}else if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async resolveListId(e){if(e.listId)return e.listId;if(!e.list)throw new Error("Either listId or list (display name) is required.");let t=e.list.toLowerCase(),r=(await this.graphRequest("/me/todo/lists")).value??[],o=r.find(n=>n.displayName.toLowerCase()===t);if(!o){let n=r.map(i=>i.displayName).join(", ");throw new Error(`List "${e.list}" not found. Available lists: ${n}`)}return o.id}async listLists(){let t=(await this.graphRequest("/me/todo/lists")).value??[],s=t.map(r=>`\u2022 **${r.displayName}**${r.wellknownListName==="defaultList"?" (Standard)":""}`).join(`
|
|
667
667
|
`);return{success:!0,data:t,display:s||"Keine Listen gefunden."}}async listTasks(e){let t=await this.resolveListId(e),s=e.includeCompleted===!0,r=`/me/todo/lists/${t}/tasks`;s||(r+="?$filter=status ne 'completed'");let n=(await this.graphRequest(r)).value??[],i=n.map(a=>{let l=a.status==="completed"?"\u2611":"\u2610",d=a.importance==="high"?" \u2757":"",m=a.dueDateTime?` (f\xE4llig: ${a.dueDateTime.dateTime.slice(0,10)})`:"";return`${l} ${a.title}${d}${m}`});return{success:!0,data:n,display:i.length>0?i.join(`
|
|
668
|
-
`):"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});import{spawn as
|
|
669
|
-
`+c.slice(-
|
|
670
|
-
`).pop();x&&t.onProgress(`[${c.name}] ${x}`)}}),c.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",$=>{clearTimeout(T);let A=Date.now()-d,x=
|
|
671
|
-
`+$.message),exitCode:127,durationMs:A,modifiedFiles:[]})})})}var
|
|
672
|
-
`).length-1;return{sha:t,message:c,filesChanged:Math.max(r,0)}}async function Vn(c,e,t){await Le(["push","-u",c,e],t)}function Kn(c){return`alfred/${c.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function
|
|
673
|
-
[...truncated]`}function
|
|
668
|
+
`):"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});import{spawn as Ku}from"node:child_process";import Vc from"node:fs";import Xc from"node:path";function Ju(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 Zu(c,e){return c.map(t=>t.replace(/\{\{prompt\}\}/g,e))}function ao(c){return c.length<=Kc?c:`[...truncated...]
|
|
669
|
+
`+c.slice(-Kc)}function Gc(c){let e=new Map;function t(s){let r;try{r=Vc.readdirSync(s,{withFileTypes:!0})}catch{return}for(let o of r){if(Yu.has(o.name))continue;let n=Xc.join(s,o.name);if(o.isDirectory())t(n);else if(o.isFile())try{let i=Vc.statSync(n);e.set(n,i.mtimeMs)}catch{}}}return u(t,"walk"),t(c),e}function Qu(c,e,t){let s=[];for(let[r,o]of e){let n=c.get(r);(n===void 0||o>n)&&s.push(Xc.relative(t,r))}return s.sort()}async function er(c,e,t={}){let s=t.cwd??c.cwd??process.cwd(),r=t.timeoutMs??c.timeoutMs??Gu,o=Math.min(r,Xu),n=Zu(c.argsTemplate,e),i={...process.env,...c.env?Ju(c.env):{}},a=process.platform==="win32",l=Gc(s),d=Date.now();return new Promise(m=>{let p=Ku(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 x=A.trim().split(`
|
|
670
|
+
`).pop();x&&t.onProgress(`[${c.name}] ${x}`)}}),c.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",$=>{clearTimeout(T);let A=Date.now()-d,x=Gc(s),U=Qu(l,x,s);m({stdout:ao(w),stderr:ao(y),exitCode:h?124:$??1,durationMs:A,modifiedFiles:U})}),p.on("error",$=>{clearTimeout(T);let A=Date.now()-d;m({stdout:ao(w),stderr:ao(y+`
|
|
671
|
+
`+$.message),exitCode:127,durationMs:A,modifiedFiles:[]})})})}var Gu,Xu,Kc,Yu,co=b(()=>{"use strict";Gu=3e5,Xu=9e5,Kc=1e5,Yu=new Set([".git","node_modules",".next","dist",".cache"]);u(Ju,"resolveEnv");u(Zu,"buildArgs");u(ao,"truncateOutput");u(Gc,"snapshotMtimes");u(Qu,"detectModifiedFiles");u(er,"executeAgent")});import{execFile as em}from"node:child_process";function Le(c,e){return new Promise((t,s)=>{em("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 lo(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 qn(c,e){await Le(["checkout","-b",c],e)}async function zn(c){await Le(["add","-A"],c)}async function Wn(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(`
|
|
672
|
+
`).length-1;return{sha:t,message:c,filesChanged:Math.max(r,0)}}async function Vn(c,e,t){await Le(["push","-u",c,e],t)}function Kn(c){return`alfred/${c.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function ts(c,e){try{return await Le(["remote","get-url",c],e)}catch{return null}}function ss(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 tr(c){await Le(["init"],c)}async function sr(c,e,t){await Le(["remote","add",c,e],t)}var Gn=b(()=>{"use strict";u(Le,"git");u(lo,"gitStatus");u(qn,"gitCreateBranch");u(zn,"gitStageAll");u(Wn,"gitCommit");u(Vn,"gitPush");u(Kn,"slugifyBranch");u(ts,"gitGetRemoteUrl");u(ss,"parseRemoteUrl");u(tr,"gitInitRepo");u(sr,"gitAddRemote")});function rs(c){switch(c.provider){case"github":{if(!c.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Xn(c.github)}case"gitlab":{if(!c.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new Yn(c.gitlab)}default:throw new Error(`Unknown forge provider: ${c.provider}`)}}var yt,Xn,Yn,Jn=b(()=>{"use strict";yt=class{static{u(this,"ForgeClient")}},Xn=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}}},Yn=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(rs,"createForgeClient")});function Yc(c,e){return c.length<=e?c:c.slice(0,e)+`
|
|
673
|
+
[...truncated]`}function Jc(c){let e=c.replace(/^```(?:json)?\s*\n?/m,"").replace(/\n?```\s*$/m,"");return JSON.parse(e)}async function cm(c,e,t){let r=`Available agents:
|
|
674
674
|
${e.map(a=>`- ${a.name}: command="${a.command}"`).join(`
|
|
675
675
|
`)}
|
|
676
676
|
|
|
677
677
|
Task:
|
|
678
|
-
${c}`,o=await t.complete({system:
|
|
678
|
+
${c}`,o=await t.complete({system:im,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"}),n=Jc(o.content);if(!Array.isArray(n.subtasks)||n.subtasks.length===0)throw new Error("LLM returned an empty plan with no subtasks");let i=new Set(e.map(a=>a.name));for(let a of n.subtasks)if(!i.has(a.agent))throw new Error(`Plan references unknown agent "${a.agent}". Available: ${[...i].join(", ")}`);return n}async function lm(c,e,t,s){let r=new Zn(t),o=[],n=c.map(async i=>{await r.acquire();try{s?.(`Running ${i.id}: ${i.description}`);let a=e.get(i.agent),l=await er(a,i.prompt,{onProgress:s?m=>s(`[${i.id}] ${m}`):void 0}),d={subtask:i,execution:l};return o.push(d),s?.(`Completed ${i.id}: exit=${l.exitCode}, ${l.modifiedFiles.length} files modified`),d}finally{r.release()}});return await Promise.all(n),o}async function dm(c,e,t){let s=e.map(n=>{let i=Yc(n.execution.stdout,om),a=Yc(n.execution.stderr,nm);return[`### ${n.subtask.id} (${n.subtask.description})`,`Agent: ${n.subtask.agent}`,`Exit code: ${n.execution.exitCode}`,`Modified files: ${n.execution.modifiedFiles.join(", ")||"none"}`,i?`stdout:
|
|
679
679
|
${i}`:"",a?`stderr:
|
|
680
680
|
${a}`:""].filter(Boolean).join(`
|
|
681
681
|
`)}).join(`
|
|
@@ -684,11 +684,11 @@ ${a}`:""].filter(Boolean).join(`
|
|
|
684
684
|
${c}
|
|
685
685
|
|
|
686
686
|
Results:
|
|
687
|
-
${s}`,o=await t.complete({system:
|
|
687
|
+
${s}`,o=await t.complete({system:am,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let n=Jc(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??tm,sm),o=s.maxConcurrent??rm,n=s.onProgress,i=Date.now(),a=new Map(e.map(h=>[h.name,h]));n?.("Planning subtasks...");let l=await cm(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 lm(m,a,o,n);d=d.concat(h),n?.(`Iteration ${p}: validating results...`);let T=await dm(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 rr(c,e,t,s={}){let r=s.onProgress,o=s.cwd??process.cwd(),n={warnings:[]},i=await lo({cwd:o});if(!i.isRepo)try{await tr({cwd:o}),i=await lo({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 ts("origin",{cwd:o});if(l){let y=ss(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=rs(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 sr("origin",T.cloneUrl,{cwd:o});let $=ss(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=Kn(c);try{await qn(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 zn({cwd:o});let y=`feat: ${c.slice(0,72)}
|
|
688
688
|
|
|
689
|
-
Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,h=await Wn(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
|
|
689
|
+
Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,h=await Wn(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 ts("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 Vn("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=rs(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(x=>`- \`${x}\``).join(`
|
|
690
690
|
`),"","_Automated by Alfred_"].join(`
|
|
691
|
-
`),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
|
|
691
|
+
`),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 tm,sm,rm,om,nm,im,am,Zn,Qn=b(()=>{"use strict";co();Gn();Jn();tm=3,sm=5,rm=3,om=2048,nm=1024,im=`You are a task planner for a multi-agent coding system.
|
|
692
692
|
You receive a high-level task and a list of available coding agents.
|
|
693
693
|
Your job is to decompose the task into concrete subtasks, each assigned to an agent.
|
|
694
694
|
|
|
@@ -704,7 +704,7 @@ Respond with ONLY valid JSON (no markdown fences):
|
|
|
704
704
|
"subtasks": [
|
|
705
705
|
{ "id": "task-1", "agent": "<agent-name>", "prompt": "<detailed prompt>", "description": "<short description>" }
|
|
706
706
|
]
|
|
707
|
-
}`,
|
|
707
|
+
}`,am=`You are a code review validator for a multi-agent coding system.
|
|
708
708
|
You receive the original task and the results from each subtask execution.
|
|
709
709
|
Your job is to determine if the task was completed successfully.
|
|
710
710
|
|
|
@@ -718,9 +718,9 @@ Respond with ONLY valid JSON (no markdown fences):
|
|
|
718
718
|
"fixTasks": [
|
|
719
719
|
{ "id": "fix-1", "agent": "<agent-name>", "prompt": "<detailed fix prompt>", "description": "<short description>" }
|
|
720
720
|
]
|
|
721
|
-
}`;u(
|
|
721
|
+
}`;u(Yc,"truncate");u(Jc,"parseJSON");Zn=class{static{u(this,"Semaphore")}max;queue=[];active=0;constructor(e){this.max=e}async acquire(){if(this.active<this.max){this.active++;return}return new Promise(e=>{this.queue.push(()=>{this.active++,e()})})}release(){this.active--;let e=this.queue.shift();e&&e()}};u(cm,"planSubtasks");u(lm,"executeSubtasksParallel");u(dm,"validateResults");u(wt,"orchestrate");u(rr,"orchestrateWithGit")});var or,Zc=b(()=>{"use strict";P();co();Qn();or=class extends I{static{u(this,"CodeAgentSkill")}llm;metadata={name:"code_agent",category:"automation",description:'Run a CLI-based coding agent (e.g. Claude Code, Codex, Gemini CLI, Aider) as a subprocess. Use action "list_agents" to see available agents, "run" to execute one with a prompt, or "orchestrate" to have the LLM decompose a task into parallel subtasks. The agent runs in a specified working directory and returns stdout, stderr, exit code, duration, and a list of files it modified.',riskLevel:"admin",version:"1.0.0",timeoutMs:6e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_agents","run","orchestrate"],description:"The action to perform"},task:{type:"string",description:'High-level task description for "orchestrate" action'},agents:{type:"array",items:{type:"string"},description:'Optional agent name filter for "orchestrate" (uses all agents if omitted)'},maxIterations:{type:"number",description:'Max validation iterations for "orchestrate" (1-5, default 3)'},agent:{type:"string",description:'Name of the agent to run (required for "run" action)'},prompt:{type:"string",description:'The prompt / task description to send to the agent (required for "run" action)'},cwd:{type:"string",description:"Working directory for the agent (optional, uses agent default or process.cwd())"},timeout:{type:"number",description:"Timeout in milliseconds (optional, max 900000)"},git:{type:"boolean",description:'Enable git workflow: auto-branch, commit, push, and PR creation (for "orchestrate")'},prTitle:{type:"string",description:"Custom PR/MR title (used with git=true)"},baseBranch:{type:"string",description:'Target branch for the PR/MR (default: "main")'}},required:["action"]}};agents;forgeConfig;constructor(e,t){super(),this.llm=t,this.agents=new Map(e.agents.map(s=>[s.name,s])),this.forgeConfig=e.forge}async execute(e,t){let s=e.action;switch(s){case"list_agents":return this.listAgents();case"run":return this.runAgent(e,t);case"orchestrate":return this.orchestrateTask(e,t);default:return{success:!1,error:`Unknown action "${s}". Use "list_agents", "run", or "orchestrate".`}}}listAgents(){let e=[...this.agents.values()].map(s=>({name:s.name,command:s.command,promptVia:s.promptVia??"arg",timeoutMs:s.timeoutMs})),t=e.length===0?"No code agents configured.":e.map(s=>`- **${s.name}**: \`${s.command}\` (prompt via ${s.promptVia})`).join(`
|
|
722
722
|
`);return{success:!0,data:{agents:e},display:`Available code agents:
|
|
723
|
-
${t}`}}async runAgent(e,t){let s=e.agent,r=e.prompt;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "agent"'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "prompt"'};let o=this.agents.get(s);if(!o){let d=[...this.agents.keys()].join(", ");return{success:!1,error:`Unknown agent "${s}". Available: ${d}`}}let n=typeof e.cwd=="string"?e.cwd:void 0,i=typeof e.timeout=="number"?e.timeout:void 0,a=await
|
|
723
|
+
${t}`}}async runAgent(e,t){let s=e.agent,r=e.prompt;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "agent"'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "prompt"'};let o=this.agents.get(s);if(!o){let d=[...this.agents.keys()].join(", ");return{success:!1,error:`Unknown agent "${s}". Available: ${d}`}}let n=typeof e.cwd=="string"?e.cwd:void 0,i=typeof e.timeout=="number"?e.timeout:void 0,a=await er(o,r,{cwd:n,timeoutMs:i,onProgress:t.onProgress}),l=[];return a.stdout&&l.push(`**stdout:**
|
|
724
724
|
\`\`\`
|
|
725
725
|
${a.stdout}
|
|
726
726
|
\`\`\``),a.stderr&&l.push(`**stderr:**
|
|
@@ -730,7 +730,7 @@ ${a.stderr}
|
|
|
730
730
|
${a.modifiedFiles.map(d=>`- ${d}`).join(`
|
|
731
731
|
`)}`),{success:a.exitCode===0,data:{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,durationMs:a.durationMs,modifiedFiles:a.modifiedFiles},display:l.join(`
|
|
732
732
|
|
|
733
|
-
`),...a.exitCode!==0&&{error:a.exitCode===124?`Agent "${s}" timed out`:`Agent "${s}" exited with code ${a.exitCode}`}}}async orchestrateTask(e,t){if(!this.llm)return{success:!1,error:"Orchestration requires an LLM provider but none was configured."};let s=e.task;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task" for orchestrate action.'};let r=[...this.agents.values()],o=e.agents;if(Array.isArray(o)&&o.length>0&&(r=o.map(d=>this.agents.get(d)).filter(d=>d!==void 0),r.length===0))return{success:!1,error:`None of the specified agents exist. Available: ${[...this.agents.keys()].join(", ")}`};let n=typeof e.maxIterations=="number"?e.maxIterations:void 0,i=e.git===!0,a=typeof e.prTitle=="string"?e.prTitle:void 0,l=typeof e.baseBranch=="string"?e.baseBranch:void 0;try{if(i){let m=await
|
|
733
|
+
`),...a.exitCode!==0&&{error:a.exitCode===124?`Agent "${s}" timed out`:`Agent "${s}" exited with code ${a.exitCode}`}}}async orchestrateTask(e,t){if(!this.llm)return{success:!1,error:"Orchestration requires an LLM provider but none was configured."};let s=e.task;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task" for orchestrate action.'};let r=[...this.agents.values()],o=e.agents;if(Array.isArray(o)&&o.length>0&&(r=o.map(d=>this.agents.get(d)).filter(d=>d!==void 0),r.length===0))return{success:!1,error:`None of the specified agents exist. Available: ${[...this.agents.keys()].join(", ")}`};let n=typeof e.maxIterations=="number"?e.maxIterations:void 0,i=e.git===!0,a=typeof e.prTitle=="string"?e.prTitle:void 0,l=typeof e.baseBranch=="string"?e.baseBranch:void 0;try{if(i){let m=await rr(s,r,this.llm,{maxIterations:n,onProgress:t.onProgress,forge:this.forgeConfig,prTitle:a,baseBranch:l});return this.formatGitOrchestrationResult(m)}let d=await wt(s,r,this.llm,{maxIterations:n,onProgress:t.onProgress});return this.formatOrchestrationResult(d)}catch(d){return{success:!1,error:`Orchestration failed: ${d instanceof Error?d.message:String(d)}`}}}formatOrchestrationResult(e){let t=[];t.push(`**Orchestration completed in ${e.iterations} iteration(s)**`),t.push(`**Plan:** ${e.plan.reasoning}`),t.push(`**Duration:** ${(e.totalDurationMs/1e3).toFixed(1)}s`);for(let r of e.subtaskResults){let o=r.execution.exitCode===0?"OK":`FAIL (exit ${r.execution.exitCode})`;t.push(`- **${r.subtask.id}** [${r.subtask.agent}]: ${r.subtask.description} \u2014 ${o}`)}return e.allModifiedFiles.length>0&&t.push(`
|
|
734
734
|
**Modified files:**
|
|
735
735
|
${e.allModifiedFiles.map(r=>`- ${r}`).join(`
|
|
736
736
|
`)}`),e.summary&&t.push(`
|
|
@@ -739,15 +739,15 @@ ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
|
|
|
739
739
|
|
|
740
740
|
**Git:**
|
|
741
741
|
${s.join(`
|
|
742
|
-
`)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+o}}}});var
|
|
742
|
+
`)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+o}}}});var Qc=b(()=>{"use strict";Zc();co();Qn();Gn();Jn()});var Z={};oe(Z,{ActivityTracker:()=>ut,BMWSkill:()=>ro,BackgroundTaskSkill:()=>Vt,BrowserSkill:()=>qt,CalculatorSkill:()=>xt,CalendarProvider:()=>Re,CalendarSkill:()=>mt,ClipboardSkill:()=>Bt,CodeAgentSkill:()=>or,CodeExecutionSkill:()=>Ys,CodeExecutor:()=>ft,ConfigureSkill:()=>es,ContactsProvider:()=>Ce,ContactsSkill:()=>Qs,CrossPlatformSkill:()=>Wt,DelegateSkill:()=>Pt,DockerSkill:()=>eo,DocumentSkill:()=>Yt,EmailProvider:()=>qe,EmailSkill:()=>Ge,FileSkill:()=>Ft,ForgeClient:()=>yt,HomeAssistantSkill:()=>Xr,HttpSkill:()=>Ut,MCPClient:()=>pt,MCPManager:()=>Xs,MCPSkillAdapter:()=>ht,MemorySkill:()=>Ot,MicrosoftTodoSkill:()=>io,MonitorSkill:()=>no,NoteSkill:()=>Nt,PluginLoader:()=>Fr,ProfileSkill:()=>zt,ProxmoxSkill:()=>Kr,ReminderSkill:()=>Lt,RoutingSkill:()=>oo,ScheduledTaskSkill:()=>Kt,ScreenshotSkill:()=>Ht,ShellSkill:()=>Mt,Skill:()=>I,SkillRegistry:()=>At,SkillSandbox:()=>It,SystemInfoSkill:()=>Rt,TTSSkill:()=>Jt,TodoSkill:()=>Zt,UniFiSkill:()=>Gr,WeatherSkill:()=>Dt,WebSearchSkill:()=>Ct,allUserIds:()=>W,createCalendarProvider:()=>Gs,createContactsProvider:()=>Pn,createEmailProvider:()=>Ws,createForgeClient:()=>rs,effectiveUserId:()=>ee,gitAddRemote:()=>sr,gitGetRemoteUrl:()=>ts,gitInitRepo:()=>tr,orchestrate:()=>wt,orchestrateWithGit:()=>rr,parseRemoteUrl:()=>ss});var X=b(()=>{"use strict";P();Me();Ia();xa();$n();Ra();Ca();La();Na();Da();Ma();Oa();Fa();ja();Ba();Wa();Ka();Xa();Ya();Za();ec();tc();ac();cc();lc();dc();mc();hc();fc();gc();yc();wc();_c();Sc();Ac();Lc();Fc();jc();qc();zc();Wc();Qc()});var nr,ei=b(()=>{"use strict";nr=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 ir=b(()=>{"use strict";u(Tt,"buildSkillContext")});function el(c,e){let t=new Set(["core"]),s=!1;for(let[r,o]of Object.entries(um))e.has(r)&&o.test(c)&&(t.add(r),s=!0);if(!s)for(let r of e)t.add(r);return t}function tl(c,e){return c.filter(t=>e.has(t.category??"core"))}var um,sl=b(()=>{"use strict";um={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(el,"selectCategories");u(tl,"filterSkills")});import rl from"node:fs";import ol from"node:path";var mm,nl,pm,il,hm,fm,gm,al,ar,ti=b(()=>{"use strict";bn();ir();sl();mm=15*60*1e3,nl=50,pm=2,il=.85,hm=1e5,fm=2e3,gm=.1,al=3,ar=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 js}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(J=>J!==o)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let J=new Set;d=[];for(let se of H)for(let Q of await this.embeddingService.semanticSearch(se,e.text,10))J.has(Q.key)||(J.add(Q.key),d.push(Q));for(let se of H)for(let Q of this.memoryRepo.getRecentForPrompt(se,5))J.has(Q.key)||(J.add(Q.key),d.push(Q))}else{let J=new Set;d=[];for(let se of H)for(let Q of this.memoryRepo.getRecentForPrompt(se,20))J.has(Q.key)||(J.add(Q.key),d.push(Q))}}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(se=>se.category??"core")),J=el(e.text,H);$=tl(T,J)}let A=$?this.promptBuilder.buildTools($):void 0,x=this.promptBuilder.buildSystemPrompt({memories:d,skills:$,userProfile:y}),U=this.buildActiveAgentStatus();U&&(x+=`
|
|
743
743
|
|
|
744
|
-
`+U);let L=this.promptBuilder.buildMessages(l),Y=this.collapseRepeatedToolErrors(L),Oe=await this.buildUserContent(e,t);Y.push({role:"user",content:Oe});let ve=A?xe(JSON.stringify(A)):0,Pe=1,ae=this.trimToContextWindow(x,Y,ve,Pe),V,pe=0,he=Date.now(),C="",F=0,fe=0,Ue=0,
|
|
744
|
+
`+U);let L=this.promptBuilder.buildMessages(l),Y=this.collapseRepeatedToolErrors(L),Oe=await this.buildUserContent(e,t);Y.push({role:"user",content:Oe});let ve=A?xe(JSON.stringify(A)):0,Pe=1,ae=this.trimToContextWindow(x,Y,ve,Pe),V,pe=0,he=Date.now(),C="",F=0,fe=0,Ue=0,ns=[];for(t?.("Thinking...");;){pe>0&&this.compressToolLoop(ae,x,ve);try{V=await this.llm.complete({messages:ae,system:x,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(x,Y,ve,Pe);continue}throw Te}if(!V.toolCalls||V.toolCalls.length===0)break;let H=Date.now()-he;if(H>=mm){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,x,`Das Zeitlimit von ${Te} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`);break}if(pe>=nl){this.logger.warn({iteration:pe,pendingToolCalls:V.toolCalls.length},"Tool loop iteration cap reached"),V=await this.abortToolLoop(ae,V,a.id,x,`Das Iterationslimit von ${nl} Tool-Aufrufen wurde erreicht.`);break}pe++,this.logger.info({iteration:pe,toolCalls:V.toolCalls.length},"Processing tool calls");let J=[];V.content&&J.push({type:"text",text:V.content});for(let Te of V.toolCalls)J.push({type:"tool_use",id:Te.id,name:Te.name,input:Te.input});ae.push({role:"assistant",content:J});let se=await this.executeToolCallsParallel(V.toolCalls,{...i,conversationId:a.id,timezone:h},t),Q=se.blocks;se.attachments.length>0&&ns.push(...se.attachments),this.conversationManager.addMessage(a.id,"assistant",V.content??"",JSON.stringify(V.toolCalls)),this.conversationManager.addMessage(a.id,"user","",JSON.stringify(Q));let Et=this.buildErrorSignature(Q);if(Et){if(Et===C?F++:(F=1,C=Et),F>=pm){this.logger.warn({iteration:pe,consecutiveErrors:F,errorSignature:Et},"Tool loop aborted: same error repeated consecutively"),V=await this.abortToolLoop(ae,V,a.id,x,`Der gleiche Tool-Fehler ist ${F}x hintereinander aufgetreten: "${C.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0);break}}else F=0,C="";ae.push({role:"user",content:Q}),t?.("Thinking...")}let te=V.content;if(!te)for(let H=ae.length-1;H>=0;H--){let J=ae[H];if(J.role==="assistant"&&Array.isArray(J.content)){let se=J.content.find(Q=>Q.type==="text");if(se&&"text"in se&&se.text){te=se.text;break}}}te||(te="(no response)"),this.conversationManager.addMessage(a.id,"assistant",te),this.activeLearning&&this.activeLearning.onMessageProcessed(o,e.text,te);let is=Date.now()-s;return this.logger.info({duration:is,tokens:V.usage,totalTokens:{inputTokens:fe,outputTokens:Ue},stopReason:V.stopReason,toolIterations:pe},"Message processed"),{text:te,attachments:ns.length>0?ns: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 l=[];t.content&&l.push({type:"text",text:t.content});for(let d of t.toolCalls)l.push({type:"tool_use",id:d.id,name:d.name,input:d.input});e.push({role:"assistant",content:l})}let i=t.toolCalls.map(l=>({type:"tool_result",tool_use_id:l.id,content:`Error: tool loop aborted \u2014 ${o}`,is_error:!0}));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));let a=e[e.length-1];return a&&a.role==="user"&&Array.isArray(a.content)?a.content.push({type:"text",text:`[System: ${o} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}):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:"user",content:`[System: The above tool error repeated ${i} times with identical input. The loop was aborted.]`}),s=a;continue}}}t.push(r),s++}return t}toolPairSignature(e,t){let s=Array.isArray(e.content)?e.content.filter(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+=`
|
|
745
745
|
|
|
746
746
|
[${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(()=>(X(),Z));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(`
|
|
747
|
-
`)}applyMemoryBudget(e){let t=e.some(n=>n.score!=null&&n.score>0),s=e;t&&(s=e.filter(n=>(n.score??1)>=
|
|
747
|
+
`)}applyMemoryBudget(e){let t=e.some(n=>n.score!=null&&n.score>0),s=e;t&&(s=e.filter(n=>(n.score??1)>=gm));let r=0,o=[];for(let n of s){let i=xe(`[${n.category}] ${n.key}: ${n.value}`);if(r+i>fm)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*il);if(xe(t)+s+e.reduce((h,T)=>h+Bs(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<=al)return;let l=a.length-al,d=a.slice(0,l),m=[];for(let h of d){let T=e[h.start],$=[];if(Array.isArray(T.content))for(let U of T.content)U.type==="tool_use"&&$.push(U.name);let A=e[h.end],x="ok";Array.isArray(A.content)&&A.content.some(L=>L.type==="tool_result"&&L.is_error)&&(x="error"),m.push(`- ${$.join(", ")}: ${x}`)}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):
|
|
748
748
|
${m.join(`
|
|
749
749
|
`)}
|
|
750
|
-
]`},{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*
|
|
750
|
+
]`},{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*il*r),i=xe(e)+s,a=t[t.length-1],l=Bs(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 x=y[A].reduce((U,L)=>U+Bs(L),0);if(x>p)break;p-=x,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),x=this.summarizeTrimmedMessages(A);T.unshift({role:"user",content:`[Earlier conversation summary \u2014 ${$} messages were trimmed to fit the context window:
|
|
751
751
|
${x}
|
|
752
752
|
|
|
753
753
|
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(`
|
|
@@ -755,20 +755,20 @@ The conversation continues below with the most recent messages.]`})}return T.pus
|
|
|
755
755
|
`)}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}
|
|
756
756
|
|
|
757
757
|
`;if(r.push({type:"text",text:`${l}[Voice transcript]: ${a}`}),this.logger.info({transcriptLength:a.length},"Voice message transcribed"),s.length===1)return r.length===1&&r[0].type==="text"?r[0].text:r}catch(a){this.logger.error({err:a},"Voice transcription failed"),r.push({type:"text",text:"[Voice message could not be transcribed]"})}}else r.push({type:"text",text:"[Voice message received but speech-to-text is not configured. Add speech config to enable transcription.]"});else if((i.type==="document"||i.type==="video"||i.type==="other")&&i.data){let a=this.saveToInbox(i);if(a){let l=this.isTextMimeType(i.mimeType),d=`[File received: "${i.fileName??"unknown"}" (${this.formatBytes(i.data.length)}, ${i.mimeType??"unknown type"})]
|
|
758
|
-
[Saved to: ${a}]`;if(l&&i.data.length<=
|
|
758
|
+
[Saved to: ${a}]`;if(l&&i.data.length<=hm){let m=i.data.toString("utf-8");d+=`
|
|
759
759
|
[File content]:
|
|
760
|
-
${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??
|
|
760
|
+
${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??ol.resolve("./data/inbox");try{rl.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=ol.join(t,n);try{return rl.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 cr,si=b(()=>{"use strict";cr=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 lr,ri=b(()=>{"use strict";lr=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 dr,oi=b(()=>{"use strict";dr=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 ur,ni=b(()=>{"use strict";ur=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,"<"),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,"&").replace(/</g,"<").replace(/>/g,">")}}});var mr,ii=b(()=>{"use strict";mr=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;let n=this.embeddingRepo.store({userId:e,sourceType:s,sourceId:r,content:t,embedding:o.embedding,model:o.model,dimensions:o.dimensions});return this.logger.debug({userId:e,sourceType:s,sourceId:r},"Embedding stored"),n.id}catch(o){this.logger.error({err:o,userId:e,sourceType:s,sourceId:r},"Failed to embed content");return}}async semanticSearch(e,t,s=10){if(!this.llm.supportsEmbeddings())return[];try{let r=await this.llm.embed(t);if(!r)return[];let 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 pr,ai=b(()=>{"use strict";pr=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{m=await this.embeddingService.embedAndStore(e,l[d],"document",`${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(`
|
|
761
761
|
|
|
762
|
-
`);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
|
|
762
|
+
`);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 hr,ci=b(()=>{"use strict";ir();hr=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}
|
|
763
763
|
|
|
764
764
|
Result: ${n.display??JSON.stringify(n.data)}`:`\u274C Background task failed: ${e.description}
|
|
765
765
|
|
|
766
766
|
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}
|
|
767
767
|
|
|
768
|
-
Error: ${s}`)}}}});import
|
|
768
|
+
Error: ${s}`)}}}});import ym from"node:crypto";var fr,li=b(()=>{"use strict";ir();fr=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-${ym.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}
|
|
769
769
|
|
|
770
770
|
${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}]
|
|
771
|
-
${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 di(c){let e=c.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of
|
|
771
|
+
${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 di(c){let e=c.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of wm)if(s.test(e))return{level:"low",matchedPatterns:[]};let t=[];for(let s of Tm)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 wm,Tm,ui=b(()=>{"use strict";wm=[/^(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],Tm=[{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(di,"scanSignal")});var _m,bm,gr,mi=b(()=>{"use strict";_m=["fact","preference","correction","entity","decision","relationship","principle","commitment","moment","skill"],bm=`You are a memory extraction system. Analyze the user message and extract personal facts about the USER (not about what they're asking).
|
|
772
772
|
|
|
773
773
|
Rules:
|
|
774
774
|
- Only extract information the user STATES about themselves
|
|
@@ -788,25 +788,25 @@ Extract memories from this conversation:
|
|
|
788
788
|
User: {USER_MESSAGE}
|
|
789
789
|
Assistant: {ASSISTANT_RESPONSE}
|
|
790
790
|
|
|
791
|
-
Return ONLY a valid JSON array, no explanation:`,
|
|
791
|
+
Return ONLY a valid JSON array, no explanation:`,gr=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=bm.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 _m.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});var yr,pi=b(()=>{"use strict";ui();mi();yr=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 gr(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;let r=di(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 Em,$m,vm,km,wr,hi=b(()=>{"use strict";Em=Math.LN2,$m=.3,vm=.7,km=3,wr=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?$m:1,x=this.applyBoosts($*A,T);d.set(T.key,{memory:{key:T.key,value:T.value,category:T.category,type:T.type,score:x},score:x}),this.memoryRepo.recordAccess(T.id)}if(l)for(let h of a){let T=h.score*vm,$=d.get(h.key);if($)$.score+=T,$.memory.score=$.score;else{let A=this.memoryRepo.recall(e,h.key),x=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:x},score:x}),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>=km)&&(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(-Em*o/2592e6);s*=n}return s}}});import{EventEmitter as Sm}from"node:events";var ie,ze=b(()=>{"use strict";ie=class extends Sm{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(`
|
|
792
792
|
|
|
793
|
-
`);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 Sm,InputFile as fi}from"grammy";function al(c){if(c==="markdown")return"MarkdownV2";if(c==="html")return"HTML"}var lo,cl=b(()=>{"use strict";ze();u(al,"mapParseMode");lo=class extends ie{static{u(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new Sm(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:al(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:al(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 fi(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 fi(t,s),{caption:r});return String(o.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new fi(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 Am,GatewayIntentBits as uo,Events as gi}from"discord.js";var mo,ll=b(()=>{"use strict";ze();mo=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 Am({intents:[uo.Guilds,uo.GuildMessages,uo.MessageContent,uo.DirectMessages]}),this.client.on(gi.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(gi.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(gi.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 po,dl=b(()=>{"use strict";ze();po=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 ho,ul=b(()=>{"use strict";ze();ho=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 fo,ml=b(()=>{"use strict";ze();fo=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 yi from"node:readline";var go,pl=b(()=>{"use strict";ze();go=class extends ie{static{u(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=yi.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
|
|
793
|
+
`);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 Am,InputFile as fi}from"grammy";function cl(c){if(c==="markdown")return"MarkdownV2";if(c==="html")return"HTML"}var uo,ll=b(()=>{"use strict";ze();u(cl,"mapParseMode");uo=class extends ie{static{u(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new Am(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:cl(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:cl(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 fi(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 fi(t,s),{caption:r});return String(o.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new fi(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 Im,GatewayIntentBits as mo,Events as gi}from"discord.js";var po,dl=b(()=>{"use strict";ze();po=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 Im({intents:[mo.Guilds,mo.GuildMessages,mo.MessageContent,mo.DirectMessages]}),this.client.on(gi.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(gi.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(gi.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 ho,ul=b(()=>{"use strict";ze();ho=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 fo,ml=b(()=>{"use strict";ze();fo=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 go,pl=b(()=>{"use strict";ze();go=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 yi from"node:readline";var yo,hl=b(()=>{"use strict";ze();yo=class extends ie{static{u(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=yi.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
|
|
794
794
|
Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leave.
|
|
795
795
|
`),this.rl.on("line",e=>{let t=e.trim();if(!t){this.prompt();return}if(t==="/quit"||t==="/exit"){console.log(`
|
|
796
796
|
Goodbye!
|
|
797
797
|
`),this.emit("disconnected");return}this.messageCounter++;let s={id:`cli-${this.messageCounter}`,platform:"cli",chatId:"cli-chat",chatType:"dm",userId:"cli-user",userName:"cli-user",displayName:"You",text:t,timestamp:new Date};this.emit("message",s)}),this.rl.on("close",()=>{this.emit("disconnected")}),this.status="connected",this.emit("connected"),this.prompt()}async disconnect(){this.rl?.close(),this.rl=void 0,this.status="disconnected"}async sendMessage(e,t,s){let r=`cli-resp-${++this.messageCounter}`;return process.stdout.write(`
|
|
798
798
|
Alfred: ${t}
|
|
799
|
-
`),this.prompt(),r}async editMessage(e,t,s,r){yi.clearLine(process.stdout,0),yi.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import
|
|
799
|
+
`),this.prompt(),r}async editMessage(e,t,s,r){yi.clearLine(process.stdout,0),yi.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import xm from"node:http";import Rm from"node:crypto";var wo,fl=b(()=>{"use strict";ze();wo=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=xm.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-${Rm.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}
|
|
800
800
|
data: ${JSON.stringify(s)}
|
|
801
801
|
|
|
802
|
-
`)}}});var Ye={};oe(Ye,{CLIAdapter:()=>go,DiscordAdapter:()=>mo,HttpAdapter:()=>yo,MatrixAdapter:()=>po,MessagingAdapter:()=>ie,SignalAdapter:()=>fo,TelegramAdapter:()=>lo,WhatsAppAdapter:()=>ho});var Je=b(()=>{"use strict";ze();cl();ll();dl();ul();ml();pl();hl()});import wo from"node:fs";import To from"node:path";import Rm from"js-yaml";var _t,fl=b(()=>{"use strict";nn();ln();Be();_n();Pr();X();ei();ti();si();ri();oi();ni();ii();ai();ci();li();pi();hi();_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=bs("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new at(this.config.storage.path);let e=this.database.getDb(),t=new Es(e),s=new $s(e);this.userRepo=s;let r=new ct(e),o=new vs(e),n=new ks(e),i=new Ss(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=Tn(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,x;$&&(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}),x=new yr(o,this.logger.child({component:"memory-retriever"}),T),this.logger.info("Active learning & memory retriever initialized"));let U=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 Y=new Ls(e);if(L.register(new Jt(Y)),L.register(new Dt),L.register(new Mt),L.register(new Ot(o,T)),L.register(new Pt(h,L,U,y)),this.config.email?.accounts?.length){let C=new Map;for(let F of this.config.email.accounts)try{F.provider==="microsoft"&&!F.microsoft?.clientId&&this.config.calendar?.microsoft&&(F.microsoft={...this.config.calendar.microsoft});let fe=await zs(F);C.set(F.name,fe),this.logger.info({account:F.name,provider:F.provider??"imap-smtp"},"Email account initialized")}catch(fe){this.logger.warn({err:fe,account:F.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,F)=>t.findByPlatformAndUser(C,F))),L.register(new Vt(d)),L.register(new Kt(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 Ks(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(()=>(X(),Z));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let F of this.mcpManager.getSkills())L.register(F);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},h)),this.logger.info({agents:this.config.codeAgents.agents.map(F=>F.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z));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:F}=await Promise.resolve().then(()=>(X(),Z)),fe=await F(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(()=>(X(),Z));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(X(),Z));L.register(new C(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant){let{MonitorSkill:C}=await Promise.resolve().then(()=>(X(),Z));L.register(new C({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant})),this.logger.info("Infrastructure monitor 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=To.resolve(To.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:U,securityManager:y,memoryRepo:o,speechTranscriber:V,inboxPath:he,embeddingService:T,activeLearning:A,memoryRetriever:x,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100}),this.reminderScheduler=new ar(n,async(C,F,fe)=>{let Ue=this.adapters.get(C);Ue?await Ue.sendMessage(F,fe):this.logger.warn({platform:C,chatId:F},"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,F)=>t.findByPlatformAndUser(C,F),"findConversation")}),this.backgroundTaskRunner=new pr(L,U,d,this.adapters,s,this.logger.child({component:"background-tasks"})),this.proactiveScheduler=new hr(m,L,U,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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye)),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(()=>(Je(),Ye)),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{rn();let t=new re().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z)),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(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(X(),Z));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}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=To.resolve(this.config.security.rulesPath),t=[];if(!wo.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!wo.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=wo.readdirSync(e).filter(o=>o.endsWith(".yml")||o.endsWith(".yaml"));for(let o of r)try{let n=To.join(e,o),i=wo.readFileSync(n,"utf-8"),a=Rm.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 gl=b(()=>{"use strict"});var wi=b(()=>{"use strict";fl();ti();ei();si();ri();oi();ni();ii();ci();li();nr();ai();pi();hi();mi();gl();ui()});import _o from"node:fs";import yl from"node:path";import Cm from"node:os";function wl(){try{let c=_o.readFileSync(Ti,"utf-8"),e=JSON.parse(c);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Tl(c){try{let e=yl.dirname(Ti);_o.existsSync(e)||_o.mkdirSync(e,{recursive:!0}),_o.writeFileSync(Ti,JSON.stringify(c,null,2),"utf-8")}catch{}}async function bt(c,e){let t=new AbortController,s=setTimeout(()=>t.abort(),Nm);try{return await fetch(c,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function _l(c,e,t){switch(c){case"anthropic":{let s=await bt("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 bt(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 bt(s);return r.ok?((await r.json()).models??[]).map(n=>({id:n.name.replace(/^models\//,""),name:n.displayName})):[]}case"mistral":{let s=await bt("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 bt("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 bt(`${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 bt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(n=>({id:n.id})):[]}default:return[]}}async function _i(c,e,t){let s=wl(),r=s.providers[c];if(r&&Date.now()-r.fetchedAt<Lm)return r.models;try{let o=await _l(c,e,t);if(o.length>0)return s.providers[c]={fetchedAt:Date.now(),models:o},Tl(s),o}catch{}return r?r.models:[]}function bo(c,e,t){_l(c,e,t).then(s=>{if(s.length>0){let r=wl();r.providers[c]={fetchedAt:Date.now(),models:s},Tl(r)}}).catch(()=>{})}function bi(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 Lm,Nm,Ti,Ei=b(()=>{"use strict";Lm=24*60*60*1e3,Nm=5e3,Ti=yl.join(Cm.homedir(),".alfred","model-cache.json");u(wl,"readCache");u(Tl,"writeCache");u(bt,"fetchWithTimeout");u(_l,"fetchModelsFromAPI");u(_i,"getModels");u(bo,"refreshCacheInBackground");u(bi,"mergeModels")});var bl={};oe(bl,{startCommand:()=>Dm});async function Dm(){let c=new re,e;try{e=c.loadConfig()}catch(n){console.error("Failed to load configuration:",n.message),process.exit(1)}let t=bs("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?bo(n.default.provider,n.default.apiKey,n.default.baseUrl):n?.provider&&bo(n.provider,void 0,n.baseUrl);for(let i of["strong","fast"]){let a=n?.[i];a?.provider&&bo(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 El=b(()=>{"use strict";Be();nn();wi();Ei();u(Dm,"startCommand")});var vl={};oe(vl,{chatCommand:()=>Pm});import $l from"node:http";import wr from"node:readline";function Mm(c,e){return new Promise(t=>{let s=$l.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 Om(c,e){let t=wr.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
|
|
802
|
+
`)}}});var Ye={};oe(Ye,{CLIAdapter:()=>yo,DiscordAdapter:()=>po,HttpAdapter:()=>wo,MatrixAdapter:()=>ho,MessagingAdapter:()=>ie,SignalAdapter:()=>go,TelegramAdapter:()=>uo,WhatsAppAdapter:()=>fo});var Je=b(()=>{"use strict";ze();ll();dl();ul();ml();pl();hl();fl()});import To from"node:fs";import _o from"node:path";import Cm from"js-yaml";var _t,gl=b(()=>{"use strict";an();dn();Be();bn();Ur();X();ei();ti();si();ri();oi();ni();ii();ai();ci();li();pi();hi();_t=class{static{u(this,"Alfred")}config;logger;database;pipeline;reminderScheduler;backgroundTaskRunner;proactiveScheduler;adapters=new Map;formatter=new ur;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 at(this.config.storage.path);let e=this.database.getDb(),t=new $s(e),s=new vs(e);this.userRepo=s;let r=new ct(e),o=new ks(e),n=new Ss(e),i=new As(e),a=new Is(e),l=new xs(e),d=new Rs(e),m=new Cs(e);this.logger.info("Storage initialized");let p=new qs,w=this.loadSecurityRules();p.loadRules(w);let y=new zs(p,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:w.length},"Security engine initialized");let h=_n(this.config.llm,this.logger.child({component:"llm"}));await h.initialize();let T=new mr(h,a,this.logger.child({component:"embeddings"})),$=this.config.activeLearning?.enabled!==!1,A,x;$&&(A=new yr({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}),x=new wr(o,this.logger.child({component:"memory-retriever"}),T),this.logger.info("Active learning & memory retriever initialized"));let U=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 Y=new Ns(e);if(L.register(new Zt(Y)),L.register(new Dt),L.register(new Mt),L.register(new Ot(o,T)),L.register(new Pt(h,L,U,y)),this.config.email?.accounts?.length){let C=new Map;for(let F of this.config.email.accounts)try{F.provider==="microsoft"&&!F.microsoft?.clientId&&this.config.calendar?.microsoft&&(F.microsoft={...this.config.calendar.microsoft});let fe=await Ws(F);C.set(F.name,fe),this.logger.info({account:F.name,provider:F.provider??"imap-smtp"},"Email account initialized")}catch(fe){this.logger.warn({err:fe,account:F.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 es;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,F)=>t.findByPlatformAndUser(C,F))),L.register(new Vt(d)),L.register(new Kt(m));let ve=new Ls(e),Pe=new pr(ve,T,this.logger.child({component:"documents"}));L.register(new Yt(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(()=>(X(),Z));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let F of this.mcpManager.getSkills())L.register(F);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},h)),this.logger.info({agents:this.config.codeAgents.agents.map(F=>F.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z));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:F}=await Promise.resolve().then(()=>(X(),Z)),fe=await F(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(()=>(X(),Z));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(X(),Z));L.register(new C(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant){let{MonitorSkill:C}=await Promise.resolve().then(()=>(X(),Z));L.register(new C({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant})),this.logger.info("Infrastructure monitor skill enabled")}this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let V;if(this.config.speech?.apiKey&&(V=new lr(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let C=new dr(this.config.speech,this.logger.child({component:"tts"}));L.register(new Jt(C)),this.logger.info("Text-to-speech skill registered")}let pe=new nr(t),he=_o.resolve(_o.dirname(this.config.storage.path),"inbox");this.pipeline=new ar({llm:h,conversationManager:pe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:U,securityManager:y,memoryRepo:o,speechTranscriber:V,inboxPath:he,embeddingService:T,activeLearning:A,memoryRetriever:x,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100}),this.reminderScheduler=new cr(n,async(C,F,fe)=>{let Ue=this.adapters.get(C);Ue?await Ue.sendMessage(F,fe):this.logger.warn({platform:C,chatId:F},"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,F)=>t.findByPlatformAndUser(C,F),"findConversation")}),this.backgroundTaskRunner=new hr(L,U,d,this.adapters,s,this.logger.child({component:"background-tasks"})),this.proactiveScheduler=new fr(m,L,U,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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye));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(()=>(Je(),Ye)),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(()=>(Je(),Ye)),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{on();let t=new re().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z)),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(()=>(X(),Z));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(()=>(X(),Z));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(()=>(X(),Z));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(X(),Z));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}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=_o.resolve(this.config.security.rulesPath),t=[];if(!To.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!To.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=To.readdirSync(e).filter(o=>o.endsWith(".yml")||o.endsWith(".yaml"));for(let o of r)try{let n=_o.join(e,o),i=To.readFileSync(n,"utf-8"),a=Cm.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 yl=b(()=>{"use strict"});var wi=b(()=>{"use strict";gl();ti();ei();si();ri();oi();ni();ii();ci();li();ir();ai();pi();hi();mi();yl();ui()});import bo from"node:fs";import wl from"node:path";import Lm from"node:os";function Tl(){try{let c=bo.readFileSync(Ti,"utf-8"),e=JSON.parse(c);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function _l(c){try{let e=wl.dirname(Ti);bo.existsSync(e)||bo.mkdirSync(e,{recursive:!0}),bo.writeFileSync(Ti,JSON.stringify(c,null,2),"utf-8")}catch{}}async function bt(c,e){let t=new AbortController,s=setTimeout(()=>t.abort(),Dm);try{return await fetch(c,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function bl(c,e,t){switch(c){case"anthropic":{let s=await bt("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 bt(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 bt(s);return r.ok?((await r.json()).models??[]).map(n=>({id:n.name.replace(/^models\//,""),name:n.displayName})):[]}case"mistral":{let s=await bt("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 bt("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 bt(`${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 bt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(n=>({id:n.id})):[]}default:return[]}}async function _i(c,e,t){let s=Tl(),r=s.providers[c];if(r&&Date.now()-r.fetchedAt<Nm)return r.models;try{let o=await bl(c,e,t);if(o.length>0)return s.providers[c]={fetchedAt:Date.now(),models:o},_l(s),o}catch{}return r?r.models:[]}function Eo(c,e,t){bl(c,e,t).then(s=>{if(s.length>0){let r=Tl();r.providers[c]={fetchedAt:Date.now(),models:s},_l(r)}}).catch(()=>{})}function bi(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 Nm,Dm,Ti,Ei=b(()=>{"use strict";Nm=24*60*60*1e3,Dm=5e3,Ti=wl.join(Lm.homedir(),".alfred","model-cache.json");u(Tl,"readCache");u(_l,"writeCache");u(bt,"fetchWithTimeout");u(bl,"fetchModelsFromAPI");u(_i,"getModels");u(Eo,"refreshCacheInBackground");u(bi,"mergeModels")});var El={};oe(El,{startCommand:()=>Mm});async function Mm(){let c=new re,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?Eo(n.default.provider,n.default.apiKey,n.default.baseUrl):n?.provider&&Eo(n.provider,void 0,n.baseUrl);for(let i of["strong","fast"]){let a=n?.[i];a?.provider&&Eo(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 $l=b(()=>{"use strict";Be();an();wi();Ei();u(Mm,"startCommand")});var kl={};oe(kl,{chatCommand:()=>Um});import vl from"node:http";import Tr from"node:readline";function Om(c,e){return new Promise(t=>{let s=vl.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 Pm(c,e){let t=Tr.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
|
|
803
803
|
Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
|
|
804
804
|
`),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
|
|
805
805
|
Goodbye!
|
|
806
|
-
`),t.close(),process.exit(0));let o=JSON.stringify({text:r,chatId:"api-chat",userId:"api-user"}),n
|
|
806
|
+
`),t.close(),process.exit(0));let o=JSON.stringify({text:r,chatId:"api-chat",userId:"api-user"}),n=vl.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(`
|
|
807
807
|
|
|
808
808
|
`);a=d.pop()??"";for(let m of d){let p=m.split(`
|
|
809
|
-
`).find(w=>w.startsWith("data: "));if(p)try{let w=JSON.parse(p.slice(6));switch(w.type){case"status":
|
|
809
|
+
`).find(w=>w.startsWith("data: "));if(p)try{let w=JSON.parse(p.slice(6));switch(w.type){case"status":Tr.clearLine(process.stdout,0),Tr.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${w.text??""}`);break;case"response":Tr.clearLine(process.stdout,0),Tr.cursorTo(process.stdout,0),process.stdout.write(`
|
|
810
810
|
Alfred: ${w.text??""}
|
|
811
811
|
`);break;case"attachment":{let y=w.fileName??w.attachmentType??"file";process.stdout.write(`[Attachment: ${y}]
|
|
812
812
|
`);break}case"done":t.prompt();break;case"error":process.stdout.write(`
|
|
@@ -814,41 +814,41 @@ Error: ${w.text??"Unknown error"}
|
|
|
814
814
|
`),t.prompt();break}}catch{}}}),i.on("end",()=>{if(a.length>0){let l=a.split(`
|
|
815
815
|
`).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(`
|
|
816
816
|
Connection error: ${l.message}`),t.prompt()})});n.on("error",i=>{console.error(`
|
|
817
|
-
Failed to send message: ${i.message}`),t.prompt()}),n.write(o),n.end()}),t.on("close",()=>{process.exit(0)})}async function
|
|
818
|
-
`);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=$i.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
|
|
817
|
+
Failed to send message: ${i.message}`),t.prompt()}),n.write(o),n.end()}),t.on("close",()=>{process.exit(0)})}async function Um(c){let e=new re,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 Om(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),Pm(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 Sl=b(()=>{"use strict";Be();wi();u(Om,"checkHealth");u(Pm,"startClientMode");u(Um,"chatCommand")});var xl={};oe(xl,{setupCommand:()=>Xm});import{createInterface as Fm}from"node:readline/promises";import{stdin as jm,stdout as Bm}from"node:process";import{execFileSync as Hm}from"node:child_process";import de from"node:fs";import qm from"node:os";import we from"node:path";import $i from"js-yaml";function D(c){return`${$o}${c}${k}`}function Vm(c){return`${M}${c}${k}`}function le(c){return`${vo}${c}${k}`}function Il(c){return`${zm}${c}${k}`}function R(c){return`${q}${c}${k}`}function _(c){return`${Ze}${c}${k}`}function me(c){return c.length<=4?"****":"*".repeat(c.length-4)+c.slice(-4)}function Km(c){let e=process.platform==="win32",t=e?"where":"which";try{let o=Hm(t,[c],{stdio:"pipe"}).toString().trim();if(o)return o.split(/\r?\n/)[0]}catch{}let s=qm.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 Gm(c){let e={},t={},s=!1,r=!1,o=30,n=we.join(c,"config","default.yml");if(de.existsSync(n))try{let p=$i.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(`
|
|
818
|
+
`);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=$i.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 Xm(){let c=Fm({input:jm,output:Bm}),e=process.cwd(),t=Gm(e),s=Object.keys(t.config).length>0;try{Ym(),console.log(s?`${vo}Existing configuration found \u2014 press Enter to keep current values.${k}
|
|
819
819
|
${Ze}Only change what you need to update.${k}
|
|
820
|
-
`:`${
|
|
820
|
+
`:`${vo}Welcome to the Alfred setup wizard!${k}
|
|
821
821
|
${Ze}This will walk you through configuring your AI assistant.${k}
|
|
822
822
|
${Ze}Press Enter to accept defaults shown in [brackets].${k}
|
|
823
823
|
`);let r=await O(c,"What should your bot be called?",t.config.name??"Alfred"),o=t.config.llm?.provider?We.findIndex(g=>g.name===t.config.llm?.provider):-1,n=o>=0?o+1:1;console.log(`
|
|
824
|
-
${R("Which LLM provider would you like to use?")}`);for(let g=0;g<We.length;g++){let E=g===o?` ${_("(current)")}`:"";console.log(` ${le(String(g+1)+")")} ${We[g].label}${E}`)}let i=await
|
|
824
|
+
${R("Which LLM provider would you like to use?")}`);for(let g=0;g<We.length;g++){let E=g===o?` ${_("(current)")}`:"";console.log(` ${le(String(g+1)+")")} ${We[g].label}${E}`)}let i=await _r(c,"> ",1,We.length,n),a=We[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 E=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if(E){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",E.replace(/\/+$/,"")),m=m.replace(/\/+$/,""),console.log(` ${D(">")} URL: ${_(m)}`)}}let w=t.config.llm?.model??a.defaultModel;console.log("");let y,h=await _i(a.name,l,m),T=bi(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 g=await O(c,"Choose model","1"),E=parseInt(g,10)-1;E>=0&&E<T.length?y=T[E].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(`
|
|
825
825
|
${R("Configure additional model tiers for specialized tasks?")}`),console.log(`${_("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let x=(await c.question(`${M}> ${k}${_(`[${A}] `)}`)).trim().toLowerCase(),U=x===""?$:x==="y"||x==="yes",L={};if(U){let g=[{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 E of g){let v=t.multiModelTiers[E.key],B=!!v?.model;console.log(`
|
|
826
|
-
${R(`${E.label} model`)} ${_(`(${E.hint})`)}`),B&&console.log(` ${_(`Current: ${v.provider}/${v.model}`)}`);let N=v?.provider??a.name,j=We.map(be=>be.name).join(", ");console.log(` ${_(`Providers: ${j}`)}`);let ge=(await c.question(` ${M}Provider: ${k}${_(`[${N}] `)}`)).trim()||N;if(!ge&&!B){console.log(` ${_("Skipped.")}`);continue}let z=ge,ye,Ae;if(z!==a.name){let be=v?.apiKey??t.env[`ALFRED_LLM_${E.key.toUpperCase()}_API_KEY`]??"";if(be?ye=await O(c,` API key for ${z}`,be):(We.find(je=>je.name===z)?.needsApiKey??!0)&&(ye=await $e(c,` API key for ${z}`)),["ollama","openwebui"].includes(z)){let je=(v?.baseUrl??"")||We.find(
|
|
826
|
+
${R(`${E.label} model`)} ${_(`(${E.hint})`)}`),B&&console.log(` ${_(`Current: ${v.provider}/${v.model}`)}`);let N=v?.provider??a.name,j=We.map(be=>be.name).join(", ");console.log(` ${_(`Providers: ${j}`)}`);let ge=(await c.question(` ${M}Provider: ${k}${_(`[${N}] `)}`)).trim()||N;if(!ge&&!B){console.log(` ${_("Skipped.")}`);continue}let z=ge,ye,Ae;if(z!==a.name){let be=v?.apiKey??t.env[`ALFRED_LLM_${E.key.toUpperCase()}_API_KEY`]??"";if(be?ye=await O(c,` API key for ${z}`,be):(We.find(je=>je.name===z)?.needsApiKey??!0)&&(ye=await $e(c,` API key for ${z}`)),["ollama","openwebui"].includes(z)){let je=(v?.baseUrl??"")||We.find(Mr=>Mr.name===z)?.baseUrl||"";je&&(Ae=await O(c,` ${z} URL`,je))}}let nt=ye??(z===a.name?l:void 0),bs=Ae??(z===a.name?m:void 0),Zo=We.find(be=>be.name===z),Qo=await _i(z,nt,bs),Ke=bi(Qo,Zo?.models??[]),Fe;if(Ke.length>0){console.log(` ${R("Available models:")}`);for(let vt=0;vt<Ke.length;vt++){let je=Ke[vt],Mr=je.desc??je.name??"",gd=je.id===v?.model?` ${D("(current)")}`:"";console.log(` ${le(`${vt+1})`)} ${je.id}${Mr?` ${_(`\u2014 ${Mr}`)}`:""}${gd}`)}console.log(` ${le(`${Ke.length+1})`)} ${_("Other (enter manually)")}`),console.log(` ${le("0)")} ${_("Skip this tier")}`);let be=(await c.question(` ${M}> ${k}${B?_(`[${v.model}] `):""}`)).trim();if(be==="0"){console.log(` ${_("Skipped.")}`);continue}let Dr=parseInt(be,10)-1;Dr>=0&&Dr<Ke.length?Fe=Ke[Dr].id:!be&&B?Fe=v.model:Fe=await O(c," Model ID",B?v.model:E.defaultModel)}else if(console.log(` ${_("Press Enter to skip.")}`),Fe=(await c.question(` ${M}Model: ${k}${B?_(`[${v.model}] `):""}`)).trim()||(B?v.model:""),!Fe){console.log(` ${_("Skipped.")}`);continue}L[E.key]={provider:z,model:Fe,...ye?{apiKey:ye}:{},...Ae?{baseUrl:Ae}:{}},console.log(` ${D(">")} ${E.label}: ${R(z)}/${R(Fe)}`)}Object.keys(L).length===0&&console.log(`
|
|
827
827
|
${_("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${_("Using single model for all tasks.")}`);let Y=["brave","tavily","duckduckgo","searxng"],Oe=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",ve=Y.indexOf(Oe),Pe=ve>=0?ve+1:0;console.log(`
|
|
828
|
-
${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(g=>ve===g?` ${_("(current)")}`:"","mark");console.log(` ${le("0)")} None (disable web search)${ve===-1&&Oe===""?` ${_("(current)")}`:""}`);for(let g=0;g<ae.length;g++)console.log(` ${le(String(g+1)+")")} ${ae[g]}${V(g)}`);let pe=await
|
|
829
|
-
${R("Which messaging platforms do you want to enable?")}`),console.log(`${_("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let g=0;g<
|
|
830
|
-
${
|
|
831
|
-
${R(g.label+" configuration:")}`);let E={};for(let v of g.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(k)),E[v.configField]=N,J[v.envKey]=N,v.configField==="token"||v.configField==="accessToken"?console.log(` ${D(">")} Set: ${_(me(N))}`):console.log(` ${D(">")} Set: ${_(N)}`)}H[g.configKey]=E}let se=t.config.email?.accounts??[],Q=se[0],Et=Q?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",Te=Q?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",
|
|
832
|
-
${R("Email access (read & send emails)?")}`),console.log(`${_("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let
|
|
833
|
-
${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=se.find(K=>K.name===N);Ne.push(await Ai(N,j))}else E=!1}}else console.log(` ${_("Email disabled \u2014 you can configure it later.")}`);let
|
|
834
|
-
${R("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${_("Transcribes voice messages from Telegram, Discord, etc.")}`);let Ii=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${le("0)")} None (disable voice transcription)${
|
|
835
|
-
${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}> ${k}${_(`[${E}] `)}`)).trim().toLowerCase();if(
|
|
836
|
-
${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
|
|
837
|
-
${R("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${_("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let
|
|
838
|
-
${R("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${_("Scanning for known coding agents on this system...")}`);let
|
|
839
|
-
${_("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let g=[...
|
|
840
|
-
${R("Which agents should Alfred use?")} ${_("(comma-separated, e.g. 1,2)")}`);let E=new Set((t.config.codeAgents?.agents??[]).map(N=>N.name));for(let N=0;N<g.length;N++){let j=g[N],K=E.has(j.name)?` ${_("(current)")}`:"";console.log(` ${M}${N+1}${k}) ${j.label}${K}`)}console.log(` ${M}0${k}) None`);let v=g.map((N,j)=>E.size>0?E.has(N.name)?String(j+1):null:N.detected?String(j+1):null).filter(Boolean).join(",")||"0",B=(await c.question(` ${M}> ${k}${_(`[${v}] `)}`)).trim()||v;B!=="0"&&(Qe=B.split(",").map(j=>parseInt(j.trim(),10)).filter(j=>!isNaN(j)&&j>=1&&j<=g.length).map(j=>{let K=g[j-1];return{name:K.name,command:K.command,argsTemplate:K.argsTemplate,promptVia:K.promptVia}})),Qe.length>0?console.log(` ${D(">")} ${R(String(Qe.length))} agent(s) selected: ${Qe.map(N=>N.name).join(", ")}`):console.log(` ${_("No agents selected.")}`)}let
|
|
841
|
-
${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 xi=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let g of xi){let E=g.name===
|
|
842
|
-
${R("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${_("Control VMs, containers, network devices, and smart home through Alfred.")}`);let
|
|
843
|
-
${q}Enable UniFi Network?${k} ${_(`[${
|
|
844
|
-
${q}Enable Home Assistant?${k} ${_(`[${
|
|
845
|
-
${q}Enable Contacts management?${k} ${_(`[${
|
|
846
|
-
${q}Enable Docker management?${k} ${_(`[${
|
|
847
|
-
${q}Enable BMW CarData (vehicle status, charging)?${k} ${_(`[${
|
|
848
|
-
${q}Enable route planning with live traffic (Google Routes)?${k} ${_(`[${
|
|
849
|
-
${R("Security configuration:")}`);let Fi=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",_e;if(Fi)_e=await O(c,"Owner user ID (for elevated permissions)",Fi);else{let g=(await c.question(`${q}Owner user ID${k} ${_("(optional, for elevated permissions)")}: ${M}`)).trim();process.stdout.write(k),_e=g}let
|
|
850
|
-
${R("Writing configuration files...")}`);let S=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(l){let g=a.envKeyName||"ALFRED_OLLAMA_API_KEY";S.push(`${g}=${l}`)}if(y!==a.defaultModel&&S.push(`ALFRED_LLM_MODEL=${y}`),m&&S.push(`ALFRED_LLM_BASE_URL=${m}`),Object.keys(L).length>0){S.push("","# === Additional Model Tiers ===");for(let[g,E]of Object.entries(L)){let v=`ALFRED_LLM_${g.toUpperCase()}`;S.push(""),S.push(`${v}_PROVIDER=${E.provider}`),S.push(`${v}_MODEL=${E.model}`),E.apiKey&&S.push(`${v}_API_KEY=${E.apiKey}`),E.baseUrl&&S.push(`${v}_BASE_URL=${E.baseUrl}`)}}S.push("","# === Messaging Platforms ===","");for(let[g,E]of Object.entries(J))S.push(`${g}=${E}`);if(S.push("","# === Web Search ===",""),he?(S.push(`ALFRED_SEARCH_PROVIDER=${he}`),C&&S.push(`ALFRED_SEARCH_API_KEY=${C}`),F&&S.push(`ALFRED_SEARCH_BASE_URL=${F}`)):(S.push("# ALFRED_SEARCH_PROVIDER=brave"),S.push("# ALFRED_SEARCH_API_KEY=")),S.push("","# === Email ===",""),
|
|
851
|
-
`),"utf-8"),console.log(` ${D("+")} ${_(".env")} written`);let
|
|
828
|
+
${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(g=>ve===g?` ${_("(current)")}`:"","mark");console.log(` ${le("0)")} None (disable web search)${ve===-1&&Oe===""?` ${_("(current)")}`:""}`);for(let g=0;g<ae.length;g++)console.log(` ${le(String(g+1)+")")} ${ae[g]}${V(g)}`);let pe=await _r(c,"> ",0,Y.length,Pe),he,C="",F="";if(pe>=1&&pe<=Y.length&&(he=Y[pe-1]),he==="brave"){let g=t.env.ALFRED_SEARCH_API_KEY??"";g?C=await O(c," Brave Search API key",g):(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 g=t.env.ALFRED_SEARCH_API_KEY??"";g?C=await O(c," Tavily API key",g):(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 g=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";F=await O(c," SearXNG URL",g),F=F.replace(/\/+$/,""),console.log(` ${D(">")} SearXNG: ${_(F)}`)}else console.log(` ${_("Web search disabled \u2014 you can configure it later.")}`);let fe=[];for(let g=0;g<os.length;g++){let E=os[g];t.config[E.configKey]?.enabled&&fe.push(g+1)}let Ue=fe.length>0?fe.join(","):"";console.log(`
|
|
829
|
+
${R("Which messaging platforms do you want to enable?")}`),console.log(`${_("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let g=0;g<os.length;g++){let E=fe.includes(g+1)?` ${_("(enabled)")}`:"";console.log(` ${le(String(g+1)+")")} ${os[g].label}${E}`)}console.log(` ${le("0)")} None (configure later)`);let ns=(await c.question(`${M}> ${k}${Ue?_(`[${Ue}] `):""}`)).trim(),te=[],is=ns||Ue;if(is&&is!=="0"){let g=is.split(",").map(E=>parseInt(E.trim(),10));for(let E of g)if(E>=1&&E<=os.length){let v=os[E-1];te.includes(v)||te.push(v)}}te.length>0?console.log(` ${D(">")} Enabling: ${te.map(g=>R(g.label)).join(", ")}`):console.log(` ${_("No platforms selected \u2014 you can configure them later.")}`);let H={},J={};for(let g of te){if(g.credentials.length===0){g.name==="whatsapp"&&console.log(`
|
|
830
|
+
${Vm("i")} WhatsApp: a QR code will be displayed on first start.`);continue}console.log(`
|
|
831
|
+
${R(g.label+" configuration:")}`);let E={};for(let v of g.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(k)),E[v.configField]=N,J[v.envKey]=N,v.configField==="token"||v.configField==="accessToken"?console.log(` ${D(">")} Set: ${_(me(N))}`):console.log(` ${D(">")} Set: ${_(N)}`)}H[g.configKey]=E}let se=t.config.email?.accounts??[],Q=se[0],Et=Q?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",Te=Q?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",So=se.length>0||!!Et||Te==="microsoft",Vl=So?"Y/n":"y/N";console.log(`
|
|
832
|
+
${R("Email access (read & send emails)?")}`),console.log(`${_("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let Ao=(await c.question(`${M}> ${k}${_(`[${Vl}] `)}`)).trim().toLowerCase(),Er=Ao===""?So:Ao==="y"||Ao==="yes",Ne=[],Kl={"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"}},Ai=u(async(g,E)=>{let v={name:g,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},B=E?.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 K=(await c.question(`${M}> ${k}${_(`[${j+1}] `)}`)).trim(),ge=K===""?j:parseInt(K,10)-1;if(v.provider=ge===1?"microsoft":"imap-smtp",v.provider==="microsoft"){let z=t.config.calendar?.microsoft,ye=E?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Ae=E?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",nt=E?.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 bs=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";v.msClientSecret=await O(c," Client Secret",bs),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",nt),v.msRefreshToken||(v.msRefreshToken=await $e(c," Refresh Token"))}console.log(` ${D(">")} Email [${g}]: Microsoft 365 (Graph API)`)}else{let z=E?.auth?.user??"";console.log(""),v.user=await O(c," Email address",z||""),v.user||(v.user=await $e(c," Email address"));let ye=E?.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()??"",nt=Kl[Ae],bs=E?.imap?.host??nt?.imap??`imap.${Ae}`,Zo=E?.smtp?.host??nt?.smtp??`smtp.${Ae}`,Qo=E?.imap?.port??993,Ke=E?.smtp?.port??587;nt&&console.log(` ${D(">")} Detected ${Ae} \u2014 using preset server settings`),v.imapHost=await O(c," IMAP server",bs);let Fe=await O(c," IMAP port",String(Qo));v.imapPort=parseInt(Fe,10)||993,v.smtpHost=await O(c," SMTP server",Zo);let be=await O(c," SMTP port",String(Ke));v.smtpPort=parseInt(be,10)||587,console.log(` ${D(">")} Email [${g}]: ${_(v.user)} via ${_(v.imapHost)}`)}return v},"configureEmailAccount");if(Er){let g=Q??(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 Ai("default",g));let E=!0;for(;E;){let v=(await c.question(`
|
|
833
|
+
${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=se.find(K=>K.name===N);Ne.push(await Ai(N,j))}else E=!1}}else console.log(` ${_("Email disabled \u2014 you can configure it later.")}`);let $r=["openai","groq"],Gl=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",vr=$r.indexOf(Gl),Xl=vr>=0?vr+1:0;console.log(`
|
|
834
|
+
${R("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${_("Transcribes voice messages from Telegram, Discord, etc.")}`);let Ii=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${le("0)")} None (disable voice transcription)${vr===-1?` ${_("(current)")}`:""}`);for(let g=0;g<Ii.length;g++){let E=vr===g?` ${_("(current)")}`:"";console.log(` ${le(String(g+1)+")")} ${Ii[g]}${E}`)}let Io=await _r(c,"> ",0,$r.length,Xl),De,Ve="",as="";if(Io>=1&&Io<=$r.length&&(De=$r[Io-1]),De==="openai"){let g=t.env.ALFRED_SPEECH_API_KEY??"";g?Ve=await O(c," OpenAI API key (for Whisper)",g):(console.log(` ${_("Uses your OpenAI API key for Whisper transcription.")}`),Ve=await $e(c," OpenAI API key")),console.log(` ${D(">")} OpenAI Whisper: ${_(me(Ve))}`)}else if(De==="groq"){let g=t.env.ALFRED_SPEECH_API_KEY??"";g?Ve=await O(c," Groq API key",g):(console.log(` ${_("Get your free API key at: https://console.groq.com/")}`),Ve=await $e(c," Groq API key"));let E=t.env.ALFRED_SPEECH_BASE_URL??"";E&&(as=await O(c," Groq API URL",E)),console.log(` ${D(">")} Groq Whisper: ${_(me(Ve))}`)}else console.log(` ${_("Voice transcription disabled \u2014 you can configure it later.")}`);let cs=!1,ls="alloy";if(De){let g=t.config.speech?.ttsEnabled??!1,E=g?"Y/n":"y/N";console.log(`
|
|
835
|
+
${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}> ${k}${_(`[${E}] `)}`)).trim().toLowerCase();if(cs=v===""?g:v==="y"||v==="yes",cs){let B=["alloy","echo","fable","onyx","nova","shimmer"],N=t.config.speech?.ttsVoice??"alloy",j=B.indexOf(N),K=j>=0?j+1:1;console.log(`
|
|
836
|
+
${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 _r(c," > ",1,B.length,K);ls=B[ge-1],console.log(` ${D(">")} TTS voice: ${R(ls)}`)}else console.log(` ${_("Voice responses disabled.")}`)}let Yl=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
|
|
837
|
+
${R("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${_("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let xo=(await c.question(`${M}> ${k}${_(`[${Yl}] `)}`)).trim().toLowerCase(),Ro=xo===""?t.codeSandboxEnabled:xo==="y"||xo==="yes";console.log(Ro?` ${D(">")} Code Sandbox ${R("enabled")} (JavaScript + Python)`:` ${_("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
|
|
838
|
+
${R("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${_("Scanning for known coding agents on this system...")}`);let Co=[];for(let g of Al){let E=Km(g.whichCmd);E?(Co.push({...g,resolvedPath:E}),console.log(` ${D("\u2713")} ${R(g.label)} ${_(`(${E})`)}`)):console.log(` ${_("\xB7")} ${_(g.label)} ${_("\u2014 not found")}`)}let Lo=(t.config.codeAgents?.agents??[]).filter(g=>!Al.some(E=>E.name===g.name));for(let g of Lo)console.log(` ${D("\u2713")} ${R(g.name)} ${_(`(${g.command}) \u2014 from existing config`)}`);let Qe=[];if(Co.length===0&&Lo.length===0)console.log(`
|
|
839
|
+
${_("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let g=[...Co.map(N=>({name:N.name,command:N.resolvedPath??N.command,argsTemplate:N.argsTemplate,promptVia:N.promptVia,label:N.label,detected:!0})),...Lo.map(N=>({name:N.name,command:N.command,argsTemplate:N.argsTemplate,promptVia:N.promptVia??"arg",label:N.name,detected:!1}))];console.log(`
|
|
840
|
+
${R("Which agents should Alfred use?")} ${_("(comma-separated, e.g. 1,2)")}`);let E=new Set((t.config.codeAgents?.agents??[]).map(N=>N.name));for(let N=0;N<g.length;N++){let j=g[N],K=E.has(j.name)?` ${_("(current)")}`:"";console.log(` ${M}${N+1}${k}) ${j.label}${K}`)}console.log(` ${M}0${k}) None`);let v=g.map((N,j)=>E.size>0?E.has(N.name)?String(j+1):null:N.detected?String(j+1):null).filter(Boolean).join(",")||"0",B=(await c.question(` ${M}> ${k}${_(`[${v}] `)}`)).trim()||v;B!=="0"&&(Qe=B.split(",").map(j=>parseInt(j.trim(),10)).filter(j=>!isNaN(j)&&j>=1&&j<=g.length).map(j=>{let K=g[j-1];return{name:K.name,command:K.command,argsTemplate:K.argsTemplate,promptVia:K.promptVia}})),Qe.length>0?console.log(` ${D(">")} ${R(String(Qe.length))} agent(s) selected: ${Qe.map(N=>N.name).join(", ")}`):console.log(` ${_("No agents selected.")}`)}let No=t.config.codeAgents?.forge,Do=No?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
|
|
841
|
+
${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 xi=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let g of xi){let E=g.name===Do?` ${_("(current)")}`:"";console.log(` ${M}${g.num}${k}) ${g.label}${E}`)}let Ri=Do==="github"?"2":Do==="gitlab"?"3":"1",Jl=(await c.question(`${M}> ${k}${_(`[${Ri}] `)}`)).trim()||Ri,et=xi.find(g=>g.num===Jl)?.name??"",ds="",us="";if(et==="github"){console.log(` ${D(">")} Forge: ${R("GitHub")}`);let g=t.env.ALFRED_GITHUB_TOKEN??No?.github?.token??"";g&&console.log(` ${_(`Current token: ${me(g)}`)}`),console.log(` ${_("Create a token at https://github.com/settings/tokens (scope: repo)")}`),ds=(await c.question(` ${q}GitHub Token${k}: ${M}`)).trim(),process.stdout.write(k),!ds&&g&&(ds=g)}else if(et==="gitlab"){console.log(` ${D(">")} Forge: ${R("GitLab")}`);let g=t.env.ALFRED_GITLAB_TOKEN??No?.gitlab?.token??"";g&&console.log(` ${_(`Current token: ${me(g)}`)}`),console.log(` ${_("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),us=(await c.question(` ${q}GitLab Token${k}: ${M}`)).trim(),process.stdout.write(k),!us&&g&&(us=g)}else console.log(` ${_("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);console.log(`
|
|
842
|
+
${R("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${_("Control VMs, containers, network devices, and smart home through Alfred.")}`);let ms=t.config.proxmox,Mo=t.env.ALFRED_PROXMOX_BASE_URL??ms?.baseUrl??"",Zl=Mo?"Y/n":"y/N",Ci=(await c.question(` ${q}Enable Proxmox VE?${k} ${_(`[${Zl}]`)}: ${M}`)).trim().toLowerCase()||(Mo?"y":"n");process.stdout.write(k);let kr=Ci==="y"||Ci==="yes",ps="",Oo="",hs="",Po=!0;if(kr){ps=await O(c," Proxmox URL (e.g. https://pve.local:8006)",Mo||"https://pve.local:8006");let g=t.env.ALFRED_PROXMOX_TOKEN_ID??ms?.tokenId??"";g&&console.log(` ${_(`Current token ID: ${g}`)}`),console.log(` ${_("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),Oo=await O(c," API Token ID (user@realm!name)",g);let E=t.env.ALFRED_PROXMOX_TOKEN_SECRET??ms?.tokenSecret??"";E&&console.log(` ${_(`Current secret: ${me(E)}`)}`),hs=(await c.question(` ${q}API Token Secret${k}: ${M}`)).trim(),process.stdout.write(k),!hs&&E&&(hs=E);let v=ms?.verifyTls===!1?"y/N":"Y/n",B=(await c.question(` ${q}Verify TLS?${k} ${_(`(self-signed? \u2192 no) [${v}]`)}: ${M}`)).trim().toLowerCase()||(ms?.verifyTls===!1?"n":"y");process.stdout.write(k),Po=B==="y"||B==="yes",console.log(` ${D(">")} Proxmox: ${R(ps)} ${_(`(TLS verify: ${Po?"yes":"no"})`)}`)}else console.log(` ${_("Proxmox disabled.")}`);let tt=t.config.unifi,Uo=t.env.ALFRED_UNIFI_BASE_URL??tt?.baseUrl??"",Ql=Uo?"Y/n":"y/N",Li=(await c.question(`
|
|
843
|
+
${q}Enable UniFi Network?${k} ${_(`[${Ql}]`)}: ${M}`)).trim().toLowerCase()||(Uo?"y":"n");process.stdout.write(k);let fs=Li==="y"||Li==="yes",$t="",st="",Fo="",gs="",jo=!0;if(fs){$t=await O(c," UniFi URL (e.g. https://unifi.local)",Uo||"https://unifi.local"),console.log(` ${_("Auth: API Key (recommended) or Username/Password")}`);let g=t.env.ALFRED_UNIFI_API_KEY??tt?.apiKey??"",E=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],v=g?"1":tt?.username?"2":"1";for(let K of E)console.log(` ${M}${K.num}${k}) ${K.label}`);if(((await c.question(` ${M}> ${k}${_(`[${v}] `)}`)).trim()||v)==="1")g&&console.log(` ${_(`Current key: ${me(g)}`)}`),console.log(` ${_("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),st=(await c.question(` ${q}API Key${k}: ${M}`)).trim(),process.stdout.write(k),!st&&g&&(st=g);else{let K=t.env.ALFRED_UNIFI_USERNAME??tt?.username??"";Fo=await O(c," Username",K||"alfred");let ge=t.env.ALFRED_UNIFI_PASSWORD??tt?.password??"";ge&&console.log(` ${_(`Current password: ${me(ge)}`)}`),gs=(await c.question(` ${q}Password${k}: ${M}`)).trim(),process.stdout.write(k),!gs&&ge&&(gs=ge)}let N=tt?.verifyTls===!1?"y/N":"Y/n",j=(await c.question(` ${q}Verify TLS?${k} ${_(`(self-signed? \u2192 no) [${N}]`)}: ${M}`)).trim().toLowerCase()||(tt?.verifyTls===!1?"n":"y");process.stdout.write(k),jo=j==="y"||j==="yes",console.log(` ${D(">")} UniFi: ${R($t)} ${_(`(TLS verify: ${jo?"yes":"no"})`)}`)}else console.log(` ${_("UniFi disabled.")}`);let Sr=t.config.homeassistant,Bo=t.env.ALFRED_HOMEASSISTANT_URL??Sr?.baseUrl??"",ed=Bo?"Y/n":"y/N",Ni=(await c.question(`
|
|
844
|
+
${q}Enable Home Assistant?${k} ${_(`[${ed}]`)}: ${M}`)).trim().toLowerCase()||(Bo?"y":"n");process.stdout.write(k);let Ar=Ni==="y"||Ni==="yes",ys="",ws="",Ho=!0;if(Ar){ys=await O(c," Home Assistant URL (e.g. http://homeassistant.local:8123)",Bo||"http://homeassistant.local:8123");let g=t.env.ALFRED_HOMEASSISTANT_TOKEN??Sr?.accessToken??"";g&&console.log(` ${_(`Current token: ${me(g)}`)}`),console.log(` ${_("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),ws=(await c.question(` ${q}Long-Lived Access Token${k}: ${M}`)).trim(),process.stdout.write(k),!ws&&g&&(ws=g);let E=Sr?.verifyTls===!1?"y/N":"Y/n",v=(await c.question(` ${q}Verify TLS?${k} ${_(`(self-signed? \u2192 no) [${E}]`)}: ${M}`)).trim().toLowerCase()||(Sr?.verifyTls===!1?"n":"y");process.stdout.write(k),Ho=v==="y"||v==="yes",console.log(` ${D(">")} Home Assistant: ${R(ys)} ${_(`(TLS verify: ${Ho?"yes":"no"})`)}`)}else console.log(` ${_("Home Assistant disabled.")}`);let ke=t.config.contacts,qo=t.env.ALFRED_CONTACTS_PROVIDER??ke?.provider??"",td=qo?"Y/n":"y/N",Di=(await c.question(`
|
|
845
|
+
${q}Enable Contacts management?${k} ${_(`[${td}]`)}: ${M}`)).trim().toLowerCase()||(qo?"y":"n");process.stdout.write(k);let Ir=Di==="y"||Di==="yes",Se="",ce={};if(Ir){let g=["carddav","google","microsoft"],E=g.indexOf(qo),v=E>=0?E+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 _r(c," > ",1,3,v);if(Se=g[B-1],ce.ALFRED_CONTACTS_PROVIDER=Se,Se==="carddav"){let N=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??ke?.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??ke?.carddav?.username??"";ce.ALFRED_CARDDAV_CONTACTS_USERNAME=await O(c," Username",j);let K=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??ke?.carddav?.password??"";K&&console.log(` ${_(`Current password: ${me(K)}`)}`);let ge=(await c.question(` ${q}Password${k}: ${M}`)).trim();process.stdout.write(k),ce.ALFRED_CARDDAV_CONTACTS_PASSWORD=ge||K}else if(Se==="google"){let N=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??ke?.google?.clientId??"";N&&console.log(` ${_(`Current client ID: ${me(N)}`)}`),ce.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await c.question(` ${q}Google Client ID${k}: ${M}`)).trim()||N,process.stdout.write(k);let j=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??ke?.google?.clientSecret??"";ce.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await c.question(` ${q}Google Client Secret${k}: ${M}`)).trim()||j,process.stdout.write(k);let K=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??ke?.google?.refreshToken??"";ce.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await c.question(` ${q}Refresh Token${k}: ${M}`)).trim()||K,process.stdout.write(k)}else if(Se==="microsoft"){let N=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??ke?.microsoft?.clientId??"";N&&console.log(` ${_(`Current client ID: ${me(N)}`)}`),ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await c.question(` ${q}Microsoft Client ID${k}: ${M}`)).trim()||N,process.stdout.write(k);let j=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??ke?.microsoft?.clientSecret??"";ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await c.question(` ${q}Microsoft Client Secret${k}: ${M}`)).trim()||j,process.stdout.write(k);let K=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??ke?.microsoft?.tenantId??"";ce.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await O(c," Tenant ID",K||"common");let ge=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??ke?.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${k}: ${M}`)).trim()||ge,process.stdout.write(k)}console.log(` ${D(">")} Contacts: ${R(Se)}`)}else console.log(` ${_("Contacts disabled.")}`);let Mi=t.config.docker,zo=t.env.ALFRED_DOCKER_SOCKET_PATH??Mi?.socketPath??"",Wo=t.env.ALFRED_DOCKER_HOST??Mi?.host??"",sd=zo||Wo?"Y/n":"y/N",Oi=(await c.question(`
|
|
846
|
+
${q}Enable Docker management?${k} ${_(`[${sd}]`)}: ${M}`)).trim().toLowerCase()||(zo||Wo?"y":"n");process.stdout.write(k);let xr=Oi==="y"||Oi==="yes",rt="",ot="";if(xr){let g=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${_("Use socket path for local Docker, or host URL for remote.")}`),rt=await O(c," Docker socket path",zo||g);let E=(await c.question(` ${q}Docker host URL (optional, for remote)${k}: ${M}`)).trim();process.stdout.write(k),ot=E||Wo,console.log(` ${D(">")} Docker: ${R(ot||rt)}`)}else console.log(` ${_("Docker disabled.")}`);let rd=t.config.bmw,Vo=t.env.ALFRED_BMW_CLIENT_ID??rd?.clientId??"",od=Vo?"Y/n":"y/N",Pi=(await c.question(`
|
|
847
|
+
${q}Enable BMW CarData (vehicle status, charging)?${k} ${_(`[${od}]`)}: ${M}`)).trim().toLowerCase()||(Vo?"y":"n");process.stdout.write(k);let Rr=Pi==="y"||Pi==="yes",Ko="";Rr?(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)')}`),Ko=await O(c," BMW CarData Client ID",Vo),console.log(` ${D(">")} BMW CarData: ${R("enabled")}`)):console.log(` ${_("BMW CarData disabled.")}`);let nd=t.config.routing,Go=t.env.ALFRED_ROUTING_API_KEY??nd?.apiKey??"",id=Go?"Y/n":"y/N",Ui=(await c.question(`
|
|
848
|
+
${q}Enable route planning with live traffic (Google Routes)?${k} ${_(`[${id}]`)}: ${M}`)).trim().toLowerCase()||(Go?"y":"n");process.stdout.write(k);let Cr=Ui==="y"||Ui==="yes",Xo="";Cr?(console.log(` ${_("Setup:")}`),console.log(` ${_(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${_(" 2. Routes API aktivieren")}`),console.log(` ${_(" 3. API Key erstellen")}`),Xo=await O(c," Google Maps API Key",Go),console.log(` ${D(">")} Routing: ${R("enabled")}`)):console.log(` ${_("Routing disabled.")}`),console.log(`
|
|
849
|
+
${R("Security configuration:")}`);let Fi=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",_e;if(Fi)_e=await O(c,"Owner user ID (for elevated permissions)",Fi);else{let g=(await c.question(`${q}Owner user ID${k} ${_("(optional, for elevated permissions)")}: ${M}`)).trim();process.stdout.write(k),_e=g}let Ts=!1;if(_e){let g=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 E=(await c.question(` ${M}> ${k}${_(`[${g}] `)}`)).trim().toLowerCase();E===""?Ts=t.shellEnabled:Ts=E==="y"||E==="yes",console.log(Ts?` ${D(">")} Shell access ${R("enabled")} for owner ${_(_e)}`:` ${_("Shell access disabled.")}`)}let ad=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 Yo=(await c.question(` ${M}> ${k}${_(`[${ad}] `)}`)).trim().toLowerCase(),_s;Yo===""?_s=t.writeInGroups:_s=Yo==="y"||Yo==="yes",console.log(_s?` ${D(">")} Write actions ${R("enabled")} in groups`:` ${_("Write actions only in DMs (default).")}`);let cd=t.rateLimit??30;console.log("");let ld=await O(c," Rate limit (max write actions per hour per user)",String(cd)),Lr=Math.max(1,parseInt(ld,10)||30);console.log(` ${D(">")} Rate limit: ${R(String(Lr))} per hour`),console.log(`
|
|
850
|
+
${R("Writing configuration files...")}`);let S=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(l){let g=a.envKeyName||"ALFRED_OLLAMA_API_KEY";S.push(`${g}=${l}`)}if(y!==a.defaultModel&&S.push(`ALFRED_LLM_MODEL=${y}`),m&&S.push(`ALFRED_LLM_BASE_URL=${m}`),Object.keys(L).length>0){S.push("","# === Additional Model Tiers ===");for(let[g,E]of Object.entries(L)){let v=`ALFRED_LLM_${g.toUpperCase()}`;S.push(""),S.push(`${v}_PROVIDER=${E.provider}`),S.push(`${v}_MODEL=${E.model}`),E.apiKey&&S.push(`${v}_API_KEY=${E.apiKey}`),E.baseUrl&&S.push(`${v}_BASE_URL=${E.baseUrl}`)}}S.push("","# === Messaging Platforms ===","");for(let[g,E]of Object.entries(J))S.push(`${g}=${E}`);if(S.push("","# === Web Search ===",""),he?(S.push(`ALFRED_SEARCH_PROVIDER=${he}`),C&&S.push(`ALFRED_SEARCH_API_KEY=${C}`),F&&S.push(`ALFRED_SEARCH_BASE_URL=${F}`)):(S.push("# ALFRED_SEARCH_PROVIDER=brave"),S.push("# ALFRED_SEARCH_API_KEY=")),S.push("","# === Email ===",""),Er&&Ne.length>0){let g=Ne[0];g.provider==="microsoft"?(S.push("ALFRED_EMAIL_PROVIDER=microsoft"),g.msClientId?(S.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${g.msClientId}`),S.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${g.msClientSecret}`),S.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${g.msTenantId}`),S.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${g.msRefreshToken}`)):S.push("# Microsoft email credentials shared from calendar config")):(S.push(`ALFRED_EMAIL_USER=${g.user}`),S.push(`ALFRED_EMAIL_PASS=${g.pass}`)),Ne.length>1&&S.push("# Additional email accounts configured in config/default.yml")}else S.push("# ALFRED_EMAIL_USER="),S.push("# ALFRED_EMAIL_PASS=");if(S.push("","# === Speech ===",""),De?(S.push(`ALFRED_SPEECH_PROVIDER=${De}`),S.push(`ALFRED_SPEECH_API_KEY=${Ve}`),as&&S.push(`ALFRED_SPEECH_BASE_URL=${as}`),cs&&(S.push("ALFRED_TTS_ENABLED=true"),S.push(`ALFRED_TTS_VOICE=${ls}`))):(S.push("# ALFRED_SPEECH_PROVIDER=groq"),S.push("# ALFRED_SPEECH_API_KEY=")),S.push("","# === Forge (GitHub / GitLab) ===",""),et==="github"?(S.push("ALFRED_FORGE_PROVIDER=github"),S.push(`ALFRED_GITHUB_TOKEN=${ds}`)):et==="gitlab"?(S.push("ALFRED_FORGE_PROVIDER=gitlab"),S.push(`ALFRED_GITLAB_TOKEN=${us}`)):(S.push("# ALFRED_FORGE_PROVIDER=github"),S.push("# ALFRED_GITHUB_TOKEN=")),S.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),kr?(S.push(`ALFRED_PROXMOX_BASE_URL=${ps}`),S.push(`ALFRED_PROXMOX_TOKEN_ID=${Oo}`),S.push(`ALFRED_PROXMOX_TOKEN_SECRET=${hs}`)):(S.push("# ALFRED_PROXMOX_BASE_URL="),S.push("# ALFRED_PROXMOX_TOKEN_ID="),S.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),fs&&st?(S.push(`ALFRED_UNIFI_BASE_URL=${$t}`),S.push(`ALFRED_UNIFI_API_KEY=${st}`)):fs?(S.push(`ALFRED_UNIFI_BASE_URL=${$t}`),S.push(`ALFRED_UNIFI_USERNAME=${Fo}`),S.push(`ALFRED_UNIFI_PASSWORD=${gs}`)):(S.push("# ALFRED_UNIFI_BASE_URL="),S.push("# ALFRED_UNIFI_API_KEY=")),Ar?(S.push(`ALFRED_HOMEASSISTANT_URL=${ys}`),S.push(`ALFRED_HOMEASSISTANT_TOKEN=${ws}`)):(S.push("# ALFRED_HOMEASSISTANT_URL="),S.push("# ALFRED_HOMEASSISTANT_TOKEN=")),S.push("","# === Contacts ===",""),Ir)for(let[g,E]of Object.entries(ce))S.push(`${g}=${E}`);else S.push("# ALFRED_CONTACTS_PROVIDER=carddav");S.push("","# === Docker ===",""),xr?(rt&&S.push(`ALFRED_DOCKER_SOCKET_PATH=${rt}`),ot&&S.push(`ALFRED_DOCKER_HOST=${ot}`)):(S.push("# ALFRED_DOCKER_SOCKET_PATH="),S.push("# ALFRED_DOCKER_HOST=")),S.push("","# === BMW CarData ===",""),Rr?S.push(`ALFRED_BMW_CLIENT_ID=${Ko}`):S.push("# ALFRED_BMW_CLIENT_ID="),S.push("","# === Routing ===",""),Cr?S.push(`ALFRED_ROUTING_API_KEY=${Xo}`):S.push("# ALFRED_ROUTING_API_KEY="),S.push("","# === Security ===",""),_e?S.push(`ALFRED_OWNER_USER_ID=${_e}`):S.push("# ALFRED_OWNER_USER_ID="),S.push("");let dd=we.join(e,".env");de.writeFileSync(dd,S.join(`
|
|
851
|
+
`),"utf-8"),console.log(` ${D("+")} ${_(".env")} written`);let Nr=we.join(e,"config");de.existsSync(Nr)||de.mkdirSync(Nr,{recursive:!0});let ji={name:r,telegram:{token:H.telegram?.token??"",enabled:te.some(g=>g.name==="telegram")},discord:{token:H.discord?.token??"",enabled:te.some(g=>g.name==="discord")},whatsapp:{enabled:te.some(g=>g.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:H.matrix?.homeserverUrl??"https://matrix.org",accessToken:H.matrix?.accessToken??"",userId:H.matrix?.userId??"",enabled:te.some(g=>g.name==="matrix")},signal:{apiUrl:H.signal?.apiUrl??"http://localhost:8080",phoneNumber:H.signal?.phoneNumber??"",enabled:te.some(g=>g.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}:{},...F?{baseUrl:F}:{}}}:{},...Er&&Ne.length>0?{email:{accounts:Ne.map(g=>g.provider==="microsoft"?{name:g.name,provider:"microsoft",...g.msClientId?{microsoft:{clientId:g.msClientId,clientSecret:g.msClientSecret,tenantId:g.msTenantId,refreshToken:g.msRefreshToken}}:{}}:{name:g.name,imap:{host:g.imapHost,port:g.imapPort,secure:g.imapPort===993},smtp:{host:g.smtpHost,port:g.smtpPort,secure:g.smtpPort===465},auth:{user:g.user,pass:g.pass}})}}:{},...De?{speech:{provider:De,apiKey:Ve,...as?{baseUrl:as}:{},...cs?{ttsEnabled:!0,ttsVoice:ls}:{}}}:{},...Ro?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Qe.length>0||et?{codeAgents:{enabled:Qe.length>0,agents:Qe,...et==="github"?{forge:{provider:"github",github:{token:ds}}}:et==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:us}}}:{}}}:{},...kr?{proxmox:{baseUrl:ps,tokenId:Oo,tokenSecret:hs,verifyTls:Po}}:{},...fs?{unifi:{baseUrl:$t,...st?{apiKey:st}:{username:Fo,password:gs},site:"default",verifyTls:jo}}:{},...Ar?{homeassistant:{baseUrl:ys,accessToken:ws,verifyTls:Ho}}:{},...Ir?{contacts:{provider:Se,...Se==="carddav"?{carddav:{serverUrl:ce.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:ce.ALFRED_CARDDAV_CONTACTS_USERNAME}}:Se==="google"?{google:{clientId:ce.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:Se==="microsoft"?{microsoft:{clientId:ce.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:ce.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...xr?{docker:{...rt?{socketPath:rt}:{},...ot?{host:ot}:{}}}:{},...Rr?{bmw:{clientId:Ko}}:{},...Cr?{routing:{apiKey:Xo}}:{},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};_e&&(ji.security.ownerUserId=_e);let ud="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+$i.dump(ji,{lineWidth:120,noRefs:!0,sortKeys:!1}),md=we.join(Nr,"default.yml");de.writeFileSync(md,ud,"utf-8"),console.log(` ${D("+")} ${_("config/default.yml")} written`);let Jo=we.join(Nr,"rules");de.existsSync(Jo)||de.mkdirSync(Jo,{recursive:!0});let pd=Ts&&_e?`
|
|
852
852
|
# Allow admin actions (shell, etc.) for the owner only
|
|
853
853
|
- id: allow-owner-admin
|
|
854
854
|
effect: allow
|
|
@@ -869,7 +869,7 @@ ${R("Writing configuration files...")}`);let S=["# Alfred Environment Variables"
|
|
|
869
869
|
# riskLevels: [admin, destructive]
|
|
870
870
|
# conditions:
|
|
871
871
|
# users: ["${_e||"YOUR_USER_ID_HERE"}"]
|
|
872
|
-
`,
|
|
872
|
+
`,hd=`# Alfred \u2014 Default Security Rules
|
|
873
873
|
# Rules are evaluated in priority order (lower number = higher priority).
|
|
874
874
|
# First matching rule wins.
|
|
875
875
|
|
|
@@ -882,7 +882,7 @@ rules:
|
|
|
882
882
|
actions: ["*"]
|
|
883
883
|
riskLevels: [read]
|
|
884
884
|
|
|
885
|
-
${
|
|
885
|
+
${_s?` # Allow write-level skills everywhere (DMs and groups)
|
|
886
886
|
- id: allow-write-all
|
|
887
887
|
effect: allow
|
|
888
888
|
priority: 200
|
|
@@ -898,7 +898,7 @@ ${Ts?` # Allow write-level skills everywhere (DMs and groups)
|
|
|
898
898
|
conditions:
|
|
899
899
|
chatType: dm`}
|
|
900
900
|
|
|
901
|
-
# Rate-limit write actions: max ${
|
|
901
|
+
# Rate-limit write actions: max ${Lr} per hour per user
|
|
902
902
|
- id: rate-limit-write
|
|
903
903
|
effect: allow
|
|
904
904
|
priority: 250
|
|
@@ -906,9 +906,9 @@ ${Ts?` # Allow write-level skills everywhere (DMs and groups)
|
|
|
906
906
|
actions: ["*"]
|
|
907
907
|
riskLevels: [write]
|
|
908
908
|
rateLimit:
|
|
909
|
-
maxInvocations: ${
|
|
909
|
+
maxInvocations: ${Lr}
|
|
910
910
|
windowSeconds: 3600
|
|
911
|
-
${
|
|
911
|
+
${pd}
|
|
912
912
|
# Deny destructive and admin actions by default
|
|
913
913
|
- id: deny-destructive
|
|
914
914
|
effect: deny
|
|
@@ -924,24 +924,24 @@ ${md}
|
|
|
924
924
|
scope: global
|
|
925
925
|
actions: ["*"]
|
|
926
926
|
riskLevels: [read, write, destructive, admin]
|
|
927
|
-
`,
|
|
928
|
-
${
|
|
927
|
+
`,fd=we.join(Jo,"default-rules.yml");de.writeFileSync(fd,hd,"utf-8"),console.log(` ${D("+")} ${_("config/rules/default-rules.yml")} written`);let Bi=we.join(e,"data");de.existsSync(Bi)||(de.mkdirSync(Bi,{recursive:!0}),console.log(` ${D("+")} ${_("data/")} directory created`)),console.log(""),console.log(`${$o}${"=".repeat(52)}${k}`),console.log(`${$o}${q} Setup complete!${k}`),console.log(`${$o}${"=".repeat(52)}${k}`),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[g,E]of Object.entries(L)){let v=g.charAt(0).toUpperCase()+g.slice(1);console.log(` ${R(`LLM ${v}:`)}${" ".repeat(Math.max(1,10-v.length))}${E.provider} (${E.model})`)}if(te.length>0?console.log(` ${R("Platforms:")} ${te.map(g=>g.label).join(", ")}`):console.log(` ${R("Platforms:")} none (configure later)`),he){let g={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${F})`};console.log(` ${R("Web search:")} ${g[he]}`)}else console.log(` ${R("Web search:")} ${_("disabled")}`);if(Er&&Ne.length>0){let g=Ne.map(E=>E.provider==="microsoft"?`${E.name} (Microsoft 365)${E.msClientId?"":" \u2014 shared from Calendar"}`:`${E.name} (${E.imapHost})`);console.log(` ${R("Email:")} ${g.join(", ")}`)}else console.log(` ${R("Email:")} ${_("disabled")}`);if(De){let g={openai:"OpenAI Whisper",groq:"Groq Whisper"},E=cs?`, TTS: ${ls}`:"";console.log(` ${R("Voice:")} ${g[De]}${E}`)}else console.log(` ${R("Voice:")} ${_("disabled")}`);console.log(` ${R("Code Sandbox:")} ${Ro?D("enabled"):_("disabled")}`),kr&&console.log(` ${R("Proxmox:")} ${D(ps)}`),fs&&console.log(` ${R("UniFi:")} ${D($t)}`),Ar&&console.log(` ${R("Home Assist.:")} ${D(ys)}`),Ir&&console.log(` ${R("Contacts:")} ${D(Se)}`),xr&&console.log(` ${R("Docker:")} ${D(ot||rt)}`),Rr&&console.log(` ${R("BMW CarData:")} ${D("enabled")}`),Cr&&console.log(` ${R("Routing:")} ${D("enabled")}`),_e&&(console.log(` ${R("Owner ID:")} ${_e}`),console.log(` ${R("Shell access:")} ${Ts?D("enabled"):_("disabled")}`)),console.log(` ${R("Write scope:")} ${_s?"DMs + Groups":"DMs only"}`),console.log(` ${R("Rate limit:")} ${Lr}/hour per user`),console.log(""),console.log(`${vo}Next steps:${k}`),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(`${Ze}Edit ${R(".env")}${Ze} or ${R("config/default.yml")}${Ze} for manual configuration.${k}`),console.log("")}finally{c.close()}}async function O(c,e,t){let s=(await c.question(`${q}${e}${k} ${_(`[${t}]`)}: ${M}`)).trim();return process.stdout.write(k),s||t}async function $e(c,e){for(;;){let t=(await c.question(`${q}${e}${k}: ${M}`)).trim();if(process.stdout.write(k),t)return t;console.log(` ${Il("!")} This field is required. Please enter a value.`)}}async function _r(c,e,t,s,r){for(;;){let o=(await c.question(`${M}${e}${k}`)).trim();if(!o)return r;let n=parseInt(o,10);if(!Number.isNaN(n)&&n>=t&&n<=s)return n;console.log(` ${Il("!")} Please enter a number between ${t} and ${s}.`)}}function Ym(){console.log(`
|
|
928
|
+
${Wm}${q} _ _ _____ ____ _____ ____
|
|
929
929
|
/ \\ | | | ___| _ \\| ____| _ \\
|
|
930
930
|
/ _ \\ | | | |_ | |_) | _| | | | |
|
|
931
931
|
/ ___ \\| |___| _| | _ <| |___| |_| |
|
|
932
932
|
/_/ \\_\\_____|_| |_| \\_\\_____|____/ ${k}
|
|
933
933
|
${Ze} Personal AI Assistant \u2014 Setup Wizard${k}
|
|
934
|
-
`)}var k,q,Ze,Eo,M,$o,qm,zm,We,rs,Sl,xl=b(()=>{"use strict";Ei();k="\x1B[0m",q="\x1B[1m",Ze="\x1B[2m",Eo="\x1B[32m",M="\x1B[33m",$o="\x1B[36m",qm="\x1B[31m",zm="\x1B[35m";u(D,"green");u(Wm,"yellow");u(le,"cyan");u(Al,"red");u(R,"bold");u(_,"dim");u(me,"maskKey");We=[{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(Vm,"findCommand");Sl=[{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(Km,"loadExistingConfig");u(Gm,"setupCommand");u(O,"askWithDefault");u($e,"askRequired");u(Tr,"askNumber");u(Xm,"printBanner")});var Cl={};oe(Cl,{configCommand:()=>Qm});function Jm(c){let e=c.toLowerCase();return Ym.some(t=>e.includes(t))}function Zm(c){return typeof c!="string"||c.length===0?"(empty)":c.length<=8?"***":c.slice(0,4)+"..."+c.slice(-4)}function Rl(c){let e={};for(let[t,s]of Object.entries(c))Jm(t)?e[t]=Zm(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Rl(s):e[t]=s;return e}async function Qm(){let c=new re,e;try{e=c.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Rl(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var Ym,Ll=b(()=>{"use strict";Be();Ym=["token","apikey","api_key","accesstoken","secret","password"];u(Jm,"isSensitiveKey");u(Zm,"redactValue");u(Rl,"redactObject");u(Qm,"configCommand")});var Dl={};oe(Dl,{rulesCommand:()=>tp});import vo from"node:fs";import Nl from"node:path";import ep from"js-yaml";async function tp(){let c=new re,e;try{e=c.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=Nl.resolve(e.security.rulesPath);if(!vo.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}vo.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=vo.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=Nl.join(t,a);try{let d=vo.readFileSync(l,"utf-8"),m=ep.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 Ml=b(()=>{"use strict";Be();Pr();u(tp,"rulesCommand")});var Ol={};oe(Ol,{statusCommand:()=>rp});import _r from"node:fs";import vi from"node:path";import sp from"js-yaml";async function rp(){let c=new re,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=vi.resolve(e.storage.path),o=_r.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${o?"exists":"not yet created"}`),console.log("");let n=vi.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=vi.join(n,m);try{let w=_r.readFileSync(p,"utf-8"),y=sp.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 Pl=b(()=>{"use strict";Be();Pr();u(rp,"statusCommand")});var jl={};oe(jl,{authCommand:()=>Tp});import{createServer as op}from"node:http";import{exec as np}from"node:child_process";import{readFileSync as ip,writeFileSync as ap,existsSync as cp}from"node:fs";import{createInterface as lp}from"node:readline";import{resolve as dp}from"node:path";async function ki(c){let e=lp({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(c,s=>{e.close(),t(s.trim())})})}function mp(){let c={};try{let s=new re().loadConfig();for(let n of["email","calendar","contacts"]){let i=s[n];if(!i)continue;let a=i.microsoft;a&&(!c.clientId&&a.clientId&&(c.clientId=a.clientId),!c.clientSecret&&a.clientSecret&&(c.clientSecret=a.clientSecret),!c.tenantId&&a.tenantId&&(c.tenantId=a.tenantId))}let r=s.todo;r&&(!c.clientId&&r.clientId&&(c.clientId=r.clientId),!c.clientSecret&&r.clientSecret&&(c.clientSecret=r.clientSecret),!c.tenantId&&r.tenantId&&(c.tenantId=r.tenantId));let o=s.email;if(o?.accounts&&Array.isArray(o.accounts))for(let n of o.accounts){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))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS","ALFRED_MICROSOFT_TODO"];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 pp(){let c=mp(),e=c.clientId||await ki(" Client ID: "),t=c.clientSecret||await ki(" Client Secret: "),s=c.tenantId||await ki(' 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 hp(c){let e=new URLSearchParams({client_id:c.clientId,response_type:"code",redirect_uri:Ul,response_mode:"query",scope:Fl,prompt:"consent"});return`https://login.microsoftonline.com/${c.tenantId}/oauth2/v2.0/authorize?${e}`}async function fp(c,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:c,redirect_uri:Ul,grant_type:"authorization_code",scope:Fl}),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 gp(c){let t={win32:`start "" "${c}"`,darwin:`open "${c}"`,linux:`xdg-open "${c}"`}[process.platform];t&&np(t,()=>{})}function yp(c,e){let t=dp(process.cwd(),".env"),s=[];cp(t)&&(s=ip(t,"utf-8").split(`
|
|
934
|
+
`)}var k,q,Ze,$o,M,vo,zm,Wm,We,os,Al,Rl=b(()=>{"use strict";Ei();k="\x1B[0m",q="\x1B[1m",Ze="\x1B[2m",$o="\x1B[32m",M="\x1B[33m",vo="\x1B[36m",zm="\x1B[31m",Wm="\x1B[35m";u(D,"green");u(Vm,"yellow");u(le,"cyan");u(Il,"red");u(R,"bold");u(_,"dim");u(me,"maskKey");We=[{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"}]}],os=[{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(Km,"findCommand");Al=[{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(Gm,"loadExistingConfig");u(Xm,"setupCommand");u(O,"askWithDefault");u($e,"askRequired");u(_r,"askNumber");u(Ym,"printBanner")});var Ll={};oe(Ll,{configCommand:()=>ep});function Zm(c){let e=c.toLowerCase();return Jm.some(t=>e.includes(t))}function Qm(c){return typeof c!="string"||c.length===0?"(empty)":c.length<=8?"***":c.slice(0,4)+"..."+c.slice(-4)}function Cl(c){let e={};for(let[t,s]of Object.entries(c))Zm(t)?e[t]=Qm(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Cl(s):e[t]=s;return e}async function ep(){let c=new re,e;try{e=c.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Cl(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var Jm,Nl=b(()=>{"use strict";Be();Jm=["token","apikey","api_key","accesstoken","secret","password"];u(Zm,"isSensitiveKey");u(Qm,"redactValue");u(Cl,"redactObject");u(ep,"configCommand")});var Ml={};oe(Ml,{rulesCommand:()=>sp});import ko from"node:fs";import Dl from"node:path";import tp from"js-yaml";async function sp(){let c=new re,e;try{e=c.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=Dl.resolve(e.security.rulesPath);if(!ko.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}ko.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=ko.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=Dl.join(t,a);try{let d=ko.readFileSync(l,"utf-8"),m=tp.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 Ol=b(()=>{"use strict";Be();Ur();u(sp,"rulesCommand")});var Pl={};oe(Pl,{statusCommand:()=>op});import br from"node:fs";import vi from"node:path";import rp from"js-yaml";async function op(){let c=new re,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=vi.resolve(e.storage.path),o=br.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${o?"exists":"not yet created"}`),console.log("");let n=vi.resolve(e.security.rulesPath),i=0,a=0;if(br.existsSync(n)&&br.statSync(n).isDirectory()){let l=br.readdirSync(n).filter(m=>m.endsWith(".yml")||m.endsWith(".yaml"));a=l.length;let d=new dt;for(let m of l){let p=vi.join(n,m);try{let w=br.readFileSync(p,"utf-8"),y=rp.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 Ul=b(()=>{"use strict";Be();Ur();u(op,"statusCommand")});var Bl={};oe(Bl,{authCommand:()=>_p});import{createServer as np}from"node:http";import{exec as ip}from"node:child_process";import{readFileSync as ap,writeFileSync as cp,existsSync as lp}from"node:fs";import{createInterface as dp}from"node:readline";import{resolve as up}from"node:path";async function ki(c){let e=dp({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(c,s=>{e.close(),t(s.trim())})})}function pp(){let c={};try{let s=new re().loadConfig();for(let n of["email","calendar","contacts"]){let i=s[n];if(!i)continue;let a=i.microsoft;a&&(!c.clientId&&a.clientId&&(c.clientId=a.clientId),!c.clientSecret&&a.clientSecret&&(c.clientSecret=a.clientSecret),!c.tenantId&&a.tenantId&&(c.tenantId=a.tenantId))}let r=s.todo;r&&(!c.clientId&&r.clientId&&(c.clientId=r.clientId),!c.clientSecret&&r.clientSecret&&(c.clientSecret=r.clientSecret),!c.tenantId&&r.tenantId&&(c.tenantId=r.tenantId));let o=s.email;if(o?.accounts&&Array.isArray(o.accounts))for(let n of o.accounts){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))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS","ALFRED_MICROSOFT_TODO"];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 hp(){let c=pp(),e=c.clientId||await ki(" Client ID: "),t=c.clientSecret||await ki(" Client Secret: "),s=c.tenantId||await ki(' 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 fp(c){let e=new URLSearchParams({client_id:c.clientId,response_type:"code",redirect_uri:Fl,response_mode:"query",scope:jl,prompt:"consent"});return`https://login.microsoftonline.com/${c.tenantId}/oauth2/v2.0/authorize?${e}`}async function gp(c,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:c,redirect_uri:Fl,grant_type:"authorization_code",scope:jl}),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 yp(c){let t={win32:`start "" "${c}"`,darwin:`open "${c}"`,linux:`xdg-open "${c}"`}[process.platform];t&&ip(t,()=>{})}function wp(c,e){let t=up(process.cwd(),".env"),s=[];lp(t)&&(s=ap(t,"utf-8").split(`
|
|
935
935
|
`));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,ALFRED_MICROSOFT_TODO_CLIENT_ID:c.clientId,ALFRED_MICROSOFT_TODO_CLIENT_SECRET:c.clientSecret,ALFRED_MICROSOFT_TODO_TENANT_ID:c.tenantId,ALFRED_MICROSOFT_TODO_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(`
|
|
936
936
|
`).replace(/\n*$/,`
|
|
937
|
-
`);
|
|
938
|
-
Fehler: ${s.message}`),process.exit(1)}process.exit(0)}var
|
|
937
|
+
`);cp(t,n)}function Tp(c){return new Promise((e,t)=>{let s=np(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 gp(i,c);o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(mp),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 _p(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 hp(),t=fp(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),yp(t);try{let s=await Tp(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),wp(e,s),console.log(" .env aktualisiert (Email, Calendar, Contacts, To Do)."),console.log(""),console.log(" Fertig! Du kannst Alfred jetzt mit Microsoft 365 nutzen."),console.log("")}catch(s){console.error(`
|
|
938
|
+
Fehler: ${s.message}`),process.exit(1)}process.exit(0)}var Fl,jl,mp,Hl=b(()=>{"use strict";Be();Fl="http://localhost:3000/callback",jl=["offline_access","Mail.Read","Mail.ReadWrite","Mail.Send","Contacts.Read","Contacts.ReadWrite","Calendars.Read","Calendars.ReadWrite","Tasks.ReadWrite"].join(" "),mp=`<!DOCTYPE html>
|
|
939
939
|
<html><head><meta charset="utf-8"><title>Alfred \u2014 Auth erfolgreich</title>
|
|
940
940
|
<style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0d1117;color:#e6edf3}
|
|
941
941
|
.card{text-align:center;padding:2rem;border:1px solid #30363d;border-radius:12px;background:#161b22}
|
|
942
942
|
h1{color:#3fb950;margin-bottom:.5rem}p{color:#8b949e}</style></head>
|
|
943
|
-
<body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;u(ki,"askQuestion");u(
|
|
944
|
-
Alfred CLI v${
|
|
943
|
+
<body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;u(ki,"askQuestion");u(pp,"resolveCredentials");u(hp,"ensureCredentials");u(fp,"buildAuthUrl");u(gp,"exchangeCode");u(yp,"openBrowser");u(wp,"updateEnvFile");u(Tp,"waitForCallback");u(_p,"authCommand")});var ql={};oe(ql,{logsCommand:()=>$p});import bp from"node:fs";import Ep from"node:path";async function $p(c){let e=new re,t;try{t=e.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let s=Ep.resolve(t.storage.path);if(!bp.existsSync(s)){console.log(`Database not found at: ${s}`),console.log("No audit log entries. Alfred has not been run yet, or the database path is incorrect.");return}let r;try{r=new at(s);let o=new ct(r.getDb()),n=o.count({}),i=o.query({limit:c});if(console.log("Alfred \u2014 Audit Log"),console.log("==================="),console.log(`Total entries: ${n}`),console.log(`Showing last ${Math.min(c,n)} entries:`),console.log(""),i.length===0){console.log("No audit log entries found.");return}for(let a of i){let l=a.timestamp.toISOString(),d=a.effect==="allow"?"ALLOW":"DENY ";console.log(` ${l} [${d}] ${a.action}`),console.log(` user: ${a.userId} | platform: ${a.platform} | risk: ${a.riskLevel}`),a.ruleId&&console.log(` rule: ${a.ruleId}`),a.chatId&&console.log(` chat: ${a.chatId}`),a.context&&console.log(` context: ${JSON.stringify(a.context)}`),console.log("")}}catch(o){console.error("Failed to read audit log:",o.message),process.exit(1)}finally{r&&r.close()}}var zl=b(()=>{"use strict";Be();dn();u($p,"logsCommand")});import{readFileSync as vp}from"node:fs";import{fileURLToPath as kp}from"node:url";import{dirname as Sp,join as Ap}from"node:path";function Ip(){try{let c=Sp(kp(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(vp(Ap(c,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}u(Ip,"getVersion");var Wl=Ip(),Si=`
|
|
944
|
+
Alfred CLI v${Wl}
|
|
945
945
|
Personal AI Assistant
|
|
946
946
|
|
|
947
947
|
Usage:
|
|
@@ -960,4 +960,4 @@ Commands:
|
|
|
960
960
|
Options:
|
|
961
961
|
--help, -h Show this help message
|
|
962
962
|
--version, -v Show version number
|
|
963
|
-
`.trim();function
|
|
963
|
+
`.trim();function xp(c){let e=c.slice(2),t=e.length>0&&!e[0].startsWith("-")?e[0]:"",s=t?e.slice(1):e,r={},o=[],n=0;for(;n<s.length;){let i=s[n];if(i.startsWith("--")){let a=i.slice(2);n+1<s.length&&!s[n+1].startsWith("-")?(r[a]=s[n+1],n+=2):(r[a]=!0,n+=1)}else if(i.startsWith("-")&&i.length===2){let a=i.slice(1);n+1<s.length&&!s[n+1].startsWith("-")?(r[a]=s[n+1],n+=2):(r[a]=!0,n+=1)}else o.push(i),n+=1}return{command:t,flags:r,positional:o}}u(xp,"parseArgs");async function Rp(){let c=xp(process.argv);switch((c.flags.help||c.flags.h)&&(console.log(Si),process.exit(0)),(c.flags.version||c.flags.v)&&(console.log(`alfred v${Wl}`),process.exit(0)),c.command){case"start":{let{startCommand:e}=await Promise.resolve().then(()=>($l(),El));await e();break}case"chat":{let{chatCommand:e}=await Promise.resolve().then(()=>(Sl(),kl));await e({model:typeof c.flags.model=="string"?c.flags.model:void 0,tier:typeof c.flags.tier=="string"?c.flags.tier:void 0});break}case"setup":{let{setupCommand:e}=await Promise.resolve().then(()=>(Rl(),xl));await e();break}case"config":{let{configCommand:e}=await Promise.resolve().then(()=>(Nl(),Ll));await e();break}case"rules":{let{rulesCommand:e}=await Promise.resolve().then(()=>(Ol(),Ml));await e();break}case"status":{let{statusCommand:e}=await Promise.resolve().then(()=>(Ul(),Pl));await e();break}case"auth":{let e=c.positional[0]??"",{authCommand:t}=await Promise.resolve().then(()=>(Hl(),Bl));await t(e);break}case"logs":{let e=c.flags.tail,t=20;if(typeof e=="string"){let r=parseInt(e,10);(Number.isNaN(r)||r<=0)&&(console.error("Error: --tail must be a positive integer"),process.exit(1)),t=r}let{logsCommand:s}=await Promise.resolve().then(()=>(zl(),ql));await s(t);break}case"help":console.log(Si);break;case"":console.log(Si),process.exit(0);break;default:console.error(`Unknown command: ${c.command}`),console.error(""),console.error('Run "alfred --help" for usage information.'),process.exit(1)}}u(Rp,"main");Rp().catch(c=>{console.error("Fatal error:",c),process.exit(1)});
|