@madh-io/alfred-ai 0.14.6 → 0.15.0
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 +280 -250
- package/bundle/web-ui/404/index.html +1 -0
- package/bundle/web-ui/404.html +1 -0
- package/bundle/web-ui/_next/static/YlgBLyRiTBlh2FCWTcPWl/_buildManifest.js +1 -0
- package/bundle/web-ui/_next/static/YlgBLyRiTBlh2FCWTcPWl/_ssgManifest.js +1 -0
- package/bundle/web-ui/_next/static/chunks/188-dca4c90c7e992695.js +1 -0
- package/bundle/web-ui/_next/static/chunks/330.a5641b2d2bd30f52.js +1 -0
- package/bundle/web-ui/_next/static/chunks/743-05c790de389fcbe8.js +1 -0
- package/bundle/web-ui/_next/static/chunks/8e6518bb-c26e82767f1faf66.js +1 -0
- package/bundle/web-ui/_next/static/chunks/943.a64b09208bd5a2a6.js +1 -0
- package/bundle/web-ui/_next/static/chunks/app/_not-found/page-67d90fd0c7991fbd.js +1 -0
- package/bundle/web-ui/_next/static/chunks/app/chat/page-6689e82356b8ef38.js +1 -0
- package/bundle/web-ui/_next/static/chunks/app/dashboard/page-4273174e2ce71336.js +1 -0
- package/bundle/web-ui/_next/static/chunks/app/layout-507127baffe3a598.js +1 -0
- package/bundle/web-ui/_next/static/chunks/app/page-d89b2a8de912a30d.js +1 -0
- package/bundle/web-ui/_next/static/chunks/app/settings/page-58106151bf0d61e7.js +1 -0
- package/bundle/web-ui/_next/static/chunks/framework-077b27ad7787463c.js +1 -0
- package/bundle/web-ui/_next/static/chunks/main-17312c3d2227ba4f.js +1 -0
- package/bundle/web-ui/_next/static/chunks/main-app-bf91f7268c1fdab4.js +1 -0
- package/bundle/web-ui/_next/static/chunks/pages/_app-e24cf063dadc79e5.js +1 -0
- package/bundle/web-ui/_next/static/chunks/pages/_error-01ab52c470df0174.js +1 -0
- package/bundle/web-ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/bundle/web-ui/_next/static/chunks/webpack-c9b0493bbc0341e8.js +1 -0
- package/bundle/web-ui/_next/static/css/ab41d248afac9f33.css +1 -0
- package/bundle/web-ui/_next/static/rWs5twouAL7PVkCH3X2Ko/_buildManifest.js +1 -0
- package/bundle/web-ui/_next/static/rWs5twouAL7PVkCH3X2Ko/_ssgManifest.js +1 -0
- package/bundle/web-ui/chat/index.html +1 -0
- package/bundle/web-ui/chat/index.txt +18 -0
- package/bundle/web-ui/dashboard/index.html +1 -0
- package/bundle/web-ui/dashboard/index.txt +18 -0
- package/bundle/web-ui/index.html +1 -0
- package/bundle/web-ui/index.txt +18 -0
- package/bundle/web-ui/settings/index.html +1 -0
- package/bundle/web-ui/settings/index.txt +18 -0
- package/package.json +1 -1
package/bundle/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0}),xc=(l=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(l,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):l)(function(l){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+l+'" is not supported')});var T=(l,e)=>()=>(l&&(e=l(l=0)),e);var he=(l,e)=>{for(var t in e)Rc(l,t,{get:e[t],enumerable:!0})};import{z as w}from"zod";var Lc,Nc,Dc,Mc,Oc,Pc,Uc,Fc,It,Xm,Km,Vm,Cc,Ym,Jm,Zm,Qm,ep,tp,sp,rp,np,op,ip,ap,cp,lp,dp,up,mp,pp,hp,fp,gp,yp,wp,Tp,_p,kp,Ep,bp,Sp,vp,$p,Ip,Ap,Rp,gi,yi=T(()=>{"use strict";Lc=w.object({token:w.string().optional(),enabled:w.boolean()}),Nc=w.object({token:w.string().optional(),enabled:w.boolean()}),Dc=w.object({enabled:w.boolean(),dataPath:w.string()}),Mc=w.object({homeserverUrl:w.string(),accessToken:w.string().optional(),userId:w.string().optional(),enabled:w.boolean()}),Oc=w.object({apiUrl:w.string(),phoneNumber:w.string().optional(),enabled:w.boolean()}),Pc=w.object({path:w.string()}),Uc=w.object({level:w.enum(["trace","debug","info","warn","error","fatal"]),pretty:w.boolean(),auditLogPath:w.string().optional()}),Fc=w.object({rulesPath:w.string(),defaultEffect:w.enum(["allow","deny"]),ownerUserId:w.string().optional()}),It=w.object({provider:w.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:w.string().optional(),baseUrl:w.string().optional(),model:w.string(),temperature:w.number().optional(),maxTokens:w.number().optional()}),Xm=w.object({default:It,strong:It.optional(),fast:It.optional(),embeddings:It.optional(),local:It.optional()}).passthrough(),Km=w.union([It,Xm]),Vm=w.object({provider:w.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:w.string().optional(),baseUrl:w.string().optional()}),Cc=w.object({name:w.string().optional(),provider:w.enum(["imap-smtp","microsoft"]).optional(),imap:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),smtp:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),auth:w.object({user:w.string(),pass:w.string()}).optional(),microsoft:w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}).optional()}),Ym=w.union([w.object({accounts:w.array(Cc)}),Cc]),Jm=w.object({provider:w.enum(["openai","groq","google"]),apiKey:w.string(),baseUrl:w.string().optional(),ttsEnabled:w.boolean().optional(),ttsModel:w.string().optional(),ttsVoice:w.string().optional()}),Zm=w.object({serverUrl:w.string(),username:w.string(),password:w.string()}),Qm=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),ep=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),tp=w.object({provider:w.enum(["caldav","google","microsoft"]),caldav:Zm.optional(),google:Qm.optional(),microsoft:ep.optional(),vorlauf:w.object({enabled:w.boolean(),minutesBefore:w.coerce.number().min(1).max(120).default(15),enrichWithRoute:w.boolean().optional(),enrichWithMemories:w.boolean().optional()}).optional()}),sp=w.object({name:w.string(),command:w.string().optional(),args:w.array(w.string()).optional(),env:w.record(w.string()).optional(),url:w.string().optional()}),rp=w.object({servers:w.array(sp)}),np=w.object({enabled:w.boolean(),allowedLanguages:w.array(w.enum(["javascript","python"])).optional(),maxTimeoutMs:w.number().optional(),allowNetwork:w.boolean().optional()}),op=w.object({enabled:w.boolean().optional(),minMessageLength:w.number().optional(),minConfidence:w.number().min(0).max(1).optional(),maxExtractionsPerMinute:w.number().optional()}),ip=w.object({enabled:w.boolean(),port:w.coerce.number().int().min(1).max(65535),host:w.string(),token:w.string().optional(),corsOrigin:w.string().optional()}),ap=w.object({name:w.string(),command:w.string(),argsTemplate:w.array(w.string()),promptVia:w.enum(["arg","stdin"]).default("arg"),env:w.record(w.string()).optional(),cwd:w.string().optional(),timeoutMs:w.number().max(9e5).optional()}),cp=w.object({token:w.string(),baseUrl:w.string().optional()}),lp=w.object({token:w.string(),baseUrl:w.string().optional()}),dp=w.object({provider:w.enum(["github","gitlab"]),baseBranch:w.string().optional(),github:cp.optional(),gitlab:lp.optional()}),up=w.object({enabled:w.boolean(),agents:w.array(ap),forge:dp.optional()}),mp=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),verifyTls:w.boolean().optional(),defaultNode:w.string().optional()}),pp=w.object({baseUrl:w.string(),apiKey:w.string().optional(),username:w.string().optional(),password:w.string().optional(),site:w.string().optional(),verifyTls:w.boolean().optional()}),hp=w.object({baseUrl:w.string(),accessToken:w.string(),verifyTls:w.boolean().optional()}),fp=w.object({serverUrl:w.string(),username:w.string(),password:w.string(),addressBookPath:w.string().optional()}),gp=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),yp=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),wp=w.object({provider:w.enum(["carddav","google","microsoft"]),carddav:fp.optional(),google:gp.optional(),microsoft:yp.optional()}),Tp=w.object({socketPath:w.string().optional(),host:w.string().optional(),verifyTls:w.boolean().optional()}),_p=w.object({clientId:w.string()}),kp=w.object({apiKey:w.string()}),Ep=w.object({gridName:w.string().optional(),gridUsageCt:w.coerce.number().optional(),gridLossCt:w.coerce.number().optional(),gridCapacityFee:w.coerce.number().optional(),gridMeterFee:w.coerce.number().optional()}),bp=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Sp=w.object({maxHistoryMessages:w.number().min(10).max(500).optional()}).optional(),vp=w.object({name:w.string(),secret:w.string(),watchId:w.string().optional(),chatId:w.string().optional(),platform:w.string().optional()}),$p=w.object({ebay:w.object({appId:w.string(),certId:w.string()}).optional()}),Ip=w.object({location:w.string().optional(),homeAddress:w.string().optional(),officeAddress:w.string().optional(),homeAssistant:w.object({entities:w.array(w.string()).optional(),domains:w.array(w.string()).optional()}).optional()}),Ap=w.object({enabled:w.boolean().optional(),schedule:w.enum(["morning_noon_evening","hourly","half_hourly"]).optional(),tier:w.enum(["fast","default"]).optional(),deduplicationHours:w.number().optional()}),Rp=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),maxAgeHours:w.coerce.number().optional(),verifyTls:w.boolean().optional()}),gi=w.object({name:w.string(),telegram:Lc,discord:Nc.optional(),whatsapp:Dc.optional(),matrix:Mc.optional(),signal:Oc.optional(),llm:Km,storage:Pc,logger:Uc,security:Fc,search:Vm.optional(),email:Ym.optional(),speech:Jm.optional(),calendar:tp.optional(),mcp:rp.optional(),codeSandbox:np.optional(),activeLearning:op.optional(),api:ip.optional(),codeAgents:up.optional(),proxmox:mp.optional(),unifi:pp.optional(),homeassistant:hp.optional(),contacts:wp.optional(),docker:Tp.optional(),bmw:_p.optional(),routing:kp.optional(),todo:bp.optional(),energy:Ep.optional(),marketplace:$p.optional(),briefing:Ip.optional(),reasoning:Ap.optional(),webhooks:w.array(vp).optional(),proxmoxBackup:Rp.optional(),conversation:Sp})});var wi,Ti=T(()=>{"use strict";wi={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 jc from"node:fs";import _i from"node:path";import{config as Bc}from"dotenv";import xp from"js-yaml";function Hc(l,e){let t={...l};for(let s of Object.keys(e)){let r=e[s],n=t[s];r!=null&&typeof r=="object"&&!Array.isArray(r)&&n!==null&&n!==void 0&&typeof n=="object"&&!Array.isArray(n)?t[s]=Hc(n,r):t[s]=r}return t}function Lp(l){let e=l.toLowerCase();return e==="true"?!0:e==="false"?!1:l}function Np(l){let e={...l};for(let[t,s]of Object.entries(Cp)){let r=process.env[t];if(r===void 0)continue;let n=e;for(let o=0;o<s.length-1;o++){let i=s[o];(n[i]===void 0||n[i]===null||typeof n[i]!="object")&&(n[i]={}),n[i]={...n[i]},n=n[i]}n[s[s.length-1]]=Lp(r)}return e}function ki(){Bc({override:!0})}function Dp(l){let e=_i.resolve(l),t=process.platform==="win32"?["C:\\Windows","C:\\Program Files","C:\\Program Files (x86)"]:["/etc","/bin","/proc","/sys","/dev","/boot"];for(let s of t)if(e.startsWith(s+_i.sep)||e.startsWith(s+"/")||e===s)throw new Error(`Storage path "${e}" is in forbidden directory ${s}`)}var Cp,pe,Wc=T(()=>{"use strict";yi();Ti();m(Hc,"deepMerge");Cp={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_TELEGRAM_ENABLED:["telegram","enabled"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_DISCORD_ENABLED:["discord","enabled"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_MATRIX_ENABLED:["matrix","enabled"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],ALFRED_SIGNAL_ENABLED:["signal","enabled"],ALFRED_ANTHROPIC_API_KEY:["llm","apiKey"],ALFRED_OPENAI_API_KEY:["llm","apiKey"],ALFRED_GOOGLE_API_KEY:["llm","apiKey"],ALFRED_OPENROUTER_API_KEY:["llm","apiKey"],ALFRED_OPENWEBUI_API_KEY:["llm","apiKey"],ALFRED_LLM_PROVIDER:["llm","provider"],ALFRED_LLM_MODEL:["llm","model"],ALFRED_LLM_BASE_URL:["llm","baseUrl"],ALFRED_LLM_STRONG_PROVIDER:["llm","strong","provider"],ALFRED_LLM_STRONG_MODEL:["llm","strong","model"],ALFRED_LLM_STRONG_API_KEY:["llm","strong","apiKey"],ALFRED_LLM_FAST_PROVIDER:["llm","fast","provider"],ALFRED_LLM_FAST_MODEL:["llm","fast","model"],ALFRED_LLM_FAST_API_KEY:["llm","fast","apiKey"],ALFRED_LLM_EMBEDDINGS_PROVIDER:["llm","embeddings","provider"],ALFRED_LLM_EMBEDDINGS_MODEL:["llm","embeddings","model"],ALFRED_LLM_EMBEDDINGS_API_KEY:["llm","embeddings","apiKey"],ALFRED_LLM_LOCAL_PROVIDER:["llm","local","provider"],ALFRED_LLM_LOCAL_MODEL:["llm","local","model"],ALFRED_LLM_LOCAL_BASE_URL:["llm","local","baseUrl"],ALFRED_STORAGE_PATH:["storage","path"],ALFRED_LOG_LEVEL:["logger","level"],ALFRED_OWNER_USER_ID:["security","ownerUserId"],ALFRED_SEARCH_PROVIDER:["search","provider"],ALFRED_SEARCH_API_KEY:["search","apiKey"],ALFRED_SEARCH_BASE_URL:["search","baseUrl"],ALFRED_EMAIL_PROVIDER:["email","provider"],ALFRED_EMAIL_USER:["email","auth","user"],ALFRED_EMAIL_PASS:["email","auth","pass"],ALFRED_MICROSOFT_EMAIL_CLIENT_ID:["email","microsoft","clientId"],ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:["email","microsoft","clientSecret"],ALFRED_MICROSOFT_EMAIL_TENANT_ID:["email","microsoft","tenantId"],ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:["email","microsoft","refreshToken"],ALFRED_SPEECH_PROVIDER:["speech","provider"],ALFRED_SPEECH_API_KEY:["speech","apiKey"],ALFRED_SPEECH_BASE_URL:["speech","baseUrl"],ALFRED_CALENDAR_PROVIDER:["calendar","provider"],ALFRED_CALDAV_SERVER_URL:["calendar","caldav","serverUrl"],ALFRED_CALDAV_USERNAME:["calendar","caldav","username"],ALFRED_CALDAV_PASSWORD:["calendar","caldav","password"],ALFRED_GOOGLE_CALENDAR_CLIENT_ID:["calendar","google","clientId"],ALFRED_GOOGLE_CALENDAR_CLIENT_SECRET:["calendar","google","clientSecret"],ALFRED_GOOGLE_CALENDAR_REFRESH_TOKEN:["calendar","google","refreshToken"],ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:["calendar","microsoft","clientId"],ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:["calendar","microsoft","clientSecret"],ALFRED_MICROSOFT_CALENDAR_TENANT_ID:["calendar","microsoft","tenantId"],ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:["calendar","microsoft","refreshToken"],ALFRED_FORGE_PROVIDER:["codeAgents","forge","provider"],ALFRED_FORGE_BASE_BRANCH:["codeAgents","forge","baseBranch"],ALFRED_GITHUB_TOKEN:["codeAgents","forge","github","token"],ALFRED_GITHUB_BASE_URL:["codeAgents","forge","github","baseUrl"],ALFRED_GITLAB_TOKEN:["codeAgents","forge","gitlab","token"],ALFRED_GITLAB_BASE_URL:["codeAgents","forge","gitlab","baseUrl"],ALFRED_PROXMOX_BASE_URL:["proxmox","baseUrl"],ALFRED_PROXMOX_TOKEN_ID:["proxmox","tokenId"],ALFRED_PROXMOX_TOKEN_SECRET:["proxmox","tokenSecret"],ALFRED_PROXMOX_VERIFY_TLS:["proxmox","verifyTls"],ALFRED_UNIFI_BASE_URL:["unifi","baseUrl"],ALFRED_UNIFI_API_KEY:["unifi","apiKey"],ALFRED_UNIFI_USERNAME:["unifi","username"],ALFRED_UNIFI_PASSWORD:["unifi","password"],ALFRED_UNIFI_SITE:["unifi","site"],ALFRED_UNIFI_VERIFY_TLS:["unifi","verifyTls"],ALFRED_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],ALFRED_HOMEASSISTANT_VERIFY_TLS:["homeassistant","verifyTls"],ALFRED_CONTACTS_PROVIDER:["contacts","provider"],ALFRED_CARDDAV_CONTACTS_SERVER_URL:["contacts","carddav","serverUrl"],ALFRED_CARDDAV_CONTACTS_USERNAME:["contacts","carddav","username"],ALFRED_CARDDAV_CONTACTS_PASSWORD:["contacts","carddav","password"],ALFRED_GOOGLE_CONTACTS_CLIENT_ID:["contacts","google","clientId"],ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET:["contacts","google","clientSecret"],ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN:["contacts","google","refreshToken"],ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:["contacts","microsoft","clientId"],ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:["contacts","microsoft","clientSecret"],ALFRED_MICROSOFT_CONTACTS_TENANT_ID:["contacts","microsoft","tenantId"],ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:["contacts","microsoft","refreshToken"],ALFRED_DOCKER_SOCKET_PATH:["docker","socketPath"],ALFRED_DOCKER_HOST:["docker","host"],ALFRED_DOCKER_VERIFY_TLS:["docker","verifyTls"],ALFRED_BMW_CLIENT_ID:["bmw","clientId"],ALFRED_ROUTING_API_KEY:["routing","apiKey"],ALFRED_MICROSOFT_TODO_CLIENT_ID:["todo","clientId"],ALFRED_MICROSOFT_TODO_CLIENT_SECRET:["todo","clientSecret"],ALFRED_MICROSOFT_TODO_TENANT_ID:["todo","tenantId"],ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:["todo","refreshToken"],ALFRED_ENERGY_GRID_NAME:["energy","gridName"],ALFRED_ENERGY_GRID_USAGE_CT:["energy","gridUsageCt"],ALFRED_ENERGY_GRID_LOSS_CT:["energy","gridLossCt"],ALFRED_ENERGY_GRID_CAPACITY_FEE:["energy","gridCapacityFee"],ALFRED_ENERGY_GRID_METER_FEE:["energy","gridMeterFee"],ALFRED_PBS_BASE_URL:["proxmoxBackup","baseUrl"],ALFRED_PBS_TOKEN_ID:["proxmoxBackup","tokenId"],ALFRED_PBS_TOKEN_SECRET:["proxmoxBackup","tokenSecret"],ALFRED_PBS_MAX_AGE_HOURS:["proxmoxBackup","maxAgeHours"],ALFRED_PBS_VERIFY_TLS:["proxmoxBackup","verifyTls"],ALFRED_EBAY_APP_ID:["marketplace","ebay","appId"],ALFRED_EBAY_CERT_ID:["marketplace","ebay","certId"],ALFRED_BRIEFING_LOCATION:["briefing","location"],ALFRED_BRIEFING_HOME_ADDRESS:["briefing","homeAddress"],ALFRED_BRIEFING_OFFICE_ADDRESS:["briefing","officeAddress"],ALFRED_REASONING_ENABLED:["reasoning","enabled"],ALFRED_REASONING_SCHEDULE:["reasoning","schedule"],ALFRED_REASONING_TIER:["reasoning","tier"]};m(Lp,"coerceEnvValue");m(Np,"applyEnvOverrides");m(ki,"reloadDotenv");pe=class{static{m(this,"ConfigLoader")}loadConfig(e){Bc();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=_i.resolve(t);if(jc.existsSync(r)){let g=jc.readFileSync(r,"utf-8"),f=xp.load(g);f&&typeof f=="object"&&(s=f)}let n=Hc(wi,s),o=Np(n),i=["strong","fast","embeddings","local"],a=o.llm;if(a&&"provider"in a&&i.some(f=>a[f]&&typeof a[f]=="object")){let f={};for(let[k,S]of Object.entries(a))!i.includes(k)&&k!=="default"&&(f[k]=S);let y={default:f};for(let k of i)a[k]&&(y[k]=a[k]);o.llm=y}let c=gi.parse(o),d=c.llm;d&&"provider"in d&&(c.llm={default:d});let u=c.llm;if(u&&typeof u=="object"){let g=u.apiKey??u.default?.apiKey;if(g)for(let f of["default","strong","fast","embeddings","local"]){let y=u[f];y&&!y.apiKey&&(y.apiKey=g)}}let p=c.email;if(p&&!("accounts"in p))c.email={accounts:[{name:"default",...p}]};else if(p&&"accounts"in p&&"microsoft"in p){let g=p.microsoft;if(g){let y=p.accounts.find(k=>k.provider==="microsoft");if(y){let k=y.microsoft??{};y.microsoft={...k,...g}}delete p.microsoft}}let h=c.storage;return h?.path&&typeof h.path=="string"&&Dp(h.path),c}};m(Dp,"validateStoragePath")});var tt=T(()=>{"use strict";yi();Ti();Wc()});import Ei from"pino";function tr(l,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=Ei.transport({target:"pino-pretty",options:{colorize:!0}});return Ei({name:l,level:t,redact:zc},r)}return Ei({name:l,level:t,redact:zc})}var zc,qc=T(()=>{"use strict";zc={paths:["**.apiKey","**.token","**.password","**.secret","**.accessToken","**.refreshToken","**.clientSecret","**.Authorization","**.authorization","**.bearer","**.credential","**.jwt","**.x-api-key","**.x-auth-token"],censor:"[REDACTED]"};m(tr,"createLogger")});import ly from"pino";var Gc=T(()=>{"use strict"});var bi=T(()=>{"use strict";qc();Gc()});var Vt,jn=T(()=>{"use strict";Vt=class{static{m(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
|
|
2
|
+
var Wc=Object.defineProperty;var m=(l,e)=>Wc(l,"name",{value:e,configurable:!0}),zc=(l=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(l,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):l)(function(l){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+l+'" is not supported')});var T=(l,e)=>()=>(l&&(e=l(l=0)),e);var fe=(l,e)=>{for(var t in e)Wc(l,t,{get:e[t],enumerable:!0})};import{z as w}from"zod";var Gc,Xc,Kc,Vc,Yc,Jc,Zc,Qc,Rt,dp,up,mp,qc,pp,hp,fp,gp,yp,wp,Tp,_p,kp,Ep,bp,Sp,vp,$p,Ip,Ap,Rp,xp,Cp,Np,Lp,Dp,Mp,Op,Pp,Up,Fp,jp,Bp,Hp,Wp,zp,qp,Gp,vi,$i=T(()=>{"use strict";Gc=w.object({token:w.string().optional(),enabled:w.boolean()}),Xc=w.object({token:w.string().optional(),enabled:w.boolean()}),Kc=w.object({enabled:w.boolean(),dataPath:w.string()}),Vc=w.object({homeserverUrl:w.string(),accessToken:w.string().optional(),userId:w.string().optional(),enabled:w.boolean()}),Yc=w.object({apiUrl:w.string(),phoneNumber:w.string().optional(),enabled:w.boolean()}),Jc=w.object({path:w.string()}),Zc=w.object({level:w.enum(["trace","debug","info","warn","error","fatal"]),pretty:w.boolean(),auditLogPath:w.string().optional()}),Qc=w.object({rulesPath:w.string(),defaultEffect:w.enum(["allow","deny"]),ownerUserId:w.string().optional()}),Rt=w.object({provider:w.enum(["anthropic","openai","openrouter","ollama","openwebui","google","mistral"]),apiKey:w.string().optional(),baseUrl:w.string().optional(),model:w.string(),temperature:w.number().optional(),maxTokens:w.number().optional()}),dp=w.object({default:Rt,strong:Rt.optional(),fast:Rt.optional(),embeddings:Rt.optional(),local:Rt.optional()}).passthrough(),up=w.union([Rt,dp]),mp=w.object({provider:w.enum(["brave","searxng","tavily","duckduckgo"]),apiKey:w.string().optional(),baseUrl:w.string().optional()}),qc=w.object({name:w.string().optional(),provider:w.enum(["imap-smtp","microsoft"]).optional(),imap:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),smtp:w.object({host:w.string(),port:w.number(),secure:w.boolean()}).optional(),auth:w.object({user:w.string(),pass:w.string()}).optional(),microsoft:w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}).optional()}),pp=w.union([w.object({accounts:w.array(qc)}),qc]),hp=w.object({provider:w.enum(["openai","groq","google"]),apiKey:w.string(),baseUrl:w.string().optional(),ttsEnabled:w.boolean().optional(),ttsModel:w.string().optional(),ttsVoice:w.string().optional()}),fp=w.object({serverUrl:w.string(),username:w.string(),password:w.string()}),gp=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),yp=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),wp=w.object({provider:w.enum(["caldav","google","microsoft"]),caldav:fp.optional(),google:gp.optional(),microsoft:yp.optional(),vorlauf:w.object({enabled:w.boolean(),minutesBefore:w.coerce.number().min(1).max(120).default(15),enrichWithRoute:w.boolean().optional(),enrichWithMemories:w.boolean().optional()}).optional()}),Tp=w.object({name:w.string(),command:w.string().optional(),args:w.array(w.string()).optional(),env:w.record(w.string()).optional(),url:w.string().optional()}),_p=w.object({servers:w.array(Tp)}),kp=w.object({enabled:w.boolean(),allowedLanguages:w.array(w.enum(["javascript","python"])).optional(),maxTimeoutMs:w.number().optional(),allowNetwork:w.boolean().optional()}),Ep=w.object({enabled:w.boolean().optional(),minMessageLength:w.number().optional(),minConfidence:w.number().min(0).max(1).optional(),maxExtractionsPerMinute:w.number().optional()}),bp=w.object({enabled:w.boolean(),port:w.coerce.number().int().min(1).max(65535),host:w.string(),token:w.string().optional(),corsOrigin:w.string().optional(),webUi:w.boolean().optional()}),Sp=w.object({name:w.string(),command:w.string(),argsTemplate:w.array(w.string()),promptVia:w.enum(["arg","stdin"]).default("arg"),env:w.record(w.string()).optional(),cwd:w.string().optional(),timeoutMs:w.number().max(9e5).optional()}),vp=w.object({token:w.string(),baseUrl:w.string().optional()}),$p=w.object({token:w.string(),baseUrl:w.string().optional()}),Ip=w.object({provider:w.enum(["github","gitlab"]),baseBranch:w.string().optional(),github:vp.optional(),gitlab:$p.optional()}),Ap=w.object({enabled:w.boolean(),agents:w.array(Sp),forge:Ip.optional()}),Rp=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),verifyTls:w.boolean().optional(),defaultNode:w.string().optional()}),xp=w.object({baseUrl:w.string(),apiKey:w.string().optional(),username:w.string().optional(),password:w.string().optional(),site:w.string().optional(),verifyTls:w.boolean().optional()}),Cp=w.object({baseUrl:w.string(),accessToken:w.string(),verifyTls:w.boolean().optional()}),Np=w.object({serverUrl:w.string(),username:w.string(),password:w.string(),addressBookPath:w.string().optional()}),Lp=w.object({clientId:w.string(),clientSecret:w.string(),refreshToken:w.string()}),Dp=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Mp=w.object({provider:w.enum(["carddav","google","microsoft"]),carddav:Np.optional(),google:Lp.optional(),microsoft:Dp.optional()}),Op=w.object({socketPath:w.string().optional(),host:w.string().optional(),verifyTls:w.boolean().optional()}),Pp=w.object({clientId:w.string()}),Up=w.object({apiKey:w.string()}),Fp=w.object({gridName:w.string().optional(),gridUsageCt:w.coerce.number().optional(),gridLossCt:w.coerce.number().optional(),gridCapacityFee:w.coerce.number().optional(),gridMeterFee:w.coerce.number().optional()}),jp=w.object({clientId:w.string(),clientSecret:w.string(),tenantId:w.string(),refreshToken:w.string()}),Bp=w.object({maxHistoryMessages:w.number().min(10).max(500).optional()}).optional(),Hp=w.object({name:w.string(),secret:w.string(),watchId:w.string().optional(),chatId:w.string().optional(),platform:w.string().optional()}),Wp=w.object({ebay:w.object({appId:w.string(),certId:w.string()}).optional()}),zp=w.object({location:w.string().optional(),homeAddress:w.string().optional(),officeAddress:w.string().optional(),homeAssistant:w.object({entities:w.array(w.string()).optional(),domains:w.array(w.string()).optional()}).optional()}),qp=w.object({enabled:w.boolean().optional(),schedule:w.enum(["morning_noon_evening","hourly","half_hourly"]).optional(),tier:w.enum(["fast","default"]).optional(),deduplicationHours:w.number().optional()}),Gp=w.object({baseUrl:w.string(),tokenId:w.string(),tokenSecret:w.string(),maxAgeHours:w.coerce.number().optional(),verifyTls:w.boolean().optional()}),vi=w.object({name:w.string(),telegram:Gc,discord:Xc.optional(),whatsapp:Kc.optional(),matrix:Vc.optional(),signal:Yc.optional(),llm:up,storage:Jc,logger:Zc,security:Qc,search:mp.optional(),email:pp.optional(),speech:hp.optional(),calendar:wp.optional(),mcp:_p.optional(),codeSandbox:kp.optional(),activeLearning:Ep.optional(),api:bp.optional(),codeAgents:Ap.optional(),proxmox:Rp.optional(),unifi:xp.optional(),homeassistant:Cp.optional(),contacts:Mp.optional(),docker:Op.optional(),bmw:Pp.optional(),routing:Up.optional(),todo:jp.optional(),energy:Fp.optional(),marketplace:Wp.optional(),briefing:zp.optional(),reasoning:qp.optional(),webhooks:w.array(Hp).optional(),proxmoxBackup:Gp.optional(),conversation:Bp})});var Ii,Ai=T(()=>{"use strict";Ii={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 el from"node:fs";import Ri from"node:path";import{config as tl}from"dotenv";import Xp from"js-yaml";function sl(l,e){let t={...l};for(let s of Object.keys(e)){let r=e[s],n=t[s];r!=null&&typeof r=="object"&&!Array.isArray(r)&&n!==null&&n!==void 0&&typeof n=="object"&&!Array.isArray(n)?t[s]=sl(n,r):t[s]=r}return t}function Vp(l){let e=l.toLowerCase();return e==="true"?!0:e==="false"?!1:l}function Yp(l){let e={...l};for(let[t,s]of Object.entries(Kp)){let r=process.env[t];if(r===void 0)continue;let n=e;for(let o=0;o<s.length-1;o++){let i=s[o];(n[i]===void 0||n[i]===null||typeof n[i]!="object")&&(n[i]={}),n[i]={...n[i]},n=n[i]}n[s[s.length-1]]=Vp(r)}return e}function xi(){tl({override:!0})}function Jp(l){let e=Ri.resolve(l),t=process.platform==="win32"?["C:\\Windows","C:\\Program Files","C:\\Program Files (x86)"]:["/etc","/bin","/proc","/sys","/dev","/boot"];for(let s of t)if(e.startsWith(s+Ri.sep)||e.startsWith(s+"/")||e===s)throw new Error(`Storage path "${e}" is in forbidden directory ${s}`)}var Kp,he,rl=T(()=>{"use strict";$i();Ai();m(sl,"deepMerge");Kp={ALFRED_TELEGRAM_TOKEN:["telegram","token"],ALFRED_TELEGRAM_ENABLED:["telegram","enabled"],ALFRED_DISCORD_TOKEN:["discord","token"],ALFRED_DISCORD_ENABLED:["discord","enabled"],ALFRED_MATRIX_HOMESERVER_URL:["matrix","homeserverUrl"],ALFRED_MATRIX_ACCESS_TOKEN:["matrix","accessToken"],ALFRED_MATRIX_USER_ID:["matrix","userId"],ALFRED_MATRIX_ENABLED:["matrix","enabled"],ALFRED_SIGNAL_API_URL:["signal","apiUrl"],ALFRED_SIGNAL_PHONE_NUMBER:["signal","phoneNumber"],ALFRED_SIGNAL_ENABLED:["signal","enabled"],ALFRED_ANTHROPIC_API_KEY:["llm","apiKey"],ALFRED_OPENAI_API_KEY:["llm","apiKey"],ALFRED_GOOGLE_API_KEY:["llm","apiKey"],ALFRED_OPENROUTER_API_KEY:["llm","apiKey"],ALFRED_OPENWEBUI_API_KEY:["llm","apiKey"],ALFRED_LLM_PROVIDER:["llm","provider"],ALFRED_LLM_MODEL:["llm","model"],ALFRED_LLM_BASE_URL:["llm","baseUrl"],ALFRED_LLM_STRONG_PROVIDER:["llm","strong","provider"],ALFRED_LLM_STRONG_MODEL:["llm","strong","model"],ALFRED_LLM_STRONG_API_KEY:["llm","strong","apiKey"],ALFRED_LLM_FAST_PROVIDER:["llm","fast","provider"],ALFRED_LLM_FAST_MODEL:["llm","fast","model"],ALFRED_LLM_FAST_API_KEY:["llm","fast","apiKey"],ALFRED_LLM_EMBEDDINGS_PROVIDER:["llm","embeddings","provider"],ALFRED_LLM_EMBEDDINGS_MODEL:["llm","embeddings","model"],ALFRED_LLM_EMBEDDINGS_API_KEY:["llm","embeddings","apiKey"],ALFRED_LLM_LOCAL_PROVIDER:["llm","local","provider"],ALFRED_LLM_LOCAL_MODEL:["llm","local","model"],ALFRED_LLM_LOCAL_BASE_URL:["llm","local","baseUrl"],ALFRED_STORAGE_PATH:["storage","path"],ALFRED_LOG_LEVEL:["logger","level"],ALFRED_OWNER_USER_ID:["security","ownerUserId"],ALFRED_SEARCH_PROVIDER:["search","provider"],ALFRED_SEARCH_API_KEY:["search","apiKey"],ALFRED_SEARCH_BASE_URL:["search","baseUrl"],ALFRED_EMAIL_PROVIDER:["email","provider"],ALFRED_EMAIL_USER:["email","auth","user"],ALFRED_EMAIL_PASS:["email","auth","pass"],ALFRED_MICROSOFT_EMAIL_CLIENT_ID:["email","microsoft","clientId"],ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:["email","microsoft","clientSecret"],ALFRED_MICROSOFT_EMAIL_TENANT_ID:["email","microsoft","tenantId"],ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:["email","microsoft","refreshToken"],ALFRED_SPEECH_PROVIDER:["speech","provider"],ALFRED_SPEECH_API_KEY:["speech","apiKey"],ALFRED_SPEECH_BASE_URL:["speech","baseUrl"],ALFRED_CALENDAR_PROVIDER:["calendar","provider"],ALFRED_CALDAV_SERVER_URL:["calendar","caldav","serverUrl"],ALFRED_CALDAV_USERNAME:["calendar","caldav","username"],ALFRED_CALDAV_PASSWORD:["calendar","caldav","password"],ALFRED_GOOGLE_CALENDAR_CLIENT_ID:["calendar","google","clientId"],ALFRED_GOOGLE_CALENDAR_CLIENT_SECRET:["calendar","google","clientSecret"],ALFRED_GOOGLE_CALENDAR_REFRESH_TOKEN:["calendar","google","refreshToken"],ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:["calendar","microsoft","clientId"],ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:["calendar","microsoft","clientSecret"],ALFRED_MICROSOFT_CALENDAR_TENANT_ID:["calendar","microsoft","tenantId"],ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:["calendar","microsoft","refreshToken"],ALFRED_FORGE_PROVIDER:["codeAgents","forge","provider"],ALFRED_FORGE_BASE_BRANCH:["codeAgents","forge","baseBranch"],ALFRED_GITHUB_TOKEN:["codeAgents","forge","github","token"],ALFRED_GITHUB_BASE_URL:["codeAgents","forge","github","baseUrl"],ALFRED_GITLAB_TOKEN:["codeAgents","forge","gitlab","token"],ALFRED_GITLAB_BASE_URL:["codeAgents","forge","gitlab","baseUrl"],ALFRED_PROXMOX_BASE_URL:["proxmox","baseUrl"],ALFRED_PROXMOX_TOKEN_ID:["proxmox","tokenId"],ALFRED_PROXMOX_TOKEN_SECRET:["proxmox","tokenSecret"],ALFRED_PROXMOX_VERIFY_TLS:["proxmox","verifyTls"],ALFRED_UNIFI_BASE_URL:["unifi","baseUrl"],ALFRED_UNIFI_API_KEY:["unifi","apiKey"],ALFRED_UNIFI_USERNAME:["unifi","username"],ALFRED_UNIFI_PASSWORD:["unifi","password"],ALFRED_UNIFI_SITE:["unifi","site"],ALFRED_UNIFI_VERIFY_TLS:["unifi","verifyTls"],ALFRED_HOMEASSISTANT_URL:["homeassistant","baseUrl"],ALFRED_HOMEASSISTANT_TOKEN:["homeassistant","accessToken"],ALFRED_HOMEASSISTANT_VERIFY_TLS:["homeassistant","verifyTls"],ALFRED_CONTACTS_PROVIDER:["contacts","provider"],ALFRED_CARDDAV_CONTACTS_SERVER_URL:["contacts","carddav","serverUrl"],ALFRED_CARDDAV_CONTACTS_USERNAME:["contacts","carddav","username"],ALFRED_CARDDAV_CONTACTS_PASSWORD:["contacts","carddav","password"],ALFRED_GOOGLE_CONTACTS_CLIENT_ID:["contacts","google","clientId"],ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET:["contacts","google","clientSecret"],ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN:["contacts","google","refreshToken"],ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:["contacts","microsoft","clientId"],ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:["contacts","microsoft","clientSecret"],ALFRED_MICROSOFT_CONTACTS_TENANT_ID:["contacts","microsoft","tenantId"],ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:["contacts","microsoft","refreshToken"],ALFRED_DOCKER_SOCKET_PATH:["docker","socketPath"],ALFRED_DOCKER_HOST:["docker","host"],ALFRED_DOCKER_VERIFY_TLS:["docker","verifyTls"],ALFRED_BMW_CLIENT_ID:["bmw","clientId"],ALFRED_ROUTING_API_KEY:["routing","apiKey"],ALFRED_MICROSOFT_TODO_CLIENT_ID:["todo","clientId"],ALFRED_MICROSOFT_TODO_CLIENT_SECRET:["todo","clientSecret"],ALFRED_MICROSOFT_TODO_TENANT_ID:["todo","tenantId"],ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:["todo","refreshToken"],ALFRED_ENERGY_GRID_NAME:["energy","gridName"],ALFRED_ENERGY_GRID_USAGE_CT:["energy","gridUsageCt"],ALFRED_ENERGY_GRID_LOSS_CT:["energy","gridLossCt"],ALFRED_ENERGY_GRID_CAPACITY_FEE:["energy","gridCapacityFee"],ALFRED_ENERGY_GRID_METER_FEE:["energy","gridMeterFee"],ALFRED_PBS_BASE_URL:["proxmoxBackup","baseUrl"],ALFRED_PBS_TOKEN_ID:["proxmoxBackup","tokenId"],ALFRED_PBS_TOKEN_SECRET:["proxmoxBackup","tokenSecret"],ALFRED_PBS_MAX_AGE_HOURS:["proxmoxBackup","maxAgeHours"],ALFRED_PBS_VERIFY_TLS:["proxmoxBackup","verifyTls"],ALFRED_EBAY_APP_ID:["marketplace","ebay","appId"],ALFRED_EBAY_CERT_ID:["marketplace","ebay","certId"],ALFRED_BRIEFING_LOCATION:["briefing","location"],ALFRED_BRIEFING_HOME_ADDRESS:["briefing","homeAddress"],ALFRED_BRIEFING_OFFICE_ADDRESS:["briefing","officeAddress"],ALFRED_REASONING_ENABLED:["reasoning","enabled"],ALFRED_REASONING_SCHEDULE:["reasoning","schedule"],ALFRED_REASONING_TIER:["reasoning","tier"]};m(Vp,"coerceEnvValue");m(Yp,"applyEnvOverrides");m(xi,"reloadDotenv");he=class{static{m(this,"ConfigLoader")}loadConfig(e){tl();let t=e??process.env.ALFRED_CONFIG_PATH??"./config/default.yml",s={},r=Ri.resolve(t);if(el.existsSync(r)){let f=el.readFileSync(r,"utf-8"),g=Xp.load(f);g&&typeof g=="object"&&(s=g)}let n=sl(Ii,s),o=Yp(n),i=["strong","fast","embeddings","local"],a=o.llm;if(a&&"provider"in a&&i.some(g=>a[g]&&typeof a[g]=="object")){let g={};for(let[_,S]of Object.entries(a))!i.includes(_)&&_!=="default"&&(g[_]=S);let y={default:g};for(let _ of i)a[_]&&(y[_]=a[_]);o.llm=y}let c=vi.parse(o),d=c.llm;d&&"provider"in d&&(c.llm={default:d});let u=c.llm;if(u&&typeof u=="object"){let f=u.apiKey??u.default?.apiKey;if(f)for(let g of["default","strong","fast","embeddings","local"]){let y=u[g];y&&!y.apiKey&&(y.apiKey=f)}}let p=c.email;if(p&&!("accounts"in p))c.email={accounts:[{name:"default",...p}]};else if(p&&"accounts"in p&&"microsoft"in p){let f=p.microsoft;if(f){let y=p.accounts.find(_=>_.provider==="microsoft");if(y){let _=y.microsoft??{};y.microsoft={..._,...f}}delete p.microsoft}}let h=c.storage;return h?.path&&typeof h.path=="string"&&Jp(h.path),c}};m(Jp,"validateStoragePath")});var rt=T(()=>{"use strict";$i();Ai();rl()});import Ci from"pino";function ir(l,e){let t=e??process.env.LOG_LEVEL??"info";if(t==="debug"||t==="trace"||process.env.NODE_ENV!=="production"){let r=Ci.transport({target:"pino-pretty",options:{colorize:!0}});return Ci({name:l,level:t,redact:nl},r)}return Ci({name:l,level:t,redact:nl})}var nl,ol=T(()=>{"use strict";nl={paths:["**.apiKey","**.token","**.password","**.secret","**.accessToken","**.refreshToken","**.clientSecret","**.Authorization","**.authorization","**.bearer","**.credential","**.jwt","**.x-api-key","**.x-auth-token"],censor:"[REDACTED]"};m(ir,"createLogger")});import Ry from"pino";var il=T(()=>{"use strict"});var Ni=T(()=>{"use strict";ol();il()});var Jt,Xn=T(()=>{"use strict";Jt=class{static{m(this,"Migrator")}db;constructor(e){this.db=e,this.ensureMigrationsTable()}ensureMigrationsTable(){this.db.exec(`
|
|
3
3
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
4
4
|
version INTEGER PRIMARY KEY,
|
|
5
5
|
description TEXT,
|
|
6
6
|
applied_at TEXT NOT NULL
|
|
7
7
|
)
|
|
8
|
-
`)}getCurrentVersion(){return this.db.prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}migrate(e){let t=[...e].sort((r,n)=>r.version-n.version),s=this.getCurrentVersion();for(let r of t){if(r.version<=s)continue;this.db.transaction(()=>{r.up(this.db),this.db.prepare("INSERT INTO _migrations (version, description, applied_at) VALUES (?, ?, ?)").run(r.version,r.description,new Date().toISOString())})()}}getAppliedMigrations(){return this.db.prepare("SELECT version, applied_at FROM _migrations ORDER BY version ASC").all().map(t=>({version:t.version,appliedAt:t.applied_at}))}}});var
|
|
8
|
+
`)}getCurrentVersion(){return this.db.prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}migrate(e){let t=[...e].sort((r,n)=>r.version-n.version),s=this.getCurrentVersion();for(let r of t){if(r.version<=s)continue;this.db.transaction(()=>{r.up(this.db),this.db.prepare("INSERT INTO _migrations (version, description, applied_at) VALUES (?, ?, ?)").run(r.version,r.description,new Date().toISOString())})()}}getAppliedMigrations(){return this.db.prepare("SELECT version, applied_at FROM _migrations ORDER BY version ASC").all().map(t=>({version:t.version,appliedAt:t.applied_at}))}}});var Li,Di=T(()=>{"use strict";Xn();Li=[{version:1,description:"Initial schema \u2014 conversations, messages, users, audit_log",up(l){}},{version:2,description:"Add plugin_skills table for tracking loaded external plugins",up(l){l.exec(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS plugin_skills (
|
|
10
10
|
name TEXT PRIMARY KEY,
|
|
11
11
|
file_path TEXT NOT NULL,
|
|
@@ -359,7 +359,20 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
359
359
|
ALTER TABLE background_tasks ADD COLUMN checkpoint_at TEXT DEFAULT NULL;
|
|
360
360
|
ALTER TABLE background_tasks ADD COLUMN resume_count INTEGER NOT NULL DEFAULT 0;
|
|
361
361
|
ALTER TABLE background_tasks ADD COLUMN max_duration_hours REAL DEFAULT NULL;
|
|
362
|
-
`)}},{version:26,description:"Memory TTL \u2014 optional expiration for short-lived memories",up(l){l.exec("ALTER TABLE memories ADD COLUMN expires_at TEXT DEFAULT NULL"),l.exec("CREATE INDEX idx_memories_expires ON memories(expires_at) WHERE expires_at IS NOT NULL")}}
|
|
362
|
+
`)}},{version:26,description:"Memory TTL \u2014 optional expiration for short-lived memories",up(l){l.exec("ALTER TABLE memories ADD COLUMN expires_at TEXT DEFAULT NULL"),l.exec("CREATE INDEX idx_memories_expires ON memories(expires_at) WHERE expires_at IS NOT NULL")}},{version:27,description:"Watch Chains \u2014 trigger_watch_id for chained watch execution",up(l){l.exec("ALTER TABLE watches ADD COLUMN trigger_watch_id TEXT DEFAULT NULL")}},{version:28,description:"Feedback Loop \u2014 feedback_events table for rejection/correction tracking",up(l){l.exec(`
|
|
363
|
+
CREATE TABLE IF NOT EXISTS feedback_events (
|
|
364
|
+
id TEXT PRIMARY KEY,
|
|
365
|
+
user_id TEXT NOT NULL,
|
|
366
|
+
feedback_type TEXT NOT NULL,
|
|
367
|
+
source_id TEXT,
|
|
368
|
+
context_key TEXT NOT NULL,
|
|
369
|
+
description TEXT NOT NULL,
|
|
370
|
+
raw_context TEXT,
|
|
371
|
+
occurred_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
372
|
+
);
|
|
373
|
+
CREATE INDEX IF NOT EXISTS idx_feedback_events_user_key ON feedback_events(user_id, context_key, occurred_at DESC);
|
|
374
|
+
CREATE INDEX IF NOT EXISTS idx_feedback_events_user_type ON feedback_events(user_id, feedback_type, occurred_at DESC);
|
|
375
|
+
`)}}]});import al from"better-sqlite3";import ar from"node:fs";import Kn from"node:path";var xt,cl=T(()=>{"use strict";Xn();Di();xt=class{static{m(this,"Database")}db;constructor(e){let t=Kn.dirname(e);ar.mkdirSync(t,{recursive:!0});let s=ar.statSync(e,{throwIfNoEntry:!1});if(s&&s.size>1e5){let r=Kn.join(Kn.dirname(e),"backups");ar.mkdirSync(r,{recursive:!0});let n=Kn.join(r,`alfred-${new Date().toISOString().slice(0,10)}.db`);if(!ar.existsSync(n))try{let o=new al(e,{readonly:!0});try{o.pragma("wal_checkpoint(TRUNCATE)")}catch{}o.close(),ar.copyFileSync(e,n)}catch(o){console.warn(`[Database] Backup failed: ${o instanceof Error?o.message:String(o)}`)}}this.db=new al(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(`
|
|
363
376
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
364
377
|
id TEXT PRIMARY KEY,
|
|
365
378
|
platform TEXT NOT NULL,
|
|
@@ -409,23 +422,23 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
409
422
|
|
|
410
423
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_platform
|
|
411
424
|
ON users(platform, platform_user_id);
|
|
412
|
-
`)}runMigrations(){new
|
|
425
|
+
`)}runMigrations(){new Jt(this.db).migrate(Li)}getDb(){return this.db}close(){this.db.close()}}});import ll from"node:crypto";var cr,dl=T(()=>{"use strict";cr=class{static{m(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),n={id:ll.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
|
|
413
426
|
INSERT INTO conversations (id, platform, chat_id, user_id, created_at, updated_at)
|
|
414
427
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
415
|
-
`).run(n.id,n.platform,n.chatId,n.userId,n.createdAt,n.updatedAt),n}findById(e){let t=this.db.prepare("SELECT * FROM conversations WHERE id = ?").get(e);if(t)return this.mapRow(t)}findByPlatformChat(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND chat_id = ?").get(e,t);if(s)return this.mapRow(s)}findByPlatformAndUser(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND user_id = ? ORDER BY updated_at DESC LIMIT 1").get(e,t);if(s)return this.mapRow(s)}addMessage(e,t,s,r){let n={id:
|
|
428
|
+
`).run(n.id,n.platform,n.chatId,n.userId,n.createdAt,n.updatedAt),n}findById(e){let t=this.db.prepare("SELECT * FROM conversations WHERE id = ?").get(e);if(t)return this.mapRow(t)}findByPlatformChat(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND chat_id = ?").get(e,t);if(s)return this.mapRow(s)}findByPlatformAndUser(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND user_id = ? ORDER BY updated_at DESC LIMIT 1").get(e,t);if(s)return this.mapRow(s)}addMessage(e,t,s,r){let n={id:ll.randomUUID(),conversationId:e,role:t,content:s,toolCalls:r,createdAt:new Date().toISOString()};return this.db.prepare(`
|
|
416
429
|
INSERT INTO messages (id, conversation_id, role, content, tool_calls, created_at)
|
|
417
430
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
418
431
|
`).run(n.id,n.conversationId,n.role,n.content,n.toolCalls??null,n.createdAt),n}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(`
|
|
419
432
|
DELETE FROM messages WHERE conversation_id = ? AND id NOT IN (
|
|
420
433
|
SELECT id FROM messages WHERE conversation_id = ? ORDER BY created_at DESC LIMIT ?
|
|
421
434
|
)
|
|
422
|
-
`).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
|
|
435
|
+
`).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 Zp from"node:crypto";var lr,ul=T(()=>{"use strict";lr=class{static{m(this,"UserRepository")}db;constructor(e){this.db=e}findOrCreate(e,t,s,r){let n=this.db.prepare("SELECT * FROM users WHERE platform = ? AND platform_user_id = ?").get(e,t);if(n)return this.mapRow(n);let o=new Date().toISOString(),i={id:Zp.randomUUID(),platform:e,platformUserId:t,username:s,displayName:r,createdAt:o,updatedAt:o};return this.db.prepare(`
|
|
423
436
|
INSERT INTO users (id, platform, platform_user_id, username, display_name, created_at, updated_at)
|
|
424
437
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
425
|
-
`).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
|
|
438
|
+
`).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,ml=T(()=>{"use strict";Ct=class{static{m(this,"AuditRepository")}db;constructor(e){this.db=e}log(e){this.db.prepare(`
|
|
426
439
|
INSERT INTO audit_log (id, timestamp, user_id, action, risk_level, rule_id, effect, platform, chat_id, context)
|
|
427
440
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
428
|
-
`).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return s.push(n),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}cleanup(e=90){return this.db.prepare("DELETE FROM audit_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}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
|
|
441
|
+
`).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return s.push(n),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}cleanup(e=90){return this.db.prepare("DELETE FROM audit_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}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 Qp}from"node:crypto";var dr,pl=T(()=>{"use strict";dr=class{static{m(this,"MemoryRepository")}db;constructor(e){this.db=e}save(e,t,s,r="general"){return this.saveWithMetadata(e,t,s,r,"general",1,"manual")}saveWithMetadata(e,t,s,r,n,o,i){let a=new Date().toISOString(),c=Qp();this.db.prepare(`INSERT INTO memories (id, user_id, key, value, category, type, confidence, source, created_at, updated_at)
|
|
429
442
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
430
443
|
ON CONFLICT(user_id, key) DO UPDATE SET
|
|
431
444
|
value = excluded.value,
|
|
@@ -434,13 +447,13 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
434
447
|
confidence = excluded.confidence,
|
|
435
448
|
source = excluded.source,
|
|
436
449
|
updated_at = excluded.updated_at,
|
|
437
|
-
expires_at = NULL`).run(c,e,t,s,r,n,o,i,a,a);let d=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);return this.mapRow(d)}saveWithTTL(e,t,s,r,n){let o=this.saveWithMetadata(e,t,s,r,"general",1,"manual"),i=new Date(Date.now()+n*6e4).toISOString();return this.db.prepare("UPDATE memories SET expires_at = ? WHERE user_id = ? AND key = ?").run(i,e,t),o.expiresAt=i,o}cleanupExpired(){return this.db.prepare("DELETE FROM memories WHERE expires_at IS NOT NULL AND expires_at < datetime('now')").run().changes}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(n=>this.mapRow(n))}keywordSearch(e,t,s=20){let r=t.toLowerCase().split(/\s+/).filter(c=>c.length>=2);if(r.length===0)return[];let n=r.map(()=>"(LOWER(key) LIKE ? OR LOWER(value) LIKE ?)").join(" OR "),o=[e];for(let c of r)o.push(`%${c}%`,`%${c}%`);let a=this.db.prepare(`SELECT * FROM memories WHERE user_id = ? AND (${n}) ORDER BY updated_at DESC`).all(...o).map(c=>{let d=this.mapRow(c),u=`${d.key} ${d.value}`.toLowerCase(),p=0;for(let h of r)u.includes(h)&&(p+=1);return{entry:d,score:p/r.length}});return a.sort((c,d)=>d.score-c.score),a.slice(0,s).map(c=>c.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(o=>this.mapRow(o))}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,expiresAt:e.expires_at??null}}}});import{randomUUID as
|
|
450
|
+
expires_at = NULL`).run(c,e,t,s,r,n,o,i,a,a);let d=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);return this.mapRow(d)}saveWithTTL(e,t,s,r,n){let o=this.saveWithMetadata(e,t,s,r,"general",1,"manual"),i=new Date(Date.now()+n*6e4).toISOString();return this.db.prepare("UPDATE memories SET expires_at = ? WHERE user_id = ? AND key = ?").run(i,e,t),o.expiresAt=i,o}cleanupExpired(){return this.db.prepare("DELETE FROM memories WHERE expires_at IS NOT NULL AND expires_at < datetime('now')").run().changes}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(n=>this.mapRow(n))}keywordSearch(e,t,s=20){let r=t.toLowerCase().split(/\s+/).filter(c=>c.length>=2);if(r.length===0)return[];let n=r.map(()=>"(LOWER(key) LIKE ? OR LOWER(value) LIKE ?)").join(" OR "),o=[e];for(let c of r)o.push(`%${c}%`,`%${c}%`);let a=this.db.prepare(`SELECT * FROM memories WHERE user_id = ? AND (${n}) ORDER BY updated_at DESC`).all(...o).map(c=>{let d=this.mapRow(c),u=`${d.key} ${d.value}`.toLowerCase(),p=0;for(let h of r)u.includes(h)&&(p+=1);return{entry:d,score:p/r.length}});return a.sort((c,d)=>d.score-c.score),a.slice(0,s).map(c=>c.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(o=>this.mapRow(o))}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,expiresAt:e.expires_at??null}}}});import{randomUUID as eh}from"node:crypto";var ur,hl=T(()=>{"use strict";ur=class{static{m(this,"ReminderRepository")}db;constructor(e){this.db=e}create(e,t,s,r,n){let o={id:eh(),userId:e,platform:t,chatId:s,message:r,triggerAt:n.toISOString(),createdAt:new Date().toISOString(),fired:!1};return this.db.prepare(`
|
|
438
451
|
INSERT INTO reminders (id, user_id, platform, chat_id, message, trigger_at, created_at, fired)
|
|
439
452
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
440
|
-
`).run(o.id,o.userId,o.platform,o.chatId,o.message,o.triggerAt,o.createdAt,0),o}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
|
|
453
|
+
`).run(o.id,o.userId,o.platform,o.chatId,o.message,o.triggerAt,o.createdAt,0),o}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 th}from"node:crypto";var mr,fl=T(()=>{"use strict";mr=class{static{m(this,"NoteRepository")}db;constructor(e){this.db=e}save(e,t,s){let r=new Date().toISOString(),n=th();return this.db.prepare("INSERT INTO notes (id, user_id, title, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").run(n,e,t,s,r,r),{id:n,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(n=>this.mapRow(n))}update(e,t,s){let r=this.getById(e);if(!r)return;let n=new Date().toISOString(),o=t??r.title,i=s??r.content;return this.db.prepare("UPDATE notes SET title = ?, content = ?, updated_at = ? WHERE id = ?").run(o,i,n,e),{...r,title:o,content:i,updatedAt:n}}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 sh}from"node:crypto";var pr,gl=T(()=>{"use strict";pr=class{static{m(this,"EmbeddingRepository")}db;constructor(e){this.db=e}store(e){let t=sh(),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 rh from"node:crypto";var hr,yl=T(()=>{"use strict";hr=class{static{m(this,"LinkTokenRepository")}db;constructor(e){this.db=e}create(e,t){for(let s=0;s<5;s++){let r={id:rh.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(`
|
|
441
454
|
INSERT INTO link_tokens (id, code, user_id, platform, created_at, expires_at)
|
|
442
455
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
443
|
-
`).run(r.id,r.code,r.userId,r.platform,r.createdAt,r.expiresAt),r}catch(n){if(!(n instanceof Error?n.message:"").includes("UNIQUE")||s===4)throw n}}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
|
|
456
|
+
`).run(r.id,r.code,r.userId,r.platform,r.createdAt,r.expiresAt),r}catch(n){if(!(n instanceof Error?n.message:"").includes("UNIQUE")||s===4)throw n}}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 nh}from"node:crypto";var fr,wl=T(()=>{"use strict";fr=class{static{m(this,"BackgroundTaskRepository")}db;constructor(e){this.db=e}create(e,t,s,r,n,o){let i={id:nh(),userId:e,platform:t,chatId:s,description:r,skillName:n,skillInput:o,status:"pending",createdAt:new Date().toISOString()};return this.db.prepare(`
|
|
444
457
|
INSERT INTO background_tasks (id, user_id, platform, chat_id, description, skill_name, skill_input, status, created_at)
|
|
445
458
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
446
459
|
`).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 n=new Date().toISOString(),o=null,i=null,a=null;t==="running"&&(o=n),(t==="completed"||t==="failed"||t==="cancelled")&&(i=n),t==="checkpointed"&&(a=n),this.db.prepare(`
|
|
@@ -471,18 +484,18 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
471
484
|
UPDATE background_tasks
|
|
472
485
|
SET status = 'cancelled', completed_at = datetime('now')
|
|
473
486
|
WHERE id = ? AND status IN ('pending', 'running', 'checkpointed', 'resuming')
|
|
474
|
-
`).run(e)}updatePersistentConfig(e,t){this.db.prepare("UPDATE background_tasks SET max_duration_hours = ? WHERE id = ?").run(t,e)}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at,agentState:e.agent_state,checkpointAt:e.checkpoint_at,resumeCount:e.resume_count??0,maxDurationHours:e.max_duration_hours}}}});var
|
|
487
|
+
`).run(e)}updatePersistentConfig(e,t){this.db.prepare("UPDATE background_tasks SET max_duration_hours = ? WHERE id = ?").run(t,e)}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at,agentState:e.agent_state,checkpointAt:e.checkpoint_at,resumeCount:e.resume_count??0,maxDurationHours:e.max_duration_hours}}}});var Tl=T(()=>{"use strict"});var _l=T(()=>{"use strict"});var kl=T(()=>{"use strict"});var El=T(()=>{"use strict"});var bl=T(()=>{"use strict"});var Sl=T(()=>{"use strict"});var vl=T(()=>{"use strict"});var $l=T(()=>{"use strict"});function oh(l,e){let t=l.trim().split(/\s+/);if(t.length!==5)return!1;let s=e.getMinutes(),r=e.getHours(),n=e.getDate(),o=e.getMonth()+1,i=e.getDay();return Zt(t[0],s)&&Zt(t[1],r)&&Zt(t[2],n)&&Zt(t[3],o)&&Zt(t[4],i)}function Vn(l,e,t=1440*6e4){let s=e.getTime()+t,r=new Date(e);for(r.setSeconds(0,0),r.setMinutes(r.getMinutes()+1);r.getTime()<=s;){if(oh(l,r))return r;r.setMinutes(r.getMinutes()+1)}return null}function Zt(l,e){if(l.includes(","))return l.split(",").some(n=>Zt(n.trim(),e));if(l==="*")return!0;let t=/^\*\/(\d+)$/.exec(l);if(t){let n=parseInt(t[1],10);return n>0&&e%n===0}let s=/^(\d+)-(\d+)(?:\/(\d+))?$/.exec(l);if(s){let n=parseInt(s[1],10),o=parseInt(s[2],10),i=s[3]?parseInt(s[3],10):1;return e<n||e>o?!1:i>0&&(e-n)%i===0}let r=parseInt(l,10);return isNaN(r)?!1:e===r}var Il=T(()=>{"use strict";m(oh,"matchesCron");m(Vn,"getNextCronDate");m(Zt,"matchCronField")});var Mi=T(()=>{"use strict";Tl();_l();kl();El();bl();Sl();vl();$l();Il()});import{randomUUID as ih}from"node:crypto";var gr,Al=T(()=>{"use strict";Mi();gr=class{static{m(this,"ScheduledActionRepository")}db;constructor(e){this.db=e}countEnabled(){return this.db.prepare("SELECT COUNT(*) as cnt FROM scheduled_actions WHERE enabled = 1").get().cnt}create(e){let t=new Date().toISOString(),s=ih(),r=this.calculateInitialNextRun(e.scheduleType,e.scheduleValue);return this.db.prepare(`
|
|
475
488
|
INSERT INTO scheduled_actions
|
|
476
489
|
(id, user_id, platform, chat_id, name, description, schedule_type, schedule_value,
|
|
477
490
|
skill_name, skill_input, prompt_template, enabled, next_run_at, created_at)
|
|
478
491
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
479
|
-
`).run(s,e.userId,e.platform,e.chatId,e.name,e.description,e.scheduleType,e.scheduleValue,e.skillName,e.skillInput,e.promptTemplate??null,r,t),{id:s,userId:e.userId,platform:e.platform,chatId:e.chatId,name:e.name,description:e.description,scheduleType:e.scheduleType,scheduleValue:e.scheduleValue,skillName:e.skillName,skillInput:e.skillInput,promptTemplate:e.promptTemplate,enabled:!0,nextRunAt:r??void 0,createdAt:t}}findById(e){let t=this.db.prepare("SELECT * FROM scheduled_actions WHERE id = ?").get(e);return t?this.mapRow(t):void 0}getByUser(e){return this.db.prepare("SELECT * FROM scheduled_actions WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapRow(s))}getDue(){let e=new Date().toISOString();return this.db.prepare(`SELECT * FROM scheduled_actions
|
|
492
|
+
`).run(s,e.userId,e.platform,e.chatId,e.name,e.description,e.scheduleType,e.scheduleValue,e.skillName,e.skillInput,e.promptTemplate??null,r,t),{id:s,userId:e.userId,platform:e.platform,chatId:e.chatId,name:e.name,description:e.description,scheduleType:e.scheduleType,scheduleValue:e.scheduleValue,skillName:e.skillName,skillInput:e.skillInput,promptTemplate:e.promptTemplate,enabled:!0,nextRunAt:r??void 0,createdAt:t}}findById(e){let t=this.db.prepare("SELECT * FROM scheduled_actions WHERE id = ?").get(e);return t?this.mapRow(t):void 0}getAll(){return this.db.prepare("SELECT * FROM scheduled_actions WHERE enabled = 1 ORDER BY next_run_at ASC").all().map(t=>this.mapRow(t))}getByUser(e){return this.db.prepare("SELECT * FROM scheduled_actions WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapRow(s))}getDue(){let e=new Date().toISOString();return this.db.prepare(`SELECT * FROM scheduled_actions
|
|
480
493
|
WHERE enabled = 1 AND next_run_at IS NOT NULL AND next_run_at <= ?
|
|
481
494
|
ORDER BY next_run_at ASC`).all(e).map(s=>this.mapRow(s))}updateLastRun(e,t,s){this.db.prepare(`
|
|
482
495
|
UPDATE scheduled_actions
|
|
483
496
|
SET last_run_at = ?, next_run_at = ?
|
|
484
497
|
WHERE id = ?
|
|
485
|
-
`).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
|
|
498
|
+
`).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 Vn(t,s)?.toISOString()??null;default:return null}}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as Rl}from"node:crypto";var yr,xl=T(()=>{"use strict";yr=class{static{m(this,"DocumentRepository")}db;constructor(e){this.db=e}createDocument(e,t,s,r,n){let o=Rl(),i=new Date().toISOString();return this.db.prepare("INSERT INTO documents (id, user_id, filename, mime_type, size_bytes, chunk_count, content_hash, created_at) VALUES (?, ?, ?, ?, ?, 0, ?, ?)").run(o,e,t,s,r,n??null,i),{id:o,userId:e,filename:t,mimeType:s,sizeBytes:r,chunkCount:0,contentHash:n,createdAt:i}}findByContentHash(e,t){let s=this.db.prepare("SELECT * FROM documents WHERE user_id = ? AND content_hash = ? ORDER BY chunk_count DESC LIMIT 1").get(e,t);return s?this.mapDocumentRow(s):void 0}updateChunkCount(e,t){this.db.prepare("UPDATE documents SET chunk_count = ? WHERE id = ?").run(t,e)}addChunk(e,t,s,r){let n=Rl(),o=new Date().toISOString();return this.db.prepare("INSERT INTO document_chunks (id, document_id, chunk_index, content, embedding_id, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(n,e,t,s,r??null,o),{id:n,documentId:e,chunkIndex:t,content:s,embeddingId:r,createdAt:o}}getDocument(e){let t=this.db.prepare("SELECT * FROM documents WHERE id = ?").get(e);return t?this.mapDocumentRow(t):void 0}getChunks(e){return this.db.prepare("SELECT * FROM document_chunks WHERE document_id = ? ORDER BY chunk_index ASC").all(e).map(s=>this.mapChunkRow(s))}listByUser(e){return this.db.prepare("SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapDocumentRow(s))}deleteDocument(e){this.db.transaction(()=>{let s=this.db.prepare("SELECT embedding_id FROM document_chunks WHERE document_id = ? AND embedding_id IS NOT NULL").all(e);if(s.length>0){let r=s.map(o=>o.embedding_id),n=r.map(()=>"?").join(", ");this.db.prepare(`DELETE FROM embeddings WHERE id IN (${n})`).run(...r)}this.db.prepare("DELETE FROM document_chunks WHERE document_id = ?").run(e),this.db.prepare("DELETE FROM documents WHERE id = ?").run(e)})()}getChunksByEmbeddingIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(", ");return this.db.prepare(`SELECT * FROM document_chunks WHERE embedding_id IN (${t}) ORDER BY chunk_index ASC`).all(...e).map(r=>this.mapChunkRow(r))}mapDocumentRow(e){return{id:e.id,userId:e.user_id,filename:e.filename,mimeType:e.mime_type,sizeBytes:e.size_bytes,chunkCount:e.chunk_count,contentHash:e.content_hash||void 0,createdAt:e.created_at}}mapChunkRow(e){return{id:e.id,documentId:e.document_id,chunkIndex:e.chunk_index,content:e.content,embeddingId:e.embedding_id||void 0,createdAt:e.created_at}}}});import{randomUUID as ah}from"node:crypto";var wr,Cl=T(()=>{"use strict";wr=class{static{m(this,"TodoRepository")}db;constructor(e){this.db=e}add(e,t,s){let r=new Date().toISOString(),n=ah(),o=s?.list??"default",i=s?.priority??"normal";return this.db.prepare("INSERT INTO todos (id, user_id, list, title, description, priority, due_date, completed, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)").run(n,e,o,t,s?.description??null,i,s?.dueDate??null,r,r),{id:n,userId:e,list:o,title:t,description:s?.description,priority:i,dueDate:s?.dueDate,completed:!1,createdAt:r,updatedAt:r}}list(e,t,s=!1){let r="SELECT * FROM todos WHERE user_id = ?",n=[e];return t&&(r+=" AND list = ?",n.push(t)),s||(r+=" AND completed = 0"),r+=" ORDER BY CASE priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'normal' THEN 2 WHEN 'low' THEN 3 END, created_at DESC",this.db.prepare(r).all(...n).map(i=>this.mapRow(i))}getById(e){let t=this.db.prepare("SELECT * FROM todos WHERE id = ?").get(e);return t?this.mapRow(t):void 0}complete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 1, updated_at = ? WHERE id = ? AND completed = 0").run(t,e).changes>0}uncomplete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 0, updated_at = ? WHERE id = ? AND completed = 1").run(t,e).changes>0}delete(e){return this.db.prepare("DELETE FROM todos WHERE id = ?").run(e).changes>0}clearCompleted(e,t){let s="DELETE FROM todos WHERE user_id = ? AND completed = 1",r=[e];return t&&(s+=" AND list = ?",r.push(t)),this.db.prepare(s).run(...r).changes}getLists(e){return this.db.prepare(`SELECT list,
|
|
486
499
|
SUM(CASE WHEN completed = 0 THEN 1 ELSE 0 END) as open,
|
|
487
500
|
SUM(CASE WHEN completed = 1 THEN 1 ELSE 0 END) as completed,
|
|
488
501
|
COUNT(*) as total
|
|
@@ -491,15 +504,15 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
491
504
|
AND due_date >= ? AND due_date <= ?
|
|
492
505
|
ORDER BY due_date ASC`).all(t,e).map(r=>this.mapRow(r))}getOverdue(){let e=new Date().toISOString();return this.db.prepare(`SELECT * FROM todos
|
|
493
506
|
WHERE completed = 0 AND due_date IS NOT NULL AND due_date < ?
|
|
494
|
-
ORDER BY due_date ASC`).all(e).map(s=>this.mapRow(s))}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}}}});import{randomUUID as
|
|
507
|
+
ORDER BY due_date ASC`).all(e).map(s=>this.mapRow(s))}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}}}});import{randomUUID as ch}from"node:crypto";var Tr,Nl=T(()=>{"use strict";Tr=class{static{m(this,"WatchRepository")}db;constructor(e){this.db=e}create(e){let t=ch(),s=new Date().toISOString();return this.db.prepare(`
|
|
495
508
|
INSERT INTO watches
|
|
496
509
|
(id, chat_id, platform, name, skill_name, skill_params,
|
|
497
510
|
condition_field, condition_operator, condition_value,
|
|
498
511
|
interval_minutes, cooldown_minutes, enabled, created_at, message_template,
|
|
499
512
|
action_skill_name, action_skill_params, action_on_trigger, conditions_json,
|
|
500
|
-
requires_confirmation)
|
|
501
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
502
|
-
`).run(t,e.chatId,e.platform,e.name,e.skillName,JSON.stringify(e.skillParams),e.condition.field,e.condition.operator,e.condition.value!=null?String(e.condition.value):null,e.intervalMinutes,e.cooldownMinutes,e.enabled?1:0,s,e.messageTemplate??null,e.actionSkillName??null,e.actionSkillParams?JSON.stringify(e.actionSkillParams):null,e.actionOnTrigger??"alert",e.compositeCondition?JSON.stringify(e.compositeCondition):null,e.requiresConfirmation?1:0),{id:t,chatId:e.chatId,platform:e.platform,name:e.name,skillName:e.skillName,skillParams:e.skillParams,condition:e.condition,intervalMinutes:e.intervalMinutes,cooldownMinutes:e.cooldownMinutes,enabled:e.enabled,lastCheckedAt:null,lastTriggeredAt:null,lastValue:null,createdAt:s,messageTemplate:e.messageTemplate,compositeCondition:e.compositeCondition,actionSkillName:e.actionSkillName,actionSkillParams:e.actionSkillParams,actionOnTrigger:e.actionOnTrigger??"alert",requiresConfirmation:e.requiresConfirmation}}countEnabled(){return this.db.prepare("SELECT COUNT(*) as cnt FROM watches WHERE enabled = 1").get().cnt}getEnabled(){return this.db.prepare("SELECT * FROM watches WHERE enabled = 1 ORDER BY created_at DESC").all().map(t=>this.mapRow(t))}getDue(){return this.db.prepare(`
|
|
513
|
+
requires_confirmation, trigger_watch_id)
|
|
514
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
515
|
+
`).run(t,e.chatId,e.platform,e.name,e.skillName,JSON.stringify(e.skillParams),e.condition.field,e.condition.operator,e.condition.value!=null?String(e.condition.value):null,e.intervalMinutes,e.cooldownMinutes,e.enabled?1:0,s,e.messageTemplate??null,e.actionSkillName??null,e.actionSkillParams?JSON.stringify(e.actionSkillParams):null,e.actionOnTrigger??"alert",e.compositeCondition?JSON.stringify(e.compositeCondition):null,e.requiresConfirmation?1:0,e.triggerWatchId??null),{id:t,chatId:e.chatId,platform:e.platform,name:e.name,skillName:e.skillName,skillParams:e.skillParams,condition:e.condition,intervalMinutes:e.intervalMinutes,cooldownMinutes:e.cooldownMinutes,enabled:e.enabled,lastCheckedAt:null,lastTriggeredAt:null,lastValue:null,createdAt:s,messageTemplate:e.messageTemplate,compositeCondition:e.compositeCondition,actionSkillName:e.actionSkillName,actionSkillParams:e.actionSkillParams,actionOnTrigger:e.actionOnTrigger??"alert",requiresConfirmation:e.requiresConfirmation,triggerWatchId:e.triggerWatchId}}countEnabled(){return this.db.prepare("SELECT COUNT(*) as cnt FROM watches WHERE enabled = 1").get().cnt}getEnabled(){return this.db.prepare("SELECT * FROM watches WHERE enabled = 1 ORDER BY created_at DESC").all().map(t=>this.mapRow(t))}getDue(){return this.db.prepare(`
|
|
503
516
|
SELECT * FROM watches
|
|
504
517
|
WHERE enabled = 1
|
|
505
518
|
AND (last_checked_at IS NULL
|
|
@@ -513,10 +526,10 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
513
526
|
UPDATE watches
|
|
514
527
|
SET last_checked_at = ?, last_value = ?
|
|
515
528
|
WHERE id = ?
|
|
516
|
-
`).run(t.lastCheckedAt,t.lastValue,e)}findByChatId(e,t){return this.db.prepare("SELECT * FROM watches WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapRow(r))}toggle(e,t){return this.db.prepare("UPDATE watches SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM watches WHERE id = ?").run(e).changes>0}updateActionError(e,t){this.db.prepare("UPDATE watches SET last_action_error = ? WHERE id = ?").run(t,e)}getById(e){let t=this.db.prepare("SELECT * FROM watches WHERE id = ?").get(e);return t?this.mapRow(t):void 0}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}let s={field:e.condition_field,operator:e.condition_operator};if(e.condition_value!=null){let n=Number(e.condition_value);s.value=isNaN(n)?e.condition_value:n}let r;if(e.conditions_json)try{r=JSON.parse(e.conditions_json)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,name:e.name,skillName:e.skill_name,skillParams:t,condition:s,intervalMinutes:e.interval_minutes,cooldownMinutes:e.cooldown_minutes,enabled:e.enabled===1,lastCheckedAt:e.last_checked_at??null,lastTriggeredAt:e.last_triggered_at??null,lastValue:e.last_value??null,createdAt:e.created_at,messageTemplate:e.message_template,compositeCondition:r,actionSkillName:e.action_skill_name,actionSkillParams:e.action_skill_params?(()=>{try{return JSON.parse(e.action_skill_params)}catch{return}})():void 0,actionOnTrigger:e.action_on_trigger??"alert",lastActionError:e.last_action_error,requiresConfirmation:e.requires_confirmation===1}}}});import{randomUUID as
|
|
529
|
+
`).run(t.lastCheckedAt,t.lastValue,e)}findByChatId(e,t){return this.db.prepare("SELECT * FROM watches WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapRow(r))}toggle(e,t){return this.db.prepare("UPDATE watches SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM watches WHERE id = ?").run(e).changes>0}updateActionError(e,t){this.db.prepare("UPDATE watches SET last_action_error = ? WHERE id = ?").run(t,e)}getById(e){let t=this.db.prepare("SELECT * FROM watches WHERE id = ?").get(e);return t?this.mapRow(t):void 0}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}let s={field:e.condition_field,operator:e.condition_operator};if(e.condition_value!=null){let n=Number(e.condition_value);s.value=isNaN(n)?e.condition_value:n}let r;if(e.conditions_json)try{r=JSON.parse(e.conditions_json)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,name:e.name,skillName:e.skill_name,skillParams:t,condition:s,intervalMinutes:e.interval_minutes,cooldownMinutes:e.cooldown_minutes,enabled:e.enabled===1,lastCheckedAt:e.last_checked_at??null,lastTriggeredAt:e.last_triggered_at??null,lastValue:e.last_value??null,createdAt:e.created_at,messageTemplate:e.message_template,compositeCondition:r,actionSkillName:e.action_skill_name,actionSkillParams:e.action_skill_params?(()=>{try{return JSON.parse(e.action_skill_params)}catch{return}})():void 0,actionOnTrigger:e.action_on_trigger??"alert",lastActionError:e.last_action_error,requiresConfirmation:e.requires_confirmation===1,triggerWatchId:e.trigger_watch_id}}}});import{randomUUID as lh}from"node:crypto";var _r,Ll=T(()=>{"use strict";_r=class{static{m(this,"ConfirmationRepository")}db;constructor(e){this.db=e}create(e){let t=lh(),s=new Date().toISOString();return this.db.prepare(`
|
|
517
530
|
INSERT INTO pending_confirmations (id, chat_id, platform, source, source_id, description, skill_name, skill_params, status, created_at, expires_at)
|
|
518
531
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)
|
|
519
|
-
`).run(t,e.chatId,e.platform,e.source,e.sourceId,e.description,e.skillName,JSON.stringify(e.skillParams),s,e.expiresAt),{id:t,...e,status:"pending",createdAt:s}}findPending(e,t){let s=this.db.prepare("SELECT * FROM pending_confirmations WHERE chat_id = ? AND platform = ? AND status = 'pending' ORDER BY created_at DESC LIMIT 1").get(e,t);return s?this.mapRow(s):void 0}resolve(e,t){this.db.prepare("UPDATE pending_confirmations SET status = ?, resolved_at = datetime('now') WHERE id = ?").run(t,e)}expireOld(){let e=this.db.prepare("SELECT * FROM pending_confirmations WHERE status = 'pending' AND expires_at <= datetime('now')").all();if(e.length>0){let t=e.map(r=>r.id),s=t.map(()=>"?").join(",");this.db.prepare(`UPDATE pending_confirmations SET status = 'expired', resolved_at = datetime('now') WHERE id IN (${s}) AND status = 'pending'`).run(...t)}return e.map(t=>this.mapRow(t))}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,source:e.source,sourceId:e.source_id,description:e.description,skillName:e.skill_name,skillParams:t,status:e.status,createdAt:e.created_at,expiresAt:e.expires_at,resolvedAt:e.resolved_at}}}});var
|
|
532
|
+
`).run(t,e.chatId,e.platform,e.source,e.sourceId,e.description,e.skillName,JSON.stringify(e.skillParams),s,e.expiresAt),{id:t,...e,status:"pending",createdAt:s}}findPending(e,t){let s=this.db.prepare("SELECT * FROM pending_confirmations WHERE chat_id = ? AND platform = ? AND status = 'pending' ORDER BY created_at DESC LIMIT 1").get(e,t);return s?this.mapRow(s):void 0}resolve(e,t){this.db.prepare("UPDATE pending_confirmations SET status = ?, resolved_at = datetime('now') WHERE id = ?").run(t,e)}expireOld(){let e=this.db.prepare("SELECT * FROM pending_confirmations WHERE status = 'pending' AND expires_at <= datetime('now')").all();if(e.length>0){let t=e.map(r=>r.id),s=t.map(()=>"?").join(",");this.db.prepare(`UPDATE pending_confirmations SET status = 'expired', resolved_at = datetime('now') WHERE id IN (${s}) AND status = 'pending'`).run(...t)}return e.map(t=>this.mapRow(t))}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,source:e.source,sourceId:e.source_id,description:e.description,skillName:e.skill_name,skillParams:t,status:e.status,createdAt:e.created_at,expiresAt:e.expires_at,resolvedAt:e.resolved_at}}}});var kr,Dl=T(()=>{"use strict";kr=class{static{m(this,"SummaryRepository")}db;constructor(e){this.db=e}get(e){let t=this.db.prepare("SELECT conversation_id, summary, message_count, last_user_message, last_assistant_message, updated_at FROM conversation_summaries WHERE conversation_id = ?").get(e);if(t)return{conversationId:t.conversation_id,summary:t.summary,messageCount:t.message_count,lastUserMessage:t.last_user_message,lastAssistantMessage:t.last_assistant_message,updatedAt:t.updated_at}}upsert(e){this.db.prepare(`
|
|
520
533
|
INSERT INTO conversation_summaries (conversation_id, summary, message_count, last_user_message, last_assistant_message, updated_at)
|
|
521
534
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
522
535
|
ON CONFLICT(conversation_id) DO UPDATE SET
|
|
@@ -525,7 +538,7 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
525
538
|
last_user_message = excluded.last_user_message,
|
|
526
539
|
last_assistant_message = excluded.last_assistant_message,
|
|
527
540
|
updated_at = excluded.updated_at
|
|
528
|
-
`).run(e.conversationId,e.summary,e.messageCount,e.lastUserMessage??null,e.lastAssistantMessage??null,e.updatedAt)}cleanup(e=180){return this.db.prepare("DELETE FROM conversation_summaries WHERE updated_at < datetime('now', '-' || ? || ' days')").run(e).changes}delete(e){this.db.prepare("DELETE FROM conversation_summaries WHERE conversation_id = ?").run(e)}}});var
|
|
541
|
+
`).run(e.conversationId,e.summary,e.messageCount,e.lastUserMessage??null,e.lastAssistantMessage??null,e.updatedAt)}cleanup(e=180){return this.db.prepare("DELETE FROM conversation_summaries WHERE updated_at < datetime('now', '-' || ? || ' days')").run(e).changes}delete(e){this.db.prepare("DELETE FROM conversation_summaries WHERE conversation_id = ?").run(e)}}});var Er,Ml=T(()=>{"use strict";Er=class{static{m(this,"UsageRepository")}db;stmtUpsert;stmtDaily;stmtRange;stmtTotal;constructor(e){this.db=e,this.stmtUpsert=e.prepare(`
|
|
529
542
|
INSERT INTO llm_usage (date, model, calls, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_usd)
|
|
530
543
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
531
544
|
ON CONFLICT(date, model) DO UPDATE SET
|
|
@@ -550,13 +563,13 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
550
563
|
SUM(cache_write_tokens) as cache_write_tokens,
|
|
551
564
|
SUM(cost_usd) as cost_usd
|
|
552
565
|
FROM llm_usage GROUP BY model
|
|
553
|
-
`)}record(e,t,s,r,n,o){let i=new Date().toISOString().slice(0,10);this.stmtUpsert.run(i,e,1,t,s,r,n,o)}getDaily(e){let t=this.stmtDaily.all(e);return this.buildSummary(e,t)}getRange(e,t){let s=this.stmtRange.all(e,t),r=new Map;for(let n of s){let o=n.date;r.has(o)||r.set(o,[]),r.get(o).push(n)}return[...r.entries()].map(([n,o])=>this.buildSummary(n,o))}getTotal(){return this.stmtTotal.all().map(t=>this.mapRow(t))}cleanup(e=365){return this.db.prepare("DELETE FROM llm_usage WHERE date < date('now', '-' || ? || ' days')").run(e).changes}buildSummary(e,t){let s=t.map(r=>this.mapRow(r));return{date:e,models:s,totalCalls:s.reduce((r,n)=>r+n.calls,0),totalInputTokens:s.reduce((r,n)=>r+n.inputTokens,0),totalOutputTokens:s.reduce((r,n)=>r+n.outputTokens,0),totalCostUsd:Math.round(s.reduce((r,n)=>r+n.costUsd,0)*1e6)/1e6}}mapRow(e){return{model:e.model,calls:e.calls,inputTokens:e.input_tokens,outputTokens:e.output_tokens,cacheReadTokens:e.cache_read_tokens,cacheWriteTokens:e.cache_write_tokens,costUsd:e.cost_usd}}}});var
|
|
566
|
+
`)}record(e,t,s,r,n,o){let i=new Date().toISOString().slice(0,10);this.stmtUpsert.run(i,e,1,t,s,r,n,o)}getDaily(e){let t=this.stmtDaily.all(e);return this.buildSummary(e,t)}getRange(e,t){let s=this.stmtRange.all(e,t),r=new Map;for(let n of s){let o=n.date;r.has(o)||r.set(o,[]),r.get(o).push(n)}return[...r.entries()].map(([n,o])=>this.buildSummary(n,o))}getTotal(){return this.stmtTotal.all().map(t=>this.mapRow(t))}cleanup(e=365){return this.db.prepare("DELETE FROM llm_usage WHERE date < date('now', '-' || ? || ' days')").run(e).changes}buildSummary(e,t){let s=t.map(r=>this.mapRow(r));return{date:e,models:s,totalCalls:s.reduce((r,n)=>r+n.calls,0),totalInputTokens:s.reduce((r,n)=>r+n.inputTokens,0),totalOutputTokens:s.reduce((r,n)=>r+n.outputTokens,0),totalCostUsd:Math.round(s.reduce((r,n)=>r+n.costUsd,0)*1e6)/1e6}}mapRow(e){return{model:e.model,calls:e.calls,inputTokens:e.input_tokens,outputTokens:e.output_tokens,cacheReadTokens:e.cache_read_tokens,cacheWriteTokens:e.cache_write_tokens,costUsd:e.cost_usd}}}});var Nt,Ol=T(()=>{"use strict";Nt=class{static{m(this,"CalendarNotificationRepository")}db;constructor(e){this.db=e}wasNotified(e,t){return!!this.db.prepare("SELECT 1 FROM calendar_notifications WHERE event_id = ? AND chat_id = ?").get(e,t)}markNotified(e,t,s,r){this.db.prepare(`
|
|
554
567
|
INSERT OR IGNORE INTO calendar_notifications (event_id, chat_id, platform, notified_at, event_start)
|
|
555
568
|
VALUES (?, ?, ?, datetime('now'), ?)
|
|
556
|
-
`).run(e,t,s,r)}cleanup(e){return this.db.prepare("DELETE FROM calendar_notifications WHERE event_start < ?").run(e).changes}}});import{randomUUID as
|
|
569
|
+
`).run(e,t,s,r)}cleanup(e){return this.db.prepare("DELETE FROM calendar_notifications WHERE event_start < ?").run(e).changes}}});import{randomUUID as dh}from"node:crypto";var Lt,Pl=T(()=>{"use strict";Lt=class{static{m(this,"ActivityRepository")}db;constructor(e){this.db=e}log(e){let t=dh(),s=new Date().toISOString();this.db.prepare(`
|
|
557
570
|
INSERT INTO activity_log (id, timestamp, event_type, source, source_id, user_id, platform, chat_id, action, outcome, error_message, duration_ms, details)
|
|
558
571
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
559
|
-
`).run(t,s,e.eventType,e.source,e.sourceId??null,e.userId??null,e.platform??null,e.chatId??null,e.action,e.outcome,e.errorMessage??null,e.durationMs??null,e.details?JSON.stringify(e.details):null)}query(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome)),e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.since&&(t.push("timestamp >= ?"),s.push(e.since));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return this.db.prepare(`SELECT * FROM activity_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s,n).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as cnt FROM activity_log ${r}`).get(...s).cnt}stats(e){let t=e?"WHERE timestamp >= ?":"",s=e?[e]:[];return this.db.prepare(`SELECT event_type, outcome, COUNT(*) as cnt FROM activity_log ${t} GROUP BY event_type, outcome ORDER BY cnt DESC`).all(...s).map(n=>({eventType:n.event_type,outcome:n.outcome,count:n.cnt}))}cleanup(e=90){return this.db.prepare("DELETE FROM activity_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}mapRow(e){let t;if(e.details)try{t=JSON.parse(e.details)}catch{}return{id:e.id,timestamp:e.timestamp,eventType:e.event_type,source:e.source,sourceId:e.source_id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,action:e.action,outcome:e.outcome,errorMessage:e.error_message,durationMs:e.duration_ms,details:t}}}});var
|
|
572
|
+
`).run(t,s,e.eventType,e.source,e.sourceId??null,e.userId??null,e.platform??null,e.chatId??null,e.action,e.outcome,e.errorMessage??null,e.durationMs??null,e.details?JSON.stringify(e.details):null)}query(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome)),e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.since&&(t.push("timestamp >= ?"),s.push(e.since));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return this.db.prepare(`SELECT * FROM activity_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s,n).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as cnt FROM activity_log ${r}`).get(...s).cnt}stats(e){let t=e?"WHERE timestamp >= ?":"",s=e?[e]:[];return this.db.prepare(`SELECT event_type, outcome, COUNT(*) as cnt FROM activity_log ${t} GROUP BY event_type, outcome ORDER BY cnt DESC`).all(...s).map(n=>({eventType:n.event_type,outcome:n.outcome,count:n.cnt}))}cleanup(e=90){return this.db.prepare("DELETE FROM activity_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}mapRow(e){let t;if(e.details)try{t=JSON.parse(e.details)}catch{}return{id:e.id,timestamp:e.timestamp,eventType:e.event_type,source:e.source,sourceId:e.source_id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,action:e.action,outcome:e.outcome,errorMessage:e.error_message,durationMs:e.duration_ms,details:t}}}});var br,Ul=T(()=>{"use strict";br=class{static{m(this,"SkillHealthRepository")}db;constructor(e){this.db=e}getByName(e){let t=this.db.prepare("SELECT * FROM skill_health WHERE skill_name = ?").get(e);return t?this.mapRow(t):void 0}getAll(){return this.db.prepare("SELECT * FROM skill_health ORDER BY updated_at DESC").all().map(t=>this.mapRow(t))}recordSuccess(e){this.db.prepare(`
|
|
560
573
|
INSERT INTO skill_health (skill_name, success_count, fail_count, consecutive_fails, updated_at)
|
|
561
574
|
VALUES (?, 1, 0, 0, datetime('now'))
|
|
562
575
|
ON CONFLICT(skill_name) DO UPDATE SET
|
|
@@ -579,16 +592,19 @@ var Rc=Object.defineProperty;var m=(l,e)=>Rc(l,"name",{value:e,configurable:!0})
|
|
|
579
592
|
`).run(t,e)}enable(e){this.db.prepare(`
|
|
580
593
|
UPDATE skill_health SET disabled_until = NULL, consecutive_fails = 0, updated_at = datetime('now')
|
|
581
594
|
WHERE skill_name = ?
|
|
582
|
-
`).run(e)}isDisabled(e){return!!this.db.prepare("SELECT disabled_until FROM skill_health WHERE skill_name = ? AND disabled_until > datetime('now')").get(e)}getDisabled(){return this.db.prepare("SELECT * FROM skill_health WHERE disabled_until > datetime('now')").all().map(t=>this.mapRow(t))}mapRow(e){return{skillName:e.skill_name,successCount:e.success_count,failCount:e.fail_count,consecutiveFails:e.consecutive_fails,lastError:e.last_error,lastErrorAt:e.last_error_at,disabledUntil:e.disabled_until,updatedAt:e.updated_at}}}});import{randomUUID as
|
|
595
|
+
`).run(e)}isDisabled(e){return!!this.db.prepare("SELECT disabled_until FROM skill_health WHERE skill_name = ? AND disabled_until > datetime('now')").get(e)}getDisabled(){return this.db.prepare("SELECT * FROM skill_health WHERE disabled_until > datetime('now')").all().map(t=>this.mapRow(t))}mapRow(e){return{skillName:e.skill_name,successCount:e.success_count,failCount:e.fail_count,consecutiveFails:e.consecutive_fails,lastError:e.last_error,lastErrorAt:e.last_error_at,disabledUntil:e.disabled_until,updatedAt:e.updated_at}}}});import{randomUUID as Fl}from"node:crypto";var Sr,jl=T(()=>{"use strict";Sr=class{static{m(this,"WorkflowRepository")}db;constructor(e){this.db=e}create(e){let t=Fl(),s=new Date().toISOString();return this.db.prepare(`
|
|
583
596
|
INSERT INTO workflow_chains (id, name, user_id, chat_id, platform, steps, trigger_type, trigger_config, enabled, created_at)
|
|
584
597
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
585
|
-
`).run(t,e.name,e.userId,e.chatId,e.platform,JSON.stringify(e.steps),e.triggerType,e.triggerConfig?JSON.stringify(e.triggerConfig):null,e.enabled?1:0,s),{...e,id:t,createdAt:s}}getById(e){let t=this.db.prepare("SELECT * FROM workflow_chains WHERE id = ?").get(e);return t?this.mapChain(t):void 0}findByUser(e){return this.db.prepare("SELECT * FROM workflow_chains WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapChain(s))}findByChatId(e,t){return this.db.prepare("SELECT * FROM workflow_chains WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapChain(r))}delete(e){return this.db.prepare("DELETE FROM workflow_chains WHERE id = ?").run(e).changes>0}toggle(e,t){this.db.prepare("UPDATE workflow_chains SET enabled = ? WHERE id = ?").run(t?1:0,e)}createExecution(e,t){let s=
|
|
598
|
+
`).run(t,e.name,e.userId,e.chatId,e.platform,JSON.stringify(e.steps),e.triggerType,e.triggerConfig?JSON.stringify(e.triggerConfig):null,e.enabled?1:0,s),{...e,id:t,createdAt:s}}getById(e){let t=this.db.prepare("SELECT * FROM workflow_chains WHERE id = ?").get(e);return t?this.mapChain(t):void 0}findByUser(e){return this.db.prepare("SELECT * FROM workflow_chains WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapChain(s))}findByChatId(e,t){return this.db.prepare("SELECT * FROM workflow_chains WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapChain(r))}delete(e){return this.db.prepare("DELETE FROM workflow_chains WHERE id = ?").run(e).changes>0}toggle(e,t){this.db.prepare("UPDATE workflow_chains SET enabled = ? WHERE id = ?").run(t?1:0,e)}createExecution(e,t){let s=Fl(),r=new Date().toISOString();return this.db.prepare(`
|
|
586
599
|
INSERT INTO workflow_executions (id, chain_id, status, steps_completed, total_steps, started_at)
|
|
587
600
|
VALUES (?, ?, 'running', 0, ?, ?)
|
|
588
|
-
`).run(s,e,t,r),{id:s,chainId:e,status:"running",stepsCompleted:0,totalSteps:t,startedAt:r}}updateExecution(e,t){let s=[],r=[];t.status!==void 0&&(s.push("status = ?"),r.push(t.status)),t.stepsCompleted!==void 0&&(s.push("steps_completed = ?"),r.push(t.stepsCompleted)),t.stepResults!==void 0&&(s.push("step_results = ?"),r.push(t.stepResults)),t.error!==void 0&&(s.push("error = ?"),r.push(t.error)),t.completedAt!==void 0&&(s.push("completed_at = ?"),r.push(t.completedAt)),s.length!==0&&(r.push(e),this.db.prepare(`UPDATE workflow_executions SET ${s.join(", ")} WHERE id = ?`).run(...r))}getExecution(e){let t=this.db.prepare("SELECT * FROM workflow_executions WHERE id = ?").get(e);return t?this.mapExecution(t):void 0}getRecentExecutions(e,t=10){return this.db.prepare("SELECT * FROM workflow_executions WHERE chain_id = ? ORDER BY started_at DESC LIMIT ?").all(e,t).map(r=>this.mapExecution(r))}mapChain(e){return{id:e.id,name:e.name,userId:e.user_id,chatId:e.chat_id,platform:e.platform,steps:JSON.parse(e.steps),triggerType:e.trigger_type,triggerConfig:e.trigger_config?JSON.parse(e.trigger_config):void 0,enabled:e.enabled===1,createdAt:e.created_at}}mapExecution(e){return{id:e.id,chainId:e.chain_id,status:e.status,stepsCompleted:e.steps_completed,totalSteps:e.total_steps,stepResults:e.step_results,error:e.error,startedAt:e.started_at,completedAt:e.completed_at}}}});var Ii=T(()=>{"use strict";Kc();Yc();Jc();Zc();Qc();jn();vi();el();tl();sl();rl();nl();hl();gl();yl();wl();Tl();_l();kl();El();bl();Sl();$l()});function st(l){if(Ai[l])return Ai[l];let e=Object.entries(Ai).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Ai,Kp,xe,Lt=T(()=>{"use strict";Ai={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Kp={maxInputTokens:128e3,maxOutputTokens:8192};m(st,"lookupContextWindow");xe=class{static{m(this,"LLMProvider")}config;contextWindow=Kp;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Vp from"@anthropic-ai/sdk";var _r,Ri=T(()=>{"use strict";Lt();_r=class extends xe{static{m(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Vp({apiKey:this.config.apiKey,maxRetries:5});let e=st(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s},n=await this.client.messages.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s});for await(let n of r)if(n.type==="content_block_delta")n.delta.type==="text_delta"?yield{type:"text_delta",text:n.delta.text}:n.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:n.delta.partial_json}});else if(n.type==="content_block_start")n.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:n.content_block.id,name:n.content_block.name}});else if(n.type==="message_stop"){let o=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(o)}}}isAvailable(){return!!this.config.apiKey}mapMessages(e){return e.map(t=>{if(typeof t.content=="string")return{role:t.role,content:t.content};let s=t.content.map(r=>{switch(r.type){case"text":return{type:"text",text:r.text};case"image":return{type:"image",source:{type:"base64",media_type:r.source.media_type,data:r.source.data}};case"tool_use":return{type:"tool_use",id:r.id,name:r.name,input:r.input};case"tool_result":return{type:"tool_result",tool_use_id:r.tool_use_id,content:r.content,is_error:r.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(r=>r!==void 0);return{role:t.role,content:s}})}mapTools(e){let t=e.map(s=>({name:s.name,description:s.description,input_schema:s.inputSchema}));return t.length>0&&(t[t.length-1].cache_control={type:"ephemeral"}),t}mapResponse(e){let t="",s=[];for(let r of e.content)r.type==="text"?t+=r.text:r.type==="tool_use"&&s.push({id:r.id,name:r.name,input:r.input});return{content:t,model:e.model??this.config.model,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens,cacheCreationTokens:e.usage.cache_creation_input_tokens??0,cacheReadTokens:e.usage.cache_read_input_tokens??0},stopReason:e.stop_reason}}}});import Yp from"openai";var je,Jt=T(()=>{"use strict";Lt();je=class extends xe{static{m(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Yp({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=st(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},n=await this.client.chat.completions.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.chat.completions.create({model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},stream:!0}),n,o,i="",a="",c=[],d=null,u=0,p=0;for await(let h of r){let g=h.choices[0];if(!g)continue;let f=g.delta;if(f?.content&&(a+=f.content,yield{type:"text_delta",text:f.content}),f?.tool_calls)for(let y of f.tool_calls)if(y.id){if(n){let k;try{k=JSON.parse(i||"{}")}catch{k={}}c.push({id:n,name:o,input:k})}n=y.id,o=y.function?.name,i=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:o}}}else y.function?.arguments&&(i+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});g.finish_reason&&(d=g.finish_reason),h.usage&&(u=h.usage.prompt_tokens,p=h.usage.completion_tokens)}if(n){let h;try{h=JSON.parse(i||"{}")}catch{h={}}c.push({id:n,name:o,input:h})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens: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(t){let s=t instanceof Error?t.message:String(t);console.warn(`[OpenAIProvider] embed() failed: ${s}`);return}}supportsEmbeddings(){return!0}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let n=[],o=[],i=[];for(let a of r.content)switch(a.type){case"text":n.push({type:"text",text:a.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":o.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input)}});break;case"tool_result":i.push({tool_call_id:a.tool_use_id,content:a.content});break}if(r.role==="assistant"&&o.length>0){let a=n.map(c=>c.text).join("");s.push({role:"assistant",content:a||null,tool_calls:o})}else if(i.length>0)for(let a of i)s.push({role:"tool",tool_call_id:a.tool_call_id,content:a.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(a=>a.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,r=s?.content??"",n=s?.tool_calls?.map(o=>({id:o.id,name:o.function.name,input:(()=>{try{return JSON.parse(o.function.arguments)}catch{return{}}})()}));return{content:r,model:e.model??this.config.model,toolCalls:n&&n.length>0?n:void 0,usage:{inputTokens:e.usage?.prompt_tokens??0,outputTokens:e.usage?.completion_tokens??0},stopReason:this.mapStopReason(t?.finish_reason??null)}}mapStopReason(e){switch(e){case"stop":return"end_turn";case"tool_calls":return"tool_use";case"length":return"max_tokens";default:return"end_turn"}}}});var kr,xi=T(()=>{"use strict";Jt();kr=class extends je{static{m(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Er,Ci=T(()=>{"use strict";Lt();Er=class extends xe{static{m(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=st(this.config.model);t?this.contextWindow=t:await this.fetchModelContextWindow()}async fetchModelContextWindow(){try{let e=await fetch(`${this.baseUrl}/api/show`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:this.config.model})});if(!e.ok)return;let s=(await e.json()).model_info??{},r=Object.keys(s).find(o=>o.includes("context_length")||o==="num_ctx"),n=r?Number(s[r]):0;n>0&&(this.contextWindow={maxInputTokens:n,maxOutputTokens:Math.min(n,4096)})}catch{}}getHeaders(){let e={"Content-Type":"application/json"};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}async complete(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text();throw new Error(`Ollama API error (${n.status}): ${i}`)}let o=await n.json();return this.mapResponse(o)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let h=await n.text();throw new Error(`Ollama API error (${n.status}): ${h}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let o=n.body.getReader(),i=new TextDecoder,a="",c="",d=0,u=0,p=[];try{for(;;){let{done:h,value:g}=await o.read();if(h)break;a+=i.decode(g,{stream:!0});let f=a.split(`
|
|
589
|
-
|
|
590
|
-
`)};return r.length>0&&(n.images=r),n}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=[];if(e.message.tool_calls)for(let s of e.message.tool_calls)t.push({id:`ollama_tool_${t.length}`,name:s.function.name,input:s.function.arguments});return{content:e.message.content,model:this.config.model,toolCalls:t.length>0?t:void 0,usage:{inputTokens:e.prompt_eval_count??0,outputTokens:e.eval_count??0},stopReason:t.length>0?"tool_use":"end_turn"}}}});var br,Li=T(()=>{"use strict";Jt();br=class extends je{static{m(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as Jp}from"@google/genai";var Sr,Ni=T(()=>{"use strict";Lt();Sr=class extends xe{static{m(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Jp({apiKey:this.config.apiKey});let e=st(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),n="",o=[],i=0,a=0,c;for await(let d of r){c=d;let u=d.text;if(u&&(n+=u,yield{type:"text_delta",text:u}),d.functionCalls)for(let p of d.functionCalls){let h={id:p.id??`google_tool_${o.length}`,name:p.name,input:p.args??{}};o.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:o.length>0?o:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:o.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(n=>n.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let n=this.rawContentCache.keys().next().value;n&&this.rawContentCache.delete(n)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let n of r.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let r of e){let n=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:n,parts:[{text:r.content}]});continue}let o=[],i=[],a=[];for(let c of r.content)switch(c.type){case"text":i.push({text:c.text});break;case"image":i.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":o.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let d=t.get(c.tool_use_id)??c.tool_use_id,u;try{let p=JSON.parse(c.content);u=typeof p=="object"&&p!==null?p:{result:p}}catch{u={result:c.content}}a.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&o.length>0){let c=this.buildCacheKeyFromBlocks(o),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...i];for(let p=0;p<o.length;p++){let h=o[p];u.push({functionCall:{id:h.id,name:h.name,args:h.input},...p===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else i.length>0&&s.push({role:n,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let c=a.functionCall.id??a.functionCall.name??"";c&&t.add(c)}s.push(i)}else{let a=(i.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let c=a.functionResponse.id??a.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&n.push({role:i.role,parts:a})}else n.push(i);if(n.length<=1)return n;let o=[n[0]];for(let i=1;i<n.length;i++){let a=o[o.length-1],c=n[i];a.role===c.role?a.parts=[...a.parts??[],...c.parts??[]]:o.push(c)}return o}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((n,o)=>({id:n.id??`google_tool_${o}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var vr,Di=T(()=>{"use strict";Jt();vr=class extends je{static{m(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function Mi(l){switch(l.provider){case"anthropic":return new _r(l);case"openai":return new je(l);case"openrouter":return new kr(l);case"ollama":return new Er(l);case"openwebui":return new br(l);case"google":return new Sr(l);case"mistral":return new vr(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var Oi=T(()=>{"use strict";Ri();Jt();xi();Ci();Li();Ni();Di();m(Mi,"createLLMProvider")});function Il(l){let e=l.toLowerCase();for(let[t,s]of Zp)if(e.startsWith(t.toLowerCase()))return s}function Wn(l,e){let t=Il(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=Math.max(0,e.inputTokens-n);return r+=i/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),o>0&&t.cacheWrite&&(r+=o/s*t.cacheWrite),r}var Zp,$r,Pi=T(()=>{"use strict";Zp=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];m(Il,"getModelPricing");m(Wn,"calculateCost");$r=class{static{m(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=Wn(e,t),r=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=r,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let o=this.data.byModel[e];o||(o={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=o),o.calls++,o.inputTokens+=t.inputTokens,o.outputTokens+=t.outputTokens,o.cacheReadTokens+=r,o.cacheWriteTokens+=n,o.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,r,n,s)}catch{}return s}getSummary(){return{...this.data,totalCostUsd:Math.round(this.data.totalCostUsd*1e6)/1e6,byModel:Object.fromEntries(Object.entries(this.data.byModel).map(([e,t])=>[e,{...t,costUsd:Math.round(t.costUsd*1e6)/1e6}]))}}}});function Ui(l,e){return new zn(l,e)}var Al,zn,Rl=T(()=>{"use strict";Lt();Oi();Pi();Al=["default","strong","fast","embeddings","local"],zn=class extends xe{static{m(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new $r;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of Al){let t=this.multiConfig[e];if(t){let s=Mi(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}if(!this.providers.has("default"))throw new Error(`ModelRouter: no "default" tier configured. Available tiers: [${[...this.providers.keys()].join(", ")}]`)}resolve(e){if(e&&this.providers.has(e))return{provider:this.providers.get(e),resolvedTier:e};let t=this.providers.get("default");if(!t)throw new Error('ModelRouter: no "default" tier available. Was initialize() called?');return{provider:t,resolvedTier:"default"}}async complete(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=this.multiConfig[s];this.logger?.debug({requestedTier:e.tier??"default",resolvedTier:s,model:r?.model},"LLM routing request");try{return await this.executeComplete(t,s,e)}catch(n){if(!this.isRetryableError(n))throw n;return this.logger?.warn({err:n,tier:s},"Provider failed, attempting fallback"),this.completeWithFallback(e,s,n)}}async executeComplete(e,t,s){let r=this.multiConfig[t],n=await e.complete(s),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:t,model:o,costUsd:Math.round(i*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let r=["default","strong","fast"].filter(n=>n!==t);for(let n of r){let o=this.providers.get(n);if(o)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(o,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=!1;try{for await(let n of t.stream(e))r=!0,yield n}catch(n){if(r||!this.isRetryableError(n))throw n;this.logger?.warn({err:n,tier:s},"Stream provider failed before first chunk, attempting fallback");let o=["default","strong","fast"].filter(i=>i!==s);for(let i of o){let a=this.providers.get(i);if(a)try{this.logger?.info({tier:i},"Stream fallback to tier"),yield*a.stream(e);return}catch{continue}}throw n}}async embed(e){return(this.providers.get("embeddings")??this.resolve().provider).embed(e)}supportsEmbeddings(){return(this.providers.get("embeddings")??this.resolve().provider).supportsEmbeddings()}isAvailable(){return this.resolve().provider.isAvailable()}getContextWindow(){return this.resolve().provider.getContextWindow()}getProviderStatuses(){let e={};for(let t of Al){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};m(Ui,"createModelRouter")});function Be(l){return Math.ceil(l.length/3.5)}function Nt(l){if(typeof l.content=="string")return Be(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=Be(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=Be(t.name)+Be(JSON.stringify(t.input));break;case"tool_result":e+=Be(t.content);break}return e}function Fi(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let a of l)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&n.set(c.id,c.name);let o=[];for(let a=0;a<l.length;a++){let c=l[a];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&o.push(a)}let i=new Set(o.slice(-t));return l.map((a,c)=>{if(i.has(c)||a.role!=="user"||!Array.isArray(a.content))return a;let d=!1,u=a.content.map(p=>{if(p.type!=="tool_result")return p;let h=p.content;if(typeof h!="string"||h.length<r)return p;d=!0;let g=n.get(p.tool_use_id)||"unknown",f=h.split(`
|
|
591
|
-
`)[0].slice(0,s),y=p.is_error?"Fehler":"Ergebnis";return{...p,content:`[${y}: ${g} \u2014 ${f}]`}});return d?{...a,content:u}:a})}var Ir,xl=T(()=>{"use strict";m(Be,"estimateTokens");m(Nt,"estimateMessageTokens");m(Fi,"trimOldToolResults");Ir=class{static{m(this,"PromptBuilder")}buildSystemPrompt(e={}){let{memories:t,skills:s,userProfile:r,todayEvents:n,conversationSummary:o}=e,i=process.platform==="darwin"?"macOS":process.platform==="win32"?"Windows":"Linux",a=process.env.HOME||process.env.USERPROFILE||"~",c=`You are Alfred, a personal AI assistant. You run on ${i} (home: ${a}).
|
|
601
|
+
`).run(s,e,t,r),{id:s,chainId:e,status:"running",stepsCompleted:0,totalSteps:t,startedAt:r}}updateExecution(e,t){let s=[],r=[];t.status!==void 0&&(s.push("status = ?"),r.push(t.status)),t.stepsCompleted!==void 0&&(s.push("steps_completed = ?"),r.push(t.stepsCompleted)),t.stepResults!==void 0&&(s.push("step_results = ?"),r.push(t.stepResults)),t.error!==void 0&&(s.push("error = ?"),r.push(t.error)),t.completedAt!==void 0&&(s.push("completed_at = ?"),r.push(t.completedAt)),s.length!==0&&(r.push(e),this.db.prepare(`UPDATE workflow_executions SET ${s.join(", ")} WHERE id = ?`).run(...r))}getExecution(e){let t=this.db.prepare("SELECT * FROM workflow_executions WHERE id = ?").get(e);return t?this.mapExecution(t):void 0}getRecentExecutions(e,t=10){return this.db.prepare("SELECT * FROM workflow_executions WHERE chain_id = ? ORDER BY started_at DESC LIMIT ?").all(e,t).map(r=>this.mapExecution(r))}mapChain(e){return{id:e.id,name:e.name,userId:e.user_id,chatId:e.chat_id,platform:e.platform,steps:JSON.parse(e.steps),triggerType:e.trigger_type,triggerConfig:e.trigger_config?JSON.parse(e.trigger_config):void 0,enabled:e.enabled===1,createdAt:e.created_at}}mapExecution(e){return{id:e.id,chainId:e.chain_id,status:e.status,stepsCompleted:e.steps_completed,totalSteps:e.total_steps,stepResults:e.step_results,error:e.error,startedAt:e.started_at,completedAt:e.completed_at}}}});import{randomUUID as uh}from"node:crypto";var vr,Bl=T(()=>{"use strict";vr=class{static{m(this,"FeedbackRepository")}db;constructor(e){this.db=e}recordEvent(e,t,s,r,n,o){let i=uh(),a=new Date().toISOString();return this.db.prepare(`
|
|
602
|
+
INSERT INTO feedback_events (id, user_id, feedback_type, source_id, context_key, description, raw_context, occurred_at)
|
|
603
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
604
|
+
`).run(i,e,t,s??null,r,n,o?JSON.stringify(o):null,a),{id:i,userId:e,feedbackType:t,sourceId:s,contextKey:r,description:n,rawContext:o?JSON.stringify(o):void 0,occurredAt:a}}countEvents(e,t,s){return s?this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ? AND occurred_at >= ?").get(e,t,s).cnt:this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ?").get(e,t).cnt}getRecentEvents(e,t=20){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? ORDER BY occurred_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}getEventsForKey(e,t){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? AND context_key = ? ORDER BY occurred_at DESC").all(e,t).map(r=>this.mapRow(r))}pruneOldEvents(e=180){let t=new Date(Date.now()-e*24*60*6e4).toISOString();return this.db.prepare("DELETE FROM feedback_events WHERE occurred_at < ?").run(t).changes}mapRow(e){return{id:e.id,userId:e.user_id,feedbackType:e.feedback_type,sourceId:e.source_id,contextKey:e.context_key,description:e.description,rawContext:e.raw_context,occurredAt:e.occurred_at}}}});var Oi=T(()=>{"use strict";cl();dl();ul();ml();pl();Xn();Di();hl();fl();gl();yl();wl();Al();xl();Cl();Nl();Ll();Dl();Ml();Ol();Pl();Ul();jl();Bl()});function nt(l){if(Pi[l])return Pi[l];let e=Object.entries(Pi).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Pi,mh,Ce,Dt=T(()=>{"use strict";Pi={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},mh={maxInputTokens:128e3,maxOutputTokens:8192};m(nt,"lookupContextWindow");Ce=class{static{m(this,"LLMProvider")}config;contextWindow=mh;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import ph from"@anthropic-ai/sdk";var $r,Ui=T(()=>{"use strict";Dt();$r=class extends Ce{static{m(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new ph({apiKey:this.config.apiKey,maxRetries:5});let e=nt(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s},n=await this.client.messages.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s});for await(let n of r)if(n.type==="content_block_delta")n.delta.type==="text_delta"?yield{type:"text_delta",text:n.delta.text}:n.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:n.delta.partial_json}});else if(n.type==="content_block_start")n.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:n.content_block.id,name:n.content_block.name}});else if(n.type==="message_stop"){let o=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(o)}}}isAvailable(){return!!this.config.apiKey}mapMessages(e){return e.map(t=>{if(typeof t.content=="string")return{role:t.role,content:t.content};let s=t.content.map(r=>{switch(r.type){case"text":return{type:"text",text:r.text};case"image":return{type:"image",source:{type:"base64",media_type:r.source.media_type,data:r.source.data}};case"tool_use":return{type:"tool_use",id:r.id,name:r.name,input:r.input};case"tool_result":return{type:"tool_result",tool_use_id:r.tool_use_id,content:r.content,is_error:r.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(r=>r!==void 0);return{role:t.role,content:s}})}mapTools(e){let t=e.map(s=>({name:s.name,description:s.description,input_schema:s.inputSchema}));return t.length>0&&(t[t.length-1].cache_control={type:"ephemeral"}),t}mapResponse(e){let t="",s=[];for(let r of e.content)r.type==="text"?t+=r.text:r.type==="tool_use"&&s.push({id:r.id,name:r.name,input:r.input});return{content:t,model:e.model??this.config.model,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens,cacheCreationTokens:e.usage.cache_creation_input_tokens??0,cacheReadTokens:e.usage.cache_read_input_tokens??0},stopReason:e.stop_reason}}}});import hh from"openai";var je,Qt=T(()=>{"use strict";Dt();je=class extends Ce{static{m(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new hh({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=nt(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},n=await this.client.chat.completions.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.chat.completions.create({model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},stream:!0}),n,o,i="",a="",c=[],d=null,u=0,p=0;for await(let h of r){let f=h.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(a+=g.content,yield{type:"text_delta",text:g.content}),g?.tool_calls)for(let y of g.tool_calls)if(y.id){if(n){let _;try{_=JSON.parse(i||"{}")}catch{_={}}c.push({id:n,name:o,input:_})}n=y.id,o=y.function?.name,i=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:o}}}else y.function?.arguments&&(i+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),h.usage&&(u=h.usage.prompt_tokens,p=h.usage.completion_tokens)}if(n){let h;try{h=JSON.parse(i||"{}")}catch{h={}}c.push({id:n,name:o,input:h})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens: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(t){let s=t instanceof Error?t.message:String(t);console.warn(`[OpenAIProvider] embed() failed: ${s}`);return}}supportsEmbeddings(){return!0}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let n=[],o=[],i=[];for(let a of r.content)switch(a.type){case"text":n.push({type:"text",text:a.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":o.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input)}});break;case"tool_result":i.push({tool_call_id:a.tool_use_id,content:a.content});break}if(r.role==="assistant"&&o.length>0){let a=n.map(c=>c.text).join("");s.push({role:"assistant",content:a||null,tool_calls:o})}else if(i.length>0)for(let a of i)s.push({role:"tool",tool_call_id:a.tool_call_id,content:a.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(a=>a.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,r=s?.content??"",n=s?.tool_calls?.map(o=>({id:o.id,name:o.function.name,input:(()=>{try{return JSON.parse(o.function.arguments)}catch{return{}}})()}));return{content:r,model:e.model??this.config.model,toolCalls:n&&n.length>0?n:void 0,usage:{inputTokens:e.usage?.prompt_tokens??0,outputTokens:e.usage?.completion_tokens??0},stopReason:this.mapStopReason(t?.finish_reason??null)}}mapStopReason(e){switch(e){case"stop":return"end_turn";case"tool_calls":return"tool_use";case"length":return"max_tokens";default:return"end_turn"}}}});var Ir,Fi=T(()=>{"use strict";Qt();Ir=class extends je{static{m(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Ar,ji=T(()=>{"use strict";Dt();Ar=class extends Ce{static{m(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=nt(this.config.model);t?this.contextWindow=t:await this.fetchModelContextWindow()}async fetchModelContextWindow(){try{let e=await fetch(`${this.baseUrl}/api/show`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:this.config.model})});if(!e.ok)return;let s=(await e.json()).model_info??{},r=Object.keys(s).find(o=>o.includes("context_length")||o==="num_ctx"),n=r?Number(s[r]):0;n>0&&(this.contextWindow={maxInputTokens:n,maxOutputTokens:Math.min(n,4096)})}catch{}}getHeaders(){let e={"Content-Type":"application/json"};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}async complete(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text();throw new Error(`Ollama API error (${n.status}): ${i}`)}let o=await n.json();return this.mapResponse(o)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let h=await n.text();throw new Error(`Ollama API error (${n.status}): ${h}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let o=n.body.getReader(),i=new TextDecoder,a="",c="",d=0,u=0,p=[];try{for(;;){let{done:h,value:f}=await o.read();if(h)break;a+=i.decode(f,{stream:!0});let g=a.split(`
|
|
605
|
+
`);a=g.pop()??"";for(let y of g){let _=y.trim();if(!_)continue;let S;try{S=JSON.parse(_)}catch{continue}if(S.message?.content&&(c+=S.message.content,yield{type:"text_delta",text:S.message.content}),S.message?.tool_calls)for(let b of S.message.tool_calls){let $={id:`ollama_tool_${p.length}`,name:b.function.name,input:b.function.arguments};p.push($),yield{type:"tool_use_start",toolCall:{id:$.id,name:$.name}},yield{type:"tool_use_delta",toolCall:{input:$.input}}}S.done&&(d=S.prompt_eval_count??0,u=S.eval_count??0,yield{type:"message_complete",response:{content:c,model:this.config.model,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:p.length>0?"tool_use":"end_turn"}})}}if(a.trim()){let h;try{h=JSON.parse(a.trim())}catch{return}if(h.message?.content&&(c+=h.message.content,yield{type:"text_delta",text:h.message.content}),h.message?.tool_calls)for(let f of h.message.tool_calls){let g={id:`ollama_tool_${p.length}`,name:f.function.name,input:f.function.arguments};p.push(g),yield{type:"tool_use_start",toolCall:{id:g.id,name:g.name}},yield{type:"tool_use_delta",toolCall:{input:g.input}}}h.done&&(d=h.prompt_eval_count??0,u=h.eval_count??0,yield{type:"message_complete",response:{content:c,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:p.length>0?"tool_use":"end_turn"}})}}finally{o.releaseLock()}}isAvailable(){try{return this.baseUrl.length>0}catch{return!1}}async embed(e){try{let t=await fetch(`${this.baseUrl}/api/embed`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({model:"nomic-embed-text",input:e})});if(!t.ok)return;let s=await t.json();if(!s.embeddings||s.embeddings.length===0)return;let r=s.embeddings[0];return{embedding:r,model:"nomic-embed-text",dimensions:r.length}}catch{return}}supportsEmbeddings(){return!0}buildOptions(e){let t={},s=e.temperature??this.config.temperature;s!==void 0&&(t.temperature=s);let r=e.maxTokens??this.config.maxTokens;return r!==void 0&&(t.num_predict=r),t}buildMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e)typeof r.content=="string"?s.push({role:r.role,content:r.content}):s.push(this.mapContentBlocks(r.role,r.content));return s}mapContentBlocks(e,t){let s=[],r=[];for(let o of t)switch(o.type){case"text":s.push(o.text);break;case"image":r.push(o.source.data);break;case"tool_use":s.push(`[Tool call: ${o.name}(${JSON.stringify(o.input)})]`);break;case"tool_result":s.push(`[Tool result for ${o.tool_use_id}]: ${o.content}`);break}let n={role:e,content:s.join(`
|
|
606
|
+
`)};return r.length>0&&(n.images=r),n}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=[];if(e.message.tool_calls)for(let s of e.message.tool_calls)t.push({id:`ollama_tool_${t.length}`,name:s.function.name,input:s.function.arguments});return{content:e.message.content,model:this.config.model,toolCalls:t.length>0?t:void 0,usage:{inputTokens:e.prompt_eval_count??0,outputTokens:e.eval_count??0},stopReason:t.length>0?"tool_use":"end_turn"}}}});var Rr,Bi=T(()=>{"use strict";Qt();Rr=class extends je{static{m(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as fh}from"@google/genai";var xr,Hi=T(()=>{"use strict";Dt();xr=class extends Ce{static{m(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new fh({apiKey:this.config.apiKey});let e=nt(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),n="",o=[],i=0,a=0,c;for await(let d of r){c=d;let u=d.text;if(u&&(n+=u,yield{type:"text_delta",text:u}),d.functionCalls)for(let p of d.functionCalls){let h={id:p.id??`google_tool_${o.length}`,name:p.name,input:p.args??{}};o.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:o.length>0?o:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:o.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(n=>n.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let n=this.rawContentCache.keys().next().value;n&&this.rawContentCache.delete(n)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let n of r.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let r of e){let n=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:n,parts:[{text:r.content}]});continue}let o=[],i=[],a=[];for(let c of r.content)switch(c.type){case"text":i.push({text:c.text});break;case"image":i.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":o.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let d=t.get(c.tool_use_id)??c.tool_use_id,u;try{let p=JSON.parse(c.content);u=typeof p=="object"&&p!==null?p:{result:p}}catch{u={result:c.content}}a.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&o.length>0){let c=this.buildCacheKeyFromBlocks(o),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...i];for(let p=0;p<o.length;p++){let h=o[p];u.push({functionCall:{id:h.id,name:h.name,args:h.input},...p===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else i.length>0&&s.push({role:n,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let c=a.functionCall.id??a.functionCall.name??"";c&&t.add(c)}s.push(i)}else{let a=(i.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let c=a.functionResponse.id??a.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&n.push({role:i.role,parts:a})}else n.push(i);if(n.length<=1)return n;let o=[n[0]];for(let i=1;i<n.length;i++){let a=o[o.length-1],c=n[i];a.role===c.role?a.parts=[...a.parts??[],...c.parts??[]]:o.push(c)}return o}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((n,o)=>({id:n.id??`google_tool_${o}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var Cr,Wi=T(()=>{"use strict";Qt();Cr=class extends je{static{m(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function zi(l){switch(l.provider){case"anthropic":return new $r(l);case"openai":return new je(l);case"openrouter":return new Ir(l);case"ollama":return new Ar(l);case"openwebui":return new Rr(l);case"google":return new xr(l);case"mistral":return new Cr(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var qi=T(()=>{"use strict";Ui();Qt();Fi();ji();Bi();Hi();Wi();m(zi,"createLLMProvider")});function Hl(l){let e=l.toLowerCase();for(let[t,s]of gh)if(e.startsWith(t.toLowerCase()))return s}function Yn(l,e){let t=Hl(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=Math.max(0,e.inputTokens-n);return r+=i/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),o>0&&t.cacheWrite&&(r+=o/s*t.cacheWrite),r}var gh,Nr,Gi=T(()=>{"use strict";gh=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];m(Hl,"getModelPricing");m(Yn,"calculateCost");Nr=class{static{m(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=Yn(e,t),r=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=r,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let o=this.data.byModel[e];o||(o={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=o),o.calls++,o.inputTokens+=t.inputTokens,o.outputTokens+=t.outputTokens,o.cacheReadTokens+=r,o.cacheWriteTokens+=n,o.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,r,n,s)}catch{}return s}getSummary(){return{...this.data,totalCostUsd:Math.round(this.data.totalCostUsd*1e6)/1e6,byModel:Object.fromEntries(Object.entries(this.data.byModel).map(([e,t])=>[e,{...t,costUsd:Math.round(t.costUsd*1e6)/1e6}]))}}}});function Xi(l,e){return new Jn(l,e)}var Wl,Jn,zl=T(()=>{"use strict";Dt();qi();Gi();Wl=["default","strong","fast","embeddings","local"],Jn=class extends Ce{static{m(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new Nr;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of Wl){let t=this.multiConfig[e];if(t){let s=zi(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}if(!this.providers.has("default"))throw new Error(`ModelRouter: no "default" tier configured. Available tiers: [${[...this.providers.keys()].join(", ")}]`)}resolve(e){if(e&&this.providers.has(e))return{provider:this.providers.get(e),resolvedTier:e};let t=this.providers.get("default");if(!t)throw new Error('ModelRouter: no "default" tier available. Was initialize() called?');return{provider:t,resolvedTier:"default"}}async complete(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=this.multiConfig[s];this.logger?.debug({requestedTier:e.tier??"default",resolvedTier:s,model:r?.model},"LLM routing request");try{return await this.executeComplete(t,s,e)}catch(n){if(!this.isRetryableError(n))throw n;return this.logger?.warn({err:n,tier:s},"Provider failed, attempting fallback"),this.completeWithFallback(e,s,n)}}async executeComplete(e,t,s){let r=this.multiConfig[t],n=await e.complete(s),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:t,model:o,costUsd:Math.round(i*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let r=["default","strong","fast"].filter(n=>n!==t);for(let n of r){let o=this.providers.get(n);if(o)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(o,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=!1;try{for await(let n of t.stream(e))r=!0,yield n}catch(n){if(r||!this.isRetryableError(n))throw n;this.logger?.warn({err:n,tier:s},"Stream provider failed before first chunk, attempting fallback");let o=["default","strong","fast"].filter(i=>i!==s);for(let i of o){let a=this.providers.get(i);if(a)try{this.logger?.info({tier:i},"Stream fallback to tier"),yield*a.stream(e);return}catch{continue}}throw n}}async embed(e){return(this.providers.get("embeddings")??this.resolve().provider).embed(e)}supportsEmbeddings(){return(this.providers.get("embeddings")??this.resolve().provider).supportsEmbeddings()}isAvailable(){return this.resolve().provider.isAvailable()}getContextWindow(){return this.resolve().provider.getContextWindow()}getProviderStatuses(){let e={};for(let t of Wl){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};m(Xi,"createModelRouter")});function Be(l){return Math.ceil(l.length/3.5)}function Mt(l){if(typeof l.content=="string")return Be(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=Be(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=Be(t.name)+Be(JSON.stringify(t.input));break;case"tool_result":e+=Be(t.content);break}return e}function Ki(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let a of l)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&n.set(c.id,c.name);let o=[];for(let a=0;a<l.length;a++){let c=l[a];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&o.push(a)}let i=new Set(o.slice(-t));return l.map((a,c)=>{if(i.has(c)||a.role!=="user"||!Array.isArray(a.content))return a;let d=!1,u=a.content.map(p=>{if(p.type!=="tool_result")return p;let h=p.content;if(typeof h!="string"||h.length<r)return p;d=!0;let f=n.get(p.tool_use_id)||"unknown",g=h.split(`
|
|
607
|
+
`)[0].slice(0,s),y=p.is_error?"Fehler":"Ergebnis";return{...p,content:`[${y}: ${f} \u2014 ${g}]`}});return d?{...a,content:u}:a})}var Lr,ql=T(()=>{"use strict";m(Be,"estimateTokens");m(Mt,"estimateMessageTokens");m(Ki,"trimOldToolResults");Lr=class{static{m(this,"PromptBuilder")}buildSystemPrompt(e={}){let{memories:t,skills:s,userProfile:r,todayEvents:n,conversationSummary:o}=e,i=process.platform==="darwin"?"macOS":process.platform==="win32"?"Windows":"Linux",a=process.env.HOME||process.env.USERPROFILE||"~",c=`You are Alfred, a personal AI assistant. You run on ${i} (home: ${a}).
|
|
592
608
|
|
|
593
609
|
## Core principles
|
|
594
610
|
- **When the user's intent is clear**, ACT immediately using your tools. Don't explain what you'll do \u2014 just do it.
|
|
@@ -637,16 +653,16 @@ For complex tasks, work through multiple steps:
|
|
|
637
653
|
- Name: ${r.displayName}`),r.timezone&&(c+=`
|
|
638
654
|
- Timezone: ${r.timezone}`),r.language&&(c+=`
|
|
639
655
|
- Language: ${r.language}`),r.bio&&(c+=`
|
|
640
|
-
- Bio: ${r.bio}`));let d=Intl.DateTimeFormat().resolvedOptions().timeZone,u=r?.timezone||d,p=new Date,h=p.toLocaleTimeString("en-GB",{timeZone:u,hour:"2-digit",minute:"2-digit"}),
|
|
656
|
+
- Bio: ${r.bio}`));let d=Intl.DateTimeFormat().resolvedOptions().timeZone,u=r?.timezone||d,p=new Date,h=p.toLocaleTimeString("en-GB",{timeZone:u,hour:"2-digit",minute:"2-digit"}),f=p.toLocaleDateString("en-CA",{timeZone:u}),g=p.toLocaleDateString("en-US",{timeZone:u,weekday:"long"});if(c+=`
|
|
641
657
|
|
|
642
658
|
## Current date & time`,c+=`
|
|
643
659
|
- Timezone: ${u}`,c+=`
|
|
644
|
-
- Date: ${
|
|
660
|
+
- Date: ${f} (${g})`,c+=`
|
|
645
661
|
- Time: ${h}`,r?.timezone&&r.timezone!==d&&(c+=`
|
|
646
662
|
- Server timezone: ${d}`),n&&n.length>0){c+=`
|
|
647
663
|
|
|
648
|
-
## Today's events`;for(let y of n){let
|
|
649
|
-
- ${
|
|
664
|
+
## Today's events`;for(let y of n){let _=y.allDay?"All day":y.start.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...r?.timezone?{timeZone:r.timezone}:{}}),S=y.allDay?"":`-${y.end.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...r?.timezone?{timeZone:r.timezone}:{}})}`,b=y.location?` @ ${y.location}`:"";c+=`
|
|
665
|
+
- ${_}${S}: ${y.title}${b}`}}if(o&&(c+=`
|
|
650
666
|
|
|
651
667
|
## Conversation context
|
|
652
668
|
`,c+=o,c+=`
|
|
@@ -654,52 +670,52 @@ For complex tasks, work through multiple steps:
|
|
|
654
670
|
This summarizes the earlier conversation. Use it to maintain continuity. The most recent messages follow below.`),t&&t.length>0){if(c+=`
|
|
655
671
|
|
|
656
672
|
## Memories about this user
|
|
657
|
-
`,t.some(
|
|
673
|
+
`,t.some(_=>_.type&&_.type!=="general")){let _=new Map;for(let b of t){let $=b.type||"general",N=_.get($);N||(N=[],_.set($,N)),N.push(b)}let S={fact:"Facts",preference:"Preferences",correction:"Corrections",entity:"Entities",decision:"Decisions",relationship:"Relationships",principle:"Principles",commitment:"Commitments",moment:"Moments",skill:"Skills",feedback:"Behavior Feedback",general:"General"};for(let[b,$]of _){c+=`
|
|
658
674
|
### ${S[b]||b}
|
|
659
|
-
`;for(let
|
|
660
|
-
`}}else for(let
|
|
675
|
+
`;for(let N of $)c+=`- ${N.key}: ${N.value}
|
|
676
|
+
`}}else for(let _ of t)c+=`- [${_.category}] ${_.key}: ${_.value}
|
|
661
677
|
`;c+=`
|
|
662
678
|
Use these memories to personalize your responses. When the user tells you new facts or preferences, use the memory tool to save them.`}else c+=`
|
|
663
679
|
|
|
664
|
-
When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return c}buildMessages(e){let t=e.filter(s=>s.role==="user"||s.role==="assistant").map(s=>{if(s.toolCalls){let r;try{r=JSON.parse(s.toolCalls)}catch{r=[]}if(s.role==="assistant"){let i=r,a=[];s.content&&a.push({type:"text",text:s.content});for(let c of i)a.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let n=r,o=[];for(let i of n)i.type==="tool_result"&&o.push(i);return o.length>0?{role:"user",content:o}:{role:"user",content:s.content||""}}return{role:s.role,content:s.content}});return this.sanitizeToolMessages(t)}sanitizeToolMessages(e){let t=new Set,s=new Set;for(let a of e)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&t.add(c.id);else if(a.role==="user"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_result"&&t.has(c.tool_use_id)&&s.add(c.tool_use_id);let r=new Set,n=new Set,o=[];for(let a of e){if(!Array.isArray(a.content)){o.push(a);continue}let c=a.content.filter(d=>d.type==="tool_use"?!s.has(d.id)||r.has(d.id)?!1:(r.add(d.id),!0):d.type==="tool_result"?!s.has(d.tool_use_id)||n.has(d.tool_use_id)?!1:(n.add(d.tool_use_id),!0):!0);c.length!==0&&o.push({...a,content:c})}let i=[];for(let a of o){let c=i[i.length-1];if(c&&c.role===a.role){let d=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content,u=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...c,content:[...d,...u]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var ji=T(()=>{"use strict";Lt();Ri();Jt();xi();Ci();Li();Ni();Di();Oi();Rl();xl();Pi()});var Ar,Bi=T(()=>{"use strict";Ar=class{static{m(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let o=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:o,resetsAt:n.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);!n||s>n.windowStart+n.windowMs?this.buckets.set(e,{count:1,windowStart:s,windowMs:r}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+s.windowMs*2&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var Rr,Cl=T(()=>{"use strict";Bi();Rr=class{static{m(this,"RuleEngine")}rules=[];rateLimiter=new Ar;loadRules(e){this.rules=[...e].sort((t,s)=>t.priority-s.priority)}getRules(){return this.rules}evaluate(e){for(let t of this.rules)if(this.ruleMatches(t,e))return t.rateLimit&&t.effect==="allow"&&!this.checkRateLimit(t,e)?{allowed:!1,matchedRule:t,reason:`Rate limit exceeded for rule: ${t.id}`,timestamp:new Date}:{allowed:t.effect==="allow",matchedRule:t,reason:`Matched rule: ${t.id}`,timestamp:new Date};return{allowed:!1,matchedRule:void 0,reason:"No matching rule found \u2014 default deny",timestamp:new Date}}checkRateLimit(e,t){if(!e.rateLimit)return!0;let s=this.getScopeKey(e.scope,t),r=`${e.id}:${s}`;return this.rateLimiter.checkAndIncrement(r,e.rateLimit).allowed}resetRateLimits(){this.rateLimiter.reset()}getScopeKey(e,t){switch(e){case"global":return"global";case"user":return t.userId;case"conversation":return t.chatId??"unknown";case"platform":return t.platform}}ruleMatches(e,t){return!(!e.actions.includes("*")&&!e.actions.includes(t.action)||!e.riskLevels.includes(t.riskLevel)||e.conditions&&(e.conditions.users&&e.conditions.users.length>0&&!e.conditions.users.includes(t.userId)||e.conditions.platforms&&e.conditions.platforms.length>0&&!e.conditions.platforms.includes(t.platform)||e.conditions.chatType&&e.conditions.chatType!==t.chatType||e.conditions.timeWindow&&!this.matchesTimeWindow(e.conditions.timeWindow)))}matchesTimeWindow(e){if(!e)return!0;let t=new Date;if(e.daysOfWeek&&e.daysOfWeek.length>0&&!e.daysOfWeek.includes(t.getDay()))return!1;let s=t.getHours();if(e.startHour!==void 0&&e.endHour!==void 0){if(e.startHour<=e.endHour){if(s<e.startHour||s>=e.endHour)return!1}else if(s>=e.endHour&&s<e.startHour)return!1}else if(e.startHour!==void 0){if(s<e.startHour)return!1}else if(e.endHour!==void 0&&s>=e.endHour)return!1;return!0}}});var Ll,Nl,Dl,rt,Ml=T(()=>{"use strict";Ll=["allow","deny"],Nl=["global","user","conversation","platform"],Dl=["read","write","destructive","admin"],rt=class{static{m(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!Ll.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Ll.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"||!Nl.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Nl.join(", ")}`);if(!Array.isArray(s.actions)||s.actions.length===0)throw new Error(`Rule "${s.id}" is missing a valid "actions" array`);for(let n of s.actions)if(typeof n!="string")throw new Error(`Rule "${s.id}" has a non-string entry in "actions"`);if(!Array.isArray(s.riskLevels)||s.riskLevels.length===0)throw new Error(`Rule "${s.id}" is missing a valid "riskLevels" array`);for(let n of s.riskLevels)if(!Dl.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${Dl.join(", ")}`);let r={id:s.id,effect:s.effect,priority:s.priority,scope:s.scope,actions:s.actions,riskLevels:s.riskLevels};if(s.conditions!==void 0){if(typeof s.conditions!="object"||s.conditions===null)throw new Error(`Rule "${s.id}" has invalid "conditions": expected an object`);let n=s.conditions;if(n.users!==void 0&&!Array.isArray(n.users))throw new Error(`Rule "${s.id}" has invalid "conditions.users": expected an array`);if(n.platforms!==void 0&&!Array.isArray(n.platforms))throw new Error(`Rule "${s.id}" has invalid "conditions.platforms": expected an array`);if(n.chatType!==void 0&&typeof n.chatType!="string")throw new Error(`Rule "${s.id}" has invalid "conditions.chatType": expected a string`);if(n.timeWindow!==void 0){let o=n.timeWindow;if(typeof o!="object"||o===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(o.startHour!==void 0&&(typeof o.startHour!="number"||o.startHour<0||o.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(o.endHour!==void 0&&(typeof o.endHour!="number"||o.endHour<0||o.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(o.daysOfWeek!==void 0&&(!Array.isArray(o.daysOfWeek)||!o.daysOfWeek.every(i=>typeof i=="number"&&i>=0&&i<=6)))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.daysOfWeek": expected array of 0-6`)}r.conditions=s.conditions}if(s.rateLimit!==void 0){if(typeof s.rateLimit!="object"||s.rateLimit===null)throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected an object`);let n=s.rateLimit;if(typeof n.maxInvocations!="number"||typeof n.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import Qp from"node:crypto";var xr,Ol=T(()=>{"use strict";xr=class{static{m(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:Qp.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 qn=T(()=>{"use strict";Cl();Bi();Ml();Ol()});var x,W=T(()=>{"use strict";x=class{static{m(this,"Skill")}}});function le(l){return l.masterUserId??l.userId}function X(l){let e=new Set;if(e.add(le(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var De=T(()=>{"use strict";m(le,"effectiveUserId");m(X,"allUserIds")});var Zt,Pl=T(()=>{"use strict";Zt=class{static{m(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var Qt,Ul=T(()=>{"use strict";Qt=class{static{m(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:o}=e.metadata;return this.logger.info({skill:o,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,o,r,n):this.executeWithHardTimeout(e,t,s,o,r)}async executeWithTracker(e,t,s,r,n,o){return new Promise(i=>{let a=!1,c,d,u,p=m(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),h=m(g=>{a||(a=!0,p(),i(g))},"finish");e.execute(t,s).then(g=>{this.logger.info({skill:r,success:g.success,...g.success?{}:{error:g.error}},"Skill execution completed"),h(g)},g=>{let f=g instanceof Error?g.message:String(g);this.logger.error({skill:r,error:f},"Skill execution failed"),h({success:!1,error:f})}),u=setTimeout(()=>{if(a)return;let g=o.getIdleMs();if(g>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:g,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),h({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(g/1e3)}s (last state: ${y.state})`});return}let f=o.getSnapshot();this.logger.info({skill:r,idleMs:g,state:f.state,iteration:f.iteration,totalMs:f.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){p();return}let y=o.getIdleMs(),k=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:k.state,iteration:k.iteration,totalMs:k.totalElapsedMs},"Agent went inactive \u2014 aborting"),h({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${k.state})`})):this.logger.debug({skill:r,idleMs:y,state:k.state,iteration:k.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let g=o.getSnapshot();this.logger.error({skill:r,totalMs:g.totalElapsedMs,state:g.state,iteration:g.iteration},"Absolute time limit reached \u2014 force killing agent"),h({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,n){try{let o,i=await Promise.race([e.execute(t,s),new Promise((a,c)=>{o=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{o&&clearTimeout(o)});return this.logger.info({skill:r,success:i.success,...i.success?{}:{error:i.error}},"Skill execution completed"),i}catch(o){let i=o instanceof Error?o.message:String(o);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var Dt,Hi=T(()=>{"use strict";Dt=class{static{m(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import eh from"node:fs";import Wi from"node:path";var Gn,Fl=T(()=>{"use strict";W();Gn=class{static{m(this,"PluginLoader")}async loadFromDirectory(e){let t=Wi.resolve(e),s;try{s=await eh.promises.readdir(t)}catch(o){let i=o instanceof Error?o.message:String(o);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(o=>o.endsWith(".js")),n=[];for(let o of r){let i=Wi.join(t,o);try{let a=await this.loadFromFile(i);n.push(a)}catch(a){let c=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${c}`)}}return n}async loadFromFile(e){let t=Wi.resolve(e),n=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof n!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let o=new n;if(!(o instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(o,t),o}validateMetadata(e,t){let{metadata:s}=e;if(!s)throw new Error(`Plugin "${t}" is missing metadata`);if(!s.name||typeof s.name!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.name`);if(!s.description||typeof s.description!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.description`);if(!["read","write","destructive","admin"].includes(s.riskLevel))throw new Error(`Plugin "${t}" has invalid metadata.riskLevel: "${String(s.riskLevel)}"`);if(!s.version||typeof s.version!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.version`)}}});function th(l){let e=[],t=0;for(;t<l.length;){if(l[t]===" "||l[t]===" "){t++;continue}if(/[\d.]/.test(l[t])){let s="";for(;t<l.length&&/[\d.]/.test(l[t]);)s+=l[t++];let r=Number(s);if(isNaN(r))throw new Error(`Invalid number: ${s}`);e.push({type:"num",value:r});continue}if(l.startsWith("Math.",t)){t+=5;let s="";for(;t<l.length&&/[a-zA-Z0-9]/.test(l[t]);)s+=l[t++];if(s in jl)e.push({type:"const",value:jl[s]});else if(s in Bl)e.push({type:"fn",value:s});else throw new Error(`Unknown Math member: Math.${s}`);continue}if("+-*/%".includes(l[t])){e.push({type:"op",value:l[t++]});continue}if(l[t]==="("||l[t]===")"){e.push({type:"paren",value:l[t++]});continue}if(l[t]===","){e.push({type:"comma"}),t++;continue}throw new Error(`Unexpected character: ${l[t]}`)}return e}function sh(l){let e=th(l);if(e.length===0)throw new Error("Empty expression");return new zi(e).parse()}var Bl,jl,zi,es,Hl=T(()=>{"use strict";W();Bl={sin:Math.sin,cos:Math.cos,tan:Math.tan,sqrt:Math.sqrt,pow:Math.pow,abs:Math.abs,floor:Math.floor,ceil:Math.ceil,round:Math.round,log:Math.log,log2:Math.log2,log10:Math.log10},jl={PI:Math.PI,E:Math.E};m(th,"tokenize");zi=class{static{m(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return Bl[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};m(sh,"safeEval");es=class extends x{static{m(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=sh(r);return typeof n!="number"||!isFinite(n)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:n,display:`${r} = ${n}`}}catch(n){let o=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${o}`}}}}});var ts,Wl=T(()=>{"use strict";W();ts=class extends x{static{m(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=m(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var ss,zl=T(()=>{"use strict";W();ss=class extends x{static{m(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let o;switch(this.config.provider){case"brave":o=await this.searchBrave(s,r);break;case"searxng":o=await this.searchSearXNG(s,r);break;case"tavily":o=await this.searchTavily(s,r);break;case"duckduckgo":o=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(o.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=o.map((a,c)=>`${c+1}. **${a.title}**
|
|
680
|
+
When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return c}buildMessages(e){let t=e.filter(s=>s.role==="user"||s.role==="assistant").map(s=>{if(s.toolCalls){let r;try{r=JSON.parse(s.toolCalls)}catch{r=[]}if(s.role==="assistant"){let i=r,a=[];s.content&&a.push({type:"text",text:s.content});for(let c of i)a.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let n=r,o=[];for(let i of n)i.type==="tool_result"&&o.push(i);return o.length>0?{role:"user",content:o}:{role:"user",content:s.content||""}}return{role:s.role,content:s.content}});return this.sanitizeToolMessages(t)}sanitizeToolMessages(e){let t=new Set,s=new Set;for(let a of e)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&t.add(c.id);else if(a.role==="user"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_result"&&t.has(c.tool_use_id)&&s.add(c.tool_use_id);let r=new Set,n=new Set,o=[];for(let a of e){if(!Array.isArray(a.content)){o.push(a);continue}let c=a.content.filter(d=>d.type==="tool_use"?!s.has(d.id)||r.has(d.id)?!1:(r.add(d.id),!0):d.type==="tool_result"?!s.has(d.tool_use_id)||n.has(d.tool_use_id)?!1:(n.add(d.tool_use_id),!0):!0);c.length!==0&&o.push({...a,content:c})}let i=[];for(let a of o){let c=i[i.length-1];if(c&&c.role===a.role){let d=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content,u=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...c,content:[...d,...u]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var Vi=T(()=>{"use strict";Dt();Ui();Qt();Fi();ji();Bi();Hi();Wi();qi();zl();ql();Gi()});var Dr,Yi=T(()=>{"use strict";Dr=class{static{m(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let o=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:o,resetsAt:n.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);!n||s>n.windowStart+n.windowMs?this.buckets.set(e,{count:1,windowStart:s,windowMs:r}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+s.windowMs*2&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var Mr,Gl=T(()=>{"use strict";Yi();Mr=class{static{m(this,"RuleEngine")}rules=[];rateLimiter=new Dr;loadRules(e){this.rules=[...e].sort((t,s)=>t.priority-s.priority)}getRules(){return this.rules}evaluate(e){for(let t of this.rules)if(this.ruleMatches(t,e))return t.rateLimit&&t.effect==="allow"&&!this.checkRateLimit(t,e)?{allowed:!1,matchedRule:t,reason:`Rate limit exceeded for rule: ${t.id}`,timestamp:new Date}:{allowed:t.effect==="allow",matchedRule:t,reason:`Matched rule: ${t.id}`,timestamp:new Date};return{allowed:!1,matchedRule:void 0,reason:"No matching rule found \u2014 default deny",timestamp:new Date}}checkRateLimit(e,t){if(!e.rateLimit)return!0;let s=this.getScopeKey(e.scope,t),r=`${e.id}:${s}`;return this.rateLimiter.checkAndIncrement(r,e.rateLimit).allowed}resetRateLimits(){this.rateLimiter.reset()}getScopeKey(e,t){switch(e){case"global":return"global";case"user":return t.userId;case"conversation":return t.chatId??"unknown";case"platform":return t.platform}}ruleMatches(e,t){return!(!e.actions.includes("*")&&!e.actions.includes(t.action)||!e.riskLevels.includes(t.riskLevel)||e.conditions&&(e.conditions.users&&e.conditions.users.length>0&&!e.conditions.users.includes(t.userId)||e.conditions.platforms&&e.conditions.platforms.length>0&&!e.conditions.platforms.includes(t.platform)||e.conditions.chatType&&e.conditions.chatType!==t.chatType||e.conditions.timeWindow&&!this.matchesTimeWindow(e.conditions.timeWindow)))}matchesTimeWindow(e){if(!e)return!0;let t=new Date;if(e.daysOfWeek&&e.daysOfWeek.length>0&&!e.daysOfWeek.includes(t.getDay()))return!1;let s=t.getHours();if(e.startHour!==void 0&&e.endHour!==void 0){if(e.startHour<=e.endHour){if(s<e.startHour||s>=e.endHour)return!1}else if(s>=e.endHour&&s<e.startHour)return!1}else if(e.startHour!==void 0){if(s<e.startHour)return!1}else if(e.endHour!==void 0&&s>=e.endHour)return!1;return!0}}});var Xl,Kl,Vl,ot,Yl=T(()=>{"use strict";Xl=["allow","deny"],Kl=["global","user","conversation","platform"],Vl=["read","write","destructive","admin"],ot=class{static{m(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!Xl.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Xl.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"||!Kl.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Kl.join(", ")}`);if(!Array.isArray(s.actions)||s.actions.length===0)throw new Error(`Rule "${s.id}" is missing a valid "actions" array`);for(let n of s.actions)if(typeof n!="string")throw new Error(`Rule "${s.id}" has a non-string entry in "actions"`);if(!Array.isArray(s.riskLevels)||s.riskLevels.length===0)throw new Error(`Rule "${s.id}" is missing a valid "riskLevels" array`);for(let n of s.riskLevels)if(!Vl.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${Vl.join(", ")}`);let r={id:s.id,effect:s.effect,priority:s.priority,scope:s.scope,actions:s.actions,riskLevels:s.riskLevels};if(s.conditions!==void 0){if(typeof s.conditions!="object"||s.conditions===null)throw new Error(`Rule "${s.id}" has invalid "conditions": expected an object`);let n=s.conditions;if(n.users!==void 0&&!Array.isArray(n.users))throw new Error(`Rule "${s.id}" has invalid "conditions.users": expected an array`);if(n.platforms!==void 0&&!Array.isArray(n.platforms))throw new Error(`Rule "${s.id}" has invalid "conditions.platforms": expected an array`);if(n.chatType!==void 0&&typeof n.chatType!="string")throw new Error(`Rule "${s.id}" has invalid "conditions.chatType": expected a string`);if(n.timeWindow!==void 0){let o=n.timeWindow;if(typeof o!="object"||o===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(o.startHour!==void 0&&(typeof o.startHour!="number"||o.startHour<0||o.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(o.endHour!==void 0&&(typeof o.endHour!="number"||o.endHour<0||o.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(o.daysOfWeek!==void 0&&(!Array.isArray(o.daysOfWeek)||!o.daysOfWeek.every(i=>typeof i=="number"&&i>=0&&i<=6)))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.daysOfWeek": expected array of 0-6`)}r.conditions=s.conditions}if(s.rateLimit!==void 0){if(typeof s.rateLimit!="object"||s.rateLimit===null)throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected an object`);let n=s.rateLimit;if(typeof n.maxInvocations!="number"||typeof n.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import yh from"node:crypto";var Or,Jl=T(()=>{"use strict";Or=class{static{m(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:yh.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 Zn=T(()=>{"use strict";Gl();Yi();Yl();Jl()});var x,W=T(()=>{"use strict";x=class{static{m(this,"Skill")}}});function de(l){return l.masterUserId??l.userId}function K(l){let e=new Set;if(e.add(de(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Me=T(()=>{"use strict";m(de,"effectiveUserId");m(K,"allUserIds")});var es,Zl=T(()=>{"use strict";es=class{static{m(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var ts,Ql=T(()=>{"use strict";ts=class{static{m(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:o}=e.metadata;return this.logger.info({skill:o,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,o,r,n):this.executeWithHardTimeout(e,t,s,o,r)}async executeWithTracker(e,t,s,r,n,o){return new Promise(i=>{let a=!1,c,d,u,p=m(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),h=m(f=>{a||(a=!0,p(),i(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),h(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),h({success:!1,error:g})}),u=setTimeout(()=>{if(a)return;let f=o.getIdleMs();if(f>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),h({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=o.getSnapshot();this.logger.info({skill:r,idleMs:f,state:g.state,iteration:g.iteration,totalMs:g.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){p();return}let y=o.getIdleMs(),_=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:_.state,iteration:_.iteration,totalMs:_.totalElapsedMs},"Agent went inactive \u2014 aborting"),h({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${_.state})`})):this.logger.debug({skill:r,idleMs:y,state:_.state,iteration:_.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let f=o.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),h({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,n){try{let o,i=await Promise.race([e.execute(t,s),new Promise((a,c)=>{o=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{o&&clearTimeout(o)});return this.logger.info({skill:r,success:i.success,...i.success?{}:{error:i.error}},"Skill execution completed"),i}catch(o){let i=o instanceof Error?o.message:String(o);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var Ot,Ji=T(()=>{"use strict";Ot=class{static{m(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import wh from"node:fs";import Zi from"node:path";var Qn,ed=T(()=>{"use strict";W();Qn=class{static{m(this,"PluginLoader")}async loadFromDirectory(e){let t=Zi.resolve(e),s;try{s=await wh.promises.readdir(t)}catch(o){let i=o instanceof Error?o.message:String(o);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(o=>o.endsWith(".js")),n=[];for(let o of r){let i=Zi.join(t,o);try{let a=await this.loadFromFile(i);n.push(a)}catch(a){let c=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${c}`)}}return n}async loadFromFile(e){let t=Zi.resolve(e),n=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof n!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let o=new n;if(!(o instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(o,t),o}validateMetadata(e,t){let{metadata:s}=e;if(!s)throw new Error(`Plugin "${t}" is missing metadata`);if(!s.name||typeof s.name!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.name`);if(!s.description||typeof s.description!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.description`);if(!["read","write","destructive","admin"].includes(s.riskLevel))throw new Error(`Plugin "${t}" has invalid metadata.riskLevel: "${String(s.riskLevel)}"`);if(!s.version||typeof s.version!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.version`)}}});function Th(l){let e=[],t=0;for(;t<l.length;){if(l[t]===" "||l[t]===" "){t++;continue}if(/[\d.]/.test(l[t])){let s="";for(;t<l.length&&/[\d.]/.test(l[t]);)s+=l[t++];let r=Number(s);if(isNaN(r))throw new Error(`Invalid number: ${s}`);e.push({type:"num",value:r});continue}if(l.startsWith("Math.",t)){t+=5;let s="";for(;t<l.length&&/[a-zA-Z0-9]/.test(l[t]);)s+=l[t++];if(s in td)e.push({type:"const",value:td[s]});else if(s in sd)e.push({type:"fn",value:s});else throw new Error(`Unknown Math member: Math.${s}`);continue}if("+-*/%".includes(l[t])){e.push({type:"op",value:l[t++]});continue}if(l[t]==="("||l[t]===")"){e.push({type:"paren",value:l[t++]});continue}if(l[t]===","){e.push({type:"comma"}),t++;continue}throw new Error(`Unexpected character: ${l[t]}`)}return e}function _h(l){let e=Th(l);if(e.length===0)throw new Error("Empty expression");return new Qi(e).parse()}var sd,td,Qi,ss,rd=T(()=>{"use strict";W();sd={sin:Math.sin,cos:Math.cos,tan:Math.tan,sqrt:Math.sqrt,pow:Math.pow,abs:Math.abs,floor:Math.floor,ceil:Math.ceil,round:Math.round,log:Math.log,log2:Math.log2,log10:Math.log10},td={PI:Math.PI,E:Math.E};m(Th,"tokenize");Qi=class{static{m(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return sd[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};m(_h,"safeEval");ss=class extends x{static{m(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=_h(r);return typeof n!="number"||!isFinite(n)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:n,display:`${r} = ${n}`}}catch(n){let o=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${o}`}}}}});var rs,nd=T(()=>{"use strict";W();rs=class extends x{static{m(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=m(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var ns,od=T(()=>{"use strict";W();ns=class extends x{static{m(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let o;switch(this.config.provider){case"brave":o=await this.searchBrave(s,r);break;case"searxng":o=await this.searchSearXNG(s,r);break;case"tavily":o=await this.searchTavily(s,r);break;case"duckduckgo":o=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(o.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=o.map((a,c)=>`${c+1}. **${a.title}**
|
|
665
681
|
${a.url}
|
|
666
682
|
${a.snippet}`).join(`
|
|
667
683
|
|
|
668
684
|
`);return{success:!0,data:{query:s,results:o},display:`Search results for "${s}":
|
|
669
685
|
|
|
670
|
-
${i}`}}catch(o){return{success:!1,error:`Search failed: ${o instanceof Error?o.message:String(o)}`}}}async searchBrave(e,t){let s=new URL("https://api.search.brave.com/res/v1/web/search");s.searchParams.set("q",e),s.searchParams.set("count",String(t));let r=await fetch(s.toString(),{headers:{Accept:"application/json","Accept-Encoding":"gzip","X-Subscription-Token":this.config.apiKey}});if(!r.ok)throw new Error(`Brave Search API returned ${r.status}: ${r.statusText}`);return((await r.json()).web?.results??[]).slice(0,t).map(o=>({title:o.title,url:o.url,snippet:o.description}))}async searchSearXNG(e,t){let s=(this.config.baseUrl??"http://localhost:8080").replace(/\/+$/,""),r=new URL(`${s}/search`);r.searchParams.set("q",e),r.searchParams.set("format","json"),r.searchParams.set("pageno","1");let n=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`SearXNG returned ${n.status}: ${n.statusText}`);return((await n.json()).results??[]).slice(0,t).map(i=>({title:i.title,url:i.url,snippet:i.content}))}async searchTavily(e,t){let s=await fetch("https://api.tavily.com/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:this.config.apiKey,query:e,max_results:t,include_answer:!1})});if(!s.ok)throw new Error(`Tavily API returned ${s.status}: ${s.statusText}`);return((await s.json()).results??[]).slice(0,t).map(n=>({title:n.title,url:n.url,snippet:n.content}))}async searchDuckDuckGo(e,t){let s=new URL("https://html.duckduckgo.com/html/");s.searchParams.set("q",e);let r=await fetch(s.toString(),{headers:{"User-Agent":"Mozilla/5.0 (compatible; Alfred/1.0)"}});if(!r.ok)throw new Error(`DuckDuckGo returned ${r.status}: ${r.statusText}`);let n=await r.text();return this.parseDuckDuckGoHtml(n,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,n=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,o=[],i;for(;(i=r.exec(e))!==null;){let c=i[1],d=this.stripHtml(i[2]).trim(),u=this.extractDdgUrl(c);d&&u&&o.push({url:u,title:d})}let a=[];for(;(i=n.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let c=0;c<Math.min(o.length,t);c++)s.push({title:o[c].title,url:o[c].url,snippet:a[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ")}}});var
|
|
686
|
+
${i}`}}catch(o){return{success:!1,error:`Search failed: ${o instanceof Error?o.message:String(o)}`}}}async searchBrave(e,t){let s=new URL("https://api.search.brave.com/res/v1/web/search");s.searchParams.set("q",e),s.searchParams.set("count",String(t));let r=await fetch(s.toString(),{headers:{Accept:"application/json","Accept-Encoding":"gzip","X-Subscription-Token":this.config.apiKey}});if(!r.ok)throw new Error(`Brave Search API returned ${r.status}: ${r.statusText}`);return((await r.json()).web?.results??[]).slice(0,t).map(o=>({title:o.title,url:o.url,snippet:o.description}))}async searchSearXNG(e,t){let s=(this.config.baseUrl??"http://localhost:8080").replace(/\/+$/,""),r=new URL(`${s}/search`);r.searchParams.set("q",e),r.searchParams.set("format","json"),r.searchParams.set("pageno","1");let n=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`SearXNG returned ${n.status}: ${n.statusText}`);return((await n.json()).results??[]).slice(0,t).map(i=>({title:i.title,url:i.url,snippet:i.content}))}async searchTavily(e,t){let s=await fetch("https://api.tavily.com/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:this.config.apiKey,query:e,max_results:t,include_answer:!1})});if(!s.ok)throw new Error(`Tavily API returned ${s.status}: ${s.statusText}`);return((await s.json()).results??[]).slice(0,t).map(n=>({title:n.title,url:n.url,snippet:n.content}))}async searchDuckDuckGo(e,t){let s=new URL("https://html.duckduckgo.com/html/");s.searchParams.set("q",e);let r=await fetch(s.toString(),{headers:{"User-Agent":"Mozilla/5.0 (compatible; Alfred/1.0)"}});if(!r.ok)throw new Error(`DuckDuckGo returned ${r.status}: ${r.statusText}`);let n=await r.text();return this.parseDuckDuckGoHtml(n,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,n=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,o=[],i;for(;(i=r.exec(e))!==null;){let c=i[1],d=this.stripHtml(i[2]).trim(),u=this.extractDdgUrl(c);d&&u&&o.push({url:u,title:d})}let a=[];for(;(i=n.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let c=0;c<Math.min(o.length,t);c++)s.push({title:o[c].title,url:o[c].url,snippet:a[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ")}}});var os,id=T(()=>{"use strict";W();Me();os=class extends x{static{m(this,"ReminderSkill")}reminderRepo;metadata={name:"reminder",category:"productivity",description:'Set timed reminders that notify the user later. Use when the user says "remind me", "erinnere mich", or asks to be notified about something at a specific time. Prefer triggerAt (absolute time like "14:30" or "2026-02-28 09:00") over delayMinutes \u2014 it is more precise and avoids calculation errors.',riskLevel:"write",version:"3.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["set","list","cancel"],description:"The reminder action to perform"},message:{type:"string",description:"The reminder message (required for set)"},triggerAt:{type:"string",description:'Absolute time for the reminder. Accepts "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date. Preferred over delayMinutes for time-specific reminders.'},delayMinutes:{type:"number",description:"Minutes until the reminder triggers. Use triggerAt instead when the user specifies a clock time."},reminderId:{type:"string",description:"The ID of the reminder to cancel (required for cancel)"}},required:["action"]}};constructor(e){super(),this.reminderRepo=e}getAllReminders(e){let t=new Set,s=[];for(let r of K(e))for(let n of this.reminderRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"set":return this.setReminder(e,t);case"list":return this.listReminders(t);case"cancel":return this.cancelReminder(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: set, list, cancel`}}}setReminder(e,t){let s=e.message,r=e.triggerAt,n=e.delayMinutes;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "message" for set action'};let o;if(r&&typeof r=="string"){let u=this.parseTriggerAt(r,t.timezone);if(!u)return{success:!1,error:`Could not parse triggerAt "${r}". Use "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date.`};if(u.getTime()<=Date.now())return{success:!1,error:`The time "${r}" is in the past. Please specify a future time.`};o=u}else if(n!==void 0&&typeof n=="number"&&n>0)o=new Date(Date.now()+n*60*1e3);else return{success:!1,error:'Provide either "triggerAt" (e.g. "14:30") or "delayMinutes" (positive number) for set action.'};let i=this.reminderRepo.create(de(t),t.platform,t.chatId,s,o),a=o.getTime()-Date.now(),c=Math.round(a/6e4),d=o.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...t.timezone?{timeZone:t.timezone}:{}});return{success:!0,data:{reminderId:i.id,message:s,triggerAt:i.triggerAt},display:`Reminder set (${i.id}): "${s}" at ${d} (in ${c} min)`}}parseTriggerAt(e,t){let s=e.trim(),r=/^(\d{1,2}):(\d{2})$/.exec(s);if(r){let o=parseInt(r[1],10),i=parseInt(r[2],10);return o>23||i>59?void 0:this.buildDateInTimezone(o,i,void 0,t)}let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(n){let o=parseInt(n[1],10),i=parseInt(n[2],10)-1,a=parseInt(n[3],10),c=parseInt(n[4],10),d=parseInt(n[5],10);return c>23||d>59||i>11||a>31?void 0:this.buildDateInTimezone(c,d,{year:o,month:i,day:a},t)}}buildDateInTimezone(e,t,s,r){if(!r){let h=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||h.setHours(e,t,0,0),h}let n=new Date,o=s?new Date(Date.UTC(s.year,s.month,s.day,e,t,0)):new Date(Date.UTC(n.getFullYear(),n.getMonth(),n.getDate(),e,t,0)),i=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});if(!s){let h=i.formatToParts(n),f=parseInt(h.find(M=>M.type==="year").value,10),g=parseInt(h.find(M=>M.type==="month").value,10)-1,y=parseInt(h.find(M=>M.type==="day").value,10),_=new Date(Date.UTC(f,g,y,e,t,0)),S=i.formatToParts(_),b=parseInt(S.find(M=>M.type==="hour").value,10),$=parseInt(S.find(M=>M.type==="minute").value,10),N=(e-b)*60+(t-$);return _=new Date(_.getTime()+N*6e4),_}let a=o,c=i.formatToParts(a),d=parseInt(c.find(h=>h.type==="hour").value,10),u=parseInt(c.find(h=>h.type==="minute").value,10),p=(e-d)*60+(t-u);return a=new Date(a.getTime()+p*6e4),a}listReminders(e){let s=this.getAllReminders(e).map(r=>({reminderId:r.id,message:r.message,triggerAt:r.triggerAt}));return{success:!0,data:s,display:s.length===0?"No active reminders.":`Active reminders:
|
|
671
687
|
${s.map(r=>`- ${r.reminderId}: "${r.message}" (triggers at ${r.triggerAt})`).join(`
|
|
672
|
-
`)}`}}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
|
|
688
|
+
`)}`}}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 is,ad=T(()=>{"use strict";W();Me();is=class extends x{static{m(this,"NoteSkill")}noteRepo;metadata={name:"note",category:"productivity",description:"Save, list, search, or delete persistent notes (stored in SQLite). Use when the user wants to write down or retrieve text notes, lists, or ideas.",riskLevel:"write",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","list","search","delete"],description:"The note action to perform"},title:{type:"string",description:"The note title (required for save)"},content:{type:"string",description:"The note content (required for save)"},noteId:{type:"string",description:"The ID of the note to delete (required for delete)"},query:{type:"string",description:"Search query to filter notes (required for search)"}},required:["action"]}};constructor(e){super(),this.noteRepo=e}async execute(e,t){let s=e.action;switch(s){case"save":return this.saveNote(e,t);case"list":return this.listNotes(t);case"search":return this.searchNotes(e,t);case"delete":return this.deleteNote(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: save, list, search, delete`}}}saveNote(e,t){let s=e.title,r=e.content;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "title" for save action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "content" for save action'};let n=this.noteRepo.save(de(t),s,r);return{success:!0,data:{noteId:n.id,title:n.title},display:`Note saved: "${s}"`}}listNotes(e){let t=new Set,s=[];for(let n of K(e))for(let o of this.noteRepo.list(n))t.has(o.id)||(t.add(o.id),s.push(o));if(s.length===0)return{success:!0,data:[],display:"No notes found."};let r=s.map(n=>`- **${n.title}** (${n.id.slice(0,8)}\u2026)
|
|
673
689
|
${n.content.slice(0,100)}${n.content.length>100?"\u2026":""}`).join(`
|
|
674
690
|
`);return{success:!0,data:s,display:`${s.length} note(s):
|
|
675
|
-
${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,n=[];for(let i of
|
|
691
|
+
${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,n=[];for(let i of K(t))for(let a of this.noteRepo.search(i,s))r.has(a.id)||(r.add(a.id),n.push(a));if(n.length===0)return{success:!0,data:[],display:`No notes matching "${s}".`};let o=n.map(i=>`- **${i.title}** (${i.id.slice(0,8)}\u2026)
|
|
676
692
|
${i.content.slice(0,100)}${i.content.length>100?"\u2026":""}`).join(`
|
|
677
693
|
`);return{success:!0,data:n,display:`Found ${n.length} note(s):
|
|
678
|
-
${o}`}}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?
|
|
679
|
-
Wind: ${n.windspeed} km/h`;return{success:!0,data:a,display:c}}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
|
|
680
|
-
[output truncated]`:l}var
|
|
681
|
-
${
|
|
682
|
-
${
|
|
694
|
+
${o}`}}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?K(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 kh,as,cd=T(()=>{"use strict";W();kh={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"},as=class extends x{static{m(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 n=await this.fetchWeather(r.latitude,r.longitude),o=kh[n.weathercode]??`Code ${n.weathercode}`,i=r.admin1?`${r.name}, ${r.admin1}, ${r.country}`:`${r.name}, ${r.country}`,a={location:i,temperature:n.temperature,unit:"\xB0C",condition:o,windSpeed:n.windspeed,windDirection:n.winddirection,isDay:n.is_day===1},c=`${i}: ${n.temperature}\xB0C, ${o}
|
|
695
|
+
Wind: ${n.windspeed} km/h`;return{success:!0,data:a,display:c}}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 Eh}from"node:child_process";function dd(l){return l.length>ld?l.slice(0,ld)+`
|
|
696
|
+
[output truncated]`:l}var bh,ld,cs,ud=T(()=>{"use strict";W();bh=3e4,ld=1e4;m(dd,"truncate");cs=class extends x{static{m(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/,/\b(bash|sh|zsh|dash|ksh|csh|tcsh|fish)\s+-[a-z]*c\b/,/\bdd\b.*\bof=\/dev\//,/\bdd\b.*\bof=\//,/\bchmod\s+777\s+\//,/\bchown\s+.*\s+\/(?:\s|$)/,/\bbase64\b.*\|/,/\bperl\s+-e\b/,/\bruby\s+-e\b/,/\bphp\s+-r\b/,/\btee\s+\/(etc|root|boot|sys|proc)\//,/\bcrontab\b/,/\bmount\b/,/\bstrace\b/,/\bgdb\b/,/\bsudo\b/,/\bchroot\b/,/\beval\s/,/\bsource\s/,/\b\.\s+\//,/`[^`]+`/,/\$\([^)]+\)/,/\/bin\/\w+\s+-rf?\s+\//];for(let i of r)if(i.test(s))return{success:!1,error:"Command blocked: potentially destructive system operation"};let n=typeof e.timeout=="number"&&e.timeout>0?e.timeout:bh,o=typeof e.cwd=="string"&&e.cwd.length>0?e.cwd:void 0;try{let{stdout:i,stderr:a,exitCode:c}=await this.run(s,n,o),d=[];return i&&d.push(`stdout:
|
|
697
|
+
${dd(i)}`),a&&d.push(`stderr:
|
|
698
|
+
${dd(a)}`),d.length===0&&d.push("(no output)"),d.push(`exit code: ${c}`),{success:c===0,data:{stdout:i,stderr:a,exitCode:c},display:d.join(`
|
|
683
699
|
|
|
684
|
-
`),...c!==0&&{error:`Command exited with code ${c}`}}}catch(i){return{success:!1,error:`Shell execution failed: ${i instanceof Error?i.message:String(i)}`}}}run(e,t,s){return new Promise(r=>{
|
|
700
|
+
`),...c!==0&&{error:`Command exited with code ${c}`}}}catch(i){return{success:!1,error:`Shell execution failed: ${i instanceof Error?i.message:String(i)}`}}}run(e,t,s){return new Promise(r=>{Eh(e,{timeout:t,cwd:s},(n,o,i)=>{let a=n&&"code"in n&&typeof n.code=="number"?n.code:n?1:0;r({stdout:typeof o=="string"?o:"",stderr:typeof i=="string"?i:"",exitCode:a})})})}}});var ls,md=T(()=>{"use strict";W();Me();ls=class extends x{static{m(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,n=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 o=this.memoryRepo.save(de(t),s,r,n??"general");return this.embeddingService&&this.embeddingService.embedAndStore(de(t),`${s}: ${r}`,"memory",s).catch(()=>{}),{success:!0,data:o,display:`Remembered "${s}" = "${r}" (category: ${o.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 n of K(t))if(r=this.memoryRepo.recall(n,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,n=[];for(let o of K(t))for(let i of this.memoryRepo.search(o,s))r.has(i.id)||(r.add(i.id),n.push(i));return{success:!0,data:n,display:n.length===0?`No memories matching "${s}".`:`Found ${n.length} memory(ies):
|
|
685
701
|
${n.map(o=>`- ${o.key}: "${o.value}"`).join(`
|
|
686
|
-
`)}`}}listMemories(e,t){let s=e.category,r=new Set,n=[];for(let i of
|
|
702
|
+
`)}`}}listMemories(e,t){let s=e.category,r=new Set,n=[];for(let i of K(t)){let a=s&&typeof s=="string"?this.memoryRepo.listByCategory(i,s):this.memoryRepo.listAll(i);for(let c of a)r.has(c.id)||(r.add(c.id),n.push(c))}let o=s?`in category "${s}"`:"total";return{success:!0,data:n,display:n.length===0?`No memories found${s?` in category "${s}"`:""}.`:`${n.length} memory(ies) ${o}:
|
|
687
703
|
${n.map(i=>`- [${i.category}] ${i.key}: "${i.value}"`).join(`
|
|
688
|
-
`)}`}}deleteMemory(e,t){let s=e.key;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for delete action'};let r=!1;for(let n of
|
|
704
|
+
`)}`}}deleteMemory(e,t){let s=e.key;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for delete action'};let r=!1;for(let n of K(t))if(this.memoryRepo.delete(n,s)){r=!0;break}return{success:!0,data:{key:s,deleted:r},display:r?`Memory "${s}" deleted.`:`No memory found for key "${s}".`}}async semanticSearchMemories(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for semantic_search action'};if(!this.embeddingService)return this.searchMemories(e,t);let r=new Set,n=[];for(let o of K(t))for(let i of await this.embeddingService.semanticSearch(o,s,10))r.has(i.key)||(r.add(i.key),n.push(i));return n.length===0?this.searchMemories(e,t):{success:!0,data:n,display:`Found ${n.length} semantically related memory(ies):
|
|
689
705
|
${n.map(o=>`- ${o.key}: "${o.value}" (score: ${o.score.toFixed(2)})`).join(`
|
|
690
|
-
`)}`}}}});var
|
|
706
|
+
`)}`}}}});var Sh,vh,$h,ds,pd=T(()=>{"use strict";W();Ji();Sh=15,vh=25,$h=12e4,ds=class extends x{static{m(this,"DelegateSkill")}llm;skillRegistry;skillSandbox;securityManager;metadata={name:"delegate",category:"core",description:'Delegate a sub-task to an autonomous sub-agent that requires ITERATIVE work \u2014 multiple rounds of tool calls with intermediate reasoning (e.g. "research X across multiple sources and synthesize", "search emails for invoices and compile a list"). Do NOT use for simple lookups or single-skill queries \u2014 call those skills directly. The sub-agent has full tool access (shell, web search, memory, email, etc.). Control depth with max_iterations (default 15, max 25).',riskLevel:"write",version:"3.0.0",timeoutMs:$h,inputSchema:{type:"object",properties:{task:{type:"string",description:"The task to delegate to the sub-agent. Be specific about what you want."},context:{type:"string",description:"Additional context the sub-agent needs (optional)"},max_iterations:{type:"number",description:"Max tool iterations (1-25). Default: 15."}},required:["task"]}};onProgress;constructor(e,t,s,r){super(),this.llm=e,this.skillRegistry=t,this.skillSandbox=s,this.securityManager=r}setProgressCallback(e){this.onProgress=e}createTracker(){return new Ot(this.onProgress)}async execute(e,t){let s=e.task,r=e.context;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task"'};let n=e.max_iterations,o=n?Math.max(1,Math.min(vh,Math.round(n))):Sh,i=t.onProgress??this.onProgress,a=t.tracker?t.tracker:new Ot(i);a.ping("starting",{maxIterations:o});let c=this.buildSubAgentTools(),d=new Map,u=0;if(t.resumeState?.dataStore)for(let[y,_]of Object.entries(t.resumeState.dataStore)){d.set(y,_);let S=y.match(/^result_(\d+)$/);S&&(u=Math.max(u,Number(S[1])))}let p=`You are a sub-agent of Alfred, a personal AI assistant. Complete the assigned task using the tools available to you. Work step by step: use tools to gather information, then synthesize a clear result. Be concise and return only the final answer when done.
|
|
691
707
|
|
|
692
708
|
When tool results contain "[Data stored as result_N]", use code_sandbox with action "run_with_data" and data="result_N" to process the data. The data will be injected as INPUT_DATA (parsed array/object). Never hardcode data in code.
|
|
693
709
|
Available JS libraries in code_sandbox (no install needed): exceljs, pdfkit, pdf-parse.`,h=s;r&&typeof r=="string"&&(h=`${s}
|
|
694
710
|
|
|
695
|
-
Additional context: ${r}`);let g
|
|
711
|
+
Additional context: ${r}`);let f,g;t.resumeState?.conversationHistory?.length?(f=t.resumeState.conversationHistory,g=t.resumeState.currentIteration):(f=[{role:"user",content:h}],g=0);try{let y=g,_=0,S=0;for(;;){if(t.abortSignal?.aborted)return t.onIteration?.({iteration:y,maxIterations:o,messages:[...f],dataStore:Object.fromEntries(d)}),a.ping("done",{iteration:y,maxIterations:o}),{success:!0,data:{response:"Task paused \u2014 can be resumed later.",iterations:y,paused:!0,usage:{inputTokens:_,outputTokens:S}},display:"Task paused \u2014 can be resumed later."};a.ping("llm_call",{iteration:y,maxIterations:o});let b=await this.llm.complete({messages:f,system:p,tools:c.length>0?c:void 0,maxTokens:8192,tier:"strong"});if(_+=b.usage.inputTokens,S+=b.usage.outputTokens,a.ping("processing",{iteration:y,maxIterations:o}),!b.toolCalls||b.toolCalls.length===0||y>=o)return a.ping("done",{iteration:y,maxIterations:o}),{success:!0,data:{response:b.content,iterations:y,usage:{inputTokens:_,outputTokens:S}},display:b.content};y++;let $=[];b.content&&$.push({type:"text",text:b.content});for(let M of b.toolCalls)$.push({type:"tool_use",id:M.id,name:M.name,input:M.input});f.push({role:"assistant",content:$});let N=[];for(let M of b.toolCalls){a.ping("tool_call",{iteration:y,maxIterations:o,tool:M.name});let J=M.input;if(M.name==="code_sandbox"&&M.input.data){let ee=String(M.input.data);d.has(ee)&&(J={...M.input,data:d.get(ee)},J.action==="run"&&(J.action="run_with_data"))}let V=await this.executeSubAgentTool({...M,input:J},t),P=V.content;if(!V.isError&&P.length>500){let ee=`result_${++u}`,ue=V.rawData!=null?JSON.stringify(V.rawData):P;d.set(ee,ue),P+=`
|
|
696
712
|
|
|
697
|
-
[Data stored as "${z}" \u2014 use code_sandbox action "run_with_data" with data="${z}" to process this data. Do NOT copy data into code.]`}D.push({type:"tool_result",tool_use_id:P.id,content:j,is_error:ae.isError})}g.push({role:"user",content:D}),t.onIteration?.({iteration:y,maxIterations:o,messages:[...g],dataStore:Object.fromEntries(d)})}}catch(y){return{success:!1,error:`Sub-agent failed: ${y instanceof Error?y.message:String(y)}`}}}buildSubAgentTools(){return this.skillRegistry?this.skillRegistry.getAll().filter(e=>e.metadata.name!=="delegate").map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema})):[]}async executeSubAgentTool(e,t){let s=this.skillRegistry?.get(e.name);if(!s)return{content:`Error: Unknown tool "${e.name}"`,isError:!0};if(this.securityManager){let r=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:s.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!r.allowed)return{content:`Access denied: ${r.reason}`,isError:!0}}if(this.skillSandbox){let r=await this.skillSandbox.execute(s,e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}try{let r=await s.execute(e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}catch(r){return{content:`Skill execution failed: ${r instanceof Error?r.message:String(r)}`,isError:!0}}}}});var nt,Xn=T(()=>{"use strict";nt=class{static{m(this,"EmailProvider")}async extractFromSearch(e,t,s,r,n){throw new Error("Extract is not supported by this email provider.")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var Ql={};he(Ql,{MicrosoftGraphEmailProvider:()=>Kn});var Kn,qi=T(()=>{"use strict";Xn();Kn=class extends nt{static{m(this,"MicrosoftGraphEmailProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){if(!this.config.refreshToken)throw new Error("Microsoft email: refreshToken is missing from config");let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${n.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=m(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let n=await s(this.accessToken);if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return this.parseJsonOrUndefined(n)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=m(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${n}`}}),"doFetch"),s=await t(this.accessToken);if(s.status===401&&(await this.refreshAccessToken(),s=await t(this.accessToken)),!s.ok)throw new Error(`Graph API error: ${s.status}`);let r=await s.arrayBuffer();return Buffer.from(r)}async fetchInbox(e){let t=new URLSearchParams({$top:String(Math.min(Math.max(1,e),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/inbox/messages?${t}`)).value??[]).map(r=>this.mapMessage(r))}async readMessage(e){let t=new URLSearchParams({$select:"id,from,toRecipients,ccRecipients,bccRecipients,subject,body,receivedDateTime,isRead,hasAttachments"}),s=await this.graphRequest(`/me/messages/${e}?${t}`),r=[];return s.hasAttachments&&(r=((await this.graphRequest(`/me/messages/${e}/attachments?$select=id,name,contentType,size`)).value??[]).map(o=>({id:o.id,name:o.name,contentType:o.contentType,size:o.size??0}))),{id:s.id,from:this.formatGraphAddress(s.from),to:(s.toRecipients??[]).map(n=>this.formatGraphAddress(n)),subject:s.subject??"(no subject)",date:new Date(s.receivedDateTime),read:s.isRead??!1,body:s.body?.contentType==="html"?this.stripHtml(s.body.content??""):s.body?.content??"",bodyHtml:s.body?.contentType==="html"?s.body.content:void 0,cc:s.ccRecipients?.map(n=>this.formatGraphAddress(n)),bcc:s.bccRecipients?.map(n=>this.formatGraphAddress(n)),hasAttachments:s.hasAttachments,attachments:r}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=new URLSearchParams({$search:`"${e}"`,$top:String(s),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"}),n=await this.graphRequest(`/me/messages?${r}`),o=(n.value??[]).map(i=>this.mapMessage(i));if(t>50){let i=n["@odata.nextLink"];for(;i&&o.length<t;){let a=await this.graphRequest(i.replace("https://graph.microsoft.com/v1.0","")),c=(a.value??[]).map(d=>this.mapMessage(d));o.push(...c),i=a["@odata.nextLink"]}}return o.slice(0,t)}async extractFromSearch(e,t,s,r,n){let o=await this.searchWithDateFilter(e,t,r,n),i=s.includes("amount"),a=[];if(i)for(let d=0;d<o.length;d+=5){let u=o.slice(d,d+5),p=await Promise.allSettled(u.map(async h=>{let g={id:h.id,from:h.from,subject:h.subject,date:h.date.toISOString().split("T")[0],preview:(h.preview??"").slice(0,200)};try{let f=await this.readMessage(h.id),y=this.extractAmount(f.body);y&&(g.amount=y.amount,g.currency=y.currency)}catch{}return g}));for(let h of p)h.status==="fulfilled"&&a.push(h.value)}else for(let c of o)a.push({id:c.id,from:c.from,subject:c.subject,date:c.date.toISOString().split("T")[0],preview:(c.preview??"").slice(0,200)});return a}async searchWithDateFilter(e,t,s,r){let n=Math.min(Math.max(1,t),50),o=[];if(s||r){let p=s?this.toKqlDate(s):"01/01/2000",h=r?this.toKqlDate(r):"12/31/2099";o.push(`received:${p}..${h}`)}e&&o.push(e.includes(" ")?`(${e})`:e);let i=o.join(" AND "),a=new URLSearchParams({$top:String(n),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});i?a.set("$search",`"${i}"`):a.set("$orderby","receivedDateTime desc");let c=await this.graphRequest(`/me/messages?${a}`),d=(c.value??[]).map(p=>this.mapMessage(p)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let p=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),h=(p.value??[]).map(g=>this.mapMessage(g));d.push(...h),u=p["@odata.nextLink"]}return d.slice(0,t)}toKqlDate(e){let[t,s,r]=e.split("-");return`${s}/${r}/${t}`}extractAmount(e){let t=[{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*€\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*€/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*EUR\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*EUR/i,currency:"EUR"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*\$\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*USD\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*([\d.,]+)\s*USD/i,currency:"USD"},{regex:/€\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\b([\d]+[.,]\d{2})\s*€/,currency:"EUR"},{regex:/EUR\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\$([\d]+[.,]\d{2})\b/,currency:"USD"},{regex:/USD\s*([\d]+[.,]\d{2})\b/,currency:"USD"}];for(let{regex:s,currency:r}of t){let n=e.match(s);if(n?.[1])return{amount:n[1].trim(),currency:r}}return null}async sendMessage(e){if(e.replyTo)return await this.graphRequest(`/me/messages/${e.replyTo}/reply`,{method:"POST",body:JSON.stringify({comment:e.body})}),{messageId:e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(s=>({emailAddress:{address:s.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(s=>({emailAddress:{address:s.trim()}}))),await this.graphRequest("/me/sendMail",{method:"POST",body:JSON.stringify({message:t})}),{messageId:`sent-${Date.now()}`}}async createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`/me/messages/${e.replyTo}/createReply`,{method:"POST",body:JSON.stringify({comment:e.body})}))?.id??e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(r=>({emailAddress:{address:r.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(r=>({emailAddress:{address:r.trim()}}))),{messageId:(await this.graphRequest("/me/messages",{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest("/me/mailFolders?$select=displayName&$top=100")).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest("/me/mailFolders?$select=id,displayName&$top=100")).value??[]).find(i=>i.displayName.toLowerCase()===e.toLowerCase());if(!r)throw new Error(`Folder "${e}" not found. Use the 'folders' action to list available folders.`);let n=new URLSearchParams({$top:String(Math.min(Math.max(1,t),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/${r.id}/messages?${n}`)).value??[]).map(i=>this.mapMessage(i))}async downloadAttachment(e,t){return this.graphRequestRaw(`/me/messages/${e}/attachments/${t}/$value`)}async forwardMessage(e,t,s){return await this.graphRequest(`/me/messages/${e}/forward`,{method:"POST",body:JSON.stringify({comment:s??"",toRecipients:t.split(",").map(r=>({emailAddress:{address:r.trim()}}))})}),{messageId:`fwd-${Date.now()}`}}mapMessage(e){return{id:e.id,from:this.formatGraphAddress(e.from),to:(e.toRecipients??[]).map(t=>this.formatGraphAddress(t)),subject:e.subject??"(no subject)",date:new Date(e.receivedDateTime),read:e.isRead??!1,preview:e.bodyPreview??void 0,hasAttachments:e.hasAttachments??!1}}formatGraphAddress(e){if(!e)return"unknown";let t=e.emailAddress??e;return t?.address?t.name?`${t.name} <${t.address}>`:t.address:"unknown"}stripHtml(e){return e.replace(/<br\s*\/?>/gi,`
|
|
713
|
+
[Data stored as "${ee}" \u2014 use code_sandbox action "run_with_data" with data="${ee}" to process this data. Do NOT copy data into code.]`}N.push({type:"tool_result",tool_use_id:M.id,content:P,is_error:V.isError})}f.push({role:"user",content:N}),t.onIteration?.({iteration:y,maxIterations:o,messages:[...f],dataStore:Object.fromEntries(d)})}}catch(y){return{success:!1,error:`Sub-agent failed: ${y instanceof Error?y.message:String(y)}`}}}buildSubAgentTools(){return this.skillRegistry?this.skillRegistry.getAll().filter(e=>e.metadata.name!=="delegate").map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema})):[]}async executeSubAgentTool(e,t){let s=this.skillRegistry?.get(e.name);if(!s)return{content:`Error: Unknown tool "${e.name}"`,isError:!0};if(this.securityManager){let r=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:s.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!r.allowed)return{content:`Access denied: ${r.reason}`,isError:!0}}if(this.skillSandbox){let r=await this.skillSandbox.execute(s,e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}try{let r=await s.execute(e.input,t);return{content:r.display??(r.success?JSON.stringify(r.data):r.error??"Unknown error"),isError:!r.success,rawData:r.data}}catch(r){return{content:`Skill execution failed: ${r instanceof Error?r.message:String(r)}`,isError:!0}}}}});var it,eo=T(()=>{"use strict";it=class{static{m(this,"EmailProvider")}async extractFromSearch(e,t,s,r,n){throw new Error("Extract is not supported by this email provider.")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var hd={};fe(hd,{MicrosoftGraphEmailProvider:()=>to});var to,ea=T(()=>{"use strict";eo();to=class extends it{static{m(this,"MicrosoftGraphEmailProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){if(!this.config.refreshToken)throw new Error("Microsoft email: refreshToken is missing from config");let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${n.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=m(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let n=await s(this.accessToken);if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return this.parseJsonOrUndefined(n)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=m(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${n}`}}),"doFetch"),s=await t(this.accessToken);if(s.status===401&&(await this.refreshAccessToken(),s=await t(this.accessToken)),!s.ok)throw new Error(`Graph API error: ${s.status}`);let r=await s.arrayBuffer();return Buffer.from(r)}async fetchInbox(e){let t=new URLSearchParams({$top:String(Math.min(Math.max(1,e),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/inbox/messages?${t}`)).value??[]).map(r=>this.mapMessage(r))}async readMessage(e){let t=new URLSearchParams({$select:"id,from,toRecipients,ccRecipients,bccRecipients,subject,body,receivedDateTime,isRead,hasAttachments"}),s=await this.graphRequest(`/me/messages/${e}?${t}`),r=[];return s.hasAttachments&&(r=((await this.graphRequest(`/me/messages/${e}/attachments?$select=id,name,contentType,size`)).value??[]).map(o=>({id:o.id,name:o.name,contentType:o.contentType,size:o.size??0}))),{id:s.id,from:this.formatGraphAddress(s.from),to:(s.toRecipients??[]).map(n=>this.formatGraphAddress(n)),subject:s.subject??"(no subject)",date:new Date(s.receivedDateTime),read:s.isRead??!1,body:s.body?.contentType==="html"?this.stripHtml(s.body.content??""):s.body?.content??"",bodyHtml:s.body?.contentType==="html"?s.body.content:void 0,cc:s.ccRecipients?.map(n=>this.formatGraphAddress(n)),bcc:s.bccRecipients?.map(n=>this.formatGraphAddress(n)),hasAttachments:s.hasAttachments,attachments:r}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=new URLSearchParams({$search:`"${e}"`,$top:String(s),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"}),n=await this.graphRequest(`/me/messages?${r}`),o=(n.value??[]).map(i=>this.mapMessage(i));if(t>50){let i=n["@odata.nextLink"];for(;i&&o.length<t;){let a=await this.graphRequest(i.replace("https://graph.microsoft.com/v1.0","")),c=(a.value??[]).map(d=>this.mapMessage(d));o.push(...c),i=a["@odata.nextLink"]}}return o.slice(0,t)}async extractFromSearch(e,t,s,r,n){let o=await this.searchWithDateFilter(e,t,r,n),i=s.includes("amount"),a=[];if(i)for(let d=0;d<o.length;d+=5){let u=o.slice(d,d+5),p=await Promise.allSettled(u.map(async h=>{let f={id:h.id,from:h.from,subject:h.subject,date:h.date.toISOString().split("T")[0],preview:(h.preview??"").slice(0,200)};try{let g=await this.readMessage(h.id),y=this.extractAmount(g.body);y&&(f.amount=y.amount,f.currency=y.currency)}catch{}return f}));for(let h of p)h.status==="fulfilled"&&a.push(h.value)}else for(let c of o)a.push({id:c.id,from:c.from,subject:c.subject,date:c.date.toISOString().split("T")[0],preview:(c.preview??"").slice(0,200)});return a}async searchWithDateFilter(e,t,s,r){let n=Math.min(Math.max(1,t),50),o=[];if(s||r){let p=s?this.toKqlDate(s):"01/01/2000",h=r?this.toKqlDate(r):"12/31/2099";o.push(`received:${p}..${h}`)}e&&o.push(e.includes(" ")?`(${e})`:e);let i=o.join(" AND "),a=new URLSearchParams({$top:String(n),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});i?a.set("$search",`"${i}"`):a.set("$orderby","receivedDateTime desc");let c=await this.graphRequest(`/me/messages?${a}`),d=(c.value??[]).map(p=>this.mapMessage(p)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let p=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),h=(p.value??[]).map(f=>this.mapMessage(f));d.push(...h),u=p["@odata.nextLink"]}return d.slice(0,t)}toKqlDate(e){let[t,s,r]=e.split("-");return`${s}/${r}/${t}`}extractAmount(e){let t=[{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*€\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*€/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*EUR\s*([\d.,]+)/i,currency:"EUR"},{regex:/(?:gesamt|total|summe|betrag|amount|charged|bezahlt|preis|price)[:\s]*([\d.,]+)\s*EUR/i,currency:"EUR"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*\$\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*USD\s*([\d.,]+)/i,currency:"USD"},{regex:/(?:total|amount|charged|price|subtotal)[:\s]*([\d.,]+)\s*USD/i,currency:"USD"},{regex:/€\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\b([\d]+[.,]\d{2})\s*€/,currency:"EUR"},{regex:/EUR\s*([\d]+[.,]\d{2})\b/,currency:"EUR"},{regex:/\$([\d]+[.,]\d{2})\b/,currency:"USD"},{regex:/USD\s*([\d]+[.,]\d{2})\b/,currency:"USD"}];for(let{regex:s,currency:r}of t){let n=e.match(s);if(n?.[1])return{amount:n[1].trim(),currency:r}}return null}async sendMessage(e){if(e.replyTo)return await this.graphRequest(`/me/messages/${e.replyTo}/reply`,{method:"POST",body:JSON.stringify({comment:e.body})}),{messageId:e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(s=>({emailAddress:{address:s.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(s=>({emailAddress:{address:s.trim()}}))),await this.graphRequest("/me/sendMail",{method:"POST",body:JSON.stringify({message:t})}),{messageId:`sent-${Date.now()}`}}async createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`/me/messages/${e.replyTo}/createReply`,{method:"POST",body:JSON.stringify({comment:e.body})}))?.id??e.replyTo};let t={subject:e.subject,body:{contentType:e.isHtml?"html":"text",content:e.body},toRecipients:e.to.split(",").map(r=>({emailAddress:{address:r.trim()}}))};return e.cc&&(t.ccRecipients=e.cc.split(",").map(r=>({emailAddress:{address:r.trim()}}))),{messageId:(await this.graphRequest("/me/messages",{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest("/me/mailFolders?$select=displayName&$top=100")).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest("/me/mailFolders?$select=id,displayName&$top=100")).value??[]).find(i=>i.displayName.toLowerCase()===e.toLowerCase());if(!r)throw new Error(`Folder "${e}" not found. Use the 'folders' action to list available folders.`);let n=new URLSearchParams({$top:String(Math.min(Math.max(1,t),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`/me/mailFolders/${r.id}/messages?${n}`)).value??[]).map(i=>this.mapMessage(i))}async downloadAttachment(e,t){return this.graphRequestRaw(`/me/messages/${e}/attachments/${t}/$value`)}async forwardMessage(e,t,s){return await this.graphRequest(`/me/messages/${e}/forward`,{method:"POST",body:JSON.stringify({comment:s??"",toRecipients:t.split(",").map(r=>({emailAddress:{address:r.trim()}}))})}),{messageId:`fwd-${Date.now()}`}}mapMessage(e){return{id:e.id,from:this.formatGraphAddress(e.from),to:(e.toRecipients??[]).map(t=>this.formatGraphAddress(t)),subject:e.subject??"(no subject)",date:new Date(e.receivedDateTime),read:e.isRead??!1,preview:e.bodyPreview??void 0,hasAttachments:e.hasAttachments??!1}}formatGraphAddress(e){if(!e)return"unknown";let t=e.emailAddress??e;return t?.address?t.name?`${t.name} <${t.address}>`:t.address:"unknown"}stripHtml(e){return e.replace(/<br\s*\/?>/gi,`
|
|
698
714
|
`).replace(/<\/p>/gi,`
|
|
699
715
|
|
|
700
716
|
`).replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/\n{3,}/g,`
|
|
701
717
|
|
|
702
|
-
`).trim()}}});var
|
|
718
|
+
`).trim()}}});var fd={};fe(fd,{StandardEmailProvider:()=>so});var so,ta=T(()=>{"use strict";eo();so=class extends it{static{m(this,"StandardEmailProvider")}config;constructor(e){super(),this.config=e}async initialize(){}createImapClient(){return import("imapflow").then(({ImapFlow:e})=>new e({host:this.config.imap.host,port:this.config.imap.port,secure:this.config.imap.secure,auth:this.config.auth,logger:!1}))}formatAddress(e){return e?e.name?`${e.name} <${e.address}>`:e.address??"unknown":"unknown"}async fetchInbox(e){return this.fetchFolder("INBOX",e)}async readMessage(e){let t=parseInt(e,10);if(isNaN(t)||t<1)throw new Error("messageId must be a positive number (sequence number).");let s=await this.createImapClient();try{await s.connect();let r=await s.getMailboxLock("INBOX");try{let n=await s.fetchOne(String(t),{envelope:!0,source:!0,bodyStructure:!0});if(!n)throw new Error(`Message #${t} not found.`);let o=this.formatAddress(n.envelope?.from?.[0]),i=n.envelope?.to?.map(p=>p.name?`${p.name} <${p.address}>`:p.address??"")??[],a=n.envelope?.cc?.map(p=>p.name?`${p.name} <${p.address}>`:p.address??""),c=n.source?.toString()??"",d=this.extractTextBody(c),u=this.extractAttachmentInfo(n.bodyStructure);return{id:String(t),from:o,to:i,subject:n.envelope?.subject??"(no subject)",date:n.envelope?.date??new Date,read:n.flags?.has("\\Seen")??!1,body:d,cc:a,attachments:u}}finally{r.release()}}finally{await s.logout()}}async searchMessages(e,t){let s=Math.min(Math.max(1,t),50),r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock("INBOX");try{let o=await r.search({or:[{subject:e},{from:e},{body:e}]}),i=Array.isArray(o)?o:[];if(i.length===0)return[];let a=i.slice(-s),c=[];for await(let d of r.fetch(a,{envelope:!0,flags:!0}))c.push({id:String(d.seq),from:this.formatAddress(d.envelope?.from?.[0]),to:d.envelope?.to?.map(u=>u.name?`${u.name} <${u.address}>`:u.address??"")??[],subject:d.envelope?.subject??"(no subject)",date:d.envelope?.date??new Date,read:d.flags?.has("\\Seen")??!1});return c.reverse(),c}finally{n.release()}}finally{await r.logout()}}async sendMessage(e){let s=(await import("nodemailer")).createTransport({host:this.config.smtp.host,port:this.config.smtp.port,secure:this.config.smtp.secure,auth:this.config.auth}),r={from:this.config.auth.user,to:e.to,subject:e.subject};return e.cc&&(r.cc=e.cc),e.isHtml?r.html=e.body:r.text=e.body,e.replyTo&&(r.inReplyTo=e.replyTo,r.references=e.replyTo),{messageId:(await s.sendMail(r)).messageId}}async listFolders(){let e=await this.createImapClient();try{await e.connect();let t=await e.list(),s=[];for(let r of t)s.push(r.path);return s}finally{await e.logout()}}async fetchFolder(e,t){let s=Math.min(Math.max(1,t),50),r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock(e);try{let o=[],i=r.mailbox,a=i&&typeof i=="object"?i.exists??0:0;if(a===0)return[];let d=`${Math.max(1,a-s+1)}:*`;for await(let u of r.fetch(d,{envelope:!0,flags:!0})){let p=this.formatAddress(u.envelope?.from?.[0]);o.push({id:String(u.seq),from:p,to:u.envelope?.to?.map(h=>h.name?`${h.name} <${h.address}>`:h.address??"")??[],subject:u.envelope?.subject??"(no subject)",date:u.envelope?.date??new Date,read:u.flags?.has("\\Seen")??!1})}return o.reverse(),o}finally{n.release()}}finally{await r.logout()}}async downloadAttachment(e,t){let s=parseInt(e,10);if(isNaN(s)||s<1)throw new Error("messageId must be a positive number.");let r=await this.createImapClient();try{await r.connect();let n=await r.getMailboxLock("INBOX");try{let i=(await r.fetchOne(String(s),{bodyParts:[t]}))?.bodyParts?.get(t);if(!i)throw new Error(`Attachment "${t}" not found in message #${s}.`);return Buffer.from(i)}finally{n.release()}}finally{await r.logout()}}extractAttachmentInfo(e){let t=[];if(!e)return t;let s=m((r,n)=>{if(r.childNodes){for(let i=0;i<r.childNodes.length;i++)s(r.childNodes[i],n?`${n}.${i+1}`:String(i+1));return}let o=r.disposition?.toLowerCase();if(o==="attachment"||r.type&&!r.type.startsWith("text/")&&o!=="inline"){let i=r.dispositionParameters?.filename??r.parameters?.name??`part-${n}`;t.push({id:r.part??n,name:i,contentType:r.type??"application/octet-stream",size:r.size??0})}},"walk");return s(e,""),t}extractTextBody(e){let t=e.split(/\r?\n\r?\n/);if(t.length<2)return e;let s=t[0].toLowerCase();if(!s.includes("multipart"))return this.decodeBody(t.slice(1).join(`
|
|
703
719
|
|
|
704
720
|
`));let r=s.match(/boundary="?([^"\s;]+)"?/i)??e.match(/boundary="?([^"\s;]+)"?/i);if(!r)return t.slice(1).join(`
|
|
705
721
|
|
|
@@ -709,7 +725,7 @@ Additional context: ${r}`);let g,f;t.resumeState?.conversationHistory?.length?(g
|
|
|
709
725
|
\r
|
|
710
726
|
`);if(d>=0)return this.decodeBody(i.slice(d+4))}}return this.decodeBody(t.slice(1).join(`
|
|
711
727
|
|
|
712
|
-
`).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
|
|
728
|
+
`).slice(0,5e3))}decodeBody(e){return e.replace(/=\r?\n/g,"").replace(/=([0-9A-Fa-f]{2})/g,(t,s)=>String.fromCharCode(parseInt(s,16))).trim()}}});async function Pr(l){if(l.provider==="microsoft"){if(!l.microsoft)throw new Error("Microsoft email config missing");let{MicrosoftGraphEmailProvider:s}=await Promise.resolve().then(()=>(ea(),hd)),r=new s(l.microsoft);return await r.initialize(),r}if(!l.imap||!l.smtp||!l.auth)throw new Error("IMAP/SMTP email config missing (imap, smtp, auth required)");let{StandardEmailProvider:e}=await Promise.resolve().then(()=>(ta(),fd)),t=new e(l);return await t.initialize(),t}var gd=T(()=>{"use strict";m(Pr,"createEmailProvider")});var ut,yd=T(()=>{"use strict";eo();gd();ta();ea();W();ut=class extends x{static{m(this,"EmailSkill")}metadata;providers;accountNames;defaultAccount;multiAccount;llm;constructor(e){super(),e instanceof Map?this.providers=e:e?this.providers=new Map([["default",e]]):this.providers=new Map,this.accountNames=[...this.providers.keys()],this.defaultAccount=this.accountNames[0]??"default",this.multiAccount=this.providers.size>1;let t=this.multiAccount?{account:{type:"string",enum:this.accountNames,description:`Email account to use (available: ${this.accountNames.join(", ")}). Required for multi-account setups.`}}:{},s=this.multiAccount?`Access the user's email accounts (${this.accountNames.join(", ")}): check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments.`:`Access the user's email: check inbox, read messages, search emails, send new emails, create drafts, list folders, read from specific folders, reply to messages, forward messages, or download attachments. Use "draft" instead of "send" when the user asks to prepare/draft an email without sending it.`;this.metadata={name:"email",category:"productivity",description:s,riskLevel:"write",version:"3.1.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["inbox","read","search","send","draft","folders","folder","reply","forward","attachment","extract","summarize_inbox","categorize"],description:'The email action to perform. Use "extract" for bulk invoice/receipt extraction. Use "summarize_inbox" for an AI-generated summary of recent unread emails. Use "categorize" to classify unread emails by priority.'},...t,count:{type:"number",description:"Number of emails to fetch (for inbox/search/folder, default: 10)"},messageId:{type:"string",description:"Message ID to read or reply to"},query:{type:"string",description:"Search query (for search action)"},to:{type:"string",description:"Recipient email address (for send action)"},subject:{type:"string",description:"Email subject (for send action)"},body:{type:"string",description:"Email body text (for send/reply action)"},cc:{type:"string",description:"CC recipients, comma-separated (for send action)"},folder:{type:"string",description:"Folder name (for folder action)"},attachmentId:{type:"string",description:"Attachment ID or filename (for attachment action)"},save:{type:"string",description:"Directory path to save the attachment to disk instead of reading its content (for attachment action)"},isHtml:{type:"boolean",description:"Whether the body is HTML (for send action)"},maxResults:{type:"number",description:"Maximum number of results for extract action (default: 200, max: 1000)"},fields:{type:"array",items:{type:"string"},description:'Fields to extract (for extract action). Available: "from", "subject", "date", "amount". Include "amount" to read email bodies and extract monetary amounts.'},dateFrom:{type:"string",description:'Start date filter for extract action (YYYY-MM-DD format, e.g. "2026-01-01")'},dateTo:{type:"string",description:'End date filter for extract action (YYYY-MM-DD format, e.g. "2026-12-31")'}},required:["action"]}}}setLLM(e){this.llm=e}async execute(e,t){if(this.providers.size===0)return{success:!1,error:"Email is not configured. Run `alfred setup` to configure email access."};let s=e.action;try{switch(s){case"inbox":return await this.handleInbox(e);case"read":return await this.handleRead(e);case"search":return await this.handleSearch(e);case"send":return await this.handleSend(e);case"draft":return await this.handleDraft(e);case"folders":return await this.handleFolders(e);case"folder":return await this.handleFolder(e);case"reply":return await this.handleReply(e);case"forward":return await this.handleForward(e);case"attachment":return await this.handleAttachment(e);case"extract":return await this.handleExtract(e);case"summarize_inbox":return await this.handleSummarizeInbox(e);case"categorize":return await this.handleCategorize(e);default:return{success:!1,error:`Unknown action: ${s}. Use: inbox, read, search, send, draft, folders, folder, reply, forward, attachment, summarize_inbox, categorize`}}}catch(r){return{success:!1,error:`Email error: ${r instanceof Error?r.message:String(r)}`}}}resolveProvider(e){let t=e.account??this.defaultAccount,s=this.providers.get(t);return s?{provider:s,account:t}:{success:!1,error:`Unknown email account "${t}". Available: ${this.accountNames.join(", ")}`}}encodeId(e,t){return this.multiAccount?`${e}::${t}`:t}decodeId(e){if(this.multiAccount){let t=e.indexOf("::");if(t>=0)return{account:e.slice(0,t),rawId:e.slice(t+2)}}return{account:this.defaultAccount,rawId:e}}accountLabel(e,t){return this.multiAccount?`[${e}] ${t}`:t}async handleInbox(e){let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,n=Math.min(Math.max(1,e.count??10),50),o=await s.fetchInbox(n);if(o.length===0)return{success:!0,data:{messages:[]},display:this.accountLabel(r,"Inbox is empty.")};let i=o.filter(c=>!c.read).length,a=o.map((c,d)=>{let u=c.read?"":" [UNREAD]",p=c.hasAttachments?" [ATT]":"";return`${d+1}. [${this.encodeId(r,c.id)}]${u}${p} ${c.subject}
|
|
713
729
|
From: ${c.from}
|
|
714
730
|
Date: ${c.date.toISOString()}`}).join(`
|
|
715
731
|
|
|
@@ -744,12 +760,12 @@ ${n.map((o,i)=>` ${i+1}. ${o}`).join(`
|
|
|
744
760
|
|
|
745
761
|
`);return{success:!0,data:{folder:t,messages:i.map(c=>({...c,id:this.encodeId(n,c.id)}))},display:this.accountLabel(n,`Folder "${t}" (${i.length} messages):
|
|
746
762
|
|
|
747
|
-
${a}`)}}async handleReply(e){let t=e.messageId,s=e.body;if(!t)return{success:!1,error:'"messageId" is required for reply.'};if(!s)return{success:!1,error:'"body" is required for reply.'};let{account:r,rawId:n}=this.decodeId(t),o=this.providers.get(r);return o?{success:!0,data:{messageId:(await o.sendMessage({to:"",subject:"",body:s,replyTo:n})).messageId},display:this.accountLabel(r,`Reply sent to message ${n}.`)}:{success:!1,error:`Unknown email account "${r}".`}}async handleForward(e){let t=e.messageId,s=e.to;if(!t)return{success:!1,error:'"messageId" is required for forward.'};if(!s)return{success:!1,error:'"to" (recipient email) is required for forward.'};let{account:r,rawId:n}=this.decodeId(t),o=this.providers.get(r);if(!o)return{success:!1,error:`Unknown email account "${r}".`};let i=e.body??void 0;return{success:!0,data:{messageId:(await o.forwardMessage(n,s,i)).messageId,to:s},display:this.accountLabel(r,`Email forwarded to ${s}.`)}}async handleAttachment(e){let t=e.messageId,s=e.attachmentId,r=e.save;if(!t)return{success:!1,error:'"messageId" is required.'};if(!s)return{success:!1,error:'"attachmentId" is required.'};let{account:n,rawId:o}=this.decodeId(t),i=this.providers.get(n);if(!i)return{success:!1,error:`Unknown email account "${n}".`};let a=await i.readMessage(o),c=a.attachments?.find(
|
|
763
|
+
${a}`)}}async handleReply(e){let t=e.messageId,s=e.body;if(!t)return{success:!1,error:'"messageId" is required for reply.'};if(!s)return{success:!1,error:'"body" is required for reply.'};let{account:r,rawId:n}=this.decodeId(t),o=this.providers.get(r);return o?{success:!0,data:{messageId:(await o.sendMessage({to:"",subject:"",body:s,replyTo:n})).messageId},display:this.accountLabel(r,`Reply sent to message ${n}.`)}:{success:!1,error:`Unknown email account "${r}".`}}async handleForward(e){let t=e.messageId,s=e.to;if(!t)return{success:!1,error:'"messageId" is required for forward.'};if(!s)return{success:!1,error:'"to" (recipient email) is required for forward.'};let{account:r,rawId:n}=this.decodeId(t),o=this.providers.get(r);if(!o)return{success:!1,error:`Unknown email account "${r}".`};let i=e.body??void 0;return{success:!0,data:{messageId:(await o.forwardMessage(n,s,i)).messageId,to:s},display:this.accountLabel(r,`Email forwarded to ${s}.`)}}async handleAttachment(e){let t=e.messageId,s=e.attachmentId,r=e.save;if(!t)return{success:!1,error:'"messageId" is required.'};if(!s)return{success:!1,error:'"attachmentId" is required.'};let{account:n,rawId:o}=this.decodeId(t),i=this.providers.get(n);if(!i)return{success:!1,error:`Unknown email account "${n}".`};let a=await i.readMessage(o),c=a.attachments?.find(f=>f.id===s);if(c||(c=a.attachments?.find(f=>f.name.toLowerCase()===s.toLowerCase())),!c){let f=a.attachments?.map(g=>`[${g.id}] ${g.name}`).join(", ")??"none";return{success:!1,error:`Attachment "${s}" not found. Available: ${f}`}}let d=await i.downloadAttachment(o,c.id),u=c.name,p=c.contentType;if(r){let f=await import("node:fs"),g=await import("node:path"),y=g.resolve(r);f.existsSync(y)||f.mkdirSync(y,{recursive:!0});let _=g.basename(u),S=g.join(y,_);return f.writeFileSync(S,d),{success:!0,data:{messageId:t,attachmentId:c.id,fileName:u,size:d.length,savedTo:S},display:this.accountLabel(n,`Saved attachment: ${u} (${this.formatSize(d.length)}) \u2192 ${S}`)}}let h=await this.extractText(d,p,u);if(h!==null){let f=h.length>6e3?h.slice(0,6e3)+`
|
|
748
764
|
|
|
749
765
|
... (truncated)`:h;return{success:!0,data:{messageId:t,attachmentId:c.id,fileName:u,size:d.length,hasContent:!0},display:this.accountLabel(n,`Attachment: ${u} (${this.formatSize(d.length)})
|
|
750
766
|
|
|
751
767
|
Content:
|
|
752
|
-
${
|
|
768
|
+
${f}`),attachments:[{fileName:u,data:d,mimeType:p}]}}return{success:!0,data:{messageId:t,attachmentId:c.id,fileName:u,size:d.length},display:this.accountLabel(n,`Downloaded attachment: ${u} (${this.formatSize(d.length)})`),attachments:[{fileName:u,data:d,mimeType:p}]}}async handleExtract(e){let t=e.query;if(!t)return{success:!1,error:'query is required for extract. Example: "rechnung OR invoice OR receipt 2026"'};let s=this.resolveProvider(e);if("success"in s)return s;let{provider:r,account:n}=s,o=Math.min(Math.max(1,e.maxResults??200),1e3),i=e.fields??["from","subject","date","amount"],a=e.dateFrom,c=e.dateTo;try{let d=await r.extractFromSearch(t,o,i,a,c);if(d.length===0)return{success:!0,data:{results:[]},display:this.accountLabel(n,`No emails found for "${t}".`)};let u=d.map((f,g)=>{let y=f.amount?` | ${f.amount} ${f.currency??""}`:"";return`${g+1}. ${f.date} | ${f.from} | ${f.subject}${y}`}),p=d.filter(f=>f.amount),h=`Found ${d.length} emails (${p.length} with detected amounts)`;return{success:!0,data:{results:d,totalFound:d.length,withAmounts:p.length},display:this.accountLabel(n,`${h}:
|
|
753
769
|
|
|
754
770
|
${u.join(`
|
|
755
771
|
`)}`)}}catch(d){if((d instanceof Error?d.message:String(d)).includes("Extract is not supported"))return{success:!1,error:"The extract action is only supported with Microsoft Graph email. Use search + read for other providers."};throw d}}async handleSummarizeInbox(e){if(!this.llm)return{success:!1,error:"LLM not configured. Email intelligence requires an LLM provider."};let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,n=Math.min(Math.max(1,e.count??20),50),i=(await s.fetchInbox(n)).filter(u=>!u.read);if(i.length===0)return{success:!0,data:{summary:"No unread emails."},display:this.accountLabel(r,"No unread emails to summarize.")};let a=i.map((u,p)=>`${p+1}. From: ${u.from} | Subject: ${u.subject} | Date: ${u.date.toISOString()}${u.hasAttachments?" [has attachments]":""}`).join(`
|
|
@@ -757,38 +773,38 @@ ${u.join(`
|
|
|
757
773
|
|
|
758
774
|
${a}`}],system:"You are an email assistant. Provide a brief, actionable summary in the user's language. Group by priority if applicable.",tier:"fast"})).content;return{success:!0,data:{summary:d,unreadCount:i.length},display:this.accountLabel(r,`Inbox Summary (${i.length} unread):
|
|
759
775
|
|
|
760
|
-
${d}`)}}async handleCategorize(e){if(!this.llm)return{success:!1,error:"LLM not configured. Email intelligence requires an LLM provider."};let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,n=Math.min(Math.max(1,e.count??20),50),i=(await s.fetchInbox(n)).filter(h=>!h.read);if(i.length===0)return{success:!0,data:{categories:{}},display:this.accountLabel(r,"No unread emails to categorize.")};let a=i.map((h,
|
|
776
|
+
${d}`)}}async handleCategorize(e){if(!this.llm)return{success:!1,error:"LLM not configured. Email intelligence requires an LLM provider."};let t=this.resolveProvider(e);if("success"in t)return t;let{provider:s,account:r}=t,n=Math.min(Math.max(1,e.count??20),50),i=(await s.fetchInbox(n)).filter(h=>!h.read);if(i.length===0)return{success:!0,data:{categories:{}},display:this.accountLabel(r,"No unread emails to categorize.")};let a=i.map((h,f)=>`${f+1}. From: ${h.from} | Subject: ${h.subject} | Date: ${h.date.toISOString()}`).join(`
|
|
761
777
|
`),c=await this.llm.complete({messages:[{role:"user",content:`Categorize each email into one of: urgent, action_required, fyi, newsletter. Return ONLY valid JSON like: {"1":"urgent","2":"fyi",...}
|
|
762
778
|
|
|
763
|
-
${a}`}],system:"You are an email classifier. Return only a JSON object mapping email number to category. No other text.",tier:"fast"}),d={};try{let h=c.content.match(/\{[^}]+\}/);h&&(d=JSON.parse(h[0]))}catch{}let u={urgent:[],action_required:[],fyi:[],newsletter:[]};for(let[h,
|
|
764
|
-
`):"Could not categorize emails.")}}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`}}});import{lookup as
|
|
779
|
+
${a}`}],system:"You are an email classifier. Return only a JSON object mapping email number to category. No other text.",tier:"fast"}),d={};try{let h=c.content.match(/\{[^}]+\}/);h&&(d=JSON.parse(h[0]))}catch{}let u={urgent:[],action_required:[],fyi:[],newsletter:[]};for(let[h,f]of Object.entries(d)){let g=parseInt(h,10)-1;g>=0&&g<i.length&&u[f]&&u[f].push({from:i[g].from,subject:i[g].subject})}let p=[];for(let[h,f]of Object.entries(u))if(f.length>0){let g=h==="urgent"?"\u{1F534}":h==="action_required"?"\u{1F7E1}":h==="fyi"?"\u{1F535}":"\u{1F4F0}";p.push(`${g} ${h.toUpperCase()} (${f.length}):`);for(let y of f)p.push(` \u2022 ${y.from}: ${y.subject}`)}return{success:!0,data:{categories:u,totalCategorized:Object.keys(d).length},display:this.accountLabel(r,p.length>0?p.join(`
|
|
780
|
+
`):"Could not categorize emails.")}}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`}}});import{lookup as Ih}from"node:dns/promises";var wd,us,Td=T(()=>{"use strict";W();wd=1e5,us=class extends x{static{m(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(),n=e.headers,o=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(await this.resolveAndCheckHost(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",...n??{}},signal:AbortSignal.timeout(15e3)};o&&["POST","PUT","PATCH"].includes(r)&&(a.body=o,!n?.["Content-Type"]&&!n?.["content-type"]&&(a.headers["Content-Type"]="application/json"));let c=await fetch(s,a),d=c.headers.get("content-type")??"",u=await c.text(),p=u.length>wd,h=p?u.slice(0,wd)+`
|
|
765
781
|
|
|
766
|
-
[... truncated]`:u,
|
|
782
|
+
[... truncated]`:u,f=h;d.includes("text/html")&&(f=this.stripHtml(h).slice(0,1e4));let g={status:c.status,statusText:c.statusText,contentType:d,bodyLength:u.length,truncated:p,body:h};return c.ok?{success:!0,data:g,display:`HTTP ${c.status} OK (${u.length} bytes)
|
|
767
783
|
|
|
768
|
-
${
|
|
784
|
+
${f.slice(0,5e3)}`}:{success:!0,data:g,display:`HTTP ${c.status} ${c.statusText}
|
|
769
785
|
|
|
770
|
-
${
|
|
786
|
+
${f.slice(0,2e3)}`}}catch(a){return{success:!1,error:`HTTP request failed: ${a instanceof Error?a.message:String(a)}`}}}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await Ih(e);if(this.isPrivateIp(t))return!0}catch{}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 ie from"node:fs";import mt from"node:path";var sa,_d,Ah,ms,kd=T(()=>{"use strict";W();sa=5e5,_d=5e7,Ah={".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"},ms=class extends x{static{m(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,n=e.content,o=e.destination;if(!s||!r)return{success:!1,error:'Missing required fields "action" and "path"'};if((s==="write"||s==="write_binary"||s==="append")&&!n)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(ie.existsSync(i)&&ie.lstatSync(i).isSymbolicLink()){let c=ie.realpathSync(i);if(this.checkBlocked(c))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,n);case"write_binary":return this.writeBinaryFile(i,n);case"append":return this.appendFile(i,n);case"list":return this.listDir(i);case"info":return this.fileInfo(i);case"exists":return this.fileExists(i);case"move":return this.moveFile(i,o);case"copy":return this.copyFile(i,o);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 mt.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"],n=["/.ssh","/.aws","/.gnupg"],o=[".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&&n.some(a=>t.startsWith(s+a)))return{success:!1,error:"Access to sensitive user directories is blocked for security"};let i=mt.basename(e);return o.includes(i.toLowerCase())?{success:!1,error:"Access to sensitive files is blocked for security"}:null}readFile(e){try{let t=ie.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file. Use action "list" instead.`};if(t.size>sa){let r=ie.readFileSync(e,"utf-8").slice(0,sa);return{success:!0,data:{path:e,size:t.size,truncated:!0},display:`${e} (${t.size} bytes, truncated to ${sa}):
|
|
771
787
|
|
|
772
|
-
${r}`}}let s=
|
|
773
|
-
`);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=
|
|
788
|
+
${r}`}}let s=ie.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=mt.dirname(e);return ie.mkdirSync(s,{recursive:!0}),ie.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 ie.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=ie.readdirSync(e,{withFileTypes:!0}).map(n=>({name:n.name,type:n.isDirectory()?"dir":n.isSymbolicLink()?"symlink":"file"})),r=s.length===0?`${e}: (empty)`:s.map(n=>`${n.type==="dir"?"\u{1F4C1}":"\u{1F4C4}"} ${n.name}`).join(`
|
|
789
|
+
`);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=ie.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}
|
|
774
790
|
Size: ${t.size} bytes
|
|
775
|
-
Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=
|
|
791
|
+
Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=ie.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=mt.dirname(e);ie.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return ie.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 n=mt.dirname(s);return ie.mkdirSync(n,{recursive:!0}),ie.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return ie.copyFileSync(e,s),ie.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(o){return{success:!1,error:`Cannot move "${e}" to "${s}": ${o.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 n=mt.dirname(s);return ie.mkdirSync(n,{recursive:!0}),ie.copyFileSync(e,s),{success:!0,data:{from:e,to:s},display:`Copied ${e} \u2192 ${s}`}}catch(n){return{success:!1,error:`Cannot copy "${e}" to "${s}": ${n.message}`}}}sendFile(e){try{if(!ie.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=ie.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file`};if(t.size===0)return{success:!1,error:`"${e}" is empty (0 bytes) \u2014 cannot send an empty file`};if(t.size>_d)return{success:!1,error:`File too large to send (${t.size} bytes, max ${_d})`};let s=ie.readFileSync(e),r=mt.basename(e),n=mt.extname(e).toLowerCase(),o=Ah[n]||"application/octet-stream",i={fileName:r,data:s,mimeType:o};return{success:!0,data:{path:e,size:t.size,fileName:r,mimeType:o},display:`Sending ${r} (${t.size} bytes)`,attachments:[i]}}catch(t){return{success:!1,error:`Cannot send "${e}": ${t.message}`}}}deleteFile(e){try{return ie.existsSync(e)?ie.statSync(e).isDirectory()?{success:!1,error:`"${e}" is a directory. Use shell for directory deletion.`}:(ie.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 ps}from"node:child_process";var hs,Ed=T(()=>{"use strict";W();hs=class extends x{static{m(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=ps("pbpaste",{encoding:"utf-8",timeout:5e3});break;case"win32":e=ps("powershell -NoProfile -Command Get-Clipboard",{encoding:"utf-8",timeout:5e3}).replace(/\r\n$/,"");break;default:e=ps("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)+`
|
|
776
792
|
|
|
777
|
-
[... 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":
|
|
793
|
+
[... 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":ps("pbcopy",{input:e,timeout:5e3});break;case"win32":ps('powershell -NoProfile -Command "$input | Set-Clipboard"',{input:e,timeout:5e3});break;default:ps("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 Ur}from"node:child_process";import bd from"node:path";import Rh from"node:os";var fs,Sd=T(()=>{"use strict";W();fs=class extends x{static{m(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=bd.join(Rh.homedir(),"Desktop"),n=e.path||bd.join(r,`screenshot-${s}.png`);try{switch(process.platform){case"darwin":Ur(`screencapture -x "${n}"`,{timeout:1e4});break;case"win32":Ur(`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('${n.replace(/'/g,"''")}'); $graphics.Dispose(); $bitmap.Dispose()"`,{timeout:1e4});break;default:try{Ur(`scrot "${n}"`,{timeout:1e4})}catch{try{Ur(`import -window root "${n}"`,{timeout:1e4})}catch{Ur(`gnome-screenshot -f "${n}"`,{timeout:1e4})}}break}return{success:!0,data:{path:n},display:`Screenshot saved to ${n}`}}catch(o){return{success:!1,error:`Screenshot failed: ${o.message}`}}}}});import xh from"node:path";import Ch from"node:os";import{lookup as Nh}from"node:dns/promises";var vd,gs,$d=T(()=>{"use strict";W();vd=5e4,gs=class extends x{static{m(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
|
|
778
794
|
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=await this.validateUrl(s);if(r)return{success:!1,error:r};try{let n=await this.ensurePage(e);await n.goto(s,{waitUntil:"networkidle2",timeout:3e4});let o=await n.title(),i=await n.evaluate(`
|
|
779
795
|
(() => {
|
|
780
796
|
document.querySelectorAll('script, style, noscript').forEach(el => el.remove());
|
|
781
797
|
return document.body?.innerText ?? '';
|
|
782
798
|
})()
|
|
783
|
-
`),c=(i.length>
|
|
799
|
+
`),c=(i.length>vd?i.slice(0,vd)+`
|
|
784
800
|
|
|
785
801
|
[... truncated]`:i).replace(/\n{3,}/g,`
|
|
786
802
|
|
|
787
803
|
`).trim();return{success:!0,data:{url:n.url(),title:o,length:i.length},display:`**${o}** (${n.url()})
|
|
788
804
|
|
|
789
|
-
${c}`}}catch(n){return{success:!1,error:`Failed to open "${s}": ${n.message}`}}}async screenshotPage(e,t){try{let s=await this.ensurePage(e),r=t.url;r&&await s.goto(r,{waitUntil:"networkidle2",timeout:3e4});let n=s.url();if(n==="about:blank")return{success:!1,error:'No page is open. Use action "open" with a URL first, or provide a URL.'};let o=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),i=t.path||
|
|
805
|
+
${c}`}}catch(n){return{success:!1,error:`Failed to open "${s}": ${n.message}`}}}async screenshotPage(e,t){try{let s=await this.ensurePage(e),r=t.url;r&&await s.goto(r,{waitUntil:"networkidle2",timeout:3e4});let n=s.url();if(n==="about:blank")return{success:!1,error:'No page is open. Use action "open" with a URL first, or provide a URL.'};let o=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),i=t.path||xh.join(Ch.homedir(),"Desktop",`browser-${o}.png`);return await s.screenshot({path:i,fullPage:!1}),{success:!0,data:{path:i,url:n},display:`Screenshot saved to ${i}`}}catch(s){return{success:!1,error:`Screenshot failed: ${s.message}`}}}async clickElement(e){let t=e.selector;if(!t)return{success:!1,error:'Missing "selector" for click action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t);try{await this.page.waitForNavigation({timeout:3e3})}catch{}let s=await this.page.title();return{success:!0,data:{selector:t,url:this.page.url(),title:s},display:`Clicked "${t}" \u2014 now on: ${s} (${this.page.url()})`}}catch(s){return{success:!1,error:`Click failed on "${t}": ${s.message}`}}}async typeText(e){let t=e.selector,s=e.text;if(!t)return{success:!1,error:'Missing "selector" for type action'};if(!s)return{success:!1,error:'Missing "text" for type action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{return await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t),await this.page.type(t,s,{delay:50}),{success:!0,data:{selector:t,textLength:s.length},display:`Typed ${s.length} characters into "${t}"`}}catch(r){return{success:!1,error:`Type failed on "${t}": ${r.message}`}}}async evaluateScript(e){let t=e.script;if(!t)return{success:!1,error:'Missing "script" for evaluate action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{let s=await this.page.evaluate(t),r=typeof s=="string"?s:JSON.stringify(s,null,2);return{success:!0,data:{result:s},display:r?.slice(0,1e4)??"(no output)"}}catch(s){return{success:!1,error:`Evaluate failed: ${s.message}`}}}async validateUrl(e){let t;try{t=new URL(e)}catch{return`Invalid URL: "${e}"`}if(["file:","chrome:","about:","data:","javascript:"].includes(t.protocol))return`Blocked URL protocol "${t.protocol}". Only http: and https: are allowed.`;if(t.protocol!=="http:"&&t.protocol!=="https:")return`Unsupported URL protocol "${t.protocol}". Only http: and https: are allowed.`;let r=t.hostname;return await this.resolveAndCheckHost(r)?`Access to private/internal network address "${r}" is blocked.`:null}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await Nh(e);if(this.isPrivateIp(t))return!0}catch{}return!1}async closeBrowser(){try{return this.page=null,this.browser&&(await this.browser.close(),this.browser=null),{success:!0,display:"Browser closed."}}catch(e){return this.browser=null,this.page=null,{success:!1,error:`Close failed: ${e.message}`}}}}});var ys,Id=T(()=>{"use strict";W();Me();ys=class extends x{static{m(this,"ProfileSkill")}userRepo;metadata={name:"profile",category:"core",description:"Manage user profile settings including timezone, language, and bio. Use this to personalize Alfred for each user.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get","set_timezone","set_language","set_bio","set_preference"],description:"The profile action to perform"},value:{type:"string",description:"The value to set (for set_* actions)"},preference_key:{type:"string",description:"The preference key (for set_preference)"},preference_value:{type:"string",description:"The preference value (for set_preference)"}},required:["action"]}};constructor(e){super(),this.userRepo=e}async execute(e,t){let s=e.action,r=de(t);switch(s){case"get":return this.getProfile(r);case"set_timezone":return this.setField(r,"timezone",e.value);case"set_language":return this.setField(r,"language",e.value);case"set_bio":return this.setField(r,"bio",e.value);case"set_preference":return this.setPreference(r,e.preference_key,e.preference_value);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}getProfile(e){let t=this.userRepo.getProfile(e);if(!t)return{success:!0,data:null,display:"No profile found. Set your timezone, language, or bio to create one."};let s=[];if(t.displayName&&s.push(`Name: ${t.displayName}`),t.timezone&&s.push(`Timezone: ${t.timezone}`),t.language&&s.push(`Language: ${t.language}`),t.bio&&s.push(`Bio: ${t.bio}`),t.preferences)for(let[r,n]of Object.entries(t.preferences))s.push(`${r}: ${String(n)}`);return{success:!0,data:t,display:s.length>0?`Profile:
|
|
790
806
|
${s.map(r=>`- ${r}`).join(`
|
|
791
|
-
`)}`:"Profile is empty."}}setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let n=this.userRepo.getProfile(e)?.preferences??{};return n[t]=s,this.userRepo.updateProfile(e,{preferences:n}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var He,
|
|
807
|
+
`)}`:"Profile is empty."}}setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let n=this.userRepo.getProfile(e)?.preferences??{};return n[t]=s,this.userRepo.updateProfile(e,{preferences:n}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var He,Fr=T(()=>{"use strict";He=class{static{m(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var Ad={};fe(Ad,{CalDAVProvider:()=>ro});var ro,ra=T(()=>{"use strict";Fr();ro=class extends He{static{m(this,"CalDAVProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"caldav"})}catch(e){throw new Error(`CalDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){let s=await this.client.fetchCalendars();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchCalendarObjects({calendar:n,timeRange:{start:e.toISOString(),end:t.toISOString()}});for(let i of o){let a=this.parseICalEvent(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.start.getTime()-o.start.getTime())}async createEvent(e){let t=await this.client.fetchCalendars();if(!t||t.length===0)throw new Error("No calendars found");let s=`alfred-${Date.now()}@alfred`,r=this.buildICalEvent(s,e);return await this.client.createCalendarObject({calendar:t[0],filename:`${s}.ics`,iCalString:r}),{id:s,title:e.title,start:e.start,end:e.end,location:e.location,description:e.description,allDay:e.allDay}}async updateEvent(e,t){let s=await this.client.fetchCalendars();for(let r of s){let n=await this.client.fetchCalendarObjects({calendar:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseICalEvent(o.data,o.url);if(!i)continue;let a={title:t.title??i.title,start:t.start??i.start,end:t.end??i.end,location:t.location??i.location,description:t.description??i.description,allDay:t.allDay??i.allDay},c=this.buildICalEvent(e,a);return await this.client.updateCalendarObject({calendarObject:{...o,data:c}}),{id:e,...a}}}throw new Error(`Event ${e} not found`)}async deleteEvent(e){let t=await this.client.fetchCalendars();for(let s of t){let r=await this.client.fetchCalendarObjects({calendar:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteCalendarObject({calendarObject:n});return}}throw new Error(`Event ${e} not found`)}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}parseICalEvent(e,t){try{let s=e.split(`
|
|
792
808
|
`).map(p=>p.trim()),r=m(p=>s.find(h=>h.startsWith(p+":"))?.slice(p.length+1),"get"),n=r("SUMMARY"),o=r("DTSTART")??r("DTSTART;VALUE=DATE"),i=r("DTEND")??r("DTEND;VALUE=DATE"),a=r("LOCATION"),c=r("DESCRIPTION"),d=r("UID")??t;if(!n||!o)return;let u=o.length===8;return{id:d,title:n,start:this.parseICalDate(o),end:i?this.parseICalDate(i):this.parseICalDate(o),location:a||void 0,description:c||void 0,allDay:u}}catch(s){console.error("[caldav] Failed to parse iCal event",s);return}}parseICalDate(e){if(e.length===8)return new Date(`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`);let t=e.replace(/[^0-9TZ]/g,"");return t.length>=15?new Date(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T${t.slice(9,11)}:${t.slice(11,13)}:${t.slice(13,15)}Z`):new Date(e)}buildICalEvent(e,t){let s=m((n,o)=>o?n.toISOString().slice(0,10).replace(/-/g,""):n.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),"formatDate"),r=`BEGIN:VCALENDAR\r
|
|
793
809
|
VERSION:2.0\r
|
|
794
810
|
PRODID:-//Alfred//EN\r
|
|
@@ -804,28 +820,28 @@ BEGIN:VEVENT\r
|
|
|
804
820
|
`),r+=`DTSTAMP:${s(new Date)}\r
|
|
805
821
|
`,r+=`END:VEVENT\r
|
|
806
822
|
END:VCALENDAR\r
|
|
807
|
-
`,r}}});var
|
|
823
|
+
`,r}}});var Rd={};fe(Rd,{GoogleCalendarProvider:()=>no});var no,na=T(()=>{"use strict";Fr();no=class extends He{static{m(this,"GoogleCalendarProvider")}config;calendar;constructor(e){super(),this.config=e}async initialize(){try{let{google:e}=await import("googleapis"),t=new e.auth.OAuth2(this.config.clientId,this.config.clientSecret);t.setCredentials({refresh_token:this.config.refreshToken}),this.calendar=e.calendar({version:"v3",auth:t})}catch(e){throw new Error(`Google Calendar initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){return((await this.calendar.events.list({calendarId:"primary",timeMin:e.toISOString(),timeMax:t.toISOString(),singleEvents:!0,orderBy:"startTime"})).data.items??[]).map(r=>this.mapEvent(r))}async createEvent(e){let t={summary:e.title,location:e.location,description:e.description};e.allDay?(t.start={date:e.start.toISOString().slice(0,10)},t.end={date:e.end.toISOString().slice(0,10)}):(t.start={dateTime:e.start.toISOString()},t.end={dateTime:e.end.toISOString()});let s=await this.calendar.events.insert({calendarId:"primary",requestBody:t});return this.mapEvent(s.data)}async updateEvent(e,t){let s={};t.title&&(s.summary=t.title),t.location&&(s.location=t.location),t.description&&(s.description=t.description),t.start&&(s.start=t.allDay?{date:t.start.toISOString().slice(0,10)}:{dateTime:t.start.toISOString()}),t.end&&(s.end=t.allDay?{date:t.end.toISOString().slice(0,10)}:{dateTime:t.end.toISOString()});let r=await this.calendar.events.patch({calendarId:"primary",eventId:e,requestBody:s});return this.mapEvent(r.data)}async deleteEvent(e){await this.calendar.events.delete({calendarId:"primary",eventId:e})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}mapEvent(e){let t=!!e.start?.date;return{id:e.id,title:e.summary??"(No title)",start:new Date(e.start?.dateTime??e.start?.date),end:new Date(e.end?.dateTime??e.end?.date),location:e.location??void 0,description:e.description??void 0,allDay:t}}}});var xd={};fe(xd,{MicrosoftCalendarProvider:()=>oo});var oo,oa=T(()=>{"use strict";Fr();oo=class extends He{static{m(this,"MicrosoftCalendarProvider")}config;client;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Calendars.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s={Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",Prefer:'outlook.timezone="UTC"',...t.headers??{}},r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:s});if(r.status===401){await this.refreshAccessToken(),s.Authorization=`Bearer ${this.accessToken}`;let n=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:s});if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return n.json()}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async listEvents(e,t){let s=new URLSearchParams({startDateTime:e.toISOString(),endDateTime:t.toISOString(),$orderby:"start/dateTime",$top:"50"});return((await this.graphRequest(`/me/calendarView?${s}`)).value??[]).map(n=>this.mapEvent(n))}async createEvent(e){let t=this.timezone,s={subject:e.title,body:e.description?{contentType:"text",content:e.description}:void 0,location:e.location?{displayName:e.location}:void 0,isAllDay:e.allDay??!1};e.allDay?(s.start={dateTime:this.formatDateInTz(e.start,t).slice(0,10)+"T00:00:00",timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t).slice(0,10)+"T00:00:00",timeZone:t}):(s.start={dateTime:this.formatDateInTz(e.start,t),timeZone:t},s.end={dateTime:this.formatDateInTz(e.end,t),timeZone:t});let r=await this.graphRequest("/me/events",{method:"POST",body:JSON.stringify(s)});return this.mapEvent(r)}async updateEvent(e,t){let s={};t.title&&(s.subject=t.title),t.description&&(s.body={contentType:"text",content:t.description}),t.location&&(s.location={displayName:t.location}),t.start&&(s.start={dateTime:this.formatDateInTz(t.start,this.timezone),timeZone:this.timezone}),t.end&&(s.end={dateTime:this.formatDateInTz(t.end,this.timezone),timeZone:this.timezone});let r=await this.graphRequest(`/me/events/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapEvent(r)}async deleteEvent(e){await this.graphRequest(`/me/events/${e}`,{method:"DELETE"})}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}formatDateInTz(e,t){let s=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),r=m(n=>s.find(o=>o.type===n)?.value??"00","g");return`${r("year")}-${r("month")}-${r("day")}T${r("hour")}:${r("minute")}:${r("second")}`}mapEvent(e){return{id:e.id,title:e.subject??"(No title)",start:this.parseGraphDateTime(e.start),end:this.parseGraphDateTime(e.end),location:e.location?.displayName??void 0,description:e.body?.content??void 0,allDay:e.isAllDay??!1}}parseGraphDateTime(e){if(!e?.dateTime)return new Date;let t=e.dateTime.replace(/(\.\d{3})\d*$/,"$1"),s=e.timeZone;return!s||s==="UTC"||s.includes("Utc")?new Date(t+"Z"):this.parseDateInTimezone(t,s)}parseDateInTimezone(e,t){let s=new Date(e+"Z"),r=new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(s),n=m(a=>r.find(c=>c.type===a)?.value??"00","g"),i=new Date(`${n("year")}-${n("month")}-${n("day")}T${n("hour")}:${n("minute")}:${n("second")}Z`).getTime()-s.getTime();return new Date(s.getTime()-i)}}});async function jr(l){switch(l.provider){case"caldav":{if(!l.caldav)throw new Error("CalDAV config missing");let{CalDAVProvider:e}=await Promise.resolve().then(()=>(ra(),Ad)),t=new e(l.caldav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google Calendar config missing");let{GoogleCalendarProvider:e}=await Promise.resolve().then(()=>(na(),Rd)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft Calendar config missing");let{MicrosoftCalendarProvider:e}=await Promise.resolve().then(()=>(oa(),xd)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown calendar provider: ${l.provider}`)}}var Cd=T(()=>{"use strict";m(jr,"createCalendarProvider")});var Pt,Nd=T(()=>{"use strict";W();Pt=class extends x{static{m(this,"CalendarSkill")}calendarProvider;timezone;metadata={name:"calendar",category:"productivity",description:"Manage calendar events. List upcoming events, create new events, update or delete existing ones, and check availability.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_events","create_event","update_event","delete_event","check_availability","find_free_slot","check_conflicts"],description:"The calendar action to perform. Use find_free_slot to find available time windows."},start:{type:"string",description:`Start date/time in ISO 8601 format WITHOUT timezone suffix (e.g. "2026-03-09T14:00:00", NOT "2026-03-09T14:00:00Z"). Times are interpreted in the user's local timezone.`},end:{type:"string",description:`End date/time in ISO 8601 format WITHOUT timezone suffix (e.g. "2026-03-09T14:30:00"). Times are interpreted in the user's local timezone.`},title:{type:"string",description:"Event title (for create/update)"},location:{type:"string",description:"Event location (for create/update)"},description:{type:"string",description:"Event description (for create/update)"},event_id:{type:"string",description:"Event ID (for update/delete)"},all_day:{type:"boolean",description:"Whether this is an all-day event"},duration_minutes:{type:"number",description:"Duration in minutes to find a free slot for (for find_free_slot)"},working_hours_only:{type:"boolean",description:"If true, only consider 08:00-18:00 for free slots (default: true)"}},required:["action"]}};constructor(e,t){super(),this.calendarProvider=e,this.timezone=t}async execute(e,t){t.timezone&&(this.calendarProvider.timezone=t.timezone);let s=e.action;switch(s){case"list_events":return this.listEvents(e);case"create_event":return this.createEvent(e);case"update_event":return this.updateEvent(e);case"delete_event":return this.deleteEvent(e);case"check_availability":return this.checkAvailability(e);case"find_free_slot":return this.findFreeSlot(e);case"check_conflicts":return this.checkConflicts(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async getTodayEvents(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate()),s=new Date(e.getFullYear(),e.getMonth(),e.getDate()+1);try{return await this.calendarProvider.listEvents(t,s)}catch(r){return console.error("[calendar] Failed to fetch today events",r),[]}}async listEvents(e){let t=e.start?new Date(e.start):new Date,s=e.end?new Date(e.end):new Date(t.getTime()+10080*60*1e3);try{let r=await this.calendarProvider.listEvents(t,s);if(r.length===0)return{success:!0,data:[],display:"No events found in this time range."};let n=r.map(o=>this.formatEvent(o)).join(`
|
|
808
824
|
`);return{success:!0,data:r,display:`${r.length} event(s):
|
|
809
825
|
${n}`}}catch(r){return{success:!1,error:`Failed to list events: ${r instanceof Error?r.message:String(r)}`}}}parseLocalTime(e){return new Date(e.replace(/Z$/i,""))}async createEvent(e){let t=e.title,s=e.start,r=e.end;if(!t)return{success:!1,error:'Missing required field "title"'};if(!s)return{success:!1,error:'Missing required field "start"'};if(!r)return{success:!1,error:'Missing required field "end"'};try{let n=await this.calendarProvider.createEvent({title:t,start:this.parseLocalTime(s),end:this.parseLocalTime(r),location:e.location,description:e.description,allDay:e.all_day});return{success:!0,data:n,display:`Event created: ${this.formatEvent(n)}`}}catch(n){return{success:!1,error:`Failed to create event: ${n instanceof Error?n.message:String(n)}`}}}async updateEvent(e){let t=e.event_id;if(!t)return{success:!1,error:'Missing required field "event_id"'};try{let s=await this.calendarProvider.updateEvent(t,{title:e.title,start:e.start?this.parseLocalTime(e.start):void 0,end:e.end?this.parseLocalTime(e.end):void 0,location:e.location,description:e.description,allDay:e.all_day});return{success:!0,data:s,display:`Event updated: ${this.formatEvent(s)}`}}catch(s){return{success:!1,error:`Failed to update event: ${s instanceof Error?s.message:String(s)}`}}}async deleteEvent(e){let t=e.event_id;if(!t)return{success:!1,error:'Missing required field "event_id"'};try{return await this.calendarProvider.deleteEvent(t),{success:!0,data:{deleted:t},display:`Event "${t}" deleted.`}}catch(s){return{success:!1,error:`Failed to delete event: ${s instanceof Error?s.message:String(s)}`}}}async checkAvailability(e){let t=e.start,s=e.end;if(!t||!s)return{success:!1,error:'Missing required fields "start" and "end"'};try{let r=await this.calendarProvider.checkAvailability(this.parseLocalTime(t),this.parseLocalTime(s)),n=r.available?"Time slot is available.":`Time slot has ${r.conflicts.length} conflict(s):
|
|
810
826
|
${r.conflicts.map(o=>this.formatEvent(o)).join(`
|
|
811
|
-
`)}`;return{success:!0,data:r,display:n}}catch(r){return{success:!1,error:`Failed to check availability: ${r instanceof Error?r.message:String(r)}`}}}async findFreeSlot(e){let t=e.duration_minutes??60,s=e.start?new Date(e.start):new Date,r=e.end?new Date(e.end):new Date(s.getTime()+10080*60*1e3),n=e.working_hours_only!==!1;if(t<5||t>480)return{success:!1,error:"duration_minutes must be between 5 and 480"};try{let i=[...await this.calendarProvider.listEvents(s,r)].sort((
|
|
827
|
+
`)}`;return{success:!0,data:r,display:n}}catch(r){return{success:!1,error:`Failed to check availability: ${r instanceof Error?r.message:String(r)}`}}}async findFreeSlot(e){let t=e.duration_minutes??60,s=e.start?new Date(e.start):new Date,r=e.end?new Date(e.end):new Date(s.getTime()+10080*60*1e3),n=e.working_hours_only!==!1;if(t<5||t>480)return{success:!1,error:"duration_minutes must be between 5 and 480"};try{let i=[...await this.calendarProvider.listEvents(s,r)].sort((_,S)=>_.start.getTime()-S.start.getTime()),a=t*6e4,c=[],d=8,u=18,p=s.getTime(),h=r.getTime();for(let _ of i){let S=_.start.getTime(),b=_.end.getTime();if(!_.allDay&&(S>p&&this.collectSlots(p,S,a,n,d,u,c),p=Math.max(p,b),c.length>=5))break}if(c.length<5&&p<h&&this.collectSlots(p,h,a,n,d,u,c),c.length===0)return{success:!0,data:{slots:[]},display:`No free ${t}-minute slots found in the given range.`};let f=this.calendarProvider.timezone||this.timezone,g={weekday:"short",day:"2-digit",month:"2-digit",hour:"2-digit",minute:"2-digit",...f?{timeZone:f}:{}},y=c.slice(0,5).map((_,S)=>{let b=_.start.toLocaleString("de-AT",g),$=_.end.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...f?{timeZone:f}:{}});return`${S+1}. ${b} \u2013 ${$}`});return{success:!0,data:{slots:c.slice(0,5).map(_=>({start:_.start.toISOString(),end:_.end.toISOString()}))},display:`Free ${t}-minute slots:
|
|
812
828
|
${y.join(`
|
|
813
|
-
`)}`}}catch(o){return{success:!1,error:`Failed to find free slots: ${o instanceof Error?o.message:String(o)}`}}}collectSlots(e,t,s,r,n,o,i){let a=e;for(;a+s<=t&&i.length<5;){let c=new Date(a),d=c.getHours(),u=a+s,p=new Date(u).getHours()+new Date(u).getMinutes()/60;if(r){let h=c.getDay();if(h===0||h===6){let
|
|
829
|
+
`)}`}}catch(o){return{success:!1,error:`Failed to find free slots: ${o instanceof Error?o.message:String(o)}`}}}collectSlots(e,t,s,r,n,o,i){let a=e;for(;a+s<=t&&i.length<5;){let c=new Date(a),d=c.getHours(),u=a+s,p=new Date(u).getHours()+new Date(u).getMinutes()/60;if(r){let h=c.getDay();if(h===0||h===6){let f=h===0?1:2;a=new Date(c.getFullYear(),c.getMonth(),c.getDate()+f,n).getTime();continue}if(d<n){a=new Date(c.getFullYear(),c.getMonth(),c.getDate(),n).getTime();continue}if(d>=o||p>o){a=new Date(c.getFullYear(),c.getMonth(),c.getDate()+1,n).getTime();continue}}i.push({start:new Date(a),end:new Date(u)}),a=u}}async checkConflicts(e){let t=e.start,s=e.end,r=e.title??"New Event";if(!t||!s)return{success:!1,error:'Missing required fields "start" and "end"'};try{let n=await this.calendarProvider.checkAvailability(this.parseLocalTime(t),this.parseLocalTime(s));if(n.available)return{success:!0,data:{conflicts:[],available:!0},display:`No conflicts found for "${r}" (${t} \u2013 ${s}). The time slot is free.`};let o=n.conflicts.map(i=>this.formatEvent(i));return{success:!0,data:{conflicts:n.conflicts,available:!1},display:`"${r}" has ${n.conflicts.length} conflict(s):
|
|
814
830
|
${o.join(`
|
|
815
|
-
`)}`}}catch(n){return{success:!1,error:`Failed to check conflicts: ${n instanceof Error?n.message:String(n)}`}}}formatEvent(e){let t=this.calendarProvider.timezone||this.timezone,s={hour:"2-digit",minute:"2-digit",...t?{timeZone:t}:{}},r={weekday:"short",day:"2-digit",month:"2-digit",year:"numeric",...t?{timeZone:t}:{}},n=e.location?` @ ${e.location}`:"",o=e.id?` [id:${e.id}]`:"",i=e.start.toLocaleDateString("de-AT",r);if(e.allDay)return`- ${i} ganzt\xE4gig: ${e.title}${n}${o}`;let a=e.start.toLocaleTimeString("en-GB",s),c=e.end.toLocaleTimeString("en-GB",s);return`- ${i} ${a}-${c}: ${e.title}${n}${o}`}}});var
|
|
831
|
+
`)}`}}catch(n){return{success:!1,error:`Failed to check conflicts: ${n instanceof Error?n.message:String(n)}`}}}formatEvent(e){let t=this.calendarProvider.timezone||this.timezone,s={hour:"2-digit",minute:"2-digit",...t?{timeZone:t}:{}},r={weekday:"short",day:"2-digit",month:"2-digit",year:"numeric",...t?{timeZone:t}:{}},n=e.location?` @ ${e.location}`:"",o=e.id?` [id:${e.id}]`:"",i=e.start.toLocaleDateString("de-AT",r);if(e.allDay)return`- ${i} ganzt\xE4gig: ${e.title}${n}${o}`;let a=e.start.toLocaleTimeString("en-GB",s),c=e.end.toLocaleTimeString("en-GB",s);return`- ${i} ${a}-${c}: ${e.title}${n}${o}`}}});var Ld=T(()=>{"use strict";Fr();ra();na();oa();Cd();Nd()});var ws,Dd=T(()=>{"use strict";W();ws=class extends x{static{m(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}**
|
|
816
832
|
|
|
817
833
|
Enter this code on your other platform within 10 minutes using:
|
|
818
|
-
"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),n=this.checkConfirmRateLimit(r);if(n)return{success:!1,error:n};let o=this.linkTokens.findByCode(s.trim());if(!o)return this.recordFailedConfirm(r),{success:!1,error:"Invalid or expired linking code. Please generate a new one."};let i=o.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),c=this.users.getMasterUserId(r),d;if(a!==i?d=a:c!==r?d=c:d=i,a!==i&&c!==r&&a!==c){let h=this.users.getLinkedUsers(c);for(let
|
|
834
|
+
"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),n=this.checkConfirmRateLimit(r);if(n)return{success:!1,error:n};let o=this.linkTokens.findByCode(s.trim());if(!o)return this.recordFailedConfirm(r),{success:!1,error:"Invalid or expired linking code. Please generate a new one."};let i=o.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),c=this.users.getMasterUserId(r),d;if(a!==i?d=a:c!==r?d=c:d=i,a!==i&&c!==r&&a!==c){let h=this.users.getLinkedUsers(c);for(let f of h)this.users.setMasterUser(f.id,d)}i!==d&&this.users.setMasterUser(i,d),r!==d&&this.users.setMasterUser(r,d),this.linkTokens.consume(o.id);let u=this.users.findById(i),p=o.platform;return{success:!0,data:{masterUserId:d,linkedPlatform:p},display:`Account linked successfully! Your ${p} account (${u?.displayName??u?.username??"unknown"}) is now linked to this ${t.platform} account.
|
|
819
835
|
|
|
820
836
|
Your memories, preferences, and context are now shared across platforms.`}}async sendMessage(e,t){let s=e.platform,r=e.chat_id,n=e.message;if(!s)return{success:!1,error:'Missing required field "platform"'};if(!n)return{success:!1,error:'Missing required field "message"'};let o=this.adapters.get(s);if(!o)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(u=>u.platform===s);if(d&&this.findConversation){let u=this.findConversation(s,d.id);u&&(r=u.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 o.sendMessage(r,n),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:
|
|
821
837
|
"Start linking my account" on the platform you want to link from, then enter the code on the other platform.`};let n=r.map(o=>{let i=o.id===t?" (current)":"",a=o.displayName??o.username??o.platformUserId;return`- **${o.platform}**: ${a}${i}`});return{success:!0,data:{identities:r.map(o=>({platform:o.platform,username:o.username,displayName:o.displayName}))},display:`Linked accounts:
|
|
822
838
|
${n.join(`
|
|
823
|
-
`)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=this.resolveInternalId(t),n=this.users.getMasterUserId(r),i=this.users.getLinkedUsers(n).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
|
|
839
|
+
`)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=this.resolveInternalId(t),n=this.users.getMasterUserId(r),i=this.users.getLinkedUsers(n).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 Ts,Md=T(()=>{"use strict";W();Me();Ts=class extends x{static{m(this,"BackgroundTaskSkill")}taskRepo;metadata={name:"background_task",category:"automation",description:'Schedule, list, cancel, pause, or resume background tasks that run a SINGLE skill call asynchronously. Use "schedule" to queue ONE skill execution in the background (user will be notified when done). NOT for multi-step tasks \u2014 use "delegate" instead when a task needs multiple tool calls (e.g. search + read + process + generate). Use "list" to see active/recent tasks. Use "cancel" to stop a pending or running task. Use "pause" to checkpoint a persistent task and "resume" to continue it. Set persistent=true and max_duration_hours for long-running persistent tasks.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["schedule","list","cancel","pause","resume"],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, pause, resume)"},persistent:{type:"boolean",description:"If true, creates a persistent task with checkpoint/resume support (for schedule)"},max_duration_hours:{type:"number",description:"Maximum duration in hours for persistent tasks (default: 24)"}},required:["action"]}};persistentRunner;constructor(e){super(),this.taskRepo=e}setPersistentRunner(e){this.persistentRunner=e}getAllTasks(e){let t=new Set,s=[];for(let r of K(e))for(let n of this.taskRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"schedule":return this.scheduleTask(e,t);case"list":return this.listTasks(t);case"cancel":return this.cancelTask(e,t);case"pause":return this.pauseTask(e,t);case"resume":return this.resumeTask(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,n=e.skill_input,o=e.persistent,i=e.max_duration_hours;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 a=this.taskRepo.create(de(t),t.platform,t.chatId,s,r,JSON.stringify(n??{}));o&&i?(this.taskRepo.updatePersistentConfig(a.id,i),a.maxDurationHours=i):o&&(this.taskRepo.updatePersistentConfig(a.id,24),a.maxDurationHours=24);let c=o?" (persistent)":"";return{success:!0,data:{taskId:a.id,description:s,skillName:r,status:a.status,persistent:!!o},display:`Background task scheduled${c} (${a.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",checkpointed:"\u23F8\uFE0F",resuming:"\u21BB",cancelled:"\u23F9"},r=t.map(n=>`- ${s[n.status]??"?"} ${n.id}: "${n.description}" [${n.status}] (${n.skillName})`);return{success:!0,data:t.map(n=>({taskId:n.id,description:n.description,status:n.status,skillName:n.skillName,createdAt:n.createdAt,completedAt:n.completedAt})),display:`Background tasks:
|
|
824
840
|
${r.join(`
|
|
825
|
-
`)}`}}async cancelTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for cancel action'};let n=this.getAllTasks(t).find(o=>o.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):this.taskRepo.cancel(s)||this.taskRepo.cancelTask(s),{success:!0,data:{taskId:s},display:`Background task "${s}" cancelled.`}):{success:!1,error:`Task "${s}" not found or already completed`}}async pauseTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for pause action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="running"&&n.status!=="resuming"?{success:!1,error:`Task "${s}" is not running (status: ${n.status})`}:(await this.persistentRunner.pause(s),{success:!0,data:{taskId:s},display:`Persistent task "${s}" paused. Use resume to continue.`}):{success:!1,error:`Task "${s}" not found`}}async resumeTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for resume action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="checkpointed"?{success:!1,error:`Task "${s}" is not checkpointed (status: ${n.status})`}:(this.persistentRunner.resume(n).catch(()=>{}),{success:!0,data:{taskId:s},display:`Persistent task "${s}" resuming. You'll be notified when it completes.`}):{success:!1,error:`Task "${s}" not found`}}}});var
|
|
841
|
+
`)}`}}async cancelTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for cancel action'};let n=this.getAllTasks(t).find(o=>o.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):this.taskRepo.cancel(s)||this.taskRepo.cancelTask(s),{success:!0,data:{taskId:s},display:`Background task "${s}" cancelled.`}):{success:!1,error:`Task "${s}" not found or already completed`}}async pauseTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for pause action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="running"&&n.status!=="resuming"?{success:!1,error:`Task "${s}" is not running (status: ${n.status})`}:(await this.persistentRunner.pause(s),{success:!0,data:{taskId:s},display:`Persistent task "${s}" paused. Use resume to continue.`}):{success:!1,error:`Task "${s}" not found`}}async resumeTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for resume action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="checkpointed"?{success:!1,error:`Task "${s}" is not checkpointed (status: ${n.status})`}:(this.persistentRunner.resume(n).catch(()=>{}),{success:!0,data:{taskId:s},display:`Persistent task "${s}" resuming. You'll be notified when it completes.`}):{success:!1,error:`Task "${s}" not found`}}}});var _s,Od=T(()=>{"use strict";W();Me();_s=class extends x{static{m(this,"ScheduledTaskSkill")}actionRepo;metadata={name:"scheduled_task",category:"automation",description:'Create, list, enable, disable, or delete scheduled actions that run automatically on a recurring basis. Supports cron expressions (e.g. "0 9 * * *" for daily at 9 AM), intervals (in minutes), and one-time schedules. Each scheduled action executes a skill or sends a prompt to the LLM at the configured time. Use this for time-based tasks (reports, periodic checks, reminders). For condition-based alerts ("notify me WHEN X happens"), use the watch tool instead.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The scheduled task action to perform"},name:{type:"string",description:"Name for the scheduled action (for create)"},description:{type:"string",description:"What the scheduled action does (for create)"},schedule_type:{type:"string",enum:["cron","interval","once"],description:"Type of schedule: cron expression, interval in minutes, or one-time ISO date (for create)"},schedule_value:{type:"string",description:"Schedule value: cron expression, minutes as string, or ISO date (for create)"},skill_name:{type:"string",description:"The skill to execute on schedule (for create)"},skill_input:{type:"object",description:"Input to pass to the skill (for create)"},prompt_template:{type:"string",description:"Optional LLM prompt to run instead of a skill (for create)"},action_id:{type:"string",description:"Scheduled action ID (for enable, disable, delete)"}},required:["action"]}};constructor(e){super(),this.actionRepo=e}getAllActions(e){let t=new Set,s=[];for(let r of K(e))for(let n of this.actionRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"create":return this.createAction(e,t);case"list":return this.listActions(t);case"enable":return this.toggleAction(e,!0,t);case"disable":return this.toggleAction(e,!1,t);case"delete":return this.deleteAction(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: create, list, enable, disable, delete`}}}createAction(e,t){let s=e.name,r=e.description,n=e.schedule_type,o=e.schedule_value,i=e.skill_name,a=e.skill_input,c=e.prompt_template;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "name" for create action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "description" for create action'};if(!n||!["cron","interval","once"].includes(n))return{success:!1,error:'Missing or invalid "schedule_type". Must be "cron", "interval", or "once"'};if(!o||typeof o!="string")return{success:!1,error:'Missing required field "schedule_value" for create action'};if((!i||typeof i!="string")&&!c)return{success:!1,error:'Missing required field "skill_name" (or "prompt_template") for create action'};if(n==="interval"){let p=parseInt(o,10);if(isNaN(p)||p<=0)return{success:!1,error:"For interval schedule, value must be a positive number of minutes"}}if(n==="cron"&&o.trim().split(/\s+/).length!==5)return{success:!1,error:"Cron expression must have 5 fields: minute hour dayOfMonth month dayOfWeek"};if(n==="once"){let p=new Date(o);if(isNaN(p.getTime()))return{success:!1,error:"For once schedule, value must be a valid ISO date string"};if(p.getTime()<=Date.now())return{success:!1,error:"The scheduled time is in the past. Please specify a future time."}}let d=this.actionRepo.create({userId:de(t),platform:t.platform,chatId:t.chatId,name:s,description:r,scheduleType:n,scheduleValue:o,skillName:i??"llm_prompt",skillInput:JSON.stringify(a??{}),promptTemplate:c}),u=n==="cron"?`cron: ${o}`:n==="interval"?`every ${o} minutes`:`once at ${o}`;return{success:!0,data:{actionId:d.id,name:s,scheduleType:n,scheduleValue:o,skillName:i},display:`Scheduled action created (${d.id}): "${s}" \u2014 ${u}, running "${i}"${d.nextRunAt?`. Next run: ${d.nextRunAt}`:""}`}}listActions(e){let t=this.getAllActions(e);if(t.length===0)return{success:!0,data:[],display:"No scheduled actions."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=r.scheduleType==="cron"?`cron: ${r.scheduleValue}`:r.scheduleType==="interval"?`every ${r.scheduleValue} min`:`once: ${r.scheduleValue}`,i=r.nextRunAt?` | next: ${r.nextRunAt}`:"";return`- ${n} ${r.id}: "${r.name}" [${o}] \u2192 ${r.skillName}${i}`});return{success:!0,data:t.map(r=>({actionId:r.id,name:r.name,scheduleType:r.scheduleType,scheduleValue:r.scheduleValue,skillName:r.skillName,enabled:r.enabled,nextRunAt:r.nextRunAt,lastRunAt:r.lastRunAt})),display:`Scheduled actions:
|
|
826
842
|
${s.join(`
|
|
827
|
-
`)}`}}toggleAction(e,t,s){let r=e.action_id;if(!r||typeof r!="string")return{success:!1,error:`Missing required field "action_id" for ${t?"enable":"disable"} action`};let n=this.actionRepo.findById(r),o=
|
|
828
|
-
`),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
|
|
843
|
+
`)}`}}toggleAction(e,t,s){let r=e.action_id;if(!r||typeof r!="string")return{success:!1,error:`Missing required field "action_id" for ${t?"enable":"disable"} action`};let n=this.actionRepo.findById(r),o=K(s);return!n||!o.includes(n.userId)?{success:!1,error:`Scheduled action "${r}" not found`}:this.actionRepo.setEnabled(r,t)?{success:!0,data:{actionId:r,enabled:t},display:`Scheduled action "${r}" ${t?"enabled":"disabled"}.`}:{success:!1,error:`Scheduled action "${r}" not found`}}deleteAction(e,t){let s=e.action_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "action_id" for delete action'};let r=this.actionRepo.findById(s),n=K(t);return!r||!n.includes(r.userId)?{success:!1,error:`Scheduled action "${s}" not found`}:this.actionRepo.delete(s)?{success:!0,data:{actionId:s},display:`Scheduled action "${s}" deleted.`}:{success:!1,error:`Scheduled action "${s}" not found`}}}});var Ut,ia=T(()=>{"use strict";Ut=class{static{m(this,"MCPClient")}serverName;config;logger;client;transport;connected=!1;constructor(e,t,s){this.serverName=e,this.config=t,this.logger=s}async connect(){try{let{Client:e}=await import("@modelcontextprotocol/sdk/client/index.js");if(this.client=new e({name:`alfred-${this.serverName}`,version:"1.0.0"},{capabilities:{}}),this.config.command){let{StdioClientTransport:t}=await import("@modelcontextprotocol/sdk/client/stdio.js"),s={PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:process.env.NODE_ENV??"",SYSTEMROOT:process.env.SYSTEMROOT??""};if(this.config.env)for(let[r,n]of Object.entries(this.config.env))s[r]=n.replace(/\$\{(\w+)\}/g,(o,i)=>process.env[i]??"");this.transport=new t({command:this.config.command,args:this.config.args??[],env:s})}else if(this.config.url){let{SSEClientTransport:t}=await import("@modelcontextprotocol/sdk/client/sse.js");this.transport=new t(new URL(this.config.url))}else throw new Error(`MCP server "${this.serverName}": must specify either command or url`);await this.client.connect(this.transport),this.connected=!0,this.logger.info({server:this.serverName},"MCP server connected")}catch(e){throw this.logger.error({server:this.serverName,err:e},"Failed to connect MCP server"),e}}async listTools(){if(!this.connected||!this.client)return[];try{return((await this.client.listTools()).tools??[]).map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema??{type:"object",properties:{}}}))}catch(e){return this.logger.error({server:this.serverName,err:e},"Failed to list MCP tools"),[]}}async callTool(e,t){if(!this.connected||!this.client)return{content:"MCP server not connected",isError:!0};try{let s=await this.client.callTool({name:e,arguments:t});return{content:(s.content??[]).map(n=>n.text??JSON.stringify(n)).join(`
|
|
844
|
+
`),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 Lh,Ft,aa=T(()=>{"use strict";W();Lh=["read","write","destructive","admin"],Ft=class extends x{static{m(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,n,o){super(),this.client=e,this.serverName=t,this.toolName=s;let i=o&&Lh.includes(o)?o:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:i,version:"1.0.0",inputSchema:n}}async execute(e,t){let s=await this.client.callTool(this.toolName,e);return{success:s.isError!==!0,data:s.content,display:s.content,error:s.isError===!0?s.content:void 0}}}});var Br,Pd=T(()=>{"use strict";ia();aa();Br=class{static{m(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new Ut(t.name,t,this.logger.child({mcp:t.name}));await s.connect(),this.clients.push(s);let r=await s.listTools();for(let n of r){let o=new Ft(s,t.name,n.name,n.description??"",n.inputSchema);this.skills.push(o)}this.logger.info({server:t.name,tools:r.length},"MCP server initialized")}catch(s){this.logger.error({server:t.name,err:s},"Failed to initialize MCP server")}}getSkills(){return this.skills}async shutdown(){for(let e of this.clients)await e.disconnect();this.clients.length=0,this.skills.length=0}}});var Ud=T(()=>{"use strict";ia();aa();Pd()});import{spawn as Dh}from"node:child_process";import We from"node:fs";import ze from"node:path";import Mh from"node:os";import Oh from"node:crypto";var jt,ca=T(()=>{"use strict";jt=class{static{m(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=zc.resolve(`${s}/package.json`);e.add(ze.dirname(ze.dirname(r)))}catch{}try{let s=We.realpathSync(process.argv[1]??""),r=ze.dirname(s),n=ze.join(r,"node_modules");We.existsSync(n)&&e.add(n);let o=ze.join(r,"..","node_modules");We.existsSync(o)&&e.add(We.realpathSync(o))}catch{}let t=ze.join(process.cwd(),"node_modules");if(We.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(ze.delimiter))s&&e.add(s);return[...e].join(ze.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=ze.join(Mh.tmpdir(),`alfred-sandbox-${Oh.randomUUID()}`);We.mkdirSync(n,{recursive:!0});try{let o=t==="javascript"?"js":"py",i=ze.join(n,`script.${o}`);We.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[i],d=Date.now();return await new Promise(u=>{let p=Dh(a,c,{cwd:n,timeout:r,env:{...process.env,NODE_ENV:"sandbox",PYTHONDONTWRITEBYTECODE:"1",...s?.env,TMPDIR:n,TEMP:n,TMP:n,NODE_PATH:this.resolveNodePath()},stdio:["pipe","pipe","pipe"]}),h="",f="";p.stdout.on("data",g=>{h+=g.toString()}),p.stderr.on("data",g=>{f+=g.toString()}),p.on("close",g=>{let y=Date.now()-d,_=[];try{let S=We.readdirSync(n).filter(b=>!b.startsWith("script."));for(let b of S){let $=ze.join(n,b),N=We.statSync($);if(N.isFile()&&N.size<1e7){let M=We.readFileSync($),J=b.endsWith(".png")?"image/png":b.endsWith(".jpg")||b.endsWith(".jpeg")?"image/jpeg":b.endsWith(".svg")?"image/svg+xml":b.endsWith(".csv")?"text/csv":b.endsWith(".json")?"application/json":b.endsWith(".html")||b.endsWith(".htm")?"text/html":b.endsWith(".txt")?"text/plain":b.endsWith(".md")?"text/markdown":b.endsWith(".xml")?"application/xml":b.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":b.endsWith(".xls")?"application/vnd.ms-excel":b.endsWith(".pdf")?"application/pdf":"application/octet-stream";_.push({name:b,data:M,mimeType:J})}}}catch{}u({stdout:h.slice(0,5e4),stderr:f.slice(0,1e4),exitCode:g??1,files:_.length>0?_:void 0,durationMs:y})}),p.on("error",g=>{u({stdout:"",stderr:g.message,exitCode:1,durationMs:Date.now()-d})}),p.stdin.end()})}finally{try{We.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var Hr,Fd=T(()=>{"use strict";W();ca();Hr=class extends x{static{m(this,"CodeExecutionSkill")}metadata={name:"code_sandbox",category:"automation",description:"Execute code in a sandboxed environment. Supports JavaScript (Node.js) and Python. Use for calculations, data processing, generating files (PDF, HTML, CSV, images, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. Any files written to the working directory are automatically collected and sent to the user as attachments \u2014 do NOT use the file skill to send them afterwards. For PDF generation use pdfkit (Node.js) or reportlab/fpdf (Python). IMPORTANT: When generating large files, write compact data-driven code \u2014 define data as arrays/objects, then build the output programmatically. Never embed large HTML/text as string literals.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","run_with_data"],description:"Action to perform"},code:{type:"string",description:"Code to execute"},language:{type:"string",enum:["javascript","python"],description:"Programming language"},data:{type:"string",description:"Input data (available as variable INPUT_DATA, already parsed if JSON). Do NOT use os.environ or process.env \u2014 use INPUT_DATA directly."},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new jt;allowedLanguages;maxTimeout;constructor(e){super(),this.allowedLanguages=new Set(e?.allowedLanguages??["javascript","python"]),this.maxTimeout=e?.maxTimeoutMs??12e4}async execute(e,t){let s=e.action,r=e.code,n=e.language,o=e.data,i=Math.min(e.timeout??3e4,this.maxTimeout);if(!r)return{success:!1,error:'Missing required field "code". IMPORTANT: Do NOT embed large HTML/text as string literals \u2014 write compact code that builds content programmatically from data arrays/objects, e.g. rows.map(r => `<tr><td>${r.time}</td><td>${r.price}</td></tr>`).join(""). Keep the code short and data-driven.'};if(!n)return{success:!1,error:'Missing required field "language"'};if(!this.allowedLanguages.has(n))return{success:!1,error:`Language "${n}" is not allowed. Allowed: ${[...this.allowedLanguages].join(", ")}`};if(s==="run"&&r.length>4e3)return{success:!1,error:`Code too large (${r.length} chars, limit 4000 for action "run"). This usually means data is hardcoded in the code. Use action "run_with_data" with the data parameter instead. The data will be available as INPUT_DATA (already parsed). If you received a data reference like "result_1", pass it as the data parameter.`};let a=r;if(s==="run_with_data"&&o){let p=!1;try{JSON.parse(o),p=!0}catch{}n==="javascript"?a=p?`const INPUT_DATA = ${o};
|
|
829
845
|
${r}`:`const INPUT_DATA = ${JSON.stringify(o)};
|
|
830
846
|
${r}`:a=p?`import json as _json
|
|
831
847
|
INPUT_DATA = _json.loads(${JSON.stringify(o)})
|
|
@@ -834,7 +850,7 @@ ${r}`}let c=await this.executor.execute(a,n,{timeout:i}),d=c.files?.map(p=>({fil
|
|
|
834
850
|
${c.stdout}`:"",c.stderr?`Errors:
|
|
835
851
|
${c.stderr}`:"",`Exit code: ${c.exitCode}`,`Duration: ${c.durationMs}ms`,d&&d.length>0?`Files generated: ${d.map(p=>p.fileName).join(", ")}`:""].filter(Boolean).join(`
|
|
836
852
|
|
|
837
|
-
`);return{success:c.exitCode===0,data:{stdout:c.stdout,stderr:c.stderr,exitCode:c.exitCode,durationMs:c.durationMs,fileCount:c.files?.length??0},display:u,error:c.exitCode!==0?`Code execution failed with exit code ${c.exitCode}`:void 0,attachments:d}}}});var
|
|
853
|
+
`);return{success:c.exitCode===0,data:{stdout:c.stdout,stderr:c.stderr,exitCode:c.exitCode,durationMs:c.durationMs,fileCount:c.files?.length??0},display:u,error:c.exitCode!==0?`Code execution failed with exit code ${c.exitCode}`:void 0,attachments:d}}}});var jd=T(()=>{"use strict";ca();Fd()});var ks,Bd=T(()=>{"use strict";W();Me();ks=class extends x{static{m(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,n=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(!n||typeof n!="string")return{success:!1,error:'Missing required field "mime_type" for ingest action'};let o=await import("node:path"),i=o.resolve(s);if(i!==o.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 c=await this.processor.ingest(de(t),s,r,n),d=c.existing?`Document "${r}" already ingested (${c.chunkCount} chunks). Ready for search. ID: ${c.documentId.slice(0,8)}...`:`Document "${r}" ingested successfully (${c.chunkCount} chunks). ID: ${c.documentId.slice(0,8)}...`;return{success:!0,data:c,display:d}}catch(c){return{success:!1,error:`Failed to ingest document: ${c instanceof Error?c.message:String(c)}`}}}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 n=K(t),o=new Set,i=[];for(let d of n)for(let u of await this.embeddingService.semanticSearch(d,s,r))o.has(u.key)||(o.add(u.key),i.push(u));let a=i.filter(d=>d.category==="document");if(a.length===0)return{success:!0,data:[],display:`No document matches found for "${s}".`};let c=a.map((d,u)=>`${u+1}. (score: ${d.score.toFixed(3)}) ${d.value.slice(0,200)}${d.value.length>200?"...":""}`).join(`
|
|
838
854
|
|
|
839
855
|
`);return{success:!0,data:a,display:`Found ${a.length} relevant chunk(s):
|
|
840
856
|
|
|
@@ -844,15 +860,15 @@ ${c}`}}summarize(e){let t=e.document_id;if(!t||typeof t!="string")return{success
|
|
|
844
860
|
|
|
845
861
|
[... truncated]`:n;return{success:!0,data:{document:s,content:a,totalChunks:r.length,truncated:i},display:`Document: **${s.filename}** (${r.length} chunks, ${s.sizeBytes} bytes)
|
|
846
862
|
|
|
847
|
-
${a}`}}list(e,t){let s=e.limit||50,r=
|
|
863
|
+
${a}`}}list(e,t){let s=e.limit||50,r=K(t),n=new Set,o=[];for(let c of r)for(let d of this.docRepo.listByUser(c))n.has(d.id)||(n.add(d.id),o.push(d));let i=o.slice(0,s);if(i.length===0)return{success:!0,data:[],display:"No documents found."};let a=i.map(c=>`- **${c.filename}** [id=${c.id}] \u2014 ${c.mimeType}, ${c.chunkCount} chunks, ${c.sizeBytes} bytes`).join(`
|
|
848
864
|
`);return{success:!0,data:i,display:`${i.length} document(s):
|
|
849
|
-
${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
|
|
850
|
-
`)}}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"?
|
|
851
|
-
`)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,n=s.memory,o=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${
|
|
852
|
-
`)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let n=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"qemu"})}if(!t||t==="lxc"){let n=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(n=>n.type===t));s.sort((n,o)=>n.vmid-o.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let n of s)r.push(`| ${n.vmid} | ${n.name??"-"} | ${n.type} | ${n.node} | ${n.status??"-"} | ${
|
|
853
|
-
`)}}async vmStatus(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/status/current`),n=[`## VM ${e} (${s.type}) on ${s.node}`,"",`**Name:** ${r.name??"-"}`,`**Status:** ${r.status}`,`**CPU:** ${
|
|
865
|
+
${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 Es,Hd=T(()=>{"use strict";W();Es=class extends x{static{m(this,"TTSSkill")}synthesizer;metadata={name:"text_to_speech",category:"media",description:"Send a voice/audio message to the user. You MUST use this tool whenever the user asks you to respond as a voice message, speak, or reply with audio. Pass the full response text \u2014 it will be converted to speech and delivered as a playable voice message.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{text:{type:"string",description:"The text to convert to speech"}},required:["text"]}};constructor(e){super(),this.synthesizer=e}async execute(e,t){let s=e.text;if(!s)return{success:!1,error:"No text provided for speech synthesis."};try{return{success:!0,display:"Voice message sent.",attachments:[{fileName:"voice.ogg",data:await this.synthesizer.synthesize(s),mimeType:"audio/ogg"}]}}catch(r){return{success:!1,error:`Speech synthesis failed: ${r instanceof Error?r.message:String(r)}`}}}}});var bs,Wd=T(()=>{"use strict";W();bs=class extends x{static{m(this,"ImageGenerateSkill")}generator;metadata={name:"image_generate",category:"media",description:"Generate an image from a text description. Use this tool when the user asks you to create, generate, draw, or design an image or picture. Returns the generated image that will be sent to the user.",riskLevel:"read",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{prompt:{type:"string",description:"Detailed description of the image to generate. Be specific about style, composition, colors, and subject matter."},model:{type:"string",description:"Optional model to use (e.g. gpt-image-1, gpt-image-1-mini, gemini-2.0-flash-exp). Uses provider default if omitted."},size:{type:"string",enum:["1024x1024","1536x1024","1024x1536"],description:"Image dimensions. 1024x1024 (square, default), 1536x1024 (landscape), 1024x1536 (portrait)."},quality:{type:"string",enum:["low","medium","high"],description:"Image quality level. Higher quality takes longer and costs more."}},required:["prompt"]}};constructor(e){super(),this.generator=e}async execute(e,t){let s=e.prompt;if(!s)return{success:!1,error:"No prompt provided for image generation."};try{let r=await this.generator.generate(s,{model:e.model,size:e.size,quality:e.quality});return{success:!0,display:"Image generated.",attachments:[{fileName:"image.png",data:r.data,mimeType:r.mimeType}]}}catch(r){return{success:!1,error:`Image generation failed: ${r instanceof Error?r.message:String(r)}`}}}}});function ge(l){return l==null?"-":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function Wr(l){return l==null?"-":`${(l*100).toFixed(1)}%`}function io(l){if(!l)return"-";let e=Math.floor(l/86400),t=Math.floor(l%86400/3600),s=Math.floor(l%3600/60),r=[];return e&&r.push(`${e}d`),t&&r.push(`${t}h`),r.push(`${s}m`),r.join(" ")}var ao,zd=T(()=>{"use strict";W();m(ge,"bytes");m(Wr,"pct");m(io,"uptimeStr");ao=class l extends x{static{m(this,"ProxmoxSkill")}metadata={name:"proxmox",category:"infrastructure",description:'Manage Proxmox VE virtual machines, containers, and cluster. Use action "list_vms" to see VMs, "start_vm"/"shutdown_vm" to control them, "cluster_status" for health, "create_snapshot" for backups.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["cluster_status","list_nodes","node_stats","list_vms","vm_status","list_snapshots","list_storage","list_tasks","task_status","start_vm","shutdown_vm","reboot_vm","suspend_vm","resume_vm","create_snapshot","backup_vm","migrate_vm","stop_vm","delete_snapshot","rollback_snapshot"],description:"The Proxmox action to perform"},vmid:{type:"number",description:"Virtual machine / container ID"},node:{type:"string",description:"Proxmox node name (optional \u2014 resolved automatically when omitted)"},type:{type:"string",enum:["qemu","lxc"],description:"VM type filter for list_vms (default: both)"},name:{type:"string",description:"Snapshot name (for create/delete/rollback_snapshot)"},description:{type:"string",description:"Snapshot description (optional)"},target:{type:"string",description:"Target node for migration"},storage:{type:"string",description:"Storage target for backup_vm"},upid:{type:"string",description:"Task UPID for task_status"}},required:["action"]}};config;vmCache=null;static VM_CACHE_TTL=3e4;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"cluster_status":return await this.clusterStatus();case"list_nodes":return await this.listNodes();case"node_stats":return await this.nodeStats(e.node);case"list_vms":return await this.listVms(e.node,e.type);case"vm_status":return await this.vmStatus(e.vmid,e.node);case"list_snapshots":return await this.listSnapshots(e.vmid,e.node);case"list_storage":return await this.listStorage(e.node);case"list_tasks":return await this.listTasks(e.node);case"task_status":return await this.taskStatus(e.upid);case"start_vm":return await this.vmPowerAction("start",e);case"shutdown_vm":return await this.vmPowerAction("shutdown",e);case"reboot_vm":return await this.vmPowerAction("reboot",e);case"suspend_vm":return await this.vmPowerAction("suspend",e);case"resume_vm":return await this.vmPowerAction("resume",e);case"stop_vm":return await this.vmPowerAction("stop",e);case"create_snapshot":return await this.createSnapshot(e);case"backup_vm":return await this.backupVm(e);case"migrate_vm":return await this.migrateVm(e);case"delete_snapshot":return await this.deleteSnapshot(e);case"rollback_snapshot":return await this.rollbackSnapshot(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Proxmox API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl}/api2/json${t}`,n={Authorization:`PVEAPIToken=${this.config.tokenId}=${this.config.tokenSecret}`},o={method:e,headers:n};s&&e!=="GET"&&(n["Content-Type"]="application/json",o.body=JSON.stringify(s));let i=this.config.verifyTls===!1;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let a;try{a=await fetch(r,o)}finally{i&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}if(!a.ok){let d="";try{d=(await a.text()).slice(0,500)}catch{}throw new Error(`HTTP ${a.status} ${a.statusText} \u2014 ${d}`)}return(await a.json()).data}async get(e){return this.api("GET",e)}async post(e,t){return this.api("POST",e,t)}async del(e){return this.api("DELETE",e)}async resolveVm(e,t){if(t)try{return await this.get(`/nodes/${t}/qemu/${e}/status/current`),{node:t,type:"qemu"}}catch{try{return await this.get(`/nodes/${t}/lxc/${e}/status/current`),{node:t,type:"lxc"}}catch{throw new Error(`VM ${e} not found on node "${t}"`)}}let r=(await this.getAllVms()).find(n=>n.vmid===e);if(!r)throw new Error(`VM ${e} not found on any node. Use "list_vms" to see available VMs.`);return{node:r.node,type:r.type}}async getAllVms(){let e=Date.now();if(this.vmCache&&e-this.vmCache.ts<l.VM_CACHE_TTL)return this.vmCache.entries;let t=await this.get("/nodes"),s=[];for(let r of t){let[n,o]=await Promise.all([this.get(`/nodes/${r.node}/qemu`).catch(()=>[]),this.get(`/nodes/${r.node}/lxc`).catch(()=>[])]);for(let i of n)s.push({...i,node:r.node,type:"qemu"});for(let i of o)s.push({...i,node:r.node,type:"lxc"})}return this.vmCache={entries:s,ts:e},s}async clusterStatus(){let e=await this.get("/cluster/status"),t=["## Cluster Status",""],s=e.find(n=>n.type==="cluster");s&&(t.push(`**Cluster:** ${s.name}`),t.push(`**Quorum:** ${s.quorate?"Yes":"No"}`),t.push(`**Nodes:** ${s.nodes??"-"}`),t.push(`**Version:** ${s.version??"-"}`),t.push(""));let r=e.filter(n=>n.type==="node");if(r.length){t.push("| Node | Online | Level | ID |"),t.push("|------|--------|-------|----|");for(let n of r)t.push(`| ${n.name} | ${n.online?"Yes":"**No**"} | ${n.level??"-"} | ${n.nodeid??"-"} |`)}return{success:!0,data:e,display:t.join(`
|
|
866
|
+
`)}}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"?Wr(s.cpu):"-",n=ge(s.mem),o=ge(s.maxmem);t.push(`| ${s.node} | ${s.status} | ${r} | ${n} / ${o} | ${io(s.uptime)} |`)}return{success:!0,data:e,display:t.join(`
|
|
867
|
+
`)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,n=s.memory,o=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${io(s.uptime)}`,`**Kernel:** ${s.kversion??"-"}`,`**PVE Version:** ${s.pveversion??"-"}`,""];return r&&(a.push(`**CPU:** ${r.model??"-"} (${r.cpus??"-"} cores)`),a.push(`**CPU Usage:** ${Wr(r.cpu)}`),a.push(`**Load:** ${Array.isArray(s.loadavg)?s.loadavg.join(", "):"-"}`)),n&&a.push(`**RAM:** ${ge(n.used)} / ${ge(n.total)} (${Wr(n.used/n.total)})`),i&&a.push(`**Swap:** ${ge(i.used)} / ${ge(i.total)}`),o&&a.push(`**Root FS:** ${ge(o.used)} / ${ge(o.total)}`),{success:!0,data:s,display:a.join(`
|
|
868
|
+
`)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let n=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"qemu"})}if(!t||t==="lxc"){let n=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(n=>n.type===t));s.sort((n,o)=>n.vmid-o.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let n of s)r.push(`| ${n.vmid} | ${n.name??"-"} | ${n.type} | ${n.node} | ${n.status??"-"} | ${Wr(n.cpu)} | ${ge(n.mem)} / ${ge(n.maxmem)} | ${io(n.uptime)} |`);return s.length===0&&r.push("| - | No VMs found | - | - | - | - | - | - |"),{success:!0,data:s,display:r.join(`
|
|
869
|
+
`)}}async vmStatus(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/status/current`),n=[`## VM ${e} (${s.type}) on ${s.node}`,"",`**Name:** ${r.name??"-"}`,`**Status:** ${r.status}`,`**CPU:** ${Wr(r.cpu)} (${r.cpus??"-"} cores)`,`**RAM:** ${ge(r.mem)} / ${ge(r.maxmem)}`,`**Disk:** ${ge(r.disk)} / ${ge(r.maxdisk)}`,`**Uptime:** ${io(r.uptime)}`,`**PID:** ${r.pid??"-"}`,`**Net In / Out:** ${ge(r.netin)} / ${ge(r.netout)}`];return r.lock&&n.push(`**Lock:** ${r.lock}`),{success:!0,data:r,display:n.join(`
|
|
854
870
|
`)}}async listSnapshots(e,t){if(e==null)return{success:!1,error:'Missing required "vmid" parameter'};let s=await this.resolveVm(e,t),r=await this.get(`/nodes/${s.node}/${s.type}/${e}/snapshot`),n=[`## Snapshots for VM ${e}`,"","| Name | Description | Date | Parent |","|------|-------------|------|--------|"];for(let o of r){let i=o.snaptime?new Date(o.snaptime*1e3).toISOString():"-";n.push(`| ${o.name} | ${o.description??"-"} | ${i} | ${o.parent??"-"} |`)}return{success:!0,data:r,display:n.join(`
|
|
855
|
-
`)}}async listStorage(e){let t=e??this.config.defaultNode,s=t?`/nodes/${t}/storage`:"/storage",r=await this.get(s),n=[`## Storage${t?` (Node: ${t})`:""}`,"","| Storage | Type | Content | Used / Total | Status |","|---------|------|---------|--------------|--------|"];for(let o of r){let i=
|
|
871
|
+
`)}}async listStorage(e){let t=e??this.config.defaultNode,s=t?`/nodes/${t}/storage`:"/storage",r=await this.get(s),n=[`## Storage${t?` (Node: ${t})`:""}`,"","| Storage | Type | Content | Used / Total | Status |","|---------|------|---------|--------------|--------|"];for(let o of r){let i=ge(o.used),a=ge(o.total);n.push(`| ${o.storage} | ${o.type} | ${o.content??"-"} | ${i} / ${a} | ${o.active?"active":o.enabled?"enabled":"disabled"} |`)}return{success:!0,data:r,display:n.join(`
|
|
856
872
|
`)}}async listTasks(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/tasks?limit=20`),r=[`## Recent Tasks (Node: ${t})`,"","| UPID | Type | Status | Start | User |","|------|------|--------|-------|------|"];for(let n of s){let o=n.starttime?new Date(n.starttime*1e3).toISOString():"-";r.push(`| \`${n.upid?.slice(-16)??"-"}\` | ${n.type??"-"} | ${n.status??"running"} | ${o} | ${n.user??"-"} |`)}return{success:!0,data:s,display:r.join(`
|
|
857
873
|
`)}}async taskStatus(e){if(!e)return{success:!1,error:'Missing required "upid" parameter'};let t=e.split(":")[1];if(!t)return{success:!1,error:"Invalid UPID format \u2014 cannot extract node"};let s=await this.get(`/nodes/${t}/tasks/${encodeURIComponent(e)}/status`),r=["## Task Status","",`**UPID:** \`${e}\``,`**Status:** ${s.status}`,`**Type:** ${s.type??"-"}`,`**Exit Status:** ${s.exitstatus??"running"}`,`**Node:** ${t}`];return{success:!0,data:s,display:r.join(`
|
|
858
874
|
`)}}async vmPowerAction(e,t){let s=t.vmid;if(s==null)return{success:!1,error:'Missing required "vmid" parameter'};let r=await this.resolveVm(s,t.node),n=await this.post(`/nodes/${r.node}/${r.type}/${s}/status/${e}`);return{success:!0,data:{vmid:s,node:r.node,type:r.type,action:e,upid:n},display:[`**${e.charAt(0).toUpperCase()+e.slice(1)}** sent to VM ${s} (${r.type}) on **${r.node}**.`,"",`UPID: \`${n}\``,"","Use `task_status` with this UPID to check progress."].join(`
|
|
@@ -861,7 +877,7 @@ ${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success
|
|
|
861
877
|
`)}}async migrateVm(e){let t=e.vmid,s=e.target;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "target" parameter (target node)'};let r=await this.resolveVm(t,e.node),n=await this.post(`/nodes/${r.node}/${r.type}/${t}/migrate`,{target:s,online:1});return{success:!0,data:{vmid:t,from:r.node,target:s,type:r.type,upid:n},display:[`Live migration of VM ${t} from **${r.node}** to **${s}** started.`,"",`UPID: \`${n}\``].join(`
|
|
862
878
|
`)}}async deleteSnapshot(e){let t=e.vmid,s=e.name;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "name" parameter (snapshot name)'};let r=await this.resolveVm(t,e.node),n=await this.del(`/nodes/${r.node}/${r.type}/${t}/snapshot/${encodeURIComponent(s)}`);return{success:!0,data:{vmid:t,node:r.node,type:r.type,snapname:s,upid:n},display:[`Snapshot **"${s}"** deletion started for VM ${t} on **${r.node}**.`,"",`UPID: \`${n}\``].join(`
|
|
863
879
|
`)}}async rollbackSnapshot(e){let t=e.vmid,s=e.name;if(t==null)return{success:!1,error:'Missing required "vmid" parameter'};if(!s)return{success:!1,error:'Missing required "name" parameter (snapshot name)'};let r=await this.resolveVm(t,e.node),n=await this.post(`/nodes/${r.node}/${r.type}/${t}/snapshot/${encodeURIComponent(s)}/rollback`);return{success:!0,data:{vmid:t,node:r.node,type:r.type,snapname:s,upid:n},display:[`Rollback to snapshot **"${s}"** started for VM ${t} on **${r.node}**.`,"",`UPID: \`${n}\``,"","**Warning:** The VM will be stopped during rollback."].join(`
|
|
864
|
-
`)}}}});var
|
|
880
|
+
`)}}}});var co,qd=T(()=>{"use strict";W();co=class extends x{static{m(this,"UniFiSkill")}metadata={name:"unifi",category:"infrastructure",description:'Manage UniFi network devices, clients, and WLANs. Use "list_devices" to see APs/switches, "list_clients" for connected clients, "restart_device" to reboot a device, "block_client"/"unblock_client" for access control.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_devices","device_info","list_clients","client_info","list_networks","list_wlans","site_stats","dpi_stats","list_alerts","list_events","list_vouchers","restart_device","locate_device","reconnect_client","create_voucher","enable_wlan","disable_wlan","archive_alerts","block_client","unblock_client","forget_client","adopt_device"],description:"The UniFi action to perform"},mac:{type:"string",description:"MAC address of device or client (for device_info, client_info, restart_device, locate_device, reconnect_client, block_client, unblock_client, forget_client, adopt_device)"},active:{type:"boolean",description:"If true list only active clients, if false list all known clients (for list_clients, default: true)"},enabled:{type:"boolean",description:"Enable or disable device locate LED (for locate_device, default: true)"},id:{type:"string",description:"WLAN config ID (for enable_wlan, disable_wlan)"},limit:{type:"number",description:"Maximum number of items to return (for list_alerts, list_events)"},count:{type:"number",description:"Number of vouchers to create (for create_voucher, default: 1)"},duration:{type:"number",description:"Voucher validity in minutes (for create_voucher)"},bandwidth_down:{type:"number",description:"Download bandwidth limit in Kbps (for create_voucher, optional)"},bandwidth_up:{type:"number",description:"Upload bandwidth limit in Kbps (for create_voucher, optional)"},quota:{type:"number",description:"Number of uses per voucher (for create_voucher, 0 = unlimited, default: 1)"}},required:["action"]}};config;site;controllerMode;cookies=[];csrfToken;constructor(e){if(super(),!e.apiKey&&!(e.username&&e.password))throw new Error('UniFi config requires either "apiKey" or both "username" and "password".');this.config=e,this.site=e.site??"default",e.apiKey&&(this.controllerMode="unifi-os")}async execute(e,t){let s=e.action;try{switch(s){case"list_devices":return await this.listDevices();case"device_info":return await this.deviceInfo(e.mac);case"list_clients":return await this.listClients(e.active);case"client_info":return await this.clientInfo(e.mac);case"list_networks":return await this.listNetworks();case"list_wlans":return await this.listWlans();case"site_stats":return await this.siteStats();case"dpi_stats":return await this.dpiStats(e.mac);case"list_alerts":return await this.listAlerts(e.limit);case"list_events":return await this.listEvents(e.limit);case"list_vouchers":return await this.listVouchers();case"restart_device":return await this.restartDevice(e.mac);case"locate_device":return await this.locateDevice(e.mac,e.enabled);case"reconnect_client":return await this.reconnectClient(e.mac);case"create_voucher":return await this.createVoucher(e.count,e.duration,e.bandwidth_down,e.bandwidth_up,e.quota);case"enable_wlan":return await this.enableWlan(e.id);case"disable_wlan":return await this.disableWlan(e.id);case"archive_alerts":return await this.archiveAlerts();case"block_client":return await this.blockClient(e.mac);case"unblock_client":return await this.unblockClient(e.mac);case"forget_client":return await this.forgetClient(e.mac);case"adopt_device":return await this.adoptDevice(e.mac);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:`UniFi error: ${r instanceof Error?r.message:String(r)}`}}}apiUrl(e){let t=this.config.baseUrl.replace(/\/+$/,"");return this.controllerMode==="unifi-os"?`${t}/proxy/network/api/s/${this.site}/${e}`:`${t}/api/s/${this.site}/${e}`}async ensureAuth(){this.config.apiKey||this.cookies.length>0||await this.login()}async login(){let e=this.config.baseUrl.replace(/\/+$/,""),t=JSON.stringify({username:this.config.username,password:this.config.password}),s=await this.rawFetch(`${e}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(s.status===200){this.controllerMode="unifi-os",this.storeCookies(s);return}if(s.status===404){let r=await this.rawFetch(`${e}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:t});if(r.ok){this.controllerMode="classic",this.storeCookies(r);return}throw new Error(`UniFi Classic login failed (HTTP ${r.status}): ${await r.text()}`)}throw new Error(`UniFi OS login failed (HTTP ${s.status}): ${await s.text()}`)}storeCookies(e){let t=e.headers.getSetCookie?.()??[];t.length>0&&(this.cookies=t.map(r=>r.split(";")[0]));let s=e.headers.get("x-csrf-token");s&&(this.csrfToken=s)}clearSession(){this.cookies=[],this.csrfToken=void 0}async rawFetch(e,t){let s=this.config.verifyTls===!1;s&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{s&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}}async request(e,t,s){await this.ensureAuth();let r=await this.doFetch(e,t,s);if(r.status===401&&!this.config.apiKey){this.clearSession(),await this.login();let n=await this.doFetch(e,t,s);if(!n.ok)throw new Error(`UniFi API error after relogin: HTTP ${n.status} ${await n.text()}`);return this.parseResponse(n)}if(!r.ok)throw new Error(`UniFi API error: HTTP ${r.status} ${await r.text()}`);return this.parseResponse(r)}async doFetch(e,t,s){let r=this.apiUrl(t),n={"Content-Type":"application/json"};return this.config.apiKey?n["X-API-Key"]=this.config.apiKey:(this.cookies.length>0&&(n.Cookie=this.cookies.join("; ")),this.csrfToken&&(n["X-CSRF-Token"]=this.csrfToken)),this.rawFetch(r,{method:e,headers:n,body:s!==void 0?JSON.stringify(s):void 0,signal:AbortSignal.timeout(3e4)})}async parseResponse(e){let t=await e.json(),s=e.headers.get("x-csrf-token");if(s&&(this.csrfToken=s),t.meta?.rc==="error")throw new Error(`UniFi: ${t.meta.msg??"unknown error"}`);return t.data}async listDevices(){let e=await this.request("GET","stat/device"),t=(e??[]).map(r=>({name:r.name??r.hostname??r.mac,model:r.model??"unknown",ip:r.ip??"-",mac:r.mac,status:r.state===1?"online":"offline",clients:r.num_sta??0,load:r["system-stats"]?.cpu!=null?`${r["system-stats"].cpu}%`:"-"})),s=t.length===0?"No devices found.":["| Name | Model | IP | MAC | Status | Clients | CPU |","|------|-------|----|-----|--------|---------|-----|",...t.map(r=>`| ${r.name} | ${r.model} | ${r.ip} | ${r.mac} | ${r.status} | ${r.clients} | ${r.load} |`)].join(`
|
|
865
881
|
`);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(`
|
|
866
882
|
`)}}async listClients(e){let t=e!==!1,s=t?"stat/sta":"rest/user",r=await this.request("GET",s),n=(r??[]).map(i=>({name:i.name??i.hostname??i.mac,ip:i.ip??i.fixed_ip??"-",mac:i.mac,network:i.essid??i.network??"-",signal:i.signal!=null?`${i.signal} dBm`:"-",tx:this.formatBytes(i.tx_bytes??0),rx:this.formatBytes(i.rx_bytes??0)})),o=n.length===0?"No clients found.":["| Name | IP | MAC | Network | Signal | TX | RX |","|------|----|-----|---------|--------|----|----|",...n.map(i=>`| ${i.name} | ${i.ip} | ${i.mac} | ${i.network} | ${i.signal} | ${i.tx} | ${i.rx} |`)].join(`
|
|
867
883
|
`);return{success:!0,data:r,display:`${t?"Active":"All known"} clients (${n.length}):
|
|
@@ -877,15 +893,15 @@ ${o}`}}async clientInfo(e){if(!e)return{success:!1,error:"mac is required for cl
|
|
|
877
893
|
`);return{success:!0,data:s,display:n}}async listEvents(e){let t=Math.min(Math.max(1,e??20),200),s=await this.request("GET",`stat/event?_limit=${t}`),r=(s??[]).slice(0,t).map(o=>({time:o.datetime??o.time??"-",type:o.key??"-",message:o.msg??"-"})),n=r.length===0?"No events.":["| Time | Type | Message |","|------|------|---------|",...r.map(o=>`| ${o.time} | ${o.type} | ${o.message} |`)].join(`
|
|
878
894
|
`);return{success:!0,data:s,display:n}}async listVouchers(){let e=await this.request("GET","stat/voucher"),t=(e??[]).map(r=>({code:r.code??"-",duration:r.duration!=null?`${r.duration} min`:"-",quota:r.quota??0,used:r.used??0,created:r.create_time?new Date(r.create_time*1e3).toISOString():"-",note:r.note??"-"})),s=t.length===0?"No vouchers.":["| Code | Duration | Quota | Used | Created | Note |","|------|----------|-------|------|---------|------|",...t.map(r=>`| ${r.code} | ${r.duration} | ${r.quota} | ${r.used} | ${r.created} | ${r.note} |`)].join(`
|
|
879
895
|
`);return{success:!0,data:e,display:s}}async restartDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"restart",mac:e}),{success:!0,data:{mac:e},display:`Restart command sent to device ${e}.`}):{success:!1,error:"mac is required for restart_device."}}async locateDevice(e,t){if(!e)return{success:!1,error:"mac is required for locate_device."};let s=t!==!1,r=s?"set-locate":"unset-locate";return await this.request("POST","cmd/devmgr",{cmd:r,mac:e}),{success:!0,data:{mac:e,enabled:s},display:`Device ${e} locate LED ${s?"enabled":"disabled"}.`}}async reconnectClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"kick-sta",mac:e}),{success:!0,data:{mac:e},display:`Reconnect (kick) command sent to client ${e}.`}):{success:!1,error:"mac is required for reconnect_client."}}async createVoucher(e,t,s,r,n){if(!t)return{success:!1,error:"duration (minutes) is required for create_voucher."};let o={cmd:"create-voucher",n:e??1,expire:t,quota:n??1};s!=null&&(o.down=s),r!=null&&(o.up=r);let i=await this.request("POST","cmd/hotspot",o),a=i?.[0]?.create_time;return{success:!0,data:i,display:`Created ${e??1} voucher(s), duration ${t} min.${a?` Batch: ${a}`:""}
|
|
880
|
-
Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!0}),{success:!0,data:{id:e,enabled:!0},display:`WLAN ${e} enabled.`}):{success:!1,error:"id is required for enable_wlan."}}async disableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!1}),{success:!0,data:{id:e,enabled:!1},display:`WLAN ${e} disabled.`}):{success:!1,error:"id is required for disable_wlan."}}async archiveAlerts(){return await this.request("POST","cmd/evtmgr",{cmd:"archive-all-alarms"}),{success:!0,data:{},display:"All alerts archived."}}async blockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"block-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} blocked.`}):{success:!1,error:"mac is required for block_client."}}async unblockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"unblock-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} unblocked.`}):{success:!1,error:"mac is required for unblock_client."}}async forgetClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"forget-sta",macs:[e]}),{success:!0,data:{mac:e},display:`Client ${e} forgotten (removed from known clients).`}):{success:!1,error:"mac is required for forget_client."}}async adoptDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"adopt",mac:e}),{success:!0,data:{mac:e},display:`Adopt command sent to device ${e}.`}):{success:!1,error:"mac is required for adopt_device."}}formatBytes(e){if(e===0)return"0 B";let t=["B","KB","MB","GB","TB"],s=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/Math.pow(1024,s)).toFixed(s===0?0:1)} ${t[s]}`}formatUptime(e){let t=Math.floor(e/86400),s=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=[];return t>0&&n.push(`${t}d`),s>0&&n.push(`${s}h`),n.push(`${r}m`),n.join(" ")}}});function ea(l){let e=l.match(/^(\d+)\s*(h|d|m|w)$/i);if(!e)return new Date(Date.now()-36e5).toISOString();let t=parseInt(e[1],10),s=e[2].toLowerCase(),r={m:6e4,h:36e5,d:864e5,w:6048e5}[s]??36e5;return new Date(Date.now()-t*r).toISOString()}function Th(l){let e=l.indexOf(".");if(e<1)throw new Error(`Invalid entity_id "${l}" \u2014 expected format "domain.name"`);return l.slice(0,e)}var so,Cd=T(()=>{"use strict";W();m(ea,"parsePeriod");m(Th,"extractDomain");so=class extends x{static{m(this,"HomeAssistantSkill")}metadata={name:"homeassistant",category:"infrastructure",description:'Control Home Assistant smart home devices. Use "states" to list entities, "turn_on"/"turn_off"/"toggle" to control devices, "call_service" for advanced service calls, "history" for entity state history. Also: "areas" for rooms/zones, "presence" for who is home, "activate_scene"/"trigger_automation"/"run_script" for automations, "notify" for notifications, "calendar_events" for calendars, "template" for Jinja2 queries, "error_log" for HA logs. Config API: "create_automation"/"delete_automation", "create_script"/"delete_script", "create_scene"/"delete_scene" \u2014 create persistent automations, scripts, and scenes in HA. Use configData (JSON) with the HA automation/script/scene schema. "briefing_summary" for a compact smart home overview (open contacts, lights on, battery/SoC, energy, climate, presence). Optionally pass entities[] or domains[] to filter. "energy_stats" for energy consumption statistics over a period (today, yesterday, last_week, etc.) \u2014 auto-discovers all energy sensors and calculates kWh consumed.',riskLevel:"write",version:"2.1.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["states","state","turn_on","turn_off","toggle","call_service","services","history","logbook","config","areas","template","presence","notify","activate_scene","trigger_automation","run_script","calendar_events","error_log","create_automation","delete_automation","create_script","delete_script","create_scene","delete_scene","briefing_summary","energy_stats"],description:"The Home Assistant action to perform"},entityId:{type:"string",description:"Entity ID, e.g. light.wohnzimmer, switch.garage, sensor.temperature"},domain:{type:"string",description:'Domain filter for "states" (e.g. light, sensor, switch) or domain for "call_service"'},service:{type:"string",description:'Service name for "call_service", e.g. set_temperature, set_hvac_mode'},serviceData:{type:"string",description:'JSON string with service parameters, e.g. {"brightness": 200, "color_name": "red"}'},period:{type:"string",description:'Time period for history/logbook/energy_stats. Formats: "1h", "24h", "7d" or friendly names "today", "yesterday", "this_week", "last_week", "this_month", "last_month" (default for energy_stats: "today")'},area:{type:"string",description:"Area name or ID (for areas action)"},template:{type:"string",description:"Jinja2 template string (for template action)"},target:{type:"string",description:"Notification target (for notify action, e.g. mobile_app_pixel)"},message:{type:"string",description:"Notification message (for notify action)"},title:{type:"string",description:"Optional title (for notify action)"},startTime:{type:"string",description:"ISO datetime start (for calendar_events, default: now)"},endTime:{type:"string",description:"ISO datetime end (for calendar_events, default: +24h)"},subAction:{type:"string",enum:["trigger","enable","disable"],description:"Sub-action for trigger_automation"},variables:{type:"string",description:"JSON string with script variables (for run_script)"},configId:{type:"string",description:'Unique ID for create/delete automation, script, or scene (e.g. "notify_garage_light"). Used as the HA config entry ID.'},configData:{type:"string",description:"JSON string with the HA config object for create actions. For automations: {alias, description, trigger[], condition[], action[], mode}. For scripts: {alias, sequence[], mode}. For scenes: {name, entities: {entity_id: state}}."},entities:{type:"array",items:{type:"string"},description:'Specific entity IDs for briefing_summary (e.g. ["sensor.victron_soc", "sensor.power_consumption"])'},domains:{type:"array",items:{type:"string"},description:'Domain filters for briefing_summary (e.g. ["binary_sensor", "light", "climate"])'}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"states":return await this.getStates(e.domain);case"state":return await this.getState(e.entityId);case"turn_on":return await this.switchAction("turn_on",e.entityId,e.serviceData);case"turn_off":return await this.switchAction("turn_off",e.entityId,e.serviceData);case"toggle":return await this.switchAction("toggle",e.entityId,e.serviceData);case"call_service":return await this.callService(e.domain,e.service,e.entityId,e.serviceData);case"services":return await this.getServices();case"history":return await this.getHistory(e.entityId,e.period);case"logbook":return await this.getLogbook(e.entityId,e.period);case"config":return await this.getConfig();case"areas":return await this.getAreas(e.area);case"template":return await this.renderTemplate(e.template);case"presence":return await this.getPresence();case"notify":return await this.sendNotification(e.message,e.title,e.target);case"activate_scene":return await this.activateScene(e.entityId);case"trigger_automation":return await this.triggerAutomation(e.entityId,e.subAction);case"run_script":return await this.runScript(e.entityId,e.variables);case"calendar_events":return await this.getCalendarEvents(e.entityId,e.startTime,e.endTime);case"error_log":return await this.getErrorLog();case"create_automation":return await this.createConfig("automation",e.configId,e.configData);case"delete_automation":return await this.deleteConfig("automation",e.configId);case"create_script":return await this.createConfig("script",e.configId,e.configData);case"delete_script":return await this.deleteConfig("script",e.configId);case"create_scene":return await this.createConfig("scene",e.configId,e.configData);case"delete_scene":return await this.deleteConfig("scene",e.configId);case"briefing_summary":return await this.getBriefingSummary(e.entities,e.domains);case"energy_stats":return await this.getEnergyStats(e.period,e.entityId);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Home Assistant API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.json()}async apiText(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.text()}async getStates(e){let t=await this.api("GET","/api/states");e&&(t=t.filter(r=>r.entity_id.startsWith(`${e}.`)));let s=[`## Entities${e?` (${e})`:""}`,"","| Entity ID | State | Name | Unit |","|-----------|-------|------|------|"];for(let r of t){let n=r.attributes?.friendly_name??"-",o=r.attributes?.unit_of_measurement??"-";s.push(`| ${r.entity_id} | ${r.state} | ${n} | ${o} |`)}return t.length===0&&s.push(`| - | No entities found${e?` for domain "${e}"`:""} | - | - |`),{success:!0,data:t,display:s.join(`
|
|
896
|
+
Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!0}),{success:!0,data:{id:e,enabled:!0},display:`WLAN ${e} enabled.`}):{success:!1,error:"id is required for enable_wlan."}}async disableWlan(e){return e?(await this.request("PUT",`rest/wlanconf/${e}`,{enabled:!1}),{success:!0,data:{id:e,enabled:!1},display:`WLAN ${e} disabled.`}):{success:!1,error:"id is required for disable_wlan."}}async archiveAlerts(){return await this.request("POST","cmd/evtmgr",{cmd:"archive-all-alarms"}),{success:!0,data:{},display:"All alerts archived."}}async blockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"block-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} blocked.`}):{success:!1,error:"mac is required for block_client."}}async unblockClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"unblock-sta",mac:e}),{success:!0,data:{mac:e},display:`Client ${e} unblocked.`}):{success:!1,error:"mac is required for unblock_client."}}async forgetClient(e){return e?(await this.request("POST","cmd/stamgr",{cmd:"forget-sta",macs:[e]}),{success:!0,data:{mac:e},display:`Client ${e} forgotten (removed from known clients).`}):{success:!1,error:"mac is required for forget_client."}}async adoptDevice(e){return e?(await this.request("POST","cmd/devmgr",{cmd:"adopt",mac:e}),{success:!0,data:{mac:e},display:`Adopt command sent to device ${e}.`}):{success:!1,error:"mac is required for adopt_device."}}formatBytes(e){if(e===0)return"0 B";let t=["B","KB","MB","GB","TB"],s=Math.min(Math.floor(Math.log(e)/Math.log(1024)),t.length-1);return`${(e/Math.pow(1024,s)).toFixed(s===0?0:1)} ${t[s]}`}formatUptime(e){let t=Math.floor(e/86400),s=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=[];return t>0&&n.push(`${t}d`),s>0&&n.push(`${s}h`),n.push(`${r}m`),n.join(" ")}}});function la(l){let e=l.match(/^(\d+)\s*(h|d|m|w)$/i);if(!e)return new Date(Date.now()-36e5).toISOString();let t=parseInt(e[1],10),s=e[2].toLowerCase(),r={m:6e4,h:36e5,d:864e5,w:6048e5}[s]??36e5;return new Date(Date.now()-t*r).toISOString()}function Ph(l){let e=l.indexOf(".");if(e<1)throw new Error(`Invalid entity_id "${l}" \u2014 expected format "domain.name"`);return l.slice(0,e)}var lo,Gd=T(()=>{"use strict";W();m(la,"parsePeriod");m(Ph,"extractDomain");lo=class extends x{static{m(this,"HomeAssistantSkill")}metadata={name:"homeassistant",category:"infrastructure",description:'Control Home Assistant smart home devices. Use "states" to list entities, "turn_on"/"turn_off"/"toggle" to control devices, "call_service" for advanced service calls, "history" for entity state history. Also: "areas" for rooms/zones, "presence" for who is home, "activate_scene"/"trigger_automation"/"run_script" for automations, "notify" for notifications, "calendar_events" for calendars, "template" for Jinja2 queries, "error_log" for HA logs. Config API: "create_automation"/"delete_automation", "create_script"/"delete_script", "create_scene"/"delete_scene" \u2014 create persistent automations, scripts, and scenes in HA. Use configData (JSON) with the HA automation/script/scene schema. "briefing_summary" for a compact smart home overview (open contacts, lights on, battery/SoC, energy, climate, presence). Optionally pass entities[] or domains[] to filter. "energy_stats" for energy consumption statistics over a period (today, yesterday, last_week, etc.) \u2014 auto-discovers all energy sensors and calculates kWh consumed.',riskLevel:"write",version:"2.1.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["states","state","turn_on","turn_off","toggle","call_service","services","history","logbook","config","areas","template","presence","notify","activate_scene","trigger_automation","run_script","calendar_events","error_log","create_automation","delete_automation","create_script","delete_script","create_scene","delete_scene","briefing_summary","energy_stats"],description:"The Home Assistant action to perform"},entityId:{type:"string",description:"Entity ID, e.g. light.wohnzimmer, switch.garage, sensor.temperature"},domain:{type:"string",description:'Domain filter for "states" (e.g. light, sensor, switch) or domain for "call_service"'},service:{type:"string",description:'Service name for "call_service", e.g. set_temperature, set_hvac_mode'},serviceData:{type:"string",description:'JSON string with service parameters, e.g. {"brightness": 200, "color_name": "red"}'},period:{type:"string",description:'Time period for history/logbook/energy_stats. Formats: "1h", "24h", "7d" or friendly names "today", "yesterday", "this_week", "last_week", "this_month", "last_month" (default for energy_stats: "today")'},area:{type:"string",description:"Area name or ID (for areas action)"},template:{type:"string",description:"Jinja2 template string (for template action)"},target:{type:"string",description:"Notification target (for notify action, e.g. mobile_app_pixel)"},message:{type:"string",description:"Notification message (for notify action)"},title:{type:"string",description:"Optional title (for notify action)"},startTime:{type:"string",description:"ISO datetime start (for calendar_events, default: now)"},endTime:{type:"string",description:"ISO datetime end (for calendar_events, default: +24h)"},subAction:{type:"string",enum:["trigger","enable","disable"],description:"Sub-action for trigger_automation"},variables:{type:"string",description:"JSON string with script variables (for run_script)"},configId:{type:"string",description:'Unique ID for create/delete automation, script, or scene (e.g. "notify_garage_light"). Used as the HA config entry ID.'},configData:{type:"string",description:"JSON string with the HA config object for create actions. For automations: {alias, description, trigger[], condition[], action[], mode}. For scripts: {alias, sequence[], mode}. For scenes: {name, entities: {entity_id: state}}."},entities:{type:"array",items:{type:"string"},description:'Specific entity IDs for briefing_summary (e.g. ["sensor.victron_soc", "sensor.power_consumption"])'},domains:{type:"array",items:{type:"string"},description:'Domain filters for briefing_summary (e.g. ["binary_sensor", "light", "climate"])'}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"states":return await this.getStates(e.domain);case"state":return await this.getState(e.entityId);case"turn_on":return await this.switchAction("turn_on",e.entityId,e.serviceData);case"turn_off":return await this.switchAction("turn_off",e.entityId,e.serviceData);case"toggle":return await this.switchAction("toggle",e.entityId,e.serviceData);case"call_service":return await this.callService(e.domain,e.service,e.entityId,e.serviceData);case"services":return await this.getServices();case"history":return await this.getHistory(e.entityId,e.period);case"logbook":return await this.getLogbook(e.entityId,e.period);case"config":return await this.getConfig();case"areas":return await this.getAreas(e.area);case"template":return await this.renderTemplate(e.template);case"presence":return await this.getPresence();case"notify":return await this.sendNotification(e.message,e.title,e.target);case"activate_scene":return await this.activateScene(e.entityId);case"trigger_automation":return await this.triggerAutomation(e.entityId,e.subAction);case"run_script":return await this.runScript(e.entityId,e.variables);case"calendar_events":return await this.getCalendarEvents(e.entityId,e.startTime,e.endTime);case"error_log":return await this.getErrorLog();case"create_automation":return await this.createConfig("automation",e.configId,e.configData);case"delete_automation":return await this.deleteConfig("automation",e.configId);case"create_script":return await this.createConfig("script",e.configId,e.configData);case"delete_script":return await this.deleteConfig("script",e.configId);case"create_scene":return await this.createConfig("scene",e.configId,e.configData);case"delete_scene":return await this.deleteConfig("scene",e.configId);case"briefing_summary":return await this.getBriefingSummary(e.entities,e.domains);case"energy_stats":return await this.getEnergyStats(e.period,e.entityId);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Home Assistant API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.json()}async apiText(e,t,s){let r=`${this.config.baseUrl.replace(/\/+$/,"")}${t}`,n={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},o={method:e,headers:n,signal:AbortSignal.timeout(15e3)};s&&e!=="GET"&&(o.body=JSON.stringify(s));let i=this.config.verifyTls===!1,a=process.env.NODE_TLS_REJECT_UNAUTHORIZED;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let c;try{c=await fetch(r,o)}finally{i&&(a===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=a)}if(!c.ok){let d="";try{d=(await c.text()).slice(0,500)}catch{}throw new Error(`HTTP ${c.status} ${c.statusText} \u2014 ${d}`)}return await c.text()}async getStates(e){let t=await this.api("GET","/api/states");e&&(t=t.filter(r=>r.entity_id.startsWith(`${e}.`)));let s=[`## Entities${e?` (${e})`:""}`,"","| Entity ID | State | Name | Unit |","|-----------|-------|------|------|"];for(let r of t){let n=r.attributes?.friendly_name??"-",o=r.attributes?.unit_of_measurement??"-";s.push(`| ${r.entity_id} | ${r.state} | ${n} | ${o} |`)}return t.length===0&&s.push(`| - | No entities found${e?` for domain "${e}"`:""} | - | - |`),{success:!0,data:t,display:s.join(`
|
|
881
897
|
`)}}async getState(e){if(!e)return{success:!1,error:'Missing required "entityId" parameter'};let t=await this.api("GET",`/api/states/${e}`),s=t.attributes??{},r=[`## ${s.friendly_name??e}`,"",`**Entity ID:** ${t.entity_id}`,`**State:** ${t.state}`,`**Last Changed:** ${t.last_changed??"-"}`,`**Last Updated:** ${t.last_updated??"-"}`,"","### Attributes"];for(let[n,o]of Object.entries(s)){let i=typeof o=="object"?JSON.stringify(o):String(o);r.push(`- **${n}:** ${i}`)}return{success:!0,data:t,display:r.join(`
|
|
882
898
|
`)}}async getServices(){let e=await this.api("GET","/api/services"),t=["## Available Services",""];for(let s of e){let r=s.domain??"unknown",n=Object.keys(s.services??{});if(n.length!==0){t.push(`### ${r}`);for(let o of n){let i=s.services[o]?.description??"";t.push(`- **${o}**${i?`: ${i}`:""}`)}t.push("")}}return{success:!0,data:e,display:t.join(`
|
|
883
|
-
`)}}async getHistory(e,t){let s=
|
|
899
|
+
`)}}async getHistory(e,t){let s=la(t??"1h"),r=new Date().toISOString(),n=e?`?filter_entity_id=${e}&end_time=${r}`:`?end_time=${r}`,o=await this.api("GET",`/api/history/period/${s}${n}`),i=["## History",""];if(!o||o.length===0||o.every(a=>a.length===0))return i.push("No history entries found for the given period."),{success:!0,data:[],display:i.join(`
|
|
884
900
|
`)};for(let a of o){if(a.length===0)continue;let c=a[0]?.entity_id??"unknown",d=a[0]?.attributes?.friendly_name??c;i.push(`### ${d} (\`${c}\`)`),i.push(""),i.push("| Time | State |"),i.push("|------|-------|");for(let u of a){let p=u.last_changed?new Date(u.last_changed).toLocaleString():"-";i.push(`| ${p} | ${u.state} |`)}i.push("")}return{success:!0,data:o,display:i.join(`
|
|
885
|
-
`)}}async getLogbook(e,t){let s=
|
|
901
|
+
`)}}async getLogbook(e,t){let s=la(t??"1h"),r=new Date().toISOString(),n=e?`?entity=${e}&end_time=${r}`:`?end_time=${r}`,o=await this.api("GET",`/api/logbook/${s}${n}`),i=["## Logbook",""];if(!o||o.length===0)return i.push("No logbook entries found for the given period."),{success:!0,data:[],display:i.join(`
|
|
886
902
|
`)};i.push("| Time | Entity | Message |"),i.push("|------|--------|---------|");for(let a of o){let c=a.when?new Date(a.when).toLocaleString():"-",d=a.name??a.entity_id??"-",u=a.message??a.state??"-";i.push(`| ${c} | ${d} | ${u} |`)}return{success:!0,data:o,display:i.join(`
|
|
887
903
|
`)}}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(`
|
|
888
|
-
`)}}async switchAction(e,t,s){if(!t)return{success:!1,error:'Missing required "entityId" parameter'};let r=
|
|
904
|
+
`)}}async switchAction(e,t,s){if(!t)return{success:!1,error:'Missing required "entityId" parameter'};let r=Ph(t),n={entity_id:t};if(s)try{let c=JSON.parse(s);Object.assign(n,c)}catch{return{success:!1,error:'Invalid "serviceData" \u2014 must be valid JSON'}}let o=await this.api("POST",`/api/services/${r}/${e}`,n),i=o?.[0]?.state??"unknown",a=o?.[0]?.attributes?.friendly_name??t;return{success:!0,data:o,display:[`**${e.replace("_"," ")}** \u2192 **${a}**`,"",`New state: **${i}**`].join(`
|
|
889
905
|
`)}}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 n={};if(s&&(n.entity_id=s),r)try{let c=JSON.parse(r);Object.assign(n,c)}catch{return{success:!1,error:'Invalid "serviceData" \u2014 must be valid JSON'}}let o=await this.api("POST",`/api/services/${e}/${t}`,n),i=o?.length??0,a=[`**Service called:** \`${e}.${t}\``,s?`**Entity:** ${s}`:"",`**Affected entities:** ${i}`].filter(Boolean);if(o&&o.length>0){a.push("");for(let c of o){let d=c.attributes?.friendly_name??c.entity_id??"unknown";a.push(`- **${d}**: ${c.state}`)}}return{success:!0,data:o,display:a.join(`
|
|
890
906
|
`)}}async getAreas(e){if(e){if(!/^[\w\s\-äöüÄÖÜß]+$/u.test(e))return{success:!1,error:`Invalid area name: "${e}"`};let o=`{% for eid in area_entities('${e.replace(/'/g,"\\'")}') %}{{ eid }}||{{ states(eid) }}||{{ state_attr(eid, 'friendly_name') }}
|
|
891
907
|
{% endfor %}`,a=(await this.apiText("POST","/api/template",{template:o})).trim().split(`
|
|
@@ -896,18 +912,18 @@ Use "list_vouchers" to see the codes.`}}async enableWlan(e){return e?(await this
|
|
|
896
912
|
`)}}async renderTemplate(e){if(!e)return{success:!1,error:'Missing required "template" parameter'};let t=await this.apiText("POST","/api/template",{template:e});return{success:!0,data:t,display:t}}async getPresence(){let t=(await this.api("GET","/api/states")).filter(r=>r.entity_id.startsWith("person.")),s=["## Presence","","| Person | Status | Last Changed |","|--------|--------|--------------|"];for(let r of t){let n=r.attributes?.friendly_name??r.entity_id,o=r.state??"unknown",i=r.last_changed?new Date(r.last_changed).toLocaleString():"-";s.push(`| ${n} | ${o} | ${i} |`)}return t.length===0&&s.push("| - | No person entities found | - |"),{success:!0,data:t,display:s.join(`
|
|
897
913
|
`)}}async sendNotification(e,t,s){if(!e)return{success:!1,error:'Missing required "message" parameter'};let r=s??"notify",n={message:e};return t&&(n.title=t),{success:!0,data:await this.api("POST",`/api/services/notify/${r}`,n),display:[`**Notification sent** \u2192 \`notify.${r}\``,t?`**Title:** ${t}`:"",`**Message:** ${e.slice(0,200)}${e.length>200?"\u2026":""}`].filter(Boolean).join(`
|
|
898
914
|
`)}}async activateScene(e){if(!e){let n=(await this.api("GET","/api/states")).filter(i=>i.entity_id.startsWith("scene.")),o=["## Available Scenes","","| Entity ID | Name |","|-----------|------|"];for(let i of n){let a=i.attributes?.friendly_name??i.entity_id;o.push(`| ${i.entity_id} | ${a} |`)}return n.length===0&&o.push("| - | No scenes found |"),{success:!0,data:n,display:o.join(`
|
|
899
|
-
`)}}let t=await this.api("POST","/api/services/scene/turn_on",{entity_id:e}),s=t?.[0]?.attributes?.friendly_name??e;return{success:!0,data:t,display:`**Scene activated:** ${s} (\`${e}\`)`}}async triggerAutomation(e,t){if(!e){let d=(await this.api("GET","/api/states")).filter(p=>p.entity_id.startsWith("automation.")),u=["## Automations","","| Entity ID | Name | State | Last Triggered |","|-----------|------|-------|----------------|"];for(let p of d){let h=p.attributes?.friendly_name??p.entity_id,
|
|
915
|
+
`)}}let t=await this.api("POST","/api/services/scene/turn_on",{entity_id:e}),s=t?.[0]?.attributes?.friendly_name??e;return{success:!0,data:t,display:`**Scene activated:** ${s} (\`${e}\`)`}}async triggerAutomation(e,t){if(!e){let d=(await this.api("GET","/api/states")).filter(p=>p.entity_id.startsWith("automation.")),u=["## Automations","","| Entity ID | Name | State | Last Triggered |","|-----------|------|-------|----------------|"];for(let p of d){let h=p.attributes?.friendly_name??p.entity_id,f=p.attributes?.last_triggered?new Date(p.attributes.last_triggered).toLocaleString():"-";u.push(`| ${p.entity_id} | ${h} | ${p.state} | ${f} |`)}return d.length===0&&u.push("| - | No automations found | - | - |"),{success:!0,data:d,display:u.join(`
|
|
900
916
|
`)}}let s={trigger:"trigger",enable:"turn_on",disable:"turn_off"},r=t??"trigger",n=s[r]??"trigger",o=await this.api("POST",`/api/services/automation/${n}`,{entity_id:e}),i=o?.[0]?.attributes?.friendly_name??e,a=o?.[0]?.attributes?.last_triggered?new Date(o[0].attributes.last_triggered).toLocaleString():"-";return{success:!0,data:o,display:[`**Automation ${r}:** ${i} (\`${e}\`)`,`**Last triggered:** ${a}`].join(`
|
|
901
917
|
`)}}async runScript(e,t){if(!e){let i=(await this.api("GET","/api/states")).filter(c=>c.entity_id.startsWith("script.")),a=["## Scripts","","| Entity ID | Name | State |","|-----------|------|-------|"];for(let c of i){let d=c.attributes?.friendly_name??c.entity_id;a.push(`| ${c.entity_id} | ${d} | ${c.state} |`)}return i.length===0&&a.push("| - | No scripts found | - |"),{success:!0,data:i,display:a.join(`
|
|
902
918
|
`)}}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"),c=["## Calendars","","| Entity ID | Name |","|-----------|------|"];for(let d of a){let u=d.name??d.entity_id??"-";c.push(`| ${d.entity_id} | ${u} |`)}return a.length===0&&c.push("| - | No calendars found |"),{success:!0,data:a,display:c.join(`
|
|
903
919
|
`)}}let r=t??new Date().toISOString(),n=s??new Date(Date.now()+864e5).toISOString(),o=await this.api("GET",`/api/calendars/${e}?start=${encodeURIComponent(r)}&end=${encodeURIComponent(n)}`),i=[`## Calendar Events: ${e}`,"","| Start | End | Summary | Location |","|-------|-----|---------|----------|"];for(let a of o){let c=a.start?.dateTime?new Date(a.start.dateTime).toLocaleString():a.start?.date??"-",d=a.end?.dateTime?new Date(a.end.dateTime).toLocaleString():a.end?.date??"-";i.push(`| ${c} | ${d} | ${a.summary??"-"} | ${a.location??"-"} |`)}return o.length===0&&i.push("| - | - | No events in range | - |"),{success:!0,data:o,display:i.join(`
|
|
904
920
|
`)}}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(`
|
|
905
|
-
`)}}async getBriefingSummary(e,t){let s=await this.api("GET","/api/states");if(e?.length){let d=new Set(e.map(p=>p.toLowerCase())),u=s.filter(p=>d.has(p.entity_id.toLowerCase()));return this.formatBriefingSummary(u)}if(t?.length){let d=new Set(t.map(p=>p.toLowerCase())),u=s.filter(p=>{let h=p.entity_id.split(".")[0];return d.has(h)});return this.formatBriefingSummary(u)}let r=[],n=[],o=[];for(let d of s){let u=d.entity_id,p=u.split(".")[0],h=d.state,
|
|
906
|
-
`).trim()}}async getEnergyStats(e,t){let{start:s,end:r,label:n}=this.parseEnergyPeriod(e??"today"),o;if(t?o=[t]:o=(await this.api("GET","/api/states")).filter(
|
|
921
|
+
`)}}async getBriefingSummary(e,t){let s=await this.api("GET","/api/states");if(e?.length){let d=new Set(e.map(p=>p.toLowerCase())),u=s.filter(p=>d.has(p.entity_id.toLowerCase()));return this.formatBriefingSummary(u)}if(t?.length){let d=new Set(t.map(p=>p.toLowerCase())),u=s.filter(p=>{let h=p.entity_id.split(".")[0];return d.has(h)});return this.formatBriefingSummary(u)}let r=[],n=[],o=[];for(let d of s){let u=d.entity_id,p=u.split(".")[0],h=d.state,f=d.attributes??{},g=f.device_class??"";if(p==="binary_sensor"){["door","window","opening","garage_door","lock","motion","occupancy","smoke","gas","moisture"].includes(g)&&h==="on"&&r.push(d);continue}if(p==="light"){if(h==="on"){let y=f.friendly_name??u;if(/^0x[a-f0-9]+$/i.test(y)||/\bLED\b/i.test(y))continue;r.push(d)}continue}if(p==="sensor"){if(h==="unavailable"||h==="unknown")continue;let _=`${u.toLowerCase()} ${(f.friendly_name??"").toLowerCase()}`;if(g==="battery"){n.push(d);continue}if(g==="power"||/power_consumption|stromverbrauch|leistung/.test(_)){o.push(d);continue}continue}if(p==="climate"){r.push(d);continue}if(p==="person"){r.push(d);continue}}n.sort((d,u)=>{let p=parseFloat(d.state)||999,h=parseFloat(u.state)||999;return p-h});let i=n.slice(0,5),a=o.filter(d=>!isNaN(parseFloat(d.state)));a.sort((d,u)=>{let p=Math.abs(parseFloat(d.state)||0);return Math.abs(parseFloat(u.state)||0)-p});let c=a.slice(0,5);return this.formatBriefingSummary(r,i,c)}formatBriefingSummary(e,t,s){let r=[...e,...t??[],...s??[]];if(r.length===0)return{success:!0,data:[],display:"Keine relevanten Smart-Home-Daten gefunden."};let n=new Map;for(let c of e){let d=c.entity_id.split(".")[0];n.has(d)||n.set(d,[]),n.get(d).push(c)}let o={binary_sensor:"Kontakte & Melder",light:"Lichter (an)",climate:"Klima",person:"Anwesenheit"},i=[];for(let[c,d]of n){let u=o[c]??c;i.push(`**${u}:**`);for(let p of d){let h=p.attributes?.friendly_name??p.entity_id,f=p.attributes?.unit_of_measurement??"",g=p.state;i.push(`- ${h}: ${g}${f?` ${f}`:""}`)}i.push("")}if(t&&t.length>0){let c=t.map(d=>`${(d.attributes?.friendly_name??d.entity_id).replace(/\s*(battery|akku|soc|ladezustand)\s*/gi," ").trim()}: ${d.state}%`);i.push(`**\u{1F50B} Akkus:** ${c.join(" | ")}`),i.push("")}if(s&&s.length>0){let c=s.map(d=>{let u=(d.attributes?.friendly_name??d.entity_id).replace(/\s*(power|leistung|stromverbrauch)\s*/gi," ").trim(),p=d.attributes?.unit_of_measurement??"W";return`${u}: ${d.state} ${p}`});i.push(`**\u26A1 Leistung:** ${c.join(" | ")}`),i.push("")}return{success:!0,data:r.map(c=>({entity_id:c.entity_id,state:c.state,friendly_name:c.attributes?.friendly_name,unit:c.attributes?.unit_of_measurement,device_class:c.attributes?.device_class})),display:i.join(`
|
|
922
|
+
`).trim()}}async getEnergyStats(e,t){let{start:s,end:r,label:n}=this.parseEnergyPeriod(e??"today"),o;if(t?o=[t]:o=(await this.api("GET","/api/states")).filter(g=>{let y=g.attributes??{},_=y.state_class,S=y.device_class,b=(y.unit_of_measurement??"").toLowerCase();return g.entity_id.startsWith("sensor.")&&(_==="total_increasing"||_==="total")&&(S==="energy"||b==="kwh"||b==="wh"||b==="mwh")}).map(g=>g.entity_id),o.length===0)return{success:!0,data:[],display:"Keine Energie-Sensoren gefunden (ben\xF6tigt state_class: total_increasing und device_class: energy)."};let i=[],a=[],c=o.join(","),d=`/api/history/period/${s}?end=${encodeURIComponent(r)}&filter_entity_id=${encodeURIComponent(c)}&minimal_response&no_attributes`,u;try{u=await this.api("GET",d)}catch{return this.getEnergyStatsViaTemplate(o,s,r,n)}for(let f of u){if(!f||f.length<2)continue;let g=f[0]?.entity_id;if(!g)continue;let y=null,_=null;for(let S of f){let b=parseFloat(S.state);isNaN(b)||(y===null&&(y=b),_=b)}if(y!==null&&_!==null){let S=_-y;S<0&&(S=0);let b=await this.api("GET",`/api/states/${g}`).catch(()=>null),$=b?.attributes?.friendly_name??g,N=b?.attributes?.unit_of_measurement??"kWh",M=S,J=N;N.toLowerCase()==="wh"?(M=S/1e3,J="kWh"):N.toLowerCase()==="mwh"&&(M=S*1e3,J="kWh"),i.push({entityId:g,name:$,consumption:Math.round(M*100)/100,unit:J})}}if(i.length===0&&a.length===0)return{success:!0,data:[],display:`Keine Verbrauchsdaten f\xFCr Zeitraum "${n}" gefunden. M\xF6glicherweise liegt der Zeitraum au\xDFerhalb der History-Retention.`};let p=i.reduce((f,g)=>f+(g.unit==="kWh"?g.consumption:0),0),h=[`## Energieverbrauch: ${n}`,"","| Sensor | Verbrauch |","|--------|-----------|"];for(let f of i.sort((g,y)=>y.consumption-g.consumption))h.push(`| ${f.name} | ${f.consumption} ${f.unit} |`);return i.length>1&&h.push(`| **Gesamt** | **${Math.round(p*100)/100} kWh** |`),a.length>0&&h.push("",`Fehler bei: ${a.join(", ")}`),{success:!0,data:i,display:h.join(`
|
|
907
923
|
`)}}async getEnergyStatsViaTemplate(e,t,s,r){let n=[`## Energie-Sensoren: ${r}`,"","*Hinweis: F\xFCr diesen Zeitraum sind keine History-Daten verf\xFCgbar. Zeige aktuelle Z\xE4hlerst\xE4nde.*","","| Sensor | Aktueller Stand | Einheit |","|--------|----------------|---------|"];for(let o of e)try{let i=await this.api("GET",`/api/states/${o}`),a=i.attributes?.friendly_name??o,c=i.attributes?.unit_of_measurement??"",d=i.state;n.push(`| ${a} | ${d} | ${c} |`)}catch{n.push(`| ${o} | Fehler | - |`)}return{success:!0,data:[],display:n.join(`
|
|
908
|
-
`)}}parseEnergyPeriod(e){let t=new Date;switch(e.toLowerCase().replace(/\s+/g,"_")){case"today":case"heute":return{start:new Date(t.getFullYear(),t.getMonth(),t.getDate()).toISOString(),end:t.toISOString(),label:"Heute"};case"yesterday":case"gestern":{let s=new Date(t.getFullYear(),t.getMonth(),t.getDate()-1),r=new Date(t.getFullYear(),t.getMonth(),t.getDate());return{start:s.toISOString(),end:r.toISOString(),label:"Gestern"}}case"this_week":case"diese_woche":{let s=t.getDay(),r=s===0?-6:1-s;return{start:new Date(t.getFullYear(),t.getMonth(),t.getDate()+r).toISOString(),end:t.toISOString(),label:"Diese Woche"}}case"last_week":case"letzte_woche":{let s=t.getDay(),r=s===0?-6:1-s,n=new Date(t.getFullYear(),t.getMonth(),t.getDate()+r);return{start:new Date(n.getTime()-7*864e5).toISOString(),end:n.toISOString(),label:"Letzte Woche"}}case"this_month":case"dieser_monat":return{start:new Date(t.getFullYear(),t.getMonth(),1).toISOString(),end:t.toISOString(),label:"Dieser Monat"};case"last_month":case"letzter_monat":{let s=new Date(t.getFullYear(),t.getMonth()-1,1),r=new Date(t.getFullYear(),t.getMonth(),1);return{start:s.toISOString(),end:r.toISOString(),label:"Letzter Monat"}}default:return{start:
|
|
924
|
+
`)}}parseEnergyPeriod(e){let t=new Date;switch(e.toLowerCase().replace(/\s+/g,"_")){case"today":case"heute":return{start:new Date(t.getFullYear(),t.getMonth(),t.getDate()).toISOString(),end:t.toISOString(),label:"Heute"};case"yesterday":case"gestern":{let s=new Date(t.getFullYear(),t.getMonth(),t.getDate()-1),r=new Date(t.getFullYear(),t.getMonth(),t.getDate());return{start:s.toISOString(),end:r.toISOString(),label:"Gestern"}}case"this_week":case"diese_woche":{let s=t.getDay(),r=s===0?-6:1-s;return{start:new Date(t.getFullYear(),t.getMonth(),t.getDate()+r).toISOString(),end:t.toISOString(),label:"Diese Woche"}}case"last_week":case"letzte_woche":{let s=t.getDay(),r=s===0?-6:1-s,n=new Date(t.getFullYear(),t.getMonth(),t.getDate()+r);return{start:new Date(n.getTime()-7*864e5).toISOString(),end:n.toISOString(),label:"Letzte Woche"}}case"this_month":case"dieser_monat":return{start:new Date(t.getFullYear(),t.getMonth(),1).toISOString(),end:t.toISOString(),label:"Dieser Monat"};case"last_month":case"letzter_monat":{let s=new Date(t.getFullYear(),t.getMonth()-1,1),r=new Date(t.getFullYear(),t.getMonth(),1);return{start:s.toISOString(),end:r.toISOString(),label:"Letzter Monat"}}default:return{start:la(e),end:t.toISOString(),label:e}}}async createConfig(e,t,s){if(!t)return{success:!1,error:`Missing required "configId" for create_${e}`};if(!s)return{success:!1,error:`Missing required "configData" for create_${e}`};let r;try{r=JSON.parse(s)}catch{return{success:!1,error:'Invalid "configData" \u2014 must be valid JSON'}}return{success:!0,data:await this.apiPost(`/api/config/${e}/config/${t}`,r),display:`**${e} created:** \`${t}\`
|
|
909
925
|
|
|
910
|
-
${r.alias??r.name??t}`}}async deleteConfig(e,t){return t?(await this.apiDelete(`/api/config/${e}/config/${t}`),{success:!0,data:{deleted:t},display:`**${e} deleted:** \`${t}\``}):{success:!1,error:`Missing required "configId" for delete_${e}`}}async apiPost(e,t){let s=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,r={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},n=this.config.verifyTls===!1,o=process.env.NODE_TLS_REJECT_UNAUTHORIZED;n&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let i;try{i=await fetch(s,{method:"POST",headers:r,body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)})}finally{n&&(o===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}if(!i.ok){let a="";try{a=(await i.text()).slice(0,500)}catch{}throw new Error(`HTTP ${i.status} ${i.statusText} \u2014 ${a}`)}return await i.json()}async apiDelete(e){let t=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,s={Authorization:`Bearer ${this.config.accessToken}`},r=this.config.verifyTls===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let o;try{o=await fetch(t,{method:"DELETE",headers:s,signal:AbortSignal.timeout(15e3)})}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}if(!o.ok){let i="";try{i=(await o.text()).slice(0,500)}catch{}throw new Error(`HTTP ${o.status} ${o.statusText} \u2014 ${i}`)}}}});var qe,
|
|
926
|
+
${r.alias??r.name??t}`}}async deleteConfig(e,t){return t?(await this.apiDelete(`/api/config/${e}/config/${t}`),{success:!0,data:{deleted:t},display:`**${e} deleted:** \`${t}\``}):{success:!1,error:`Missing required "configId" for delete_${e}`}}async apiPost(e,t){let s=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,r={Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json"},n=this.config.verifyTls===!1,o=process.env.NODE_TLS_REJECT_UNAUTHORIZED;n&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let i;try{i=await fetch(s,{method:"POST",headers:r,body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)})}finally{n&&(o===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=o)}if(!i.ok){let a="";try{a=(await i.text()).slice(0,500)}catch{}throw new Error(`HTTP ${i.status} ${i.statusText} \u2014 ${a}`)}return await i.json()}async apiDelete(e){let t=`${this.config.baseUrl.replace(/\/+$/,"")}${e}`,s={Authorization:`Bearer ${this.config.accessToken}`},r=this.config.verifyTls===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let o;try{o=await fetch(t,{method:"DELETE",headers:s,signal:AbortSignal.timeout(15e3)})}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}if(!o.ok){let i="";try{i=(await o.text()).slice(0,500)}catch{}throw new Error(`HTTP ${o.status} ${o.statusText} \u2014 ${i}`)}}}});var qe,zr=T(()=>{"use strict";qe=class{static{m(this,"ContactsProvider")}}});var Xd={};fe(Xd,{CardDAVContactsProvider:()=>uo});var uo,da=T(()=>{"use strict";zr();uo=class extends qe{static{m(this,"CardDAVContactsProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"carddav"})}catch(e){throw new Error(`CardDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async list(e,t){let s=await this.client.fetchAddressBooks();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchVCards({addressBook:n});for(let i of o){let a=this.parseVCard(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.displayName.localeCompare(o.displayName)),e?r.slice(0,e):r}async search(e){let t=await this.list(),s=e.toLowerCase();return t.filter(r=>r.displayName.toLowerCase().includes(s)||r.emails.some(n=>n.address.toLowerCase().includes(s))||r.phones.some(n=>n.number.includes(s)))}async get(e){return(await this.list()).find(s=>s.id===e)}async create(e){let t=await this.client.fetchAddressBooks();if(!t||t.length===0)throw new Error("No address books found");let s=`alfred-${Date.now()}@alfred`,r=this.buildVCard(s,e);await this.client.createVCard({addressBook:t[0],filename:`${s}.vcf`,vCardString:r});let n=e.displayName??([e.firstName,e.lastName].filter(Boolean).join(" ")||"Unknown");return{id:s,displayName:n,firstName:e.firstName,lastName:e.lastName,emails:e.emails??[],phones:e.phones??[],addresses:e.addresses??[],organization:e.organization,birthday:e.birthday,notes:e.notes}}async update(e,t){let s=await this.client.fetchAddressBooks();for(let r of s){let n=await this.client.fetchVCards({addressBook:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseVCard(o.data,o.url);if(!i)continue;let a={firstName:t.firstName??i.firstName,lastName:t.lastName??i.lastName,displayName:t.displayName??i.displayName,emails:t.emails??i.emails,phones:t.phones??i.phones,addresses:t.addresses??i.addresses,organization:t.organization??i.organization,birthday:t.birthday??i.birthday,notes:t.notes??i.notes},c=this.buildVCard(e,a);await this.client.updateVCard({vCard:{...o,data:c}});let d=a.displayName??([a.firstName,a.lastName].filter(Boolean).join(" ")||"Unknown");return{id:e,displayName:d,firstName:a.firstName,lastName:a.lastName,emails:a.emails??[],phones:a.phones??[],addresses:a.addresses??[],organization:a.organization,birthday:a.birthday,notes:a.notes}}}throw new Error(`Contact ${e} not found`)}async delete(e){let t=await this.client.fetchAddressBooks();for(let s of t){let r=await this.client.fetchVCards({addressBook:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteVCard({vCard:n});return}}throw new Error(`Contact ${e} not found`)}parseVCard(e,t){let s=m(g=>e.match(new RegExp(`^${g}[;:](.*)$`,"mi"))?.[1]?.trim(),"get"),r=s("FN");if(!r)return;let n=s("N"),[o,i]=n?n.split(";"):[void 0,void 0],a=[];for(let g of e.matchAll(/^EMAIL[^:]*:(.+)$/gmi)){let y=g[0],_=g[1].trim(),S=y.match(/TYPE=([^;:,]+)/i)?.[1],b=/TYPE=pref/i.test(y);a.push({address:_,label:S,primary:b})}let c=[];for(let g of e.matchAll(/^TEL[^:]*:(.+)$/gmi)){let y=g[0],_=g[1].trim(),S=y.match(/TYPE=([^;:,]+)/i)?.[1],b=/TYPE=pref/i.test(y);c.push({number:_,label:S,primary:b})}let d=[];for(let g of e.matchAll(/^ADR[^:]*:(.+)$/gmi)){let y=g[1].split(";");d.push({street:y[2]?.trim()||void 0,city:y[3]?.trim()||void 0,region:y[4]?.trim()||void 0,postalCode:y[5]?.trim()||void 0,country:y[6]?.trim()||void 0})}let u=s("ORG")?.replace(/;.*$/,""),p=s("BDAY"),h=s("NOTE");return{id:s("UID")??t,displayName:r,firstName:i,lastName:o,emails:a,phones:c,addresses:d,organization:u,birthday:p,notes:h}}buildVCard(e,t){let s=t.displayName??([t.firstName,t.lastName].filter(Boolean).join(" ")||"Unknown"),r=`BEGIN:VCARD\r
|
|
911
927
|
VERSION:3.0\r
|
|
912
928
|
`;r+=`UID:${e}\r
|
|
913
929
|
`,r+=`FN:${s}\r
|
|
@@ -919,108 +935,108 @@ VERSION:3.0\r
|
|
|
919
935
|
`),t.birthday&&(r+=`BDAY:${t.birthday}\r
|
|
920
936
|
`),t.notes&&(r+=`NOTE:${t.notes}\r
|
|
921
937
|
`),r+=`END:VCARD\r
|
|
922
|
-
`,r}}});var Nd={};he(Nd,{GoogleContactsProvider:()=>oo});var no,Ft,oo,sa=T(()=>{"use strict";Ur();no="names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies",Ft="https://people.googleapis.com/v1",oo=class extends qe{static{m(this,"GoogleContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),t=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!t.ok)throw new Error(`Google token refresh failed: ${t.status}`);let s=await t.json();this.accessToken=s.access_token}async apiRequest(e,t,s){let r={method:e,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}};s&&(r.body=JSON.stringify(s));let n=await fetch(t,r);if(n.status===401){await this.refreshAccessToken();let o=await fetch(t,{...r,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}});if(!o.ok)throw new Error(`People API error: ${o.status}`);return o.status===204?void 0:o.json()}if(!n.ok)throw new Error(`People API error: ${n.status}`);if(n.status!==204)return n.json()}async list(e=50){let t=`${Ft}/people/me/connections?personFields=${no}&pageSize=${e}`;return((await this.apiRequest("GET",t)).connections??[]).map(r=>this.mapPerson(r))}async search(e){let t=`${Ft}/people:searchContacts?query=${encodeURIComponent(e)}&readMask=${no}&pageSize=30`;return((await this.apiRequest("GET",t)).results??[]).map(r=>this.mapPerson(r.person))}async get(e){try{let t=`${Ft}/${e}?personFields=${no}`,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",`${Ft}/people:createContact`,t);return this.mapPerson(s)}async update(e,t){let s=await this.apiRequest("GET",`${Ft}/${e}?personFields=${no}`),r=this.buildPersonBody(t);r.etag=s.etag;let o=`${Ft}/${e}:updateContact?updatePersonFields=names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies`,i=await this.apiRequest("PATCH",o,r);return this.mapPerson(i)}async delete(e){await this.apiRequest("DELETE",`${Ft}/${e}:deleteContact`)}mapPerson(e){let t=e.names?.[0],s=(e.emailAddresses??[]).map(c=>({address:c.value,label:c.type,primary:c.metadata?.primary??!1})),r=(e.phoneNumbers??[]).map(c=>({number:c.value,label:c.type,primary:c.metadata?.primary??!1})),n=(e.addresses??[]).map(c=>({street:c.streetAddress??void 0,city:c.city??void 0,region:c.region??void 0,postalCode:c.postalCode??void 0,country:c.country??void 0,label:c.type??void 0})),o=e.organizations?.[0]?.name,i=e.birthdays?.[0]?.date?`${e.birthdays[0].date.year??"????"}-${String(e.birthdays[0].date.month).padStart(2,"0")}-${String(e.birthdays[0].date.day).padStart(2,"0")}`:void 0,a=e.biographies?.[0]?.value;return{id:e.resourceName??e.etag??"",displayName:t?.displayName??"(No name)",firstName:t?.givenName,lastName:t?.familyName,emails:s,phones:r,addresses:n,organization:o,birthday:i,notes:a}}buildPersonBody(e){let t={};if((e.firstName!==void 0||e.lastName!==void 0||e.displayName!==void 0)&&(t.names=[{givenName:e.firstName,familyName:e.lastName,displayName:e.displayName}]),e.emails&&(t.emailAddresses=e.emails.map(s=>({value:s.address,type:s.label??"home"}))),e.phones&&(t.phoneNumbers=e.phones.map(s=>({value:s.number,type:s.label??"mobile"}))),e.addresses&&(t.addresses=e.addresses.map(s=>({streetAddress:s.street,city:s.city,region:s.region,postalCode:s.postalCode,country:s.country,type:s.label??"home"}))),e.organization&&(t.organizations=[{name:e.organization}]),e.birthday){let s=e.birthday.split("-");t.birthdays=[{date:{year:s[0]!=="????"?parseInt(s[0],10):void 0,month:parseInt(s[1],10),day:parseInt(s[2],10)}}]}return e.notes&&(t.biographies=[{value:e.notes,contentType:"TEXT_PLAIN"}]),t}}});var Dd={};he(Dd,{MicrosoftContactsProvider:()=>io});var io,ra=T(()=>{"use strict";Ur();io=class extends qe{static{m(this,"MicrosoftContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Contacts.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.status===204?void 0:r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async list(e=50){return((await this.graphRequest(`/me/contacts?$top=${e}&$orderby=displayName`)).value??[]).map(s=>this.mapContact(s))}async search(e){try{return((await this.graphRequest(`/me/contacts?$search="${encodeURIComponent(e)}"`,{headers:{ConsistencyLevel:"eventual"}})).value??[]).map(s=>this.mapContact(s))}catch{return((await this.graphRequest(`/me/contacts?$filter=contains(displayName, '${encodeURIComponent(e)}')`)).value??[]).map(s=>this.mapContact(s))}}async get(e){try{let t=await this.graphRequest(`/me/contacts/${e}`);return this.mapContact(t)}catch{return}}async create(e){let t=this.buildContactBody(e),s=await this.graphRequest("/me/contacts",{method:"POST",body:JSON.stringify(t)});return this.mapContact(s)}async update(e,t){let s=this.buildContactBody(t),r=await this.graphRequest(`/me/contacts/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapContact(r)}async delete(e){await this.graphRequest(`/me/contacts/${e}`,{method:"DELETE"})}mapContact(e){let t=(e.emailAddresses??[]).map(o=>({address:o.address,label:o.name??void 0,primary:!1})),s=[];if(e.mobilePhone&&s.push({number:e.mobilePhone,label:"mobile"}),e.businessPhones)for(let o of e.businessPhones)s.push({number:o,label:"work"});if(e.homePhones)for(let o of e.homePhones)s.push({number:o,label:"home"});let r=[];e.homeAddress&&Object.values(e.homeAddress).some(Boolean)&&r.push({street:e.homeAddress.street??void 0,city:e.homeAddress.city??void 0,region:e.homeAddress.state??void 0,postalCode:e.homeAddress.postalCode??void 0,country:e.homeAddress.countryOrRegion??void 0,label:"home"}),e.businessAddress&&Object.values(e.businessAddress).some(Boolean)&&r.push({street:e.businessAddress.street??void 0,city:e.businessAddress.city??void 0,region:e.businessAddress.state??void 0,postalCode:e.businessAddress.postalCode??void 0,country:e.businessAddress.countryOrRegion??void 0,label:"work"});let n=e.birthday?e.birthday.slice(0,10):void 0;return{id:e.id,displayName:e.displayName??"(No name)",firstName:e.givenName??void 0,lastName:e.surname??void 0,emails:t,phones:s,addresses:r,organization:e.companyName??void 0,birthday:n,notes:e.personalNotes??void 0}}buildContactBody(e){let t={};if(e.firstName!==void 0&&(t.givenName=e.firstName),e.lastName!==void 0&&(t.surname=e.lastName),e.displayName!==void 0&&(t.displayName=e.displayName),e.emails&&(t.emailAddresses=e.emails.map(s=>({address:s.address,name:s.label??s.address}))),e.phones){let s=e.phones.find(i=>i.label==="mobile"),r=e.phones.filter(i=>i.label==="work"),n=e.phones.filter(i=>i.label==="home"),o=e.phones.filter(i=>!["mobile","work","home"].includes(i.label??""));s&&(t.mobilePhone=s.number),r.length>0&&(t.businessPhones=r.map(i=>i.number)),n.length>0&&(t.homePhones=n.map(i=>i.number)),o.length>0&&!r.length&&(t.businessPhones=o.map(i=>i.number))}if(e.addresses)for(let s of e.addresses){let r={street:s.street,city:s.city,state:s.region,postalCode:s.postalCode,countryOrRegion:s.country};s.label==="work"?t.businessAddress=r:t.homeAddress=r}return e.organization!==void 0&&(t.companyName=e.organization),e.birthday!==void 0&&(t.birthday=e.birthday),e.notes!==void 0&&(t.personalNotes=e.notes),t}}});async function na(l){switch(l.provider){case"carddav":{if(!l.carddav)throw new Error("CardDAV contacts config missing");let{CardDAVContactsProvider:e}=await Promise.resolve().then(()=>(ta(),Ld)),t=new e(l.carddav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google contacts config missing");let{GoogleContactsProvider:e}=await Promise.resolve().then(()=>(sa(),Nd)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft contacts config missing");let{MicrosoftContactsProvider:e}=await Promise.resolve().then(()=>(ra(),Dd)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown contacts provider: ${l.provider}`)}}var Md=T(()=>{"use strict";m(na,"createContactsProvider")});var Fr,Od=T(()=>{"use strict";W();Fr=class extends x{static{m(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:
|
|
938
|
+
`,r}}});var Kd={};fe(Kd,{GoogleContactsProvider:()=>po});var mo,Bt,po,ua=T(()=>{"use strict";zr();mo="names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies",Bt="https://people.googleapis.com/v1",po=class extends qe{static{m(this,"GoogleContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),t=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString()});if(!t.ok)throw new Error(`Google token refresh failed: ${t.status}`);let s=await t.json();this.accessToken=s.access_token}async apiRequest(e,t,s){let r={method:e,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}};s&&(r.body=JSON.stringify(s));let n=await fetch(t,r);if(n.status===401){await this.refreshAccessToken();let o=await fetch(t,{...r,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json"}});if(!o.ok)throw new Error(`People API error: ${o.status}`);return o.status===204?void 0:o.json()}if(!n.ok)throw new Error(`People API error: ${n.status}`);if(n.status!==204)return n.json()}async list(e=50){let t=`${Bt}/people/me/connections?personFields=${mo}&pageSize=${e}`;return((await this.apiRequest("GET",t)).connections??[]).map(r=>this.mapPerson(r))}async search(e){let t=`${Bt}/people:searchContacts?query=${encodeURIComponent(e)}&readMask=${mo}&pageSize=30`;return((await this.apiRequest("GET",t)).results??[]).map(r=>this.mapPerson(r.person))}async get(e){try{let t=`${Bt}/${e}?personFields=${mo}`,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",`${Bt}/people:createContact`,t);return this.mapPerson(s)}async update(e,t){let s=await this.apiRequest("GET",`${Bt}/${e}?personFields=${mo}`),r=this.buildPersonBody(t);r.etag=s.etag;let o=`${Bt}/${e}:updateContact?updatePersonFields=names,emailAddresses,phoneNumbers,addresses,organizations,birthdays,biographies`,i=await this.apiRequest("PATCH",o,r);return this.mapPerson(i)}async delete(e){await this.apiRequest("DELETE",`${Bt}/${e}:deleteContact`)}mapPerson(e){let t=e.names?.[0],s=(e.emailAddresses??[]).map(c=>({address:c.value,label:c.type,primary:c.metadata?.primary??!1})),r=(e.phoneNumbers??[]).map(c=>({number:c.value,label:c.type,primary:c.metadata?.primary??!1})),n=(e.addresses??[]).map(c=>({street:c.streetAddress??void 0,city:c.city??void 0,region:c.region??void 0,postalCode:c.postalCode??void 0,country:c.country??void 0,label:c.type??void 0})),o=e.organizations?.[0]?.name,i=e.birthdays?.[0]?.date?`${e.birthdays[0].date.year??"????"}-${String(e.birthdays[0].date.month).padStart(2,"0")}-${String(e.birthdays[0].date.day).padStart(2,"0")}`:void 0,a=e.biographies?.[0]?.value;return{id:e.resourceName??e.etag??"",displayName:t?.displayName??"(No name)",firstName:t?.givenName,lastName:t?.familyName,emails:s,phones:r,addresses:n,organization:o,birthday:i,notes:a}}buildPersonBody(e){let t={};if((e.firstName!==void 0||e.lastName!==void 0||e.displayName!==void 0)&&(t.names=[{givenName:e.firstName,familyName:e.lastName,displayName:e.displayName}]),e.emails&&(t.emailAddresses=e.emails.map(s=>({value:s.address,type:s.label??"home"}))),e.phones&&(t.phoneNumbers=e.phones.map(s=>({value:s.number,type:s.label??"mobile"}))),e.addresses&&(t.addresses=e.addresses.map(s=>({streetAddress:s.street,city:s.city,region:s.region,postalCode:s.postalCode,country:s.country,type:s.label??"home"}))),e.organization&&(t.organizations=[{name:e.organization}]),e.birthday){let s=e.birthday.split("-");t.birthdays=[{date:{year:s[0]!=="????"?parseInt(s[0],10):void 0,month:parseInt(s[1],10),day:parseInt(s[2],10)}}]}return e.notes&&(t.biographies=[{value:e.notes,contentType:"TEXT_PLAIN"}]),t}}});var Vd={};fe(Vd,{MicrosoftContactsProvider:()=>ho});var ho,ma=T(()=>{"use strict";zr();ho=class extends qe{static{m(this,"MicrosoftContactsProvider")}config;accessToken="";constructor(e){super(),this.config=e}async initialize(){await this.refreshAccessToken()}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Contacts.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(s.status===401){await this.refreshAccessToken();let r=await fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}});if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return r.status===204?void 0:r.json()}if(!s.ok)throw new Error(`Graph API error: ${s.status}`);if(s.status!==204)return s.json()}async list(e=50){return((await this.graphRequest(`/me/contacts?$top=${e}&$orderby=displayName`)).value??[]).map(s=>this.mapContact(s))}async search(e){try{return((await this.graphRequest(`/me/contacts?$search="${encodeURIComponent(e)}"`,{headers:{ConsistencyLevel:"eventual"}})).value??[]).map(s=>this.mapContact(s))}catch{return((await this.graphRequest(`/me/contacts?$filter=contains(displayName, '${encodeURIComponent(e)}')`)).value??[]).map(s=>this.mapContact(s))}}async get(e){try{let t=await this.graphRequest(`/me/contacts/${e}`);return this.mapContact(t)}catch{return}}async create(e){let t=this.buildContactBody(e),s=await this.graphRequest("/me/contacts",{method:"POST",body:JSON.stringify(t)});return this.mapContact(s)}async update(e,t){let s=this.buildContactBody(t),r=await this.graphRequest(`/me/contacts/${e}`,{method:"PATCH",body:JSON.stringify(s)});return this.mapContact(r)}async delete(e){await this.graphRequest(`/me/contacts/${e}`,{method:"DELETE"})}mapContact(e){let t=(e.emailAddresses??[]).map(o=>({address:o.address,label:o.name??void 0,primary:!1})),s=[];if(e.mobilePhone&&s.push({number:e.mobilePhone,label:"mobile"}),e.businessPhones)for(let o of e.businessPhones)s.push({number:o,label:"work"});if(e.homePhones)for(let o of e.homePhones)s.push({number:o,label:"home"});let r=[];e.homeAddress&&Object.values(e.homeAddress).some(Boolean)&&r.push({street:e.homeAddress.street??void 0,city:e.homeAddress.city??void 0,region:e.homeAddress.state??void 0,postalCode:e.homeAddress.postalCode??void 0,country:e.homeAddress.countryOrRegion??void 0,label:"home"}),e.businessAddress&&Object.values(e.businessAddress).some(Boolean)&&r.push({street:e.businessAddress.street??void 0,city:e.businessAddress.city??void 0,region:e.businessAddress.state??void 0,postalCode:e.businessAddress.postalCode??void 0,country:e.businessAddress.countryOrRegion??void 0,label:"work"});let n=e.birthday?e.birthday.slice(0,10):void 0;return{id:e.id,displayName:e.displayName??"(No name)",firstName:e.givenName??void 0,lastName:e.surname??void 0,emails:t,phones:s,addresses:r,organization:e.companyName??void 0,birthday:n,notes:e.personalNotes??void 0}}buildContactBody(e){let t={};if(e.firstName!==void 0&&(t.givenName=e.firstName),e.lastName!==void 0&&(t.surname=e.lastName),e.displayName!==void 0&&(t.displayName=e.displayName),e.emails&&(t.emailAddresses=e.emails.map(s=>({address:s.address,name:s.label??s.address}))),e.phones){let s=e.phones.find(i=>i.label==="mobile"),r=e.phones.filter(i=>i.label==="work"),n=e.phones.filter(i=>i.label==="home"),o=e.phones.filter(i=>!["mobile","work","home"].includes(i.label??""));s&&(t.mobilePhone=s.number),r.length>0&&(t.businessPhones=r.map(i=>i.number)),n.length>0&&(t.homePhones=n.map(i=>i.number)),o.length>0&&!r.length&&(t.businessPhones=o.map(i=>i.number))}if(e.addresses)for(let s of e.addresses){let r={street:s.street,city:s.city,state:s.region,postalCode:s.postalCode,countryOrRegion:s.country};s.label==="work"?t.businessAddress=r:t.homeAddress=r}return e.organization!==void 0&&(t.companyName=e.organization),e.birthday!==void 0&&(t.birthday=e.birthday),e.notes!==void 0&&(t.personalNotes=e.notes),t}}});async function pa(l){switch(l.provider){case"carddav":{if(!l.carddav)throw new Error("CardDAV contacts config missing");let{CardDAVContactsProvider:e}=await Promise.resolve().then(()=>(da(),Xd)),t=new e(l.carddav);return await t.initialize(),t}case"google":{if(!l.google)throw new Error("Google contacts config missing");let{GoogleContactsProvider:e}=await Promise.resolve().then(()=>(ua(),Kd)),t=new e(l.google);return await t.initialize(),t}case"microsoft":{if(!l.microsoft)throw new Error("Microsoft contacts config missing");let{MicrosoftContactsProvider:e}=await Promise.resolve().then(()=>(ma(),Vd)),t=new e(l.microsoft);return await t.initialize(),t}default:throw new Error(`Unknown contacts provider: ${l.provider}`)}}var Yd=T(()=>{"use strict";m(pa,"createContactsProvider")});var qr,Jd=T(()=>{"use strict";W();qr=class extends x{static{m(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:
|
|
923
939
|
${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):
|
|
924
940
|
${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 |
|
|
925
941
|
|------|-------|-------|`,s=e.map(r=>{let n=r.emails[0]?.address??"-",o=r.phones[0]?.number??"-";return`| ${r.displayName} | ${n} | ${o} |`});return`${t}
|
|
926
942
|
${s.join(`
|
|
927
943
|
`)}`}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(`
|
|
928
|
-
`)}}});var
|
|
944
|
+
`)}}});var Zd=T(()=>{"use strict";zr();da();ua();ma();Yd();Jd()});var Ss,Qd=T(()=>{"use strict";W();Me();Ss=class extends x{static{m(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",n=e.description,o=e.priority,i=e.dueDate,a=this.todoRepo.add(de(t),s,{list:r,description:n,priority:o,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,n=new Set,o=[];for(let c of K(t))for(let d of this.todoRepo.list(c,s,r))n.has(d.id)||(n.add(d.id),o.push(d));if(o.length===0)return{success:!0,data:[],display:"No todos found."};let i=`| | Priority | Title | Due | ID |
|
|
929
945
|
|---|---|---|---|---|`,a=o.map(c=>{let d=c.completed?"\u2611":"\u2610",u=c.dueDate??"";return`| ${d} | ${c.priority} | ${c.title} | ${u} | ${c.id} |`}).join(`
|
|
930
946
|
`);return{success:!0,data:o,display:`${o.length} todo(s):
|
|
931
947
|
${i}
|
|
932
|
-
${a}`}}completeTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "todoId" for complete action'};let r=this.todoRepo.getById(s);return r?
|
|
948
|
+
${a}`}}completeTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "todoId" for complete action'};let r=this.todoRepo.getById(s);return r?K(t).includes(r.userId)?this.todoRepo.complete(s)?{success:!0,data:{todoId:s},display:"Todo completed."}:{success:!1,error:`Todo "${s}" is already completed`}:{success:!1,error:`Todo "${s}" not found`}:{success:!1,error:`Todo "${s}" not found`}}uncompleteTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "todoId" for uncomplete action'};let r=this.todoRepo.getById(s);return r?K(t).includes(r.userId)?this.todoRepo.uncomplete(s)?{success:!0,data:{todoId:s},display:"Todo reopened."}:{success:!1,error:`Todo "${s}" is not completed`}:{success:!1,error:`Todo "${s}" not found`}:{success:!1,error:`Todo "${s}" not found`}}deleteTodo(e,t){let s=e.todoId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "todoId" for delete action'};let r=this.todoRepo.getById(s);return r?K(t).includes(r.userId)?this.todoRepo.delete(s)?{success:!0,data:{todoId:s},display:"Todo deleted."}:{success:!1,error:`Todo "${s}" not found`}:{success:!1,error:`Todo "${s}" not found`}:{success:!1,error:`Todo "${s}" not found`}}showLists(e){let t=new Map;for(let o of K(e))for(let i of this.todoRepo.getLists(o)){let a=t.get(i.list);a?(a.open+=i.open,a.completed+=i.completed,a.total+=i.total):t.set(i.list,{open:i.open,completed:i.completed,total:i.total})}if(t.size===0)return{success:!0,data:[],display:"No todo lists found."};let s=[...t.entries()].map(([o,i])=>({list:o,...i})),r=`| List | Open | Completed | Total |
|
|
933
949
|
|---|---|---|---|`,n=s.map(o=>`| ${o.list} | ${o.open} | ${o.completed} | ${o.total} |`).join(`
|
|
934
950
|
`);return{success:!0,data:s,display:`${s.length} list(s):
|
|
935
951
|
${r}
|
|
936
|
-
${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(
|
|
937
|
-
`)}}async inspectContainer(e){if(!e)return{success:!1,error:'Missing required "containerId" parameter'};let t=await this.api("GET",`/containers/${encodeURIComponent(e)}/json`),s=t.State??{},r=t.Config??{},n=t.NetworkSettings??{},o=t.Mounts??[],a=Object.entries(n.Ports??{}).filter(([,p])=>p&&p.length>0).map(([p,h])=>`${h.map(
|
|
952
|
+
${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(de(t),s);return{success:!0,data:{cleared:r},display:`Cleared ${r} completed todo(s).`}}}});import eu from"node:http";import tu from"node:https";import{execFile as Uh}from"node:child_process";import{promisify as Fh}from"node:util";function ha(l){return l==null||l<0?"-":l===0?"0 B":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function ru(l){return!l||l.length===0?"-":l.filter(e=>e.PublicPort||e.PrivatePort).map(e=>e.PublicPort?`${e.IP??"0.0.0.0"}:${e.PublicPort}->${e.PrivatePort}/${e.Type??"tcp"}`:`${e.PrivatePort}/${e.Type??"tcp"}`).join(", ")}function fa(l){return!l||l.length===0?"-":l.map(e=>e.replace(/^\//,"")).join(", ")}function jh(l){let e=Buffer.from(l,"binary"),t=[],s=0;for(;s<e.length;)if(s+8<=e.length){let r=e.readUInt32BE(s+4),n=e.subarray(s+8,s+8+r).toString("utf8");t.push(n),s+=8+r}else{t.push(e.subarray(s).toString("utf8"));break}return t.join("")}function Bh(l){return l?new Date(l*1e3).toISOString().replace("T"," ").slice(0,19):"-"}var su,fo,nu=T(()=>{"use strict";W();su=Fh(Uh);m(ha,"formatBytes");m(ru,"formatPorts");m(fa,"containerName");m(jh,"stripDockerStreamHeaders");m(Bh,"relativeTime");fo=class extends x{static{m(this,"DockerSkill")}metadata={name:"docker",category:"infrastructure",description:"Manage Docker containers, images, volumes, networks. Actions: containers, container, logs, start, stop, restart, images, pull_image, remove_image, networks, volumes, system_info, prune, compose_ps, compose_up, compose_down.",riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["containers","container","logs","start","stop","restart","images","pull_image","remove_image","networks","volumes","system_info","prune","compose_ps","compose_up","compose_down"],description:"The Docker action to perform"},containerId:{type:"string",description:"Container ID or name (for container, logs, start, stop, restart)"},imageName:{type:"string",description:"Image name (for pull_image, remove_image), e.g. nginx, ghcr.io/org/app"},imageTag:{type:"string",description:"Image tag (for pull_image), default: latest"},networkId:{type:"string",description:"Network ID or name"},project:{type:"string",description:"Docker Compose project name (for compose_ps, compose_up, compose_down)"},tail:{type:"number",description:"Number of log lines to retrieve (default: 100)"}},required:["action"]}};config;defaultSocket;constructor(e){super(),this.config=e,this.defaultSocket=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock"}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"containers":return await this.listContainers();case"container":return await this.inspectContainer(e.containerId);case"logs":return await this.getLogs(e.containerId,e.tail);case"start":return await this.startContainer(e.containerId);case"stop":return await this.stopContainer(e.containerId);case"restart":return await this.restartContainer(e.containerId);case"images":return await this.listImages();case"pull_image":return await this.pullImage(e.imageName,e.imageTag);case"remove_image":return await this.removeImage(e.imageName);case"networks":return await this.listNetworks();case"volumes":return await this.listVolumes();case"system_info":return await this.getSystemInfo();case"prune":return await this.pruneAll();case"compose_ps":return await this.composePs(e.project);case"compose_up":return await this.composeUp(e.project);case"compose_down":return await this.composeDown(e.project);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Docker API error: ${r instanceof Error?r.message:String(r)}`}}}api(e,t,s){return new Promise((r,n)=>{let o={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let c=new URL(this.config.host);o.hostname=c.hostname,o.port=c.port}else o.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?tu:eu).request(o,c=>{let d="";c.on("data",u=>{d+=u}),c.on("end",()=>{if(c.statusCode&&c.statusCode>=400){n(new Error(`Docker API ${c.statusCode}: ${d.slice(0,500)}`));return}try{r(d?JSON.parse(d):void 0)}catch{n(new Error(`Invalid JSON from Docker API: ${d.slice(0,200)}`))}})});a.on("error",n),a.setTimeout(3e4,()=>{a.destroy(),n(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}apiRaw(e,t,s){return new Promise((r,n)=>{let o={method:e,path:`/v1.45${t}`,headers:{"Content-Type":"application/json"}};if(this.config.host){let c=new URL(this.config.host);o.hostname=c.hostname,o.port=c.port}else o.socketPath=this.config.socketPath??this.defaultSocket;let a=(this.config.host?.startsWith("https")?tu:eu).request(o,c=>{let d=[];c.on("data",u=>{d.push(u)}),c.on("end",()=>{if(c.statusCode&&c.statusCode>=400){let u=Buffer.concat(d).toString("utf8");n(new Error(`Docker API ${c.statusCode}: ${u.slice(0,500)}`));return}r(Buffer.concat(d).toString("binary"))})});a.on("error",n),a.setTimeout(3e4,()=>{a.destroy(),n(new Error("Docker API timeout"))}),s&&a.write(JSON.stringify(s)),a.end()})}async listContainers(){let e=await this.api("GET","/containers/json?all=true"),t=["## Docker Containers","","| Name | Image | Status | Ports |","|------|-------|--------|-------|"];for(let s of e)t.push(`| ${fa(s.Names)} | ${s.Image??"-"} | ${s.Status??s.State??"-"} | ${ru(s.Ports)} |`);return e.length===0&&t.push("| - | No containers found | - | - |"),{success:!0,data:e,display:t.join(`
|
|
953
|
+
`)}}async inspectContainer(e){if(!e)return{success:!1,error:'Missing required "containerId" parameter'};let t=await this.api("GET",`/containers/${encodeURIComponent(e)}/json`),s=t.State??{},r=t.Config??{},n=t.NetworkSettings??{},o=t.Mounts??[],a=Object.entries(n.Ports??{}).filter(([,p])=>p&&p.length>0).map(([p,h])=>`${h.map(g=>`${g.HostIp??"0.0.0.0"}:${g.HostPort}`).join(", ")} -> ${p}`),c=o.map(p=>`- ${p.Source??"-"} -> ${p.Destination??"-"} (${p.Type??"-"}, ${p.RW?"rw":"ro"})`),d=n.IPAddress||Object.values(n.Networks??{}).map(p=>p.IPAddress).filter(Boolean).join(", ")||"-",u=[`## Container: ${fa(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(`
|
|
938
954
|
`):"- No port bindings","","### Mounts",c.length>0?c.join(`
|
|
939
955
|
`):"- No mounts"];return{success:!0,data:t,display:u.join(`
|
|
940
|
-
`)}}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}`),n=
|
|
941
|
-
`)}}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 n=(s.RepoTags??["<none>:<none>"]).join(", "),o=
|
|
956
|
+
`)}}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}`),n=jh(r),o=[`## Logs: ${e} (last ${s} lines)`,"","```",n.trimEnd(),"```"];return{success:!0,data:n,display:o.join(`
|
|
957
|
+
`)}}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 n=(s.RepoTags??["<none>:<none>"]).join(", "),o=ha(s.Size),i=Bh(s.Created);t.push(`| ${n} | ${o} | ${i} |`)}return e.length===0&&t.push("| - | No images found | - |"),{success:!0,data:e,display:t.join(`
|
|
942
958
|
`)}}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(o=>o.Deleted).map(o=>o.Deleted),r=(t??[]).filter(o=>o.Untagged).map(o=>o.Untagged),n=[`**Image removed:** \`${e}\``,"",`**Untagged:** ${r.length>0?r.join(", "):"-"}`,`**Deleted layers:** ${s.length}`];return{success:!0,data:t,display:n.join(`
|
|
943
959
|
`)}}async listNetworks(){let e=await this.api("GET","/networks"),t=["## Docker Networks","","| Name | Driver | Scope | Subnet |","|------|--------|-------|--------|"];for(let s of e){let n=(s.IPAM?.Config??[]).map(o=>o.Subnet).filter(Boolean).join(", ")||"-";t.push(`| ${s.Name??"-"} | ${s.Driver??"-"} | ${s.Scope??"-"} | ${n} |`)}return e.length===0&&t.push("| - | No networks found | - | - |"),{success:!0,data:e,display:t.join(`
|
|
944
960
|
`)}}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(`
|
|
945
|
-
`)}}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:** ${
|
|
946
|
-
`)}}async pruneAll(){let[e,t,s,r]=await Promise.all([this.api("POST","/containers/prune"),this.api("POST","/images/prune"),this.api("POST","/volumes/prune"),this.api("POST","/networks/prune")]),n=e.ContainersDeleted?.length??0,o=t.ImagesDeleted?.length??0,i=s.VolumesDeleted?.length??0,a=r.NetworksDeleted?.length??0,c=(e.SpaceReclaimed??0)+(t.SpaceReclaimed??0)+(s.SpaceReclaimed??0),d=["## Docker Prune Results","",`**Containers removed:** ${n}`,`**Images removed:** ${o}`,`**Volumes removed:** ${i}`,`**Networks removed:** ${a}`,"",`**Total space reclaimed:** ${
|
|
961
|
+
`)}}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:** ${ha(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(`
|
|
962
|
+
`)}}async pruneAll(){let[e,t,s,r]=await Promise.all([this.api("POST","/containers/prune"),this.api("POST","/images/prune"),this.api("POST","/volumes/prune"),this.api("POST","/networks/prune")]),n=e.ContainersDeleted?.length??0,o=t.ImagesDeleted?.length??0,i=s.VolumesDeleted?.length??0,a=r.NetworksDeleted?.length??0,c=(e.SpaceReclaimed??0)+(t.SpaceReclaimed??0)+(s.SpaceReclaimed??0),d=["## Docker Prune Results","",`**Containers removed:** ${n}`,`**Images removed:** ${o}`,`**Volumes removed:** ${i}`,`**Networks removed:** ${a}`,"",`**Total space reclaimed:** ${ha(c)}`];return{success:!0,data:{containers:e,images:t,volumes:s,networks:r},display:d.join(`
|
|
947
963
|
`)}}async composePs(e){let s=(await this.api("GET","/containers/json?all=true")).filter(o=>o.Labels?.["com.docker.compose.project"]),r=new Map;for(let o of s){let i=o.Labels["com.docker.compose.project"];e&&i!==e||(r.has(i)||r.set(i,[]),r.get(i).push(o))}let n=["## Docker Compose Projects",""];if(r.size===0)return n.push(e?`No containers found for project "${e}".`:"No Compose-managed containers found."),{success:!0,data:[],display:n.join(`
|
|
948
|
-
`)};for(let[o,i]of r){n.push(`### ${o}`),n.push(""),n.push("| Service | Name | Status | Ports |"),n.push("|---------|------|--------|-------|");for(let a of i){let c=a.Labels?.["com.docker.compose.service"]??"-";n.push(`| ${c} | ${
|
|
949
|
-
`)}}async composeUp(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await
|
|
964
|
+
`)};for(let[o,i]of r){n.push(`### ${o}`),n.push(""),n.push("| Service | Name | Status | Ports |"),n.push("|---------|------|--------|-------|");for(let a of i){let c=a.Labels?.["com.docker.compose.service"]??"-";n.push(`| ${c} | ${fa(a.Names)} | ${a.Status??a.State??"-"} | ${ru(a.Ports)} |`)}n.push("")}return{success:!0,data:[...r.entries()],display:n.join(`
|
|
965
|
+
`)}}async composeUp(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await su("docker",["compose","-p",e,"up","-d"],{timeout:12e4}),r=(t+`
|
|
950
966
|
`+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose up:** \`${e}\``,"","```",r,"```"].join(`
|
|
951
|
-
`)}}async composeDown(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await
|
|
967
|
+
`)}}async composeDown(e){if(!e)return{success:!1,error:'Missing required "project" parameter'};let{stdout:t,stderr:s}=await su("docker",["compose","-p",e,"down"],{timeout:12e4}),r=(t+`
|
|
952
968
|
`+s).trim();return{success:!0,data:{project:e,output:r},display:[`**Compose down:** \`${e}\``,"","```",r,"```"].join(`
|
|
953
|
-
`)}}}});import{readFile as
|
|
954
|
-
`)}}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(
|
|
955
|
-
`)}}async fetchVin(e){let t=await fetch(`${
|
|
956
|
-
`)}}async getCharging(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),n=(await this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`)).telematicData??{},o=Te(n,"vehicle.drivetrain.electricEngine.charging.status"),i=Te(n,"vehicle.drivetrain.batteryManagement.header"),a=Te(n,"vehicle.drivetrain.electricEngine.charging.level"),c=Te(n,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=Te(n,"vehicle.powertrain.electric.battery.charging.power"),u=Te(n,"vehicle.drivetrain.electricEngine.charging.hvStatus"),p=Te(n,"vehicle.powertrain.electric.battery.stateOfCharge.target"),h=Te(n,"vehicle.drivetrain.electricEngine.charging.acVoltage"),
|
|
957
|
-
`)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),n=new Date,o=s??n.toISOString(),i=t??new Date(n.getTime()-720*60*6e4).toISOString(),a=await this.apiGet(`/customers/vehicles/${r}/chargingHistory?from=${encodeURIComponent(i)}&to=${encodeURIComponent(o)}`),c=a.data??a.chargingSessions??[],d=[`## BMW Lade-Sessions (${i.slice(0,10)} \u2013 ${o.slice(0,10)})`,"","| Start | Ende | Dauer | Energie | Start-SoC | End-SoC | km-Stand | Ort |","|-------|------|-------|---------|-----------|---------|----------|-----|"];for(let u of c.slice(0,20)){let p=u.startTime,h=u.endTime,
|
|
958
|
-
`)}}async getConsumption(e,t){let s=await this.resolveVin(e),r=await this.resolveContainerId(),n=new Date,i={last:7,week:7,month:30,year:365,all:730}[t??"month"]??30,a=new Date(n.getTime()-i*864e5).toISOString(),c=n.toISOString(),[d,u]=await Promise.all([this.apiGet(`/customers/vehicles/${s}/chargingHistory?from=${encodeURIComponent(a)}&to=${encodeURIComponent(c)}`),this.apiGet(`/customers/vehicles/${s}/telematicData?containerId=${r}`)]),p=d.data??d.chargingSessions??[],h=parseFloat(Te(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(p.length<2)return{success:!0,data:{sessions:p.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let
|
|
959
|
-
`)}}let y=
|
|
960
|
-
`)}}}});var
|
|
969
|
+
`)}}}});import{readFile as ou,writeFile as iu,mkdir as au,chmod as Hh}from"node:fs/promises";import{homedir as ga}from"node:os";import{join as ya}from"node:path";import du from"node:crypto";function Xh(){let l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",e=du.randomBytes(86);return Array.from(e).map(t=>l[t%l.length]).join("")}function Kh(l){return du.createHash("sha256").update(l).digest("base64url")}function Te(l,e){return l[e]?.value??"?"}var Wh,cu,go,zh,qh,Gh,lu,Gr,Vh,yo,uu=T(()=>{"use strict";W();Wh="https://customer.bmwgroup.com/gcdm/oauth/device/code",cu="https://customer.bmwgroup.com/gcdm/oauth/token",go="https://api-cardata.bmwgroup.com",zh="v1",qh="authenticate_user openid cardata:api:read cardata:streaming:read",Gh=5*6e4,lu="Alfred",Gr=ya(ga(),".alfred","bmw-tokens.json");m(Xh,"generateCodeVerifier");m(Kh,"generateCodeChallenge");Vh=["vehicle.drivetrain.batteryManagement.header","vehicle.drivetrain.batteryManagement.maxEnergy","vehicle.drivetrain.batteryManagement.batterySizeMax","vehicle.powertrain.electric.battery.stateOfHealth.displayed","vehicle.powertrain.electric.battery.stateOfCharge.target","vehicle.drivetrain.electricEngine.remainingElectricRange","vehicle.drivetrain.electricEngine.charging.status","vehicle.drivetrain.electricEngine.charging.level","vehicle.drivetrain.electricEngine.charging.timeRemaining","vehicle.drivetrain.electricEngine.charging.timeToFullyCharged","vehicle.drivetrain.electricEngine.charging.hvStatus","vehicle.drivetrain.electricEngine.charging.method","vehicle.drivetrain.electricEngine.charging.phaseNumber","vehicle.drivetrain.electricEngine.charging.lastChargingReason","vehicle.drivetrain.electricEngine.charging.lastChargingResult","vehicle.drivetrain.electricEngine.charging.reasonChargingEnd","vehicle.powertrain.electric.battery.charging.power","vehicle.drivetrain.electricEngine.charging.acVoltage","vehicle.drivetrain.electricEngine.charging.acAmpere","vehicle.powertrain.electric.battery.charging.acLimit.selected","vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged","vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen","vehicle.body.chargingPort.lockedStatus","vehicle.body.chargingPort.plugEventId","vehicle.powertrain.electric.battery.preconditioning.automaticMode.statusFeedback","vehicle.powertrain.electric.battery.preconditioning.manualMode.statusFeedback","vehicle.vehicle.avgAuxPower","vehicle.trip.segment.end.drivetrain.batteryManagement.hvSoc","vehicle.trip.segment.accumulated.drivetrain.electricEngine.recuperationTotal","vehicle.vehicleIdentification.basicVehicleData"];m(Te,"tv");yo=class extends x{static{m(this,"BMWSkill")}metadata={name:"bmw",category:"infrastructure",description:'BMW CarData \u2014 Fahrzeugdaten abrufen. "authorize" startet den Device-Auth-Flow (einmalig). WICHTIG: authorize ist ein 2-Schritt-Prozess. Schritt 1 (ohne device_code) liefert einen User-Code + URL. Schritt 2: Nachdem der User im Browser best\xE4tigt hat, rufe authorize ERNEUT auf \u2014 entweder mit dem device_code aus Schritt 1, oder einfach ohne Parameter (auto-resume). NIEMALS Schritt 1 wiederholen wenn bereits ein Code ausgegeben wurde! "status" zeigt SoC, Reichweite, Modell, Batterie-Gesundheit. "charging" zeigt Ladestatus, Leistung, Restzeit, Ziel-SoC, Stecker. "charging_sessions" listet Lade-Sessions (from/to Zeitraum). "consumption" berechnet Durchschnittsverbrauch (kWh/100km) aus Lade-Sessions \u2014 optional mit period: "last" (letzte Fahrt), "week", "month", "year", "all" (default: month).',riskLevel:"read",version:"2.2.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["authorize","status","charging","charging_sessions","consumption"],description:"BMW CarData action"},vin:{type:"string",description:"Vehicle Identification Number (optional \u2014 uses stored VIN if omitted)"},device_code:{type:"string",description:"Device code from authorize step 1 (optional \u2014 if omitted, auto-resumes pending authorization)"},from:{type:"string",description:"ISO date-time start for charging_sessions (required for that action)"},to:{type:"string",description:"ISO date-time end for charging_sessions (required for that action)"},period:{type:"string",enum:["last","week","month","year","all"],description:"Zeitraum f\xFCr consumption: last (letzte Fahrt), week, month, year, all (default: month)"}},required:["action"]}};config;tokens=null;cache=new Map;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"authorize":return await this.authorize(e.device_code);case"status":return await this.getStatus(e.vin);case"charging":return await this.getCharging(e.vin);case"charging_sessions":return await this.getChargingSessions(e.vin,e.from,e.to);case"consumption":return await this.getConsumption(e.vin,e.period);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`BMW API error: ${r instanceof Error?r.message:String(r)}`}}}async authorize(e){if(e)return await this.pollToken(e);let t=await this.loadTokensFromDisk();if(t?.deviceCode&&t?.codeVerifier)try{return await this.pollToken(t.deviceCode)}catch{}let s=Xh(),r=Kh(s),n=await fetch(Wh,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,response_type:"device_code",code_challenge:r,code_challenge_method:"S256",scope:qh}),signal:AbortSignal.timeout(15e3)});if(!n.ok){let a=await n.text().catch(()=>"");throw new Error(`Device code request failed: HTTP ${n.status} \u2014 ${a.slice(0,300)}`)}let o=await n.json(),i={codeVerifier:s,deviceCode:o.device_code};return await this.savePartialTokens(i),this.tokens=null,{success:!0,data:o,display:["## BMW Autorisierung","",`1. \xD6ffne: **${o.verification_uri_complete??o.verification_uri}**`,`2. Gib diesen Code ein: **${o.user_code}**`,"","Danach rufe einfach `authorize` erneut auf (ohne Parameter) \u2014 der Token wird automatisch abgeholt."].join(`
|
|
970
|
+
`)}}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(cu,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,device_code:e,grant_type:"urn:ietf:params:oauth:grant-type:device_code",code_verifier:s}),signal:AbortSignal.timeout(15e3)});if(!r.ok){let p=await r.text().catch(()=>"");if(p.includes("authorization_pending"))return{success:!0,data:{status:"pending"},display:"Autorisierung noch ausstehend \u2014 bitte zuerst im Browser best\xE4tigen, dann erneut versuchen."};throw new Error(`Token poll failed: HTTP ${r.status} \u2014 ${p.slice(0,300)}`)}let n=await r.json(),o=n.access_token,i={accessToken:o,refreshToken:n.refresh_token,idToken:n.id_token,expiresAt:Date.now()+(n.expires_in??3600)*1e3,vin:"",containerId:""},a=await this.fetchVin(o);i.vin=a,await this.saveTokens(i);let c="",d="";try{c=await this.ensureContainer(o),i.containerId=c,await this.saveTokens(i)}catch(p){d=p instanceof Error?p.message:String(p)}this.tokens=i;let u=["## BMW Autorisierung erfolgreich","",`**VIN:** ${a}`];return c?(u.push(`**Container:** ${c}`),u.push("Tokens gespeichert. Du kannst jetzt Fahrzeugdaten abrufen.")):(u.push(`**Container-Fehler:** ${d}`),u.push("Tokens + VIN gespeichert, aber Container konnte nicht erstellt werden."),u.push("Erstelle den Container manuell im BMW CarData Portal oder versuche es erneut.")),{success:c!=="",data:{vin:a,containerId:c,containerError:d||void 0},display:u.join(`
|
|
971
|
+
`)}}async fetchVin(e){let t=await fetch(`${go}/customers/vehicles/mappings`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(!t.ok)throw new Error(`Failed to fetch vehicles: HTTP ${t.status}`);let s=await t.json();if(typeof s.vin=="string")return s.vin;if(Array.isArray(s)){let r=s;return r.find(o=>o.mappingType==="PRIMARY")?.vin??r[0]?.vin??(()=>{throw new Error("No vehicles found")})()}throw new Error(`No vehicles found in account (response: ${JSON.stringify(s).slice(0,200)})`)}async ensureContainer(e){let t=await fetch(`${go}/customers/containers`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(t.ok){let n=await t.json(),i=(Array.isArray(n)?n:Array.isArray(n.containers)?n.containers:[]).find(a=>a.name===lu);if(i)return i.containerId}let s=await fetch(`${go}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:lu,purpose:"Alfred AI Assistant",technicalDescriptors:Vh}),signal:AbortSignal.timeout(15e3)});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Container creation failed: HTTP ${s.status} \u2014 ${n.slice(0,300)}`)}return(await s.json()).containerId}apiHeaders(e){return{Authorization:`Bearer ${e}`,"x-version":zh,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<Gh)return s.data;let r=await this.ensureToken(),n=`${go}${e}`,o=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)});if(o.status===401){let a=await this.loadTokens();a&&(r=await this.refreshAccessToken(a),o=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)}))}if(!o.ok){let a=await o.text().catch(()=>"");throw new Error(`HTTP ${o.status} \u2014 ${a.slice(0,300)}`)}let i=await o.json();return this.cache.set(t,{data:i,ts:Date.now()}),i}async loadTokens(){return this.tokens?this.tokens:await this.loadTokensFromDisk()}async loadTokensFromDisk(){try{let e=await ou(Gr,"utf-8"),t=JSON.parse(e);return this.tokens=t,t}catch{return null}}async saveTokens(e){await au(ya(ga(),".alfred"),{recursive:!0}),await iu(Gr,JSON.stringify(e,null,2),"utf-8");try{await Hh(Gr,384)}catch{}}async savePartialTokens(e){await au(ya(ga(),".alfred"),{recursive:!0});let t={};try{let s=await ou(Gr,"utf-8");t=JSON.parse(s)}catch{}await iu(Gr,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(cu,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.config.clientId,grant_type:"refresh_token",refresh_token:e.refreshToken}),signal:AbortSignal.timeout(15e3)});if(!t.ok)throw this.tokens=null,new Error('Token-Refresh fehlgeschlagen. Bitte erneut "authorize" aufrufen.');let s=await t.json(),r={...e,accessToken:s.access_token,refreshToken:s.refresh_token??e.refreshToken,idToken:s.id_token??e.idToken,expiresAt:Date.now()+(s.expires_in??3600)*1e3};return delete r.codeVerifier,delete r.deviceCode,await this.saveTokens(r),this.tokens=r,r.accessToken}async resolveVin(e){if(e)return e;let t=await this.loadTokens();if(t?.vin)return t.vin;throw new Error('Keine VIN angegeben und keine gespeicherte VIN gefunden. Bitte zuerst "authorize" aufrufen.')}async resolveContainerId(){let e=await this.loadTokens();if(e?.containerId)return e.containerId;throw new Error('Kein Container gefunden. Bitte zuerst "authorize" aufrufen.')}async getStatus(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),[r,n]=await Promise.all([this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`),this.apiGet(`/customers/vehicles/${t}/basicData`)]),o=r.telematicData??{},i=Te(o,"vehicle.drivetrain.batteryManagement.header"),a=Te(o,"vehicle.drivetrain.electricEngine.remainingElectricRange"),c=Te(o,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=Te(o,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),p=["## BMW Fahrzeugstatus","",`**Modell:** ${n.modelName??n.model??"?"}`,`**VIN:** ${t}`,`**Ladestand (SoC):** ${i} %`,`**Elektrische Reichweite:** ${a} km`,`**Batteriekapazit\xE4t:** ${c} kWh`,`**Batterie-Gesundheit (SoH):** ${d} %`];return{success:!0,data:{telematic:o,basic:n},display:p.join(`
|
|
972
|
+
`)}}async getCharging(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),n=(await this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`)).telematicData??{},o=Te(n,"vehicle.drivetrain.electricEngine.charging.status"),i=Te(n,"vehicle.drivetrain.batteryManagement.header"),a=Te(n,"vehicle.drivetrain.electricEngine.charging.level"),c=Te(n,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=Te(n,"vehicle.powertrain.electric.battery.charging.power"),u=Te(n,"vehicle.drivetrain.electricEngine.charging.hvStatus"),p=Te(n,"vehicle.powertrain.electric.battery.stateOfCharge.target"),h=Te(n,"vehicle.drivetrain.electricEngine.charging.acVoltage"),f=Te(n,"vehicle.drivetrain.electricEngine.charging.acAmpere"),g=Te(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"),y=Te(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen"),_=Te(n,"vehicle.body.chargingPort.lockedStatus"),S=["## BMW Ladestatus","",`**Status:** ${o}`,`**Ladestand:** ${i} %`,`**Ladelevel:** ${a}`,`**Ladeleistung:** ${d} kW`,`**Restzeit:** ${c} min`,`**Ziel-SoC:** ${p} %`,`**HV-Batterie:** ${u}`,`**AC Spannung:** ${h} V`,`**AC Strom:** ${f} A`,`**Stecker eingesteckt:** ${g}`,`**Ladeklappe offen:** ${y}`,`**Ladeport-Schloss:** ${_}`];return{success:!0,data:n,display:S.join(`
|
|
973
|
+
`)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),n=new Date,o=s??n.toISOString(),i=t??new Date(n.getTime()-720*60*6e4).toISOString(),a=await this.apiGet(`/customers/vehicles/${r}/chargingHistory?from=${encodeURIComponent(i)}&to=${encodeURIComponent(o)}`),c=a.data??a.chargingSessions??[],d=[`## BMW Lade-Sessions (${i.slice(0,10)} \u2013 ${o.slice(0,10)})`,"","| Start | Ende | Dauer | Energie | Start-SoC | End-SoC | km-Stand | Ort |","|-------|------|-------|---------|-----------|---------|----------|-----|"];for(let u of c.slice(0,20)){let p=u.startTime,h=u.endTime,f=m(P=>new Date(P*1e3).toLocaleString("de-AT",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"}),"fmtDateTime"),g=p?f(p):"-",y=h?f(h):"-",_=u.totalChargingDurationSec,S=_!=null?Math.round(_/60):"-",b=u.energyConsumedFromPowerGridKwh??"-",$=u.displayedStartSoc??"-",N=u.displayedSoc??"-",M=u.mileage!=null?`${u.mileage}`:"-",J=u.chargingLocation,V=J?.formattedAddress??J?.streetAddress??"-";d.push(`| ${g} | ${y} | ${S} min | ${b} kWh | ${$}% | ${N}% | ${M} | ${V} |`)}return c.length===0&&d.push("| - | - | Keine Sessions gefunden | - | - | - | - | - |"),{success:!0,data:a,display:d.join(`
|
|
974
|
+
`)}}async getConsumption(e,t){let s=await this.resolveVin(e),r=await this.resolveContainerId(),n=new Date,i={last:7,week:7,month:30,year:365,all:730}[t??"month"]??30,a=new Date(n.getTime()-i*864e5).toISOString(),c=n.toISOString(),[d,u]=await Promise.all([this.apiGet(`/customers/vehicles/${s}/chargingHistory?from=${encodeURIComponent(a)}&to=${encodeURIComponent(c)}`),this.apiGet(`/customers/vehicles/${s}/telematicData?containerId=${r}`)]),p=d.data??d.chargingSessions??[],h=parseFloat(Te(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(p.length<2)return{success:!0,data:{sessions:p.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let f=p.filter(P=>typeof P.mileage=="number"&&typeof P.displayedStartSoc=="number"&&typeof P.displayedSoc=="number").sort((P,ee)=>P.mileage-ee.mileage);if(f.length<2)return{success:!0,data:{sessions:f.length},display:"Nicht gen\xFCgend Lade-Sessions mit vollst\xE4ndigen Daten."};let g=[];for(let P=1;P<f.length;P++){let ee=f[P-1],ue=f[P],L=ee.mileage,se=ue.mileage,ne=se-L;if(ne<=0)continue;let Z=ee.displayedSoc,j=ue.displayedStartSoc,pe=Z-j;if(pe<=0)continue;let Xe=pe/100*h,ce=Xe/ne*100,be=ue.startTime,me=be?new Date(be*1e3).toLocaleDateString("de-AT"):"-";g.push({fromKm:L,toKm:se,distance:ne,socUsed:pe,kWhUsed:Xe,consumption:ce,date:me})}if(g.length===0)return{success:!0,data:{},display:"Keine auswertbaren Fahrtabschnitte gefunden."};if(t==="last"){let P=g[g.length-1];return{success:!0,data:P,display:["## Letzte Fahrt (gesch\xE4tzt)","",`**Datum:** ${P.date}`,`**Strecke:** ${P.distance} km`,`**Verbrauch:** ${P.consumption.toFixed(1)} kWh/100km`,`**Energie:** ${P.kWhUsed.toFixed(1)} kWh (${P.socUsed}% SoC)`,`**km-Stand:** ${P.fromKm} \u2192 ${P.toKm}`].join(`
|
|
975
|
+
`)}}let y=g.reduce((P,ee)=>P+ee.distance,0),_=g.reduce((P,ee)=>P+ee.kWhUsed,0),S=_/y*100,b=g.map(P=>P.consumption).sort((P,ee)=>P-ee),$=b[0],N=b[b.length-1],M=b[Math.floor(b.length/2)],V=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${h} kWh`,`**Ausgewertete Fahrten:** ${g.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${_.toFixed(1)} kWh`,"",`**Durchschnitt:** ${S.toFixed(1)} kWh/100km`,`**Min:** ${$.toFixed(1)} kWh/100km`,`**Max:** ${N.toFixed(1)} kWh/100km`,`**Median:** ${M.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let P of g)V.push(`| ${P.date} | ${P.distance} km | ${P.consumption.toFixed(1)} kWh/100km | ${P.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:S,totalDistance:y,totalKwh:_,segments:g},display:V.join(`
|
|
976
|
+
`)}}}});var Yh,wo,mu=T(()=>{"use strict";W();Yh="https://routes.googleapis.com/directions/v2:computeRoutes",wo=class extends x{static{m(this,"RoutingSkill")}metadata={name:"routing",category:"information",description:'Routenberechnung mit Live-Traffic via Google Routes API. "route" berechnet Route mit Distanz, Dauer und Dauer im aktuellen Verkehr. "departure_time" empfiehlt wann man losfahren soll, um zu einer bestimmten Zeit anzukommen. WICHTIG: Aliase wie "zuhause", "daheim", "home", "bei mir", "im B\xFCro", "work" VOR dem Tool-Call in konkrete Adressen aufl\xF6sen \u2014 daf\xFCr bekannte Adressen aus Memory/Kontext verwenden. Nie rohe Alias-Werte wie "home" oder "work" als origin/destination senden. Wenn keine Adresse im Kontext vorhanden ist, den User nach der Adresse fragen.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["route","departure_time"],description:"Routing action"},origin:{type:"string",description:'Start-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},departure_time:{type:"string",description:"ISO-Zeitpunkt f\xFCr Abfahrt (optional, f\xFCr Traffic-Berechnung)"},arrival_time:{type:"string",description:"ISO-Zeitpunkt gew\xFCnschte Ankunft (f\xFCr departure_time-Action)"},travel_mode:{type:"string",enum:["DRIVE","BICYCLE","WALK","TRANSIT"],description:"Fortbewegungsart (Standard: DRIVE)"}},required:["action","origin","destination"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};let r=e.origin,n=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!n)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,n,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,n,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(o){return{success:!1,error:`Google Routes API error: ${o instanceof Error?o.message:String(o)}`}}}async computeRoute(e,t,s,r){let n=this.buildRequestBody(e,t,r,s),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=(i.distanceMeters/1e3).toFixed(1),c=this.parseDuration(i.duration),d=this.parseDuration(i.staticDuration),u=c-d,p=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(c)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(u>1&&p.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(u)}`),s){let h=new Date(new Date(s).getTime()+c*6e4);p.push(`**Gesch\xE4tzte Ankunft:** ${h.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:c,staticDurationMinutes:d},display:p.join(`
|
|
961
977
|
`)}}async computeDepartureTime(e,t,s,r){if(!s)return{success:!1,error:'Missing required field "arrival_time" for departure_time action'};let n=this.buildRequestBody(e,t,r),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=this.parseDuration(i.duration),c=Math.max(5,Math.round(a*.15)),d=new Date(s),u=new Date(d.getTime()-(a+c)*6e4),p=["## Abfahrtszeit-Empfehlung","",`**Route:** ${e} \u2192 ${t}`,`**Gew\xFCnschte Ankunft:** ${d.toLocaleString("de-AT")}`,`**Gesch\xE4tzte Fahrzeit:** ${this.formatMinutes(a)} (inkl. Verkehr)`,`**Puffer:** ${c} min`,"",`**Empfohlene Abfahrt:** ${u.toLocaleString("de-AT")}`];return{success:!0,data:{departureTime:u.toISOString(),durationMinutes:a,bufferMinutes:c},display:p.join(`
|
|
962
|
-
`)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",n=Math.abs(s),o=String(Math.floor(n/60)).padStart(2,"0"),i=String(n%60).padStart(2,"0"),a=m(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())}T${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}${r}${o}:${i}`}buildRequestBody(e,t,s,r,n){let o={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let i=this.normalizeTimestamp(r);new Date(i).getTime()>Date.now()+6e4&&(o.departureTime=i)}if(n){let i=this.normalizeTimestamp(n);new Date(i).getTime()>Date.now()+6e4&&(o.arrivalTime=i)}return o}async callRoutesApi(e){let t=await fetch(
|
|
963
|
-
`)}}async dayPrices(e){let t=new Date,s=new Date(t);e==="tomorrow"&&s.setDate(s.getDate()+1);let r=new Date(s);r.setHours(0,0,0,0);let n=new Date(r);n.setDate(n.getDate()+1);let o=await this.fetchMarketData(r.getTime(),n.getTime());if(o.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${e==="today"?"heute":"morgen"} verf\xFCgbar.${e==="tomorrow"?" Preise f\xFCr morgen sind ab ca. 14:00 verf\xFCgbar.":""}`};let i=e==="today"?"Heute":"Morgen",a=r.toLocaleDateString("de-AT"),c=[`## Strompreise ${i} (${a})`,""];c.push("| Uhrzeit | Markt ct/kWh | Brutto ct/kWh |"),c.push("|---|---|---|");let d=1/0,u=-1/0,p=0;for(let
|
|
978
|
+
`)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",n=Math.abs(s),o=String(Math.floor(n/60)).padStart(2,"0"),i=String(n%60).padStart(2,"0"),a=m(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())}T${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}${r}${o}:${i}`}buildRequestBody(e,t,s,r,n){let o={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let i=this.normalizeTimestamp(r);new Date(i).getTime()>Date.now()+6e4&&(o.departureTime=i)}if(n){let i=this.normalizeTimestamp(n);new Date(i).getTime()>Date.now()+6e4&&(o.arrivalTime=i)}return o}async callRoutesApi(e){let t=await fetch(Yh,{method:"POST",headers:{"Content-Type":"application/json","X-Goog-Api-Key":this.config.apiKey,"X-Goog-FieldMask":"routes.duration,routes.staticDuration,routes.distanceMeters,routes.legs"},body:JSON.stringify(e),signal:AbortSignal.timeout(15e3)});if(!t.ok){let s=await t.text().catch(()=>"");throw new Error(`HTTP ${t.status} \u2014 ${s.slice(0,300)}`)}return await t.json()}parseDuration(e){let t=e?.match(/(\d+)s/);return t?Math.round(parseInt(t[1],10)/60):0}formatMinutes(e){if(e<60)return`${e} min`;let t=Math.floor(e/60),s=e%60;return s>0?`${t} h ${s} min`:`${t} h`}}});var pu,hu,Jh,Zh,Qh,vs,fu,gu,yu,wa,Ta,wu,To,Tu=T(()=>{"use strict";W();pu=1.5,hu=4.79,Jh=5.75,Zh=1.03,Qh=new Date("2026-04-01T00:00:00+02:00"),vs=1.2,fu=.1,gu=.58,yu=.04,wa=.32,Ta=1.62,wu="https://api.awattar.at/v1/marketdata",To=class extends x{static{m(this,"EnergyPriceSkill")}metadata={name:"energy_price",category:"information",description:'Strompreise (aWATTar HOURLY Tarif, EPEX Spot AT). "current" zeigt den aktuellen Strompreis mit Aufschl\xFCsselung (Marktpreis, Netzentgelte, Abgaben, Brutto). "today" zeigt alle Stundenpreise f\xFCr heute. "tomorrow" zeigt Stundenpreise f\xFCr morgen (verf\xFCgbar ab ~14:00). "cheapest" findet die g\xFCnstigsten Stunden (Standard: 3 Stunden in den n\xE4chsten 24h). "average" zeigt den Durchschnittspreis f\xFCr heute oder ein bestimmtes Datum.',riskLevel:"read",version:"1.0.0",timeoutMs:15e3,inputSchema:{type:"object",properties:{action:{type:"string",enum:["current","today","tomorrow","cheapest","average","briefing"],description:"Aktion (briefing = kompakte Tages\xFCbersicht f\xFCr Morgenbriefing)"},hours:{type:"number",description:"F\xFCr cheapest: Anzahl g\xFCnstigster Stunden (Standard: 3)"},date:{type:"string",description:"ISO-Datum f\xFCr average (Standard: heute)"}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"current":return await this.current();case"today":return await this.dayPrices("today");case"tomorrow":return await this.dayPrices("tomorrow");case"cheapest":return await this.cheapest(e.hours);case"average":return await this.average(e.date);case"briefing":return await this.briefingSummary();default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`aWATTar API error: ${r instanceof Error?r.message:String(r)}`}}}async current(){let e=Date.now(),s=(await this.fetchMarketData()).find(i=>i.start_timestamp<=e&&i.end_timestamp>e);if(!s)return{success:!1,error:"Kein Marktpreis f\xFCr die aktuelle Stunde verf\xFCgbar."};let r=this.calculatePrice(s.marketprice),o=[`## Aktueller Strompreis (${this.formatHourRange(s.start_timestamp,s.end_timestamp)})`,""];return o.push(this.formatBreakdown(r)),{success:!0,data:r,display:o.join(`
|
|
979
|
+
`)}}async dayPrices(e){let t=new Date,s=new Date(t);e==="tomorrow"&&s.setDate(s.getDate()+1);let r=new Date(s);r.setHours(0,0,0,0);let n=new Date(r);n.setDate(n.getDate()+1);let o=await this.fetchMarketData(r.getTime(),n.getTime());if(o.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${e==="today"?"heute":"morgen"} verf\xFCgbar.${e==="tomorrow"?" Preise f\xFCr morgen sind ab ca. 14:00 verf\xFCgbar.":""}`};let i=e==="today"?"Heute":"Morgen",a=r.toLocaleDateString("de-AT"),c=[`## Strompreise ${i} (${a})`,""];c.push("| Uhrzeit | Markt ct/kWh | Brutto ct/kWh |"),c.push("|---|---|---|");let d=1/0,u=-1/0,p=0;for(let f of o){let g=this.calculatePrice(f.marketprice),y=this.formatHourRange(f.start_timestamp,f.end_timestamp),_=this.spotCtKwh(f.marketprice);c.push(`| ${y} | ${_.toFixed(2)} | ${g.bruttoCt.toFixed(2)} |`),d=Math.min(d,g.bruttoCt),u=Math.max(u,g.bruttoCt),p+=g.bruttoCt}let h=p/o.length;return c.push(""),c.push(`**Min:** ${d.toFixed(2)} ct/kWh | **Max:** ${u.toFixed(2)} ct/kWh | **\xD8:** ${h.toFixed(2)} ct/kWh`),{success:!0,data:{entries:o.length,min:d,max:u,avg:h},display:c.join(`
|
|
964
980
|
`)}}async cheapest(e){let t=e??3,s=Date.now(),r=s+1440*60*1e3,n=await this.fetchMarketData(s,r);if(n.length===0)return{success:!1,error:"Keine Preisdaten f\xFCr die n\xE4chsten 24 Stunden verf\xFCgbar."};let o=n.map(c=>({entry:c,breakdown:this.calculatePrice(c.marketprice)}));o.sort((c,d)=>c.breakdown.bruttoCt-d.breakdown.bruttoCt);let i=o.slice(0,Math.min(t,o.length));i.sort((c,d)=>c.entry.start_timestamp-d.entry.start_timestamp);let a=[`## ${t} g\xFCnstigste Stunden (n\xE4chste 24h)`,""];for(let{entry:c,breakdown:d}of i){let u=this.formatHourRange(c.start_timestamp,c.end_timestamp),p=new Date(c.start_timestamp).toLocaleDateString("de-AT",{weekday:"short"});a.push(`- **${p} ${u}**: ${d.bruttoCt.toFixed(2)} ct/kWh brutto (Markt: ${this.spotCtKwh(c.marketprice).toFixed(2)} ct/kWh)`)}return{success:!0,data:i.map(c=>({time:this.formatHourRange(c.entry.start_timestamp,c.entry.end_timestamp),bruttoCt:c.breakdown.bruttoCt})),display:a.join(`
|
|
965
981
|
`)}}async average(e){let t;e?(t=new Date(e),t.setHours(0,0,0,0)):(t=new Date,t.setHours(0,0,0,0));let s=new Date(t);s.setDate(s.getDate()+1);let r=await this.fetchMarketData(t.getTime(),s.getTime());if(r.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${t.toLocaleDateString("de-AT")} verf\xFCgbar.`};let n=0,o=0;for(let u of r)n+=this.spotCtKwh(u.marketprice),o+=this.calculatePrice(u.marketprice).bruttoCt;let i=n/r.length,a=o/r.length,c=t.toLocaleDateString("de-AT"),d=[`## Durchschnittspreis ${c}`,"",`**\xD8 Marktpreis:** ${i.toFixed(2)} ct/kWh`,`**\xD8 Brutto-Gesamtpreis:** ${a.toFixed(2)} ct/kWh`,"",`Basierend auf ${r.length} Stundenwerten.`];return{success:!0,data:{date:c,avgSpotCt:i,avgBruttoCt:a,hours:r.length},display:d.join(`
|
|
966
|
-
`)}}async briefingSummary(){let e=Date.now(),t=new Date;t.setHours(0,0,0,0);let s=new Date(t);s.setDate(s.getDate()+1);let r=await this.fetchMarketData(t.getTime(),s.getTime());if(r.length===0)return{success:!1,error:"Keine Preisdaten f\xFCr heute verf\xFCgbar."};let n=r.map(y=>({time:this.formatHourRange(y.start_timestamp,y.end_timestamp),bruttoCt:this.calculatePrice(y.marketprice).bruttoCt,start:y.start_timestamp,isCurrent:y.start_timestamp<=e&&y.end_timestamp>e,isPast:y.end_timestamp<=e})),o=n.find(y=>y.isCurrent),i=n.filter(y=>!y.isPast),a=n.map(y=>y.bruttoCt),c=a.reduce((y,
|
|
967
|
-
`)}}spotCtKwh(e){return e/10}calculatePrice(e){let t=this.spotCtKwh(e),s=new Date<
|
|
968
|
-
`)}async fetchMarketData(e,t){let s=new URLSearchParams;e!=null&&s.set("start",e.toString()),t!=null&&s.set("end",t.toString());let r=s.toString()?`${
|
|
982
|
+
`)}}async briefingSummary(){let e=Date.now(),t=new Date;t.setHours(0,0,0,0);let s=new Date(t);s.setDate(s.getDate()+1);let r=await this.fetchMarketData(t.getTime(),s.getTime());if(r.length===0)return{success:!1,error:"Keine Preisdaten f\xFCr heute verf\xFCgbar."};let n=r.map(y=>({time:this.formatHourRange(y.start_timestamp,y.end_timestamp),bruttoCt:this.calculatePrice(y.marketprice).bruttoCt,start:y.start_timestamp,isCurrent:y.start_timestamp<=e&&y.end_timestamp>e,isPast:y.end_timestamp<=e})),o=n.find(y=>y.isCurrent),i=n.filter(y=>!y.isPast),a=n.map(y=>y.bruttoCt),c=a.reduce((y,_)=>y+_,0)/a.length,d=Math.min(...a),u=Math.max(...a),p=[...i].sort((y,_)=>y.bruttoCt-_.bruttoCt),h=p.slice(0,3),f=p.slice(-3).reverse(),g=[];o&&g.push(`**Aktuell (${o.time}):** ${o.bruttoCt.toFixed(2)} ct/kWh brutto`),g.push(`**Tagesdurchschnitt:** ${c.toFixed(2)} ct/kWh | **Min:** ${d.toFixed(2)} | **Max:** ${u.toFixed(2)}`),g.push(""),g.push("**G\xFCnstigste 3 Stunden (Rest des Tages):**");for(let y of h)g.push(`- ${y.time}: ${y.bruttoCt.toFixed(2)} ct/kWh`);g.push(""),g.push("**Teuerste 3 Stunden (Rest des Tages):**");for(let y of f)g.push(`- ${y.time}: ${y.bruttoCt.toFixed(2)} ct/kWh`);return{success:!0,data:{currentCt:o?.bruttoCt,avgCt:c,minCt:d,maxCt:u,cheapest:h.map(y=>({time:y.time,bruttoCt:y.bruttoCt})),expensive:f.map(y=>({time:y.time,bruttoCt:y.bruttoCt}))},display:g.join(`
|
|
983
|
+
`)}}spotCtKwh(e){return e/10}calculatePrice(e){let t=this.spotCtKwh(e),s=new Date<Qh,n=(s?t*Zh:t)+pu,o=this.getGridCosts(),i=o.usageCt+o.lossCt,a=fu+gu+yu,c=n+i+a,d=c*vs;return{spotCt:t,ausgleichCt:s?t*.03:0,aufschlagCt:pu,energieNettoCt:n,netznutzungCt:o.usageCt,netzverlustCt:o.lossCt,eAbgabeCt:fu,oekoArbeitCt:gu,oekoVerlustCt:yu,gesamtNettoCt:c,ustCt:c*.2,bruttoCt:d,gridName:o.name,hasGrid:o.usageCt>0}}getGridCosts(){let e=this.config?.gridUsageCt??0,t=this.config?.gridLossCt??0,s=this.config?.gridName??"";return e>0?{name:s,usageCt:e,lossCt:t}:{name:"",usageCt:0,lossCt:0}}formatBreakdown(e){let t=["| Komponente | ct/kWh |","|---|---:|",`| EPEX Spot Marktpreis | ${e.spotCt.toFixed(2)} |`];e.ausgleichCt>0&&t.push(`| Ausgleichsenergie (3%) | ${e.ausgleichCt.toFixed(2)} |`),t.push(`| aWATTar Aufschlag | ${e.aufschlagCt.toFixed(2)} |`),t.push(`| **Energie netto** | **${e.energieNettoCt.toFixed(2)}** |`),e.hasGrid&&(t.push(`| Netznutzung (${e.gridName}) | ${e.netznutzungCt.toFixed(2)} |`),t.push(`| Netzverlust | ${e.netzverlustCt.toFixed(2)} |`)),t.push(`| Elektrizit\xE4tsabgabe | ${e.eAbgabeCt.toFixed(2)} |`),t.push(`| \xD6kostrom-F\xF6rderbeitrag | ${e.oekoArbeitCt.toFixed(2)} |`),t.push(`| \xD6kostrom-Verlust | ${e.oekoVerlustCt.toFixed(2)} |`),t.push(`| **Gesamt netto** | **${e.gesamtNettoCt.toFixed(2)}** |`),t.push(`| USt (20%) | ${e.ustCt.toFixed(2)} |`),t.push(`| **Gesamt brutto** | **${e.bruttoCt.toFixed(2)}** |`),e.hasGrid||(t.push(""),t.push("*Netzentgelte nicht inkludiert \u2014 Netzkosten via `alfred setup` oder ENV konfigurieren*"));let s=this.config?.gridCapacityFee??0,r=this.config?.gridMeterFee??0;if(t.push(""),t.push("**Fixe Monatskosten (netto \u2192 brutto):**"),t.push(`- aWATTar Grundgeb\xFChr: ${hu.toFixed(2)} \u20AC \u2192 ${Jh.toFixed(2)} \u20AC`),s>0){let i=this.config?.gridName?` (${this.config.gridName})`:"";t.push(`- Leistungspauschale${i}: ${s.toFixed(2)} \u20AC \u2192 ${(s*vs).toFixed(2)} \u20AC`)}r>0&&t.push(`- Messentgelt: ${r.toFixed(2)} \u20AC \u2192 ${(r*vs).toFixed(2)} \u20AC`),t.push(`- \xD6kostrom-F\xF6rderpauschale: ${wa.toFixed(2)} \u20AC \u2192 ${(wa*vs).toFixed(2)} \u20AC`),t.push(`- Erneuerbaren-F\xF6rderpauschale: ${Ta.toFixed(2)} \u20AC \u2192 ${(Ta*vs).toFixed(2)} \u20AC`);let n=hu+wa+Ta+s+r,o=n*vs;return t.push(`- **Summe:** ${n.toFixed(2)} \u20AC \u2192 **${o.toFixed(2)} \u20AC brutto/Monat**`),t.join(`
|
|
984
|
+
`)}async fetchMarketData(e,t){let s=new URLSearchParams;e!=null&&s.set("start",e.toString()),t!=null&&s.set("end",t.toString());let r=s.toString()?`${wu}?${s}`:wu,n=await fetch(r,{signal:AbortSignal.timeout(1e4)});if(!n.ok){let i=await n.text().catch(()=>"");throw new Error(`HTTP ${n.status} \u2014 ${i.slice(0,300)}`)}return(await n.json()).data||[]}formatHourRange(e,t){let s=new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}),r=new Date(t).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"});return`${s}\u2013${r}`}}});var $s,_u=T(()=>{"use strict";W();$s=class extends x{static{m(this,"TransitSkill")}metadata={name:"transit_search",category:"information",description:'\xD6ffentlicher Nahverkehr in \xD6sterreich (\xD6BB, Wiener Linien, etc.). "search_stop" sucht Haltestellen nach Name. "journeys" berechnet Verbindungen zwischen zwei Orten (Name oder Stop-ID). "departures" zeigt Abfahrten an einer Haltestelle (Stop-ID erforderlich, zuerst search_stop verwenden). Deckt Busse, Stra\xDFenbahnen, U-Bahn, S-Bahn, Regionalz\xFCge und Fernz\xFCge ab.',riskLevel:"read",version:"1.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["journeys","departures","search_stop"],description:"Transit action"},query:{type:"string",description:"Haltestellenname f\xFCr search_stop"},from:{type:"string",description:"Start-Haltestelle (Name oder ID) f\xFCr journeys"},to:{type:"string",description:"Ziel-Haltestelle (Name oder ID) f\xFCr journeys"},stop_id:{type:"string",description:"Stop-ID f\xFCr departures (von search_stop erhalten)"},departure:{type:"string",description:"ISO-Zeitpunkt f\xFCr gew\xFCnschte Abfahrt (optional)"},arrival:{type:"string",description:"ISO-Zeitpunkt f\xFCr gew\xFCnschte Ankunft (optional, nur f\xFCr journeys)"},results:{type:"number",description:"Anzahl Ergebnisse (Standard: 3)"},duration:{type:"number",description:"Zeitfenster in Minuten f\xFCr departures (Standard: 30)"}},required:["action"]}};client;constructor(e){super(),this.client=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"search_stop":return await this.searchStop(e);case"journeys":return await this.findJourneys(e);case"departures":return await this.findDepartures(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Transit API error: ${r instanceof Error?r.message:String(r)}`}}}async searchStop(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query" for search_stop'};let s=await this.client.searchStops(t);if(s.length===0)return{success:!0,data:[],display:`Keine Haltestellen gefunden f\xFCr "${t}".`};let r=["## Haltestellen",""];for(let n of s.slice(0,10))r.push(`- **${n.name}** (ID: \`${n.id}\`)`);return{success:!0,data:s,display:r.join(`
|
|
969
985
|
`)}}async findJourneys(e){let t=e.from,s=e.to;if(!t)return{success:!1,error:'Missing required field "from" for journeys'};if(!s)return{success:!1,error:'Missing required field "to" for journeys'};let r={};e.departure&&(r.departure=new Date(e.departure)),e.arrival&&(r.arrival=new Date(e.arrival)),e.results&&(r.results=e.results);let n=await this.client.journeys(t,s,r);if(n.length===0)return{success:!0,data:[],display:`Keine Verbindungen gefunden von ${t} nach ${s}.`};let o=[`## Verbindungen: ${t} \u2192 ${s}`,""];for(let i=0;i<n.length;i++){let a=n[i],c=this.formatTime(a.departure),d=this.formatTime(a.arrival);o.push(`### Verbindung ${i+1}: ${c} \u2192 ${d} (${a.duration} min, ${a.transfers} Umstieg${a.transfers!==1?"e":""})`);for(let u of a.legs)u.walking?o.push(` - \u{1F6B6} Fu\xDFweg \u2192 ${u.destination} (${this.formatTime(u.departure)}\u2013${this.formatTime(u.arrival)})`):o.push(` - ${u.line||u.mode} Ri. ${u.direction||u.destination}: ${u.origin} ${this.formatTime(u.departure)} \u2192 ${u.destination} ${this.formatTime(u.arrival)}`);o.push("")}return{success:!0,data:n,display:o.join(`
|
|
970
986
|
`)}}async findDepartures(e){let t=e.stop_id;if(!t)return{success:!1,error:'Missing required field "stop_id" for departures. Use search_stop first to find the stop ID.'};let s={};e.departure&&(s.when=new Date(e.departure)),e.duration&&(s.duration=e.duration);let r=await this.client.departures(t,s);if(r.length===0)return{success:!0,data:[],display:"Keine Abfahrten gefunden."};let n=["## Abfahrten",""];for(let o of r){let i=this.formatTime(o.when),a=o.delay?` (+${o.delay} min)`:"",c=o.platform?` [Steig ${o.platform}]`:"";n.push(`- **${i}${a}** ${o.line} \u2192 ${o.direction}${c}`)}return{success:!0,data:r,display:n.join(`
|
|
971
|
-
`)}}formatTime(e){try{return new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"})}catch{return e}}}});import
|
|
972
|
-
`)}}showService(e){let t=
|
|
973
|
-
`],r={};for(let n of t.fields){let o=process.env[n.env];r[n.env]=o;let i=o?n.secret?
|
|
974
|
-
`)}}async setService(e,t){let s=
|
|
987
|
+
`)}}formatTime(e){try{return new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"})}catch{return e}}}});import _a from"node:fs";import ku from"node:path";function Eu(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function ef(){let l=process.cwd();for(let e=0;e<10;e++){let t=ku.join(l,".env");if(_a.existsSync(t))return t;let s=ku.dirname(l);if(s===l)break;l=s}return null}var Is,As,bu=T(()=>{"use strict";W();Is={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)"}]}},As=class extends x{static{m(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(Is)){let n=s.fields.filter(i=>i.required).every(i=>!!process.env[i.env])?"configured":"not configured",o=`ALFRED_${t.toUpperCase()}_*`;e.push(`| ${s.label} | ${n} | \`${o}\` |`)}return{success:!0,data:Object.keys(Is),display:e.join(`
|
|
988
|
+
`)}}showService(e){let t=Is[e];if(!t)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Is).join(", ")}`};let s=[`**${t.label}** configuration:
|
|
989
|
+
`],r={};for(let n of t.fields){let o=process.env[n.env];r[n.env]=o;let i=o?n.secret?Eu(o):o:"_not set_",a=n.required?" (required)":"";s.push(`- \`${n.env}\`: ${i}${a}`)}return{success:!0,data:r,display:s.join(`
|
|
990
|
+
`)}}async setService(e,t){let s=Is[e];if(!s)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Is).join(", ")}`};if(!t||Object.keys(t).length===0)return{success:!1,error:`No values provided. Pass an object with ENV variable names as keys.
|
|
975
991
|
|
|
976
992
|
Available keys for ${s.label}:
|
|
977
993
|
${s.fields.map(d=>`- \`${d.env}\`: ${d.label}${d.required?" (required)":""}`).join(`
|
|
978
|
-
`)}`};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 n=
|
|
994
|
+
`)}`};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 n=ef();if(!n)return{success:!1,error:"Could not find .env file. Run `alfred setup` first or create a .env in your project root."};let o=_a.readFileSync(n,"utf-8"),i=[];for(let[d,u]of Object.entries(t)){let p=u.replace(/\n/g,"\\n"),h=new RegExp(`^#?\\s*${d}=.*$`,"m");h.test(o)?o=o.replace(h,`${d}=${p}`):o=o.trimEnd()+`
|
|
979
995
|
${d}=${p}
|
|
980
|
-
`,i.push(d)}
|
|
981
|
-
`,...i.map(d=>`- \`${d}\` = ${s.fields.find(u=>u.env===d)?.secret?
|
|
996
|
+
`,i.push(d)}_a.writeFileSync(n,o,"utf-8");let a=s.fields.filter(d=>d.required).filter(d=>!t[d.env]&&!process.env[d.env]).map(d=>`\`${d.env}\``),c=[`Written to \`${n}\`:
|
|
997
|
+
`,...i.map(d=>`- \`${d}\` = ${s.fields.find(u=>u.env===d)?.secret?Eu(t[d]):t[d]}`)];if(a.length>0)c.push(`
|
|
982
998
|
**Still missing:** ${a.join(", ")}`);else if(this.reloadCallback){let d=await this.reloadCallback(e);d.success?c.push(`
|
|
983
999
|
**${s.label} wurde aktiviert.** Du kannst es jetzt sofort nutzen.`):c.push(`
|
|
984
1000
|
**${s.label} is fully configured.** Hot-Reload fehlgeschlagen: ${d.error??"unbekannter Fehler"}. Restart Alfred: \`alfred start\``)}else c.push(`
|
|
985
1001
|
**${s.label} is fully configured.** Restart Alfred to activate: \`alfred start\``);return{success:!0,data:{envPath:n,written:i},display:c.join(`
|
|
986
|
-
`)}}};m(
|
|
987
|
-
`)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let n of s)n.type==="node"&&!n.online&&t.push({source:"proxmox",message:`Node "${n.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let n of r){let o=n.name??`VMID ${n.vmid}`,i=n.status,a=n.maxdisk,c=n.disk;if(a&&a>0&&c!=null){let d=c/a*100;d>90&&t.push({source:"proxmox",message:`${o} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=n.maxmem,u=n.mem;if(d&&d>0&&u!=null){let p=u/d*100;p>95&&t.push({source:"proxmox",message:`${o} RAM usage ${p.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`Proxmox HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return(await n.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,n=[],o;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let c=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),u=await this.apiFetch(`${c}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),p;if(u.status===200)p="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(h=>h.split(";")[0]),o=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let h=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!h.ok)throw new Error(`UniFi login failed: HTTP ${h.status}`);p="classic",n=(h.headers.getSetCookie?.()??[]).map(
|
|
1002
|
+
`)}}};m(Eu,"maskValue");m(ef,"findEnvFile")});var _o,Su=T(()=>{"use strict";W();_o=class extends x{static{m(this,"MonitorSkill")}metadata={name:"monitor",category:"infrastructure",description:"Deterministic infrastructure health checks without LLM. Checks Proxmox cluster, UniFi network, and Home Assistant for issues. Returns alerts only when problems are detected \u2014 empty display means all OK.",riskLevel:"read",version:"1.0.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{checks:{type:"array",items:{type:"string",enum:["proxmox","unifi","homeassistant","proxmox_backup"]},description:"Which checks to run (default: all configured)"}}}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.checks,r=[],n=m(c=>!s||s.length===0||s.includes(c),"shouldRun");if(this.config.proxmox&&n("proxmox")&&r.push({name:"proxmox",promise:this.checkProxmox()}),this.config.unifi&&n("unifi")&&r.push({name:"unifi",promise:this.checkUnifi()}),this.config.homeassistant&&n("homeassistant")&&r.push({name:"homeassistant",promise:this.checkHomeAssistant()}),this.config.proxmoxBackup&&n("proxmox_backup")&&r.push({name:"proxmox_backup",promise:this.checkProxmoxBackup()}),r.length===0)return{success:!0,display:""};let o=await Promise.allSettled(r.map(c=>c.promise)),i=[];for(let c=0;c<o.length;c++){let d=o[c];if(d.status==="fulfilled")i.push(...d.value);else{let u=d.reason instanceof Error?d.reason.message:String(d.reason);i.push({source:r[c].name,message:`Health check failed: ${u}`})}}if(i.length===0)return{success:!0,display:""};let a=["\u26A0 Infrastructure Alerts:",""];for(let c of i)a.push(`- [${c.source}] ${c.message}`);return{success:!0,display:a.join(`
|
|
1003
|
+
`)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let n of s)n.type==="node"&&!n.online&&t.push({source:"proxmox",message:`Node "${n.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let n of r){let o=n.name??`VMID ${n.vmid}`,i=n.status,a=n.maxdisk,c=n.disk;if(a&&a>0&&c!=null){let d=c/a*100;d>90&&t.push({source:"proxmox",message:`${o} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=n.maxmem,u=n.mem;if(d&&d>0&&u!=null){let p=u/d*100;p>95&&t.push({source:"proxmox",message:`${o} RAM usage ${p.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`Proxmox HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return(await n.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,n=[],o;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let c=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),u=await this.apiFetch(`${c}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),p;if(u.status===200)p="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(h=>h.split(";")[0]),o=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let h=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!h.ok)throw new Error(`UniFi login failed: HTTP ${h.status}`);p="classic",n=(h.headers.getSetCookie?.()??[]).map(f=>f.split(";")[0])}else throw new Error(`UniFi login failed: HTTP ${u.status}`);r={"Content-Type":"application/json"},n.length>0&&(r.Cookie=n.join("; ")),o&&(r["X-CSRF-Token"]=o)}let i=m(c=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${c}`,"apiUrl"),a=m(async c=>{let d=await this.apiFetch(i(c),{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!d.ok)throw new Error(`UniFi HTTP ${d.status}`);return(await d.json()).data},"unifiGet");try{let c=await a("stat/health");for(let d of c??[])d.status&&d.status!=="ok"&&t.push({source:"unifi",message:`Subsystem "${d.subsystem}" status: ${d.status}`})}catch{}try{let c=await a("stat/device");for(let d of c??[])if(d.state!==1){let u=d.name??d.hostname??d.mac??"unknown";t.push({source:"unifi",message:`Device "${u}" is not connected (state: ${d.state})`})}}catch{}try{let c=await a("rest/alarm?archived=false");c&&c.length>0&&t.push({source:"unifi",message:`${c.length} open alert(s): ${c.slice(0,3).map(d=>d.key??d.msg??"unknown").join(", ")}`})}catch{}return t}async checkHomeAssistant(){let e=this.config.homeassistant,t=[],s=await this.haGet(e,"/api/states"),r=0,n=[];for(let o of s){let i=o.entity_id;if(i.startsWith("update."))continue;if(o.state==="unavailable"&&(r++,n.length<5)){let d=o.attributes?.friendly_name??i;n.push(d)}let a=o.attributes?.device_class??"",c=o.attributes?.unit_of_measurement??"";if(i.startsWith("sensor.")&&a==="battery"&&c==="%"){let d=parseFloat(o.state);if(!isNaN(d)&&d>=0&&d<20){let u=o.attributes?.friendly_name??i;t.push({source:"homeassistant",message:`Low battery: ${u} at ${d}%`})}}}if(r>0){let o=n.join(", "),i=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${o}${i}`})}return t}async haGet(e,t){let s=`${e.baseUrl.replace(/\/+$/,"")}${t}`,r={Authorization:`Bearer ${e.accessToken}`,"Content-Type":"application/json"},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`HA HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return await n.json()}async checkProxmoxBackup(){let e=this.config.proxmoxBackup,t=[],s=e.maxAgeHours??24,r=`${e.baseUrl.replace(/\/+$/,"")}/api2/json/nodes/localhost/tasks`,n={Authorization:`PBSAPIToken=${e.tokenId}:${e.tokenSecret}`},o=await this.apiFetch(r,{method:"GET",headers:n,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)return t.push({source:"proxmox_backup",message:`PBS unreachable: HTTP ${o.status}`}),t;let c=((await o.json()).data??[]).filter(h=>h.worker_type==="backup"),d=Date.now()/1e3,u=c.filter(h=>h.status==="OK").sort((h,f)=>(f.endtime??f.starttime)-(h.endtime??h.starttime));if(u.length===0)t.push({source:"proxmox_backup",message:"No successful backups found"});else{let h=u[0].endtime??u[0].starttime,f=(d-h)/3600;f>s&&t.push({source:"proxmox_backup",message:`Last successful backup is ${f.toFixed(1)}h old (threshold: ${s}h)`})}let p=c.filter(h=>h.status!=="OK"&&d-(h.endtime??h.starttime)<s*3600);return p.length>0&&t.push({source:"proxmox_backup",message:`${p.length} failed backup(s) in the last ${s}h`}),t}async apiFetch(e,t,s){let r=s===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}}}});var ko,vu=T(()=>{"use strict";W();ko=class extends x{static{m(this,"MicrosoftTodoSkill")}config;accessToken="";metadata={name:"microsoft_todo",description:"Manage Microsoft To Do lists and tasks \u2014 list, create, complete, update and delete tasks across all lists.",version:"1.0.0",riskLevel:"write",category:"productivity",inputSchema:{type:"object",required:["action"],properties:{action:{type:"string",enum:["list_lists","list_tasks","add_task","complete_task","uncomplete_task","delete_task","update_task","create_list"],description:"Action to perform."},listId:{type:"string",description:"To Do list ID. Either listId or list (display name) is required for task actions."},list:{type:"string",description:'To Do list display name (resolved to listId automatically). E.g. "Einkaufsliste".'},taskId:{type:"string",description:"Task ID (required for complete/uncomplete/delete/update)."},title:{type:"string",description:"Task or list title (required for add_task, create_list; optional for update_task)."},body:{type:"string",description:"Task body/notes."},dueDate:{type:"string",description:"Due date in YYYY-MM-DD format."},importance:{type:"string",enum:["low","normal","high"],description:"Task importance."},includeCompleted:{type:"boolean",description:"Include completed tasks in list_tasks (default: false)."}}}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;try{switch(s){case"list_lists":return await this.listLists();case"list_tasks":return await this.listTasks(e);case"add_task":return await this.addTask(e);case"complete_task":return await this.completeTask(e);case"uncomplete_task":return await this.uncompleteTask(e);case"delete_task":return await this.deleteTask(e);case"update_task":return await this.updateTask(e);case"create_list":return await this.createList(e);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Tasks.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=m(()=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s();if(r.status===401){if(await this.refreshAccessToken(),r=await s(),!r.ok)throw new Error(`Graph API error: ${r.status}`)}else if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async resolveListId(e){if(e.listId)return e.listId;let s=(await this.graphRequest("/me/todo/lists")).value??[];if(e.list){let n=e.list.toLowerCase(),o=s.find(i=>i.displayName.toLowerCase()===n);if(!o){let i=s.map(a=>a.displayName).join(", ");throw new Error(`List "${e.list}" not found. Available lists: ${i}`)}return o.id}let r=s.find(n=>n.wellknownListName==="defaultList");if(r)return r.id;if(s.length>0)return s[0].id;throw new Error("No To Do lists found.")}async listLists(){let t=(await this.graphRequest("/me/todo/lists")).value??[],s=t.map(r=>`\u2022 **${r.displayName}**${r.wellknownListName==="defaultList"?" (Standard)":""} [listId=${r.id}]`).join(`
|
|
988
1004
|
`);return{success:!0,data:t,display:s||"Keine Listen gefunden."}}async listTasks(e){let t=await this.resolveListId(e),s=e.includeCompleted===!0,r=`/me/todo/lists/${t}/tasks`;s||(r+="?$filter=status ne 'completed'");let o=(await this.graphRequest(r)).value??[],i=o.map(a=>{let c=a.status==="completed"?"\u2611":"\u2610",d=a.importance==="high"?" \u2757":"",u=a.dueDateTime?` (f\xE4llig: ${a.dueDateTime.dateTime.slice(0,10)})`:"";return`${c} ${a.title}${d}${u} [taskId=${a.id}]`});return{success:!0,data:o,display:i.length>0?`listId=${t}
|
|
989
1005
|
${i.join(`
|
|
990
|
-
`)}`:"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});var fo,Is,uu=T(()=>{"use strict";W();fo=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Is=class extends x{static{m(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action"],description:"What to do on trigger: alert (default), action_only, or alert_and_action (for create)"},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,!0);case"disable":return this.toggleWatch(e,!1);case"delete":return this.deleteWatch(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},o=e.condition_field,i=e.condition_operator,a=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,p=e.action_skill_name,h=e.action_skill_params,g=e.action_on_trigger??"alert",f=e.requires_confirmation,y=e.conditions,k=e.conditions_logic??"and";if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};let S=Array.isArray(y)&&y.length>0,b=!!o&&!!i;if(!S&&!b)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let C;if(S){for(let z of y){if(!z.field||!z.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!fo.includes(z.operator))return{success:!1,error:`Invalid operator "${z.operator}" in conditions. Must be one of: ${fo.join(", ")}`}}C={logic:k,conditions:y.map(z=>({field:z.field,operator:z.operator,value:z.value}))}}if(b&&!fo.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${fo.join(", ")}`};if(c<1)return{success:!1,error:"interval_minutes must be >= 1"};if(d<0)return{success:!1,error:"cooldown_minutes must be >= 0"};if(this.skillRegistry){let z=this.skillRegistry.get(r);if(!z)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let re=z.metadata.inputSchema;if(re&&Array.isArray(re.required)){let N=re.required.filter(ie=>!(ie in n));if(N.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${N.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(re.required)}`}}}let D=o??(C?C.conditions[0].field:""),P=i??(C?C.conditions[0].operator:"changed"),Q=a??(C?C.conditions[0].value:void 0),ae=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:D,operator:P,value:Q},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:C,actionSkillName:p,actionSkillParams:h,actionOnTrigger:g,requiresConfirmation:f}),j=C?`${C.logic.toUpperCase()}(${C.conditions.map(z=>`${z.field} ${z.operator}${z.value!=null?" "+z.value:""}`).join(", ")})`:`${D} ${P}${Q!=null?" "+Q:""}`;return{success:!0,data:{watchId:ae.id,name:s,skillName:r,conditionField:D,conditionOperator:P,conditionValue:Q,intervalMinutes:c,compositeCondition:C},display:`Watch erstellt (${ae.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${j}${p?` \u2192 Aktion: ${p} (${g})`:""}`}}listWatches(e){let t=this.watchRepo.findByChatId(e.chatId,e.platform);if(t.length===0)return{success:!0,data:[],display:"Keine Watches vorhanden."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,i=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",a=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${a}${i}`});return{success:!0,data:t.map(r=>({watchId:r.id,name:r.name,skillName:r.skillName,condition:r.condition,intervalMinutes:r.intervalMinutes,enabled:r.enabled,lastCheckedAt:r.lastCheckedAt,lastTriggeredAt:r.lastTriggeredAt})),display:`Watches:
|
|
1006
|
+
`)}`:"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});var Eo,Rs,$u=T(()=>{"use strict";W();Eo=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Rs=class extends x{static{m(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,!0);case"disable":return this.toggleWatch(e,!1);case"delete":return this.deleteWatch(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},o=e.condition_field,i=e.condition_operator,a=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,p=e.action_skill_name,h=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,_=e.conditions,S=e.conditions_logic??"and";if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};let b=Array.isArray(_)&&_.length>0,$=!!o&&!!i;if(!b&&!$)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let N;if(b){for(let L of _){if(!L.field||!L.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!Eo.includes(L.operator))return{success:!1,error:`Invalid operator "${L.operator}" in conditions. Must be one of: ${Eo.join(", ")}`}}N={logic:S,conditions:_.map(L=>({field:L.field,operator:L.operator,value:L.value}))}}if($&&!Eo.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${Eo.join(", ")}`};if(c<1)return{success:!1,error:"interval_minutes must be >= 1"};if(d<0)return{success:!1,error:"cooldown_minutes must be >= 0"};if(f==="trigger_watch"&&!y)return{success:!1,error:'Missing "trigger_watch_id" \u2014 required when action_on_trigger is "trigger_watch"'};if(y&&!this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let L=this.skillRegistry.get(r);if(!L)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let se=L.metadata.inputSchema;if(se&&Array.isArray(se.required)){let ne=se.required.filter(Z=>!(Z in n));if(ne.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${ne.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(se.required)}`}}}let M=o??(N?N.conditions[0].field:""),J=i??(N?N.conditions[0].operator:"changed"),V=a??(N?N.conditions[0].value:void 0),P=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:M,operator:J,value:V},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:N,actionSkillName:p,actionSkillParams:h,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),ee=N?`${N.logic.toUpperCase()}(${N.conditions.map(L=>`${L.field} ${L.operator}${L.value!=null?" "+L.value:""}`).join(", ")})`:`${M} ${J}${V!=null?" "+V:""}`,ue=y?` \u2192 Chain \u2192 Watch ${y}`:p?` \u2192 Aktion: ${p} (${f})`:"";return{success:!0,data:{watchId:P.id,name:s,skillName:r,conditionField:M,conditionOperator:J,conditionValue:V,intervalMinutes:c,compositeCondition:N,triggerWatchId:y},display:`Watch erstellt (${P.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${ee}${ue}`}}listWatches(e){let t=this.watchRepo.findByChatId(e.chatId,e.platform);if(t.length===0)return{success:!0,data:[],display:"Keine Watches vorhanden."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,i=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",a=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${a}${i}`});return{success:!0,data:t.map(r=>({watchId:r.id,name:r.name,skillName:r.skillName,condition:r.condition,intervalMinutes:r.intervalMinutes,enabled:r.enabled,lastCheckedAt:r.lastCheckedAt,lastTriggeredAt:r.lastTriggeredAt})),display:`Watches:
|
|
991
1007
|
${s.join(`
|
|
992
|
-
`)}`}}toggleWatch(e,t){let s=e.watch_id;return s?this.watchRepo.toggle(s,t)?{success:!0,data:{watchId:s,enabled:t},display:`Watch "${s}" ${t?"aktiviert":"deaktiviert"}.`}:{success:!1,error:`Watch "${s}" not found`}:{success:!1,error:`Missing "watch_id" for ${t?"enable":"disable"}`}}deleteWatch(e){let t=e.watch_id;return t?this.watchRepo.delete(t)?{success:!0,data:{watchId:t},display:`Watch "${t}" gel\xF6scht.`}:{success:!1,error:`Watch "${t}" not found`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var
|
|
1008
|
+
`)}`}}toggleWatch(e,t){let s=e.watch_id;return s?this.watchRepo.toggle(s,t)?{success:!0,data:{watchId:s,enabled:t},display:`Watch "${s}" ${t?"aktiviert":"deaktiviert"}.`}:{success:!1,error:`Watch "${s}" not found`}:{success:!1,error:`Missing "watch_id" for ${t?"enable":"disable"}`}}deleteWatch(e){let t=e.watch_id;return t?this.watchRepo.delete(t)?{success:!0,data:{watchId:t},display:`Watch "${t}" gel\xF6scht.`}:{success:!1,error:`Watch "${t}" not found`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var xs,Iu=T(()=>{"use strict";W();Me();xs=class extends x{static{m(this,"WorkflowSkill")}workflowRepo;metadata={name:"workflow",category:"automation",description:'Create and manage multi-step workflows (skill chains). Use "create" to define a workflow with sequential steps. Each step runs a skill and can pass data to the next via {{prev.field}} or {{steps.0.field}} templates. Use "run" to execute a workflow, "list" to see all workflows, "delete" to remove, "history" to see recent executions.',riskLevel:"write",version:"1.0.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","run","delete","history"],description:"Workflow action"},name:{type:"string",description:"Workflow name (for create)"},steps:{type:"array",description:'Workflow steps (for create). Action step: { skillName, inputMapping: { paramName: "{{prev.field}}" }, onError: "stop"|"skip"|"retry", jumpTo?: stepIndex|"end" }. Condition step: { type: "condition", condition: { field: "prev.rain", operator: "eq", value: "true" }, then: stepIndex|"end"|null, else: stepIndex|"end"|null, label?: "Regen?" }. Jump targets are 0-based step indices, "end" finishes the workflow, null proceeds to next step.',items:{type:"object"}},workflow_id:{type:"string",description:"Workflow ID (for run/delete/history)"}},required:["action"]}};runner;constructor(e){super(),this.workflowRepo=e}setRunner(e){this.runner=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWorkflow(e,t);case"list":return this.listWorkflows(t);case"run":return this.runWorkflow(e,t);case"delete":return this.deleteWorkflow(e,t);case"history":return this.getHistory(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}createWorkflow(e,t){let s=e.name,r=e.steps;if(!s)return{success:!1,error:'Missing required field "name"'};if(!r||!Array.isArray(r)||r.length===0)return{success:!1,error:'Missing or empty "steps" array'};let n=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"];for(let i=0;i<r.length;i++){let a=r[i];if(a.type==="condition"){if(!a.condition||typeof a.condition!="object")return{success:!1,error:`Step ${i}: condition step missing "condition" object`};if(!a.condition.field||typeof a.condition.field!="string")return{success:!1,error:`Step ${i}: condition.field must be a non-empty string`};if(!n.includes(a.condition.operator))return{success:!1,error:`Step ${i}: condition.operator must be one of: ${n.join(", ")}`};for(let c of["then","else"]){let d=a[c];if(d!==null&&d!=="end"&&(typeof d!="number"||d<0||d>=r.length))return{success:!1,error:`Step ${i}: "${c}" must be null, "end", or a step index (0-${r.length-1})`}}}else{if(!a.skillName)return{success:!1,error:`Step ${i}: missing skillName`};if(!a.inputMapping||typeof a.inputMapping!="object")return{success:!1,error:`Step ${i}: missing inputMapping`};if(!["stop","skip","retry"].includes(a.onError))return{success:!1,error:`Step ${i}: onError must be stop|skip|retry`};if(a.jumpTo!==void 0&&a.jumpTo!=="end"&&(typeof a.jumpTo!="number"||a.jumpTo<0||a.jumpTo>=r.length))return{success:!1,error:`Step ${i}: jumpTo must be "end" or a step index (0-${r.length-1})`}}}let o=this.workflowRepo.create({name:s,userId:de(t),chatId:t.chatId,platform:t.platform,steps:r,triggerType:"manual",enabled:!0});return{success:!0,data:{workflowId:o.id,name:s,stepCount:r.length},display:`Workflow "${s}" erstellt (${o.id}) mit ${r.length} Schritten.`}}listWorkflows(e){let t=[],s=new Set;for(let n of K(e))for(let o of this.workflowRepo.findByUser(n))s.has(o.id)||(s.add(o.id),t.push(o));if(t.length===0)return{success:!0,data:[],display:"Keine Workflows vorhanden."};let r=t.map(n=>`- ${n.enabled?"\u2705":"\u23F8\uFE0F"} ${n.name} (${n.id.slice(0,8)}) \u2014 ${n.steps.length} Schritte, Trigger: ${n.triggerType}`);return{success:!0,data:t.map(n=>({id:n.id,name:n.name,steps:n.steps.length,triggerType:n.triggerType,enabled:n.enabled})),display:`Workflows:
|
|
993
1009
|
${r.join(`
|
|
994
1010
|
`)}`}}async runWorkflow(e,t){if(!this.runner)return{success:!1,error:"WorkflowRunner not available"};let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);if(!r)return{success:!1,error:`Workflow "${s}" not found`};if(!r.enabled)return{success:!1,error:`Workflow "${r.name}" is disabled`};let n=await this.runner.run(r,t),i=[`${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} Workflow "${r.name}": ${n.status}`];i.push(`Schritte: ${n.stepsCompleted}/${n.totalSteps}`),n.error&&i.push(`Fehler: ${n.error}`);for(let a=0;a<n.stepResults.length;a++){let c=n.stepResults[a];i.push(` ${a+1}. ${c.skillName}: ${c.success?"\u2705":"\u274C "+(c.error??"")}`)}return{success:n.status==="completed",data:n,display:i.join(`
|
|
995
|
-
`)}}deleteWorkflow(e,t){let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);return r?
|
|
1011
|
+
`)}}deleteWorkflow(e,t){let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);return r?K(t).includes(r.userId)?(this.workflowRepo.delete(s),{success:!0,data:{workflowId:s},display:`Workflow "${r.name}" gel\xF6scht.`}):{success:!1,error:"Not authorized to delete this workflow"}:{success:!1,error:`Workflow "${s}" not found`}}getHistory(e){let t=e.workflow_id;if(!t)return{success:!1,error:'Missing "workflow_id"'};let s=this.workflowRepo.getRecentExecutions(t);if(s.length===0)return{success:!0,data:[],display:"Keine Ausf\xFChrungen vorhanden."};let r=s.map(n=>`- ${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} ${n.startedAt} \u2014 ${n.stepsCompleted}/${n.totalSteps} Schritte (${n.status})`);return{success:!0,data:s,display:`Letzte Ausf\xFChrungen:
|
|
996
1012
|
${r.join(`
|
|
997
|
-
`)}`}}}});var
|
|
998
|
-
`),o.push("| # | Titel | Preis | Standort | Plattform | Link |"),o.push("|---|-------|-------|----------|-----------|------|");for(let i=0;i<r.length;i++){let a=r[i],c=a.title.length>60?a.title.slice(0,57)+"...":a.title;o.push(`| ${i+1} | ${c} | ${
|
|
1013
|
+
`)}`}}}});var Ht,bo=T(()=>{"use strict";Ht=class{static{m(this,"MarketplaceProvider")}async getDetail(e){throw new Error("Detail not supported")}}});var Au,Xr,ka=T(()=>{"use strict";bo();Au="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",Xr=class extends Ht{static{m(this,"WillhabenProvider")}platform="willhaben";async search(e){let t=Math.min(e.rows??100,100),s=new URL("https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz");if(s.searchParams.set("keyword",e.query),s.searchParams.set("rows",String(t)),e.priceMin!=null&&s.searchParams.set("PRICE_FROM",String(e.priceMin)),e.priceMax!=null&&s.searchParams.set("PRICE_TO",String(e.priceMax)),e.sort){let d={date_desc:"1",price_asc:"2",price_desc:"3"};s.searchParams.set("sfId",d[e.sort])}e.postcode&&s.searchParams.set("postcode",e.postcode);let r=await fetch(s.toString(),{headers:{"User-Agent":Au,Accept:"text/html"}});if(!r.ok)throw new Error(`willhaben HTTP ${r.status}`);let n=await r.text(),i=this.parseNextData(n).map(d=>this.mapAdvert(d)),a=e.query.toLowerCase().split(/\s+/).filter(d=>d.length>=2);return{listings:a.length>0?i.filter(d=>a.every(u=>d.title.toLowerCase().includes(u))):i,totalCount:this.extractTotalCount(n)??i.length,query:e.query,platform:"willhaben"}}async getDetail(e){let t=`https://www.willhaben.at/iad/object?adId=${e}`,s=await fetch(t,{headers:{"User-Agent":Au,Accept:"text/html"},redirect:"follow"});if(!s.ok)throw new Error(`willhaben detail HTTP ${s.status}`);let n=(await s.text()).match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!n)throw new Error("willhaben detail: __NEXT_DATA__ not found");let o;try{o=JSON.parse(n[1])}catch{throw new Error("willhaben detail: __NEXT_DATA__ contains invalid JSON")}let i=o?.props?.pageProps?.advertDetails;if(!i)throw new Error("willhaben detail: advertDetails not found in page data");let a=i.attributes?.attribute??[],c=m($=>a.find(M=>M.name===$)?.values?.[0]??void 0,"attr"),d={};for(let $ of a)$.name&&$.values?.[0]&&(d[$.name]=$.values[0]);let u=i.attributeInformation??[];for(let $ of u){let N=$.treeAttributeElement?.label,M=$.values?.[0]?.label;N&&M&&(d[N]=M)}let p=(i.advertImageList?.advertImage??[]).map($=>$.mainImageUrl??$.referenceImageUrl).filter(Boolean),h=i.advertAddressDetails,f=h?[h.postalName,h.postCode,h.district,h.province].filter(Boolean).join(", "):[c("LOCATION/ADDRESS_2"),c("LOCATION/ADDRESS_3")].filter(Boolean).join(", "),g=i.sellerProfileUserData,_=(c("DESCRIPTION")??i.description??"").replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim(),S=c("PRICE"),b=u.find($=>$.treeAttributeElement?.code==="Zustand")?.values?.[0]?.label;return{id:e,title:i.description??"Kein Titel",price:S?parseFloat(S):null,currency:"EUR",condition:b,location:f,url:s.url||t,imageUrls:p,seller:g?.name??void 0,sellerSince:g?.registerDate??void 0,publishedAt:i.publishedDate??void 0,description:_,attributes:d,platform:"willhaben"}}parseNextData(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)throw new Error("willhaben: __NEXT_DATA__ not found \u2014 page structure may have changed");let s;try{s=JSON.parse(t[1])}catch{throw new Error("willhaben: __NEXT_DATA__ contains invalid JSON")}return s?.props?.pageProps?.searchResult?.advertSummaryList?.advertSummary??[]}extractTotalCount(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)return;let s;try{s=JSON.parse(t[1])}catch{return}return s?.props?.pageProps?.searchResult?.rowsFound}mapAdvert(e){let t=e.attributes?.attribute??[],s=m(o=>t.find(a=>a.name===o)?.values?.[0]??void 0,"attr"),r=s("PRICE"),n=r?parseFloat(r):null;return{id:String(e.id),title:s("HEADING")??e.description??"Kein Titel",price:n,currency:"EUR",condition:s("CONDITION"),location:[s("LOCATION"),s("POSTCODE")].filter(Boolean).join(" "),url:`https://www.willhaben.at/iad/object?adId=${e.id}`,imageUrl:e.advertImageList?.advertImage?.[0]?.mainImageUrl??void 0,seller:s("ORGANIZER")??void 0,publishedAt:s("PUBLISHED_String")??void 0,platform:"willhaben"}}}});var Kr,Ea=T(()=>{"use strict";bo();Kr=class extends Ht{static{m(this,"EbayProvider")}appId;certId;platform="ebay";tokenCache=null;constructor(e,t){super(),this.appId=e,this.certId=t}async getToken(){if(this.tokenCache&&Date.now()<this.tokenCache.expiresAt)return this.tokenCache.token;let e=Buffer.from(`${this.appId}:${this.certId}`).toString("base64"),t=await fetch("https://api.ebay.com/identity/v1/oauth2/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:`Basic ${e}`},body:"grant_type=client_credentials&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope"});if(!t.ok)throw new Error(`eBay OAuth failed: HTTP ${t.status}`);let s=await t.json();return this.tokenCache={token:s.access_token,expiresAt:Date.now()+(s.expires_in-300)*1e3},this.tokenCache.token}async search(e){let t=await this.getToken(),s=Math.min(e.rows??50,200),r=new URL("https://api.ebay.com/buy/browse/v1/item_summary/search");if(r.searchParams.set("q",e.query),r.searchParams.set("limit",String(s)),e.sort){let d={price_asc:"price",price_desc:"-price",date_desc:"newlyListed"};r.searchParams.set("sort",d[e.sort])}let n=[];if(e.priceMin!=null||e.priceMax!=null){let d=e.priceMin!=null?String(e.priceMin):"",u=e.priceMax!=null?String(e.priceMax):"";n.push(`price:[${d}..${u}]`)}e.condition==="new"&&n.push("conditionIds:{1000}"),e.condition==="used"&&n.push("conditionIds:{3000}"),n.length>0&&r.searchParams.set("filter",n.join(","));let o=await fetch(r.toString(),{headers:{Authorization:`Bearer ${t}`,"X-EBAY-C-MARKETPLACE-ID":"EBAY_AT"}});if(!o.ok)throw new Error(`eBay API error: HTTP ${o.status}`);let i=await o.json(),c=(i.itemSummaries??[]).map(d=>({id:d.itemId??d.legacyItemId??"",title:d.title??"",price:d.price?.value?parseFloat(d.price.value):null,currency:d.price?.currency??"EUR",condition:d.condition??d.conditionId??void 0,location:d.itemLocation?.postalCode?`${d.itemLocation.city??""} ${d.itemLocation.postalCode}`.trim():d.itemLocation?.country??void 0,url:d.itemWebUrl??d.itemHref??"",imageUrl:d.image?.imageUrl??d.thumbnailImages?.[0]?.imageUrl??void 0,seller:d.seller?.username??void 0,publishedAt:void 0,platform:"ebay"}));return{listings:c,totalCount:i.total??c.length,query:e.query,platform:"ebay"}}}});function So(l){let e=[...l].sort((s,r)=>s-r),t=Math.floor(e.length/2);return e.length%2?e[t]:(e[t-1]+e[t])/2}function ba(l,e){return l==null?"k.A.":`${l.toFixed(2)} ${e}`}var Vr,Ru=T(()=>{"use strict";W();ka();Ea();m(So,"median");m(ba,"formatPrice");Vr=class extends x{static{m(this,"MarketplaceSkill")}metadata={name:"marketplace",category:"information",description:'Marktplatz-Suche auf willhaben.at und eBay. "search" liefert Inseratliste mit Preisstatistik. "compare" liefert Preisvergleich + g\xFCnstigste 5. "detail" zeigt Einzelinserat mit Beschreibung, Fotos, Verk\xE4ufer-Info \u2014 bewerte bei detail immer Seriosit\xE4t (Preis vs. Markt, Account-Alter, Foto-Anzahl, Beschreibungsqualit\xE4t, Zahlungsmethode). Filter: priceMin/priceMax, sort, condition (new/used), postcode. Watch-kompatibel: search\u2192"count"/"minPrice", compare\u2192"minPrice"/"avgPrice".',riskLevel:"read",version:"2.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","compare","detail"],description:"Aktion: search = Inserate auflisten, compare = Preisstatistik, detail = Einzelinserat"},query:{type:"string",description:"Suchbegriff (f\xFCr search/compare)"},platform:{type:"string",enum:["willhaben","ebay","all"],description:"Plattform (default: willhaben)"},priceMin:{type:"number",description:"Mindestpreis EUR"},priceMax:{type:"number",description:"H\xF6chstpreis EUR"},rows:{type:"number",description:"Max Ergebnisse (default 50, max 200)"},sort:{type:"string",enum:["price_asc","price_desc","date_desc"],description:"Sortierung"},condition:{type:"string",enum:["new","used"],description:"Zustand"},postcode:{type:"string",description:'PLZ-Filter (z.B. "1010")'},listing_id:{type:"string",description:"Inserat-ID f\xFCr detail-Aktion"}},required:["action"]}};providers=[];constructor(e){super(),this.providers.push(new Xr),e?.ebay?.appId&&e?.ebay?.certId&&this.providers.push(new Kr(e.ebay.appId,e.ebay.certId))}async execute(e,t){let s=e.action,r=e.platform??"willhaben",n=e.query,o=e.priceMin,i=e.priceMax,a=Math.min(e.rows??50,200),c=e.sort,d=e.condition,u=e.postcode;if(s==="detail"){let f=e.listing_id;return f?this.handleDetail(r,f):{success:!1,error:"listing_id ist erforderlich f\xFCr detail-Aktion"}}if(!n)return{success:!1,error:"query ist erforderlich f\xFCr search/compare"};let p=this.getProviders(r);if(p.length===0)return{success:!1,error:"Keine Marketplace-Provider verf\xFCgbar f\xFCr diese Plattform"};let h={query:n,priceMin:o,priceMax:i,rows:a,sort:c,condition:d,postcode:u};switch(s){case"search":return this.handleSearch(p,h);case"compare":return this.handleCompare(p,{...h,rows:Math.min(a,200)});default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getProviders(e){return e==="all"?this.providers:this.providers.filter(t=>t.platform===e)}async handleSearch(e,t){let s=await this.searchAll(e,t),r=s.flatMap(i=>i.listings);if(r.length===0)return{success:!0,data:{query:t.query,count:0,totalCount:0,minPrice:null,maxPrice:null,medianPrice:null,listings:[]},display:`Keine Inserate gefunden f\xFCr "${t.query}".`};let n=r.map(i=>i.price).filter(i=>i!=null),o=[];o.push(`**${r.length} Inserate** f\xFCr "${t.query}"${s.length>1?` (${s.map(i=>`${i.platform}: ${i.listings.length}`).join(", ")})`:""}
|
|
1014
|
+
`),o.push("| # | Titel | Preis | Standort | Plattform | Link |"),o.push("|---|-------|-------|----------|-----------|------|");for(let i=0;i<r.length;i++){let a=r[i],c=a.title.length>60?a.title.slice(0,57)+"...":a.title;o.push(`| ${i+1} | ${c} | ${ba(a.price,a.currency)} | ${a.location??"\u2014"} | ${a.platform} | [Link](${a.url}) |`)}return n.length>0&&(o.push(""),o.push(`**Min:** ${Math.min(...n).toFixed(2)} EUR | **Max:** ${Math.max(...n).toFixed(2)} EUR | **Median:** ${So(n).toFixed(2)} EUR`)),{success:!0,data:{query:t.query,count:r.length,totalCount:s.reduce((i,a)=>i+a.totalCount,0),minPrice:n.length?Math.min(...n):null,maxPrice:n.length?Math.max(...n):null,medianPrice:n.length?So(n):null,listings:r.map(i=>({id:i.id,title:i.title,price:i.price,location:i.location,url:i.url,platform:i.platform}))},display:o.join(`
|
|
999
1015
|
`)}}async handleCompare(e,t){let r=(await this.searchAll(e,t)).flatMap(d=>d.listings),n=r.map(d=>d.price).filter(d=>d!=null);if(n.length===0)return{success:!0,data:{query:t.query,count:0,minPrice:null,maxPrice:null,medianPrice:null,avgPrice:null,cheapest:[]},display:`Keine Inserate mit Preisangabe gefunden f\xFCr "${t.query}".`};let i=r.filter(d=>d.price!=null).sort((d,u)=>d.price-u.price).slice(0,5),a=n.reduce((d,u)=>d+u,0)/n.length,c=[];c.push(`**Preisvergleich** "${t.query}" \u2014 ${r.length} Inserate (${n.length} mit Preis)
|
|
1000
|
-
`),c.push("| Statistik | Wert |"),c.push("|-----------|------|"),c.push(`| Anzahl | ${n.length} |`),c.push(`| Minimum | ${Math.min(...n).toFixed(2)} EUR |`),c.push(`| Maximum | ${Math.max(...n).toFixed(2)} EUR |`),c.push(`| Median | ${
|
|
1001
|
-
`),c.push("| # | Titel | Preis | Standort | Plattform | Link |"),c.push("|---|-------|-------|----------|-----------|------|");for(let d=0;d<i.length;d++){let u=i[d],p=u.title.length>60?u.title.slice(0,57)+"...":u.title;c.push(`| ${d+1} | ${p} | ${
|
|
1002
|
-
`)}}async handleDetail(e,t){let r=(e==="all"?this.providers:this.providers.filter(c=>c.platform===e))[0];if(!r)return{success:!1,error:"Kein Provider verf\xFCgbar f\xFCr diese Plattform"};let n=await r.getDetail(t),o=[];o.push(`**${n.title}** \u2014 ${
|
|
1016
|
+
`),c.push("| Statistik | Wert |"),c.push("|-----------|------|"),c.push(`| Anzahl | ${n.length} |`),c.push(`| Minimum | ${Math.min(...n).toFixed(2)} EUR |`),c.push(`| Maximum | ${Math.max(...n).toFixed(2)} EUR |`),c.push(`| Median | ${So(n).toFixed(2)} EUR |`),c.push(`| Durchschnitt | ${a.toFixed(2)} EUR |`),c.push(""),c.push(`**G\xFCnstigste 5:**
|
|
1017
|
+
`),c.push("| # | Titel | Preis | Standort | Plattform | Link |"),c.push("|---|-------|-------|----------|-----------|------|");for(let d=0;d<i.length;d++){let u=i[d],p=u.title.length>60?u.title.slice(0,57)+"...":u.title;c.push(`| ${d+1} | ${p} | ${ba(u.price,u.currency)} | ${u.location??"\u2014"} | ${u.platform} | [Link](${u.url}) |`)}return{success:!0,data:{query:t.query,count:n.length,minPrice:Math.min(...n),maxPrice:Math.max(...n),medianPrice:So(n),avgPrice:a,cheapest:i.map(d=>({id:d.id,title:d.title,price:d.price,location:d.location,url:d.url,platform:d.platform}))},display:c.join(`
|
|
1018
|
+
`)}}async handleDetail(e,t){let r=(e==="all"?this.providers:this.providers.filter(c=>c.platform===e))[0];if(!r)return{success:!1,error:"Kein Provider verf\xFCgbar f\xFCr diese Plattform"};let n=await r.getDetail(t),o=[];o.push(`**${n.title}** \u2014 ${ba(n.price,n.currency)}`),o.push(`\u{1F4CD} ${n.location??"k.A."}`),n.condition&&o.push(`Zustand: ${n.condition}`),o.push(`Verk\xE4ufer: ${n.seller??"k.A."}${n.sellerSince?` (registriert seit ${n.sellerSince.split("T")[0]})`:""}`),o.push(`Fotos: ${n.imageUrls.length}`),n.publishedAt&&o.push(`Ver\xF6ffentlicht: ${n.publishedAt.split("T")[0]}`);let i=new Set(["DESCRIPTION","PRICE","PRICE/AMOUNT","PRICE_FOR_DISPLAY","AREA_ID","REGION_AREA_ID","SHOW_MAP","SHOW_SHADOWMAP","ISPRIVATE","DEALER","ORG_TYPE","LOCATION/ADDRESS_2","LOCATION/ADDRESS_3","LOCATION/ADDRESS_4"]),a=Object.entries(n.attributes).filter(([c])=>!i.has(c));return a.length>0&&o.push(`Attribute: ${a.map(([c,d])=>`${c}=${d}`).join(", ")}`),o.push(`
|
|
1003
1019
|
${n.description.slice(0,500)}`),o.push(`
|
|
1004
1020
|
Link: ${n.url}`),{success:!0,data:{id:n.id,title:n.title,price:n.price,currency:n.currency,condition:n.condition,location:n.location,url:n.url,description:n.description.slice(0,1e3),imageCount:n.imageUrls.length,imageUrls:n.imageUrls.slice(0,3),seller:n.seller,sellerSince:n.sellerSince,publishedAt:n.publishedAt,attributes:n.attributes,platform:n.platform},display:o.join(`
|
|
1005
|
-
`)}}async searchAll(e,t){return await Promise.all(e.map(r=>r.search(t).catch(n=>({listings:[],totalCount:0,query:t.query,platform:r.platform,error:String(n)}))))}}});var
|
|
1021
|
+
`)}}async searchAll(e,t){return await Promise.all(e.map(r=>r.search(t).catch(n=>({listings:[],totalCount:0,query:t.query,platform:r.platform,error:String(n)}))))}}});var xu=T(()=>{"use strict";Ru();bo();ka();Ea()});function tf(){let l=new Date,e=new Date(l.getFullYear(),l.getMonth(),l.getDate()),t=new Date(e.getTime()+1440*60*1e3);return{start:e.toISOString(),end:t.toISOString()}}function sf(l){let e=l.split(",").map(s=>s.trim());for(let s of e){let r=s.match(/^\d{4,5}\s+(.+)/);if(r)return r[1].trim()}return e.length>=3?e[e.length-2]:e[e.length-1]}function rf(){let l=new Date().getDay();return l>=1&&l<=5}var Sa,vo,Cu=T(()=>{"use strict";W();Me();m(tf,"todayRange");Sa=[{name:"calendar",skill:"calendar",input:{action:"list_events"},label:"Kalender"},{name:"weather",skill:"weather",input:{},label:"Wetter"},{name:"todo",skill:"todo",input:{action:"list"},label:"Lokale Todos"},{name:"mstodo",skill:"microsoft_todo",input:{action:"list_tasks"},label:"Microsoft To Do"},{name:"email",skill:"email",input:{action:"inbox"},label:"E-Mail"},{name:"energy",skill:"energy_price",input:{action:"briefing"},label:"Strompreise"},{name:"bmw",skill:"bmw",input:{action:"status"},label:"BMW Status"},{name:"home",skill:"homeassistant",input:{action:"briefing_summary"},label:"Smart Home"},{name:"infra",skill:"monitor",input:{},label:"Infrastruktur"}];m(sf,"extractCity");m(rf,"isWeekday");vo=class extends x{static{m(this,"BriefingSkill")}skillRegistry;alfredConfig;memoryRepo;metadata={name:"briefing",category:"productivity",description:'T\xE4gliches Morgenbriefing \u2014 sammelt Daten aus mehreren Skills parallel und liefert ein strukturiertes Ergebnis: Kalender, Wetter, Todos, E-Mails, Strompreise, Auto-Status, Smart Home, Infrastruktur. Mo\u2013Fr automatisch: Pendelzeit Heim\u2192B\xFCro + BMW-Akkucheck (wenn kein ausw\xE4rtiger Termin). "run" f\xFChrt das Briefing aus (optional mit location f\xFCr Wetter). "modules" zeigt verf\xFCgbare und aktive Module.',riskLevel:"read",version:"1.1.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","modules"],description:"run = Briefing ausf\xFChren, modules = verf\xFCgbare Module anzeigen"},location:{type:"string",description:'Ort f\xFCr Wetterabfrage (default: aus Config oder "Vienna")'},modules:{type:"array",items:{type:"string"},description:"Optionale Liste aktiver Module (default: alle verf\xFCgbaren)"}},required:["action"]}};constructor(e,t,s){super(),this.skillRegistry=e,this.alfredConfig=t,this.memoryRepo=s}async execute(e,t){let s=e.action??"run";switch(s){case"run":return this.runBriefing(e,t);case"modules":return this.showModules();default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getAvailableModules(){return Sa.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=Sa.map(n=>`${e.some(i=>i.name===n.name)?"\u2705":"\u274C"} ${n.name} (${n.label}) \u2192 ${n.skill}`),s=this.skillRegistry.has("routing"),r=!!(this.alfredConfig.briefing?.homeAddress&&this.alfredConfig.briefing?.officeAddress);return{success:!0,data:{available:e.map(n=>n.name),all:Sa.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
|
|
1006
1022
|
${t.join(`
|
|
1007
1023
|
`)}
|
|
1008
1024
|
|
|
1009
|
-
Pendler-Check (Mo\u2013Fr): ${s?r?"\u2705 konfiguriert (Config)":"\u23F3 Adressen werden aus Memories gelesen (oder ALFRED_BRIEFING_HOME/OFFICE_ADDRESS setzen)":"\u274C Routing-Skill nicht verf\xFCgbar"}`}}async runBriefing(e,t){let{home:s}=this.resolveAddresses(t),n=(s?
|
|
1010
|
-
`);for(let
|
|
1011
|
-
${this.cleanDisplay(
|
|
1012
|
-
${typeof
|
|
1013
|
-
\u26A0\uFE0F ${
|
|
1025
|
+
Pendler-Check (Mo\u2013Fr): ${s?r?"\u2705 konfiguriert (Config)":"\u23F3 Adressen werden aus Memories gelesen (oder ALFRED_BRIEFING_HOME/OFFICE_ADDRESS setzen)":"\u274C Routing-Skill nicht verf\xFCgbar"}`}}async runBriefing(e,t){let{home:s}=this.resolveAddresses(t),n=(s?sf(s):void 0)??this.alfredConfig.briefing?.location??e.location??"Vienna",o=e.modules,i=this.getAvailableModules();o?.length&&(i=i.filter(g=>o.includes(g.name)));let a=this.resolveHaPreferences(t),c=i.map(g=>{let y={...g.input};if(g.name==="calendar"){let{start:_,end:S}=tf();y.start=_,y.end=S}return g.name==="weather"&&(y.location=n),g.name==="home"&&(a.entities?.length&&(y.entities=a.entities),a.domains?.length&&(y.domains=a.domains)),{module:g,input:y}}),d=await Promise.all(c.map(g=>this.executeModule(g.module,g.input,t))),u=await this.runCommuteCheck(d,t);u&&d.push(u);let p=new Date().toLocaleDateString("de-AT",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),h=[];h.push(`**\u2600\uFE0F Morgenbriefing \u2013 ${p}**
|
|
1026
|
+
`);for(let g of d)g.success&&g.display?h.push(`**${g.label}**
|
|
1027
|
+
${this.cleanDisplay(g.module,g.display)}`):g.success&&g.data?h.push(`**${g.label}**
|
|
1028
|
+
${typeof g.data=="string"?g.data:JSON.stringify(g.data,null,2)}`):!g.success&&g.error&&h.push(`**${g.label}**
|
|
1029
|
+
\u26A0\uFE0F ${g.error}`);let f=this.buildHighlights(d);return f.length>0&&(h.push("---"),h.push("**Highlights:**"),h.push(f.join(`
|
|
1014
1030
|
`))),{success:!0,data:d,display:h.join(`
|
|
1015
1031
|
|
|
1016
|
-
`)}}async executeModule(e,t,s){try{let r=this.skillRegistry.get(e.skill);if(!r)return{module:e.name,label:e.label,success:!1,error:"Skill nicht gefunden"};let n=await r.execute(t,s);return{module:e.name,label:e.label,success:n.success,data:n.data,display:n.display,error:n.error}}catch(r){return{module:e.name,label:e.label,success:!1,error:String(r instanceof Error?r.message:r)}}}async runCommuteCheck(e,t){if(!
|
|
1032
|
+
`)}}async executeModule(e,t,s){try{let r=this.skillRegistry.get(e.skill);if(!r)return{module:e.name,label:e.label,success:!1,error:"Skill nicht gefunden"};let n=await r.execute(t,s);return{module:e.name,label:e.label,success:n.success,data:n.data,display:n.display,error:n.error}}catch(r){return{module:e.name,label:e.label,success:!1,error:String(r instanceof Error?r.message:r)}}}async runCommuteCheck(e,t){if(!rf()||!this.skillRegistry.has("routing"))return null;let{home:s,office:r}=this.resolveAddresses(t);if(!s||!r)return null;let n=e.find(u=>u.module==="calendar");if(n?.success&&n.data&&this.detectExternalAppointment(n.data))return null;let o=[];o.push(this.executeModule({name:"commute",skill:"routing",input:{},label:"Pendelzeit"},{action:"route",origin:s,destination:r},t));let a=(await Promise.all(o))[0],c=e.find(u=>u.module==="bmw"),d=[];if(a.success&&a.display?d.push(`**Route Heim \u2192 B\xFCro:**
|
|
1017
1033
|
${a.display}`):a.error&&d.push(`**Route:** \u26A0\uFE0F ${a.error}`),c?.success&&c.data){let u=this.extractBatteryLevel(c.data);u!=null&&u<30?d.push(`
|
|
1018
1034
|
\u26A0\uFE0F **BMW Akku niedrig (${u}%)** \u2014 Laden vor der Fahrt empfohlen!`):u!=null&&d.push(`
|
|
1019
1035
|
\u{1F50B} BMW Akku: ${u}% \u2014 ausreichend f\xFCr den Arbeitsweg`)}return d.length===0?null:{module:"commute",label:"Arbeitsweg (Mo\u2013Fr)",success:!0,data:{route:a.data,bmwBattery:this.extractBatteryLevel(c?.data)},display:d.join(`
|
|
1020
|
-
`)}}resolveAddresses(e){let t=this.alfredConfig.briefing?.homeAddress,s=this.alfredConfig.briefing?.officeAddress;if(!this.memoryRepo)return{home:t,office:s};let r=t,n=s;for(let o of
|
|
1036
|
+
`)}}resolveAddresses(e){let t=this.alfredConfig.briefing?.homeAddress,s=this.alfredConfig.briefing?.officeAddress;if(!this.memoryRepo)return{home:t,office:s};let r=t,n=s;for(let o of K(e)){let i=this.memoryRepo.search(o,"adresse");for(let a of i){let c=a.key.toLowerCase(),d=a.value;!r&&/heim|home|wohn|zuhause|privat/.test(c)&&(r=d),!n&&/büro|office|arbeit|firma|work/.test(c)&&(n=d)}if(r&&n)break}return{home:r,office:n}}resolveHaPreferences(e){let t=this.alfredConfig.briefing?.homeAssistant?.entities,s=this.alfredConfig.briefing?.homeAssistant?.domains;if(t?.length||s?.length)return{entities:t,domains:s};if(!this.memoryRepo)return{};for(let r of K(e)){let n=this.memoryRepo.search(r,"briefing");for(let o of n){let i=o.key.toLowerCase();if(/ha_entit|home.?assistant.*entit|briefing.*entit/.test(i)){let a=o.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(a.length)return{entities:a}}if(/ha_domain|home.?assistant.*domain|briefing.*domain/.test(i)){let a=o.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(a.length)return{domains:a}}}}return{}}detectExternalAppointment(e){return Array.isArray(e)?e.some(t=>{let s=t.location??t.loc??"";return!s||typeof s!="string"||/teams|zoom|meet\.google|webex|skype/i.test(s)?!1:s.trim().length>0}):!1}cleanDisplay(e,t){let s=t;return s=s.replace(/\s*\[(?:id:)?[A-Za-z0-9+/=\-]{20,}\]/g,""),e==="email"&&(s=s.replace(/^\d+\.\s*/gm,"- ").replace(/\[UNREAD\]/g,"\u{1F4E9}").replace(/\[ATT\]/g,"\u{1F4CE}").replace(/\n\s+Date:\s+\S+/g,"")),e==="calendar"&&(s=s.replace(/^\d+\s+event\(s\):\n?/i,"")),e==="todo"&&(s=s.replace(/^\|.*\|$/gm,r=>{if(/^[\|\s\-:]+$/.test(r))return"";let n=r.split("|").map(o=>o.trim()).filter(Boolean);if(n.length>=3){let o=n[0],i=n[1]&&n[1]!==""?` [${n[1]}]`:"",a=n[2];return`${o}${i} ${a}`}return r}),s=s.replace(/^\d+\s+todo\(s\):\n?/i,""),s=s.replace(/\n{2,}/g,`
|
|
1021
1037
|
`)),e==="mstodo"&&(s=s.replace(/\s*\[(?:taskId|listId)=[^\]]+\]/g,"")),s=s.replace(/^\[[\w-]+\]\s*/gm,""),s=s.replace(/\n{3,}/g,`
|
|
1022
1038
|
|
|
1023
|
-
`),s.trim()}buildHighlights(e){let t=[],s=e.find(i=>i.module==="bmw")?.data;if(s){let i=this.extractBatteryLevel(s);i!=null&&i<30&&t.push(`\u{1F697} BMW Akku bei ${i}% \u2014 laden empfohlen`)}let r=e.find(i=>i.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(i=>i.module==="energy")?.data;if(n){let i=n.currentCt,a=n.avgCt;i!=null&&a!=null&&i<a&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${i} ct/kWh)`)}let o=e.find(i=>i.module==="calendar")?.data;return Array.isArray(o)&&o.length>0&&t.push(`\u{1F4C5} ${o.length} Termin(e) heute`),t}extractBatteryLevel(e){if(!e||typeof e!="object")return null;let t=e,s=t.chargingLevelPercent??t.batterySoc??t.soc??t.chargingState?.chargingLevelPercent;if(typeof s=="number")return s;if(typeof s=="string"){let r=parseFloat(s);return isNaN(r)?null:r}return null}}});var
|
|
1039
|
+
`),s.trim()}buildHighlights(e){let t=[],s=e.find(i=>i.module==="bmw")?.data;if(s){let i=this.extractBatteryLevel(s);i!=null&&i<30&&t.push(`\u{1F697} BMW Akku bei ${i}% \u2014 laden empfohlen`)}let r=e.find(i=>i.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(i=>i.module==="energy")?.data;if(n){let i=n.currentCt,a=n.avgCt;i!=null&&a!=null&&i<a&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${i} ct/kWh)`)}let o=e.find(i=>i.module==="calendar")?.data;return Array.isArray(o)&&o.length>0&&t.push(`\u{1F4C5} ${o.length} Termin(e) heute`),t}extractBatteryLevel(e){if(!e||typeof e!="object")return null;let t=e,s=t.chargingLevelPercent??t.batterySoc??t.soc??t.chargingState?.chargingLevelPercent;if(typeof s=="number")return s;if(typeof s=="string"){let r=parseFloat(s);return isNaN(r)?null:r}return null}}});var Cs,Nu=T(()=>{"use strict";W();Cs=class extends x{static{m(this,"FeedReaderSkill")}memoryRepo;metadata={name:"feed_reader",category:"information",description:"Subscribe to RSS/Atom feeds and check for new entries. Actions: subscribe, unsubscribe, list_feeds, check.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["subscribe","unsubscribe","list_feeds","check","check_all"],description:"The action to perform"},url:{type:"string",description:"Feed URL (for subscribe, unsubscribe, check)"},label:{type:"string",description:"Human-readable label for the feed (for subscribe)"}},required:["action"]}};constructor(e){super(),this.memoryRepo=e}async execute(e,t){let s=e.action,r=e.url,n=t.userId;switch(s){case"subscribe":return this.subscribe(n,r,e.label);case"unsubscribe":return this.unsubscribe(n,r);case"list_feeds":return this.listFeeds(n);case"check":case"check_all":return this.check(n,r);default:return{success:!1,error:`Unknown action: ${s}`}}}async subscribe(e,t,s){if(!t)return{success:!1,error:"URL is required for subscribe"};let r={url:t,label:s??t,lastCheckedAt:null,lastEntryId:null};return this.memoryRepo.save(e,`feed:${t}`,JSON.stringify(r),"feed"),{success:!0,data:r,display:`Subscribed to feed: ${r.label} (${t})`}}async unsubscribe(e,t){return t?this.memoryRepo.delete(e,`feed:${t}`)?{success:!0,display:`Unsubscribed from feed: ${t}`}:{success:!1,error:`No subscription found for ${t}`}:{success:!1,error:"URL is required for unsubscribe"}}async listFeeds(e){let s=this.memoryRepo.listByCategory(e,"feed").map(n=>{try{return JSON.parse(n.value)}catch{return null}}).filter(Boolean);if(s.length===0)return{success:!0,data:[],display:"No feed subscriptions found."};let r=s.map(n=>`\u2022 ${n.label} \u2014 ${n.url} (last checked: ${n.lastCheckedAt??"never"})`);return{success:!0,data:s,display:`Feed subscriptions:
|
|
1024
1040
|
${r.join(`
|
|
1025
1041
|
`)}`}}async check(e,t){if(!t){let i=this.memoryRepo.listByCategory(e,"feed");if(i.length===0)return{success:!0,data:{newCount:0},display:"No feed subscriptions to check."};let a=0,c=[];for(let u of i)try{let p=JSON.parse(u.value),h=await this.checkSingleFeed(e,p);h.newCount>0&&(a+=h.newCount,c.push(h))}catch{}let d=c.map(u=>`${u.label}: ${u.newCount} new
|
|
1026
1042
|
${u.items.map(p=>` \u2022 ${p.title}${p.link?` \u2014 ${p.link}`:""}${p.snippet?`
|
|
@@ -1031,17 +1047,17 @@ ${d.join(`
|
|
|
1031
1047
|
`)}`:"No new entries in any feed."}}let s=this.memoryRepo.listByCategory(e,"feed").find(i=>i.key===`feed:${t}`);if(!s)return{success:!1,error:`Not subscribed to ${t}. Use subscribe first.`};let r=JSON.parse(s.value),n=await this.checkSingleFeed(e,r),o=n.items.map(i=>`\u2022 ${i.title}${i.link?` \u2014 ${i.link}`:""}${i.snippet?`
|
|
1032
1048
|
${i.snippet}`:""}`);return{success:!0,data:{newCount:n.newCount,items:n.items},display:n.newCount>0?`${n.newCount} new in ${n.label}:
|
|
1033
1049
|
${o.join(`
|
|
1034
|
-
`)}`:`No new entries in ${n.label}.`}}async checkSingleFeed(e,t){let s=(await import("rss-parser")).default,o=(await new s({timeout:15e3}).parseURL(t.url)).items??[],i;if(t.lastEntryId){let d=o.findIndex(u=>(u.guid??u.link??u.title)===t.lastEntryId);i=d>0?o.slice(0,d):d===0?[]:o.slice(0,10)}else i=o.slice(0,5);let a=o[0]?o[0].guid??o[0].link??o[0].title??null:null,c={...t,lastCheckedAt:new Date().toISOString(),lastEntryId:a};return this.memoryRepo.save(e,`feed:${t.url}`,JSON.stringify(c),"feed"),{label:t.label,newCount:i.length,items:i.map(d=>{let u=d.contentSnippet??d.summary??"";return!u&&typeof d.content=="string"&&(u=d.content.replace(/<[^>]*>/g,"").slice(0,200)),{title:d.title??"(untitled)",link:d.link,pubDate:d.pubDate,snippet:u?u.slice(0,200).trim():void 0}})}}}});import{spawn as
|
|
1035
|
-
`+l.slice(-
|
|
1036
|
-
`).pop();b&&t.onProgress(`[${l.name}] ${b}`)}}),l.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",
|
|
1037
|
-
`+
|
|
1038
|
-
`).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function
|
|
1039
|
-
[...truncated]`}function
|
|
1050
|
+
`)}`:`No new entries in ${n.label}.`}}async checkSingleFeed(e,t){let s=(await import("rss-parser")).default,o=(await new s({timeout:15e3}).parseURL(t.url)).items??[],i;if(t.lastEntryId){let d=o.findIndex(u=>(u.guid??u.link??u.title)===t.lastEntryId);i=d>0?o.slice(0,d):d===0?[]:o.slice(0,10)}else i=o.slice(0,5);let a=o[0]?o[0].guid??o[0].link??o[0].title??null:null,c={...t,lastCheckedAt:new Date().toISOString(),lastEntryId:a};return this.memoryRepo.save(e,`feed:${t.url}`,JSON.stringify(c),"feed"),{label:t.label,newCount:i.length,items:i.map(d=>{let u=d.contentSnippet??d.summary??"";return!u&&typeof d.content=="string"&&(u=d.content.replace(/<[^>]*>/g,"").slice(0,200)),{title:d.title??"(untitled)",link:d.link,pubDate:d.pubDate,snippet:u?u.slice(0,200).trim():void 0}})}}}});import{spawn as nf}from"node:child_process";import Lu from"node:fs";import Ou from"node:path";function lf(l){let e={};for(let[t,s]of Object.entries(l))e[t]=s.replace(/\$\{(\w+)\}/g,(r,n)=>process.env[n]??"");return e}function df(l,e){return l.map(t=>t.replace(/\{\{prompt\}\}/g,e))}function $o(l){return l.length<=Du?l:`[...truncated...]
|
|
1051
|
+
`+l.slice(-Du)}function Mu(l){let e=new Map;function t(s){let r;try{r=Lu.readdirSync(s,{withFileTypes:!0})}catch{return}for(let n of r){if(cf.has(n.name))continue;let o=Ou.join(s,n.name);if(n.isDirectory())t(o);else if(n.isFile())try{let i=Lu.statSync(o);e.set(o,i.mtimeMs)}catch{}}}return m(t,"walk"),t(l),e}function uf(l,e,t){let s=[];for(let[r,n]of e){let o=l.get(r);(o===void 0||n>o)&&s.push(Ou.relative(t,r))}return s.sort()}async function Yr(l,e,t={}){let s=t.cwd??l.cwd??process.cwd(),r=t.timeoutMs??l.timeoutMs??of,n=Math.min(r,af),o=df(l.argsTemplate,e),i={...process.env,...l.env?lf(l.env):{}},a=process.platform==="win32",c=Mu(s),d=Date.now();return new Promise(u=>{let p=nf(l.command,o,{cwd:s,env:i,shell:a,stdio:l.promptVia==="stdin"?["pipe","pipe","pipe"]:["ignore","pipe","pipe"]}),h="",f="",g=!1,y=setTimeout(()=>{g=!0,p.kill("SIGTERM"),setTimeout(()=>p.kill("SIGKILL"),5e3)},n);p.stdout?.on("data",_=>{h+=_.toString()}),p.stderr?.on("data",_=>{let S=_.toString();if(f+=S,t.onProgress){let b=S.trim().split(`
|
|
1052
|
+
`).pop();b&&t.onProgress(`[${l.name}] ${b}`)}}),l.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",_=>{clearTimeout(y);let S=Date.now()-d,b=Mu(s),$=uf(c,b,s);u({stdout:$o(h),stderr:$o(f),exitCode:g?124:_??1,durationMs:S,modifiedFiles:$})}),p.on("error",_=>{clearTimeout(y);let S=Date.now()-d;u({stdout:$o(h),stderr:$o(f+`
|
|
1053
|
+
`+_.message),exitCode:127,durationMs:S,modifiedFiles:[]})})})}var of,af,Du,cf,Io=T(()=>{"use strict";of=3e5,af=9e5,Du=1e5,cf=new Set([".git","node_modules",".next","dist",".cache"]);m(lf,"resolveEnv");m(df,"buildArgs");m($o,"truncateOutput");m(Mu,"snapshotMtimes");m(uf,"detectModifiedFiles");m(Yr,"executeAgent")});import{execFile as mf}from"node:child_process";function Ge(l,e){return new Promise((t,s)=>{mf("git",l,{cwd:e.cwd,maxBuffer:10*1024*1024},(r,n,o)=>{if(r){let i=o?.trim()||r.message;s(new Error(`git ${l[0]} failed: ${i}`));return}t(n.trim())})})}async function Ao(l){try{let e=await Ge(["rev-parse","--abbrev-ref","HEAD"],l),t=await Ge(["status","--porcelain"],l);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function va(l,e){await Ge(["checkout","-b",l],e)}async function $a(l){await Ge(["add","-A"],l)}async function Ia(l,e){await Ge(["commit","-m",l],e);let t=await Ge(["rev-parse","--short","HEAD"],e),r=(await Ge(["diff","--stat","HEAD~1","HEAD"],e)).split(`
|
|
1054
|
+
`).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function Aa(l,e,t){await Ge(["push","-u",l,e],t)}function Ra(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function Ns(l,e){try{return await Ge(["remote","get-url",l],e)}catch{return null}}function Ls(l){let e=l.match(/^git@([^:]+):(.+?)(?:\.git)?$/);if(e){let s=e[1],n=e[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}let t=l.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);if(t){let s=t[1],n=t[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}return null}async function Jr(l){await Ge(["init"],l)}async function Zr(l,e,t){await Ge(["remote","add",l,e],t)}var xa=T(()=>{"use strict";m(Ge,"git");m(Ao,"gitStatus");m(va,"gitCreateBranch");m($a,"gitStageAll");m(Ia,"gitCommit");m(Aa,"gitPush");m(Ra,"slugifyBranch");m(Ns,"gitGetRemoteUrl");m(Ls,"parseRemoteUrl");m(Jr,"gitInitRepo");m(Zr,"gitAddRemote")});function Ds(l){switch(l.provider){case"github":{if(!l.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Ca(l.github)}case"gitlab":{if(!l.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new Na(l.gitlab)}default:throw new Error(`Unknown forge provider: ${l.provider}`)}}var Wt,Ca,Na,La=T(()=>{"use strict";Wt=class{static{m(this,"ForgeClient")}},Ca=class extends Wt{static{m(this,"GitHubForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://api.github.com"}async createPullRequest(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/pulls`,r=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({title:t.title,body:t.body,head:t.head,base:t.base})});if(!r.ok){let o=await r.text();throw new Error(`GitHub PR creation failed (${r.status}): ${o}`)}let n=await r.json();return{id:n.id,url:n.html_url,number:n.number,state:n.state}}async getPipelineStatus(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/commits/${t}/status`,r=await fetch(s,{headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json"}});if(!r.ok)return{state:"unknown"};let o=(await r.json()).state;return{state:{pending:"pending",success:"success",failure:"failure",error:"failure"}[o]??"unknown"}}async createProject(e){let t=`${this.baseUrl}/user/repos`,s=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",private:(e.visibility??"private")==="private"})});if(!s.ok){let n=await s.text();throw new Error(`GitHub project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.html_url,cloneUrl:r.clone_url}}},Na=class extends Wt{static{m(this,"GitLabForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://gitlab.com"}async createPullRequest(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/merge_requests`,n=await fetch(r,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({title:t.title,description:t.body,source_branch:t.head,target_branch:t.base})});if(!n.ok){let i=await n.text();throw new Error(`GitLab MR creation failed (${n.status}): ${i}`)}let o=await n.json();return{id:o.id,url:o.web_url,number:o.iid,state:o.state}}async getPipelineStatus(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/pipelines?ref=${encodeURIComponent(t)}&per_page=1`,n=await fetch(r,{headers:{"PRIVATE-TOKEN":this.config.token}});if(!n.ok)return{state:"unknown"};let o=await n.json();if(o.length===0)return{state:"unknown"};let i=o[0],a=i.status;return{state:{pending:"pending",running:"running",success:"success",failed:"failure",canceled:"failure"}[a]??"unknown",url:i.web_url}}async createProject(e){let t=`${this.baseUrl}/api/v4/projects`,s=await fetch(t,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",visibility:e.visibility??"private"})});if(!s.ok){let n=await s.text();throw new Error(`GitLab project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.web_url,cloneUrl:r.http_url_to_repo}}};m(Ds,"createForgeClient")});function Pu(l,e){return l.length<=e?l:l.slice(0,e)+`
|
|
1055
|
+
[...truncated]`}function Uu(l){let e=l.replace(/^```(?:json)?\s*\n?/m,"").replace(/\n?```\s*$/m,"");return JSON.parse(e)}async function _f(l,e,t){let r=`Available agents:
|
|
1040
1056
|
${e.map(a=>`- ${a.name}: command="${a.command}"`).join(`
|
|
1041
1057
|
`)}
|
|
1042
1058
|
|
|
1043
1059
|
Task:
|
|
1044
|
-
${l}`,n=await t.complete({system:
|
|
1060
|
+
${l}`,n=await t.complete({system:wf,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"}),o=Uu(n.content);if(!Array.isArray(o.subtasks)||o.subtasks.length===0)throw new Error("LLM returned an empty plan with no subtasks");let i=new Set(e.map(a=>a.name));for(let a of o.subtasks)if(!i.has(a.agent))throw new Error(`Plan references unknown agent "${a.agent}". Available: ${[...i].join(", ")}`);return o}async function kf(l,e,t,s){let r=new Da(t),n=[],o=l.map(async i=>{await r.acquire();try{s?.(`Running ${i.id}: ${i.description}`);let a=e.get(i.agent),c=await Yr(a,i.prompt,{onProgress:s?u=>s(`[${i.id}] ${u}`):void 0}),d={subtask:i,execution:c};return n.push(d),s?.(`Completed ${i.id}: exit=${c.exitCode}, ${c.modifiedFiles.length} files modified`),d}finally{r.release()}});return await Promise.all(o),n}async function Ef(l,e,t){let s=e.map(o=>{let i=Pu(o.execution.stdout,gf),a=Pu(o.execution.stderr,yf);return[`### ${o.subtask.id} (${o.subtask.description})`,`Agent: ${o.subtask.agent}`,`Exit code: ${o.execution.exitCode}`,`Modified files: ${o.execution.modifiedFiles.join(", ")||"none"}`,i?`stdout:
|
|
1045
1061
|
${i}`:"",a?`stderr:
|
|
1046
1062
|
${a}`:""].filter(Boolean).join(`
|
|
1047
1063
|
`)}).join(`
|
|
@@ -1050,11 +1066,11 @@ ${a}`:""].filter(Boolean).join(`
|
|
|
1050
1066
|
${l}
|
|
1051
1067
|
|
|
1052
1068
|
Results:
|
|
1053
|
-
${s}`,n=await t.complete({system:
|
|
1069
|
+
${s}`,n=await t.complete({system:Tf,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=Uu(n.content);return{approved:o.approved??!0,summary:o.summary??"",fixTasks:Array.isArray(o.fixTasks)?o.fixTasks:[]}}catch{return{approved:!0,summary:n.content,fixTasks:[]}}}async function zt(l,e,t,s={}){let r=Math.min(s.maxIterations??pf,hf),n=s.maxConcurrent??ff,o=s.onProgress,i=Date.now(),a=new Map(e.map(g=>[g.name,g]));o?.("Planning subtasks...");let c=await _f(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,p=0,h="";for(;p<r;){p++,o?.(`Iteration ${p}: executing ${u.length} subtask(s)...`);let g=await kf(u,a,n,o);d=d.concat(g),o?.(`Iteration ${p}: validating results...`);let y=await Ef(l,d,t);if(h=y.summary,y.approved||y.fixTasks.length===0)break;let _=y.fixTasks.filter(S=>a.has(S.agent)?!0:(o?.(`Warning: fix task "${S.id}" references unknown agent "${S.agent}", skipping`),!1));if(_.length===0)break;u=_,o?.(`Validation requested ${_.length} fix task(s), iterating...`)}let f=[...new Set(d.flatMap(g=>g.execution.modifiedFiles))].sort();return{plan:c,iterations:p,subtaskResults:d,allModifiedFiles:f,summary:h,totalDurationMs:Date.now()-i}}async function Qr(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await Ao({cwd:n});if(!i.isRepo)try{await Jr({cwd:n}),i=await Ao({cwd:n}),r?.("Initialised new git repository")}catch{return o.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await zt(l,e,t,s),git:o}}let a=null,c=await Ns("origin",{cwd:n});if(c){let f=Ls(c);f?(a={owner:f.owner,repo:f.repo},r?.(`Detected remote: ${f.owner}/${f.repo} (${f.baseUrl})`)):o.warnings.push(`Could not parse remote URL: ${c}`)}let d=s.forge;if(!c&&d)try{let f=Ds(d),g=n.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${g}" on forge...`);let y=await f.createProject({name:g,visibility:"private"});await Zr("origin",y.cloneUrl,{cwd:n});let _=Ls(y.cloneUrl);_&&(a={owner:_.owner,repo:_.repo}),r?.(`Project created: ${y.url} \u2014 remote "origin" set`)}catch(f){let g=f instanceof Error?f.message:String(f);o.warnings.push(`Project creation failed: ${g}`),r?.(`Warning: project creation failed \u2014 ${g}`)}let u=Ra(l);try{await va(u,{cwd:n}),o.branch=u,r?.(`Created branch: ${u}`)}catch(f){throw new Error(`Failed to create branch "${u}": ${f instanceof Error?f.message:String(f)}`)}let p=await zt(l,e,t,s);try{await $a({cwd:n});let f=`feat: ${l.slice(0,72)}
|
|
1054
1070
|
|
|
1055
|
-
Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,
|
|
1071
|
+
Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,g=await Ia(f,{cwd:n});o.commit=g,r?.(`Committed: ${g.sha} (${g.filesChanged} files changed)`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Commit failed: ${g}`),r?.(`Warning: commit failed \u2014 ${g}`),{...p,git:o}}if(!await Ns("origin",{cwd:n}))return o.warnings.push("No remote configured \u2014 skipping push and PR creation"),r?.("No remote configured, skipping push and PR"),{...p,git:o};try{await Aa("origin",u,{cwd:n}),r?.(`Pushed branch: ${u}`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Push failed: ${g}`),r?.(`Warning: push failed \u2014 ${g}`),{...p,git:o}}if(d&&a)try{let f=Ds(d),g=s.baseBranch??d.baseBranch??"main",y=s.prTitle??`feat: ${l.slice(0,72)}`,_=["## Summary",p.summary,"",`**Iterations:** ${p.iterations}`,`**Modified files:** ${p.allModifiedFiles.length}`,p.allModifiedFiles.map(b=>`- \`${b}\``).join(`
|
|
1056
1072
|
`),"","_Automated by Alfred_"].join(`
|
|
1057
|
-
`),S=await
|
|
1073
|
+
`),S=await f.createPullRequest(a,{title:y,body:_,head:u,base:g});o.pullRequest=S,r?.(`PR created: ${S.url}`)}catch(f){let g=f instanceof Error?f.message:String(f);o.warnings.push(`PR creation failed: ${g}`),r?.(`Warning: PR creation failed \u2014 ${g}`)}else d||(o.warnings.push("No forge configured \u2014 skipping PR creation"),r?.("No forge configured, skipping PR creation"));return{...p,git:o}}var pf,hf,ff,gf,yf,wf,Tf,Da,Ma=T(()=>{"use strict";Io();xa();La();pf=3,hf=5,ff=3,gf=2048,yf=1024,wf=`You are a task planner for a multi-agent coding system.
|
|
1058
1074
|
You receive a high-level task and a list of available coding agents.
|
|
1059
1075
|
Your job is to decompose the task into concrete subtasks, each assigned to an agent.
|
|
1060
1076
|
|
|
@@ -1070,7 +1086,7 @@ Respond with ONLY valid JSON (no markdown fences):
|
|
|
1070
1086
|
"subtasks": [
|
|
1071
1087
|
{ "id": "task-1", "agent": "<agent-name>", "prompt": "<detailed prompt>", "description": "<short description>" }
|
|
1072
1088
|
]
|
|
1073
|
-
}`,
|
|
1089
|
+
}`,Tf=`You are a code review validator for a multi-agent coding system.
|
|
1074
1090
|
You receive the original task and the results from each subtask execution.
|
|
1075
1091
|
Your job is to determine if the task was completed successfully.
|
|
1076
1092
|
|
|
@@ -1084,9 +1100,9 @@ Respond with ONLY valid JSON (no markdown fences):
|
|
|
1084
1100
|
"fixTasks": [
|
|
1085
1101
|
{ "id": "fix-1", "agent": "<agent-name>", "prompt": "<detailed fix prompt>", "description": "<short description>" }
|
|
1086
1102
|
]
|
|
1087
|
-
}`;m(
|
|
1103
|
+
}`;m(Pu,"truncate");m(Uu,"parseJSON");Da=class{static{m(this,"Semaphore")}max;queue=[];active=0;constructor(e){this.max=e}async acquire(){if(this.active<this.max){this.active++;return}return new Promise(e=>{this.queue.push(()=>{this.active++,e()})})}release(){this.active--;let e=this.queue.shift();e&&e()}};m(_f,"planSubtasks");m(kf,"executeSubtasksParallel");m(Ef,"validateResults");m(zt,"orchestrate");m(Qr,"orchestrateWithGit")});var en,Fu=T(()=>{"use strict";W();Io();Ma();en=class extends x{static{m(this,"CodeAgentSkill")}llm;metadata={name:"code_agent",category:"automation",description:'Run a CLI-based coding agent (e.g. Claude Code, Codex, Gemini CLI, Aider) as a subprocess. Use action "list_agents" to see available agents, "run" to execute one with a prompt, or "orchestrate" to have the LLM decompose a task into parallel subtasks. The agent runs in a specified working directory and returns stdout, stderr, exit code, duration, and a list of files it modified.',riskLevel:"admin",version:"1.0.0",timeoutMs:6e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_agents","run","orchestrate"],description:"The action to perform"},task:{type:"string",description:'High-level task description for "orchestrate" action'},agents:{type:"array",items:{type:"string"},description:'Optional agent name filter for "orchestrate" (uses all agents if omitted)'},maxIterations:{type:"number",description:'Max validation iterations for "orchestrate" (1-5, default 3)'},agent:{type:"string",description:'Name of the agent to run (required for "run" action)'},prompt:{type:"string",description:'The prompt / task description to send to the agent (required for "run" action)'},cwd:{type:"string",description:"Working directory for the agent (optional, uses agent default or process.cwd())"},timeout:{type:"number",description:"Timeout in milliseconds (optional, max 900000)"},git:{type:"boolean",description:'Enable git workflow: auto-branch, commit, push, and PR creation (for "orchestrate")'},prTitle:{type:"string",description:"Custom PR/MR title (used with git=true)"},baseBranch:{type:"string",description:'Target branch for the PR/MR (default: "main")'}},required:["action"]}};agents;forgeConfig;constructor(e,t){super(),this.llm=t,this.agents=new Map(e.agents.map(s=>[s.name,s])),this.forgeConfig=e.forge}async execute(e,t){let s=e.action;switch(s){case"list_agents":return this.listAgents();case"run":return this.runAgent(e,t);case"orchestrate":return this.orchestrateTask(e,t);default:return{success:!1,error:`Unknown action "${s}". Use "list_agents", "run", or "orchestrate".`}}}listAgents(){let e=[...this.agents.values()].map(s=>({name:s.name,command:s.command,promptVia:s.promptVia??"arg",timeoutMs:s.timeoutMs})),t=e.length===0?"No code agents configured.":e.map(s=>`- **${s.name}**: \`${s.command}\` (prompt via ${s.promptVia})`).join(`
|
|
1088
1104
|
`);return{success:!0,data:{agents:e},display:`Available code agents:
|
|
1089
|
-
${t}`}}async runAgent(e,t){let s=e.agent,r=e.prompt;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "agent"'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "prompt"'};let n=this.agents.get(s);if(!n){let d=[...this.agents.keys()].join(", ");return{success:!1,error:`Unknown agent "${s}". Available: ${d}`}}let o=typeof e.cwd=="string"?e.cwd:void 0,i=typeof e.timeout=="number"?e.timeout:void 0,a=await
|
|
1105
|
+
${t}`}}async runAgent(e,t){let s=e.agent,r=e.prompt;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "agent"'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "prompt"'};let n=this.agents.get(s);if(!n){let d=[...this.agents.keys()].join(", ");return{success:!1,error:`Unknown agent "${s}". Available: ${d}`}}let o=typeof e.cwd=="string"?e.cwd:void 0,i=typeof e.timeout=="number"?e.timeout:void 0,a=await Yr(n,r,{cwd:o,timeoutMs:i,onProgress:t.onProgress}),c=[];return a.stdout&&c.push(`**stdout:**
|
|
1090
1106
|
\`\`\`
|
|
1091
1107
|
${a.stdout}
|
|
1092
1108
|
\`\`\``),a.stderr&&c.push(`**stderr:**
|
|
@@ -1096,7 +1112,7 @@ ${a.stderr}
|
|
|
1096
1112
|
${a.modifiedFiles.map(d=>`- ${d}`).join(`
|
|
1097
1113
|
`)}`),{success:a.exitCode===0,data:{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,durationMs:a.durationMs,modifiedFiles:a.modifiedFiles},display:c.join(`
|
|
1098
1114
|
|
|
1099
|
-
`),...a.exitCode!==0&&{error:a.exitCode===124?`Agent "${s}" timed out`:`Agent "${s}" exited with code ${a.exitCode}`}}}async orchestrateTask(e,t){if(!this.llm)return{success:!1,error:"Orchestration requires an LLM provider but none was configured."};let s=e.task;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task" for orchestrate action.'};let r=[...this.agents.values()],n=e.agents;if(Array.isArray(n)&&n.length>0&&(r=n.map(d=>this.agents.get(d)).filter(d=>d!==void 0),r.length===0))return{success:!1,error:`None of the specified agents exist. Available: ${[...this.agents.keys()].join(", ")}`};let o=typeof e.maxIterations=="number"?e.maxIterations:void 0,i=e.git===!0,a=typeof e.prTitle=="string"?e.prTitle:void 0,c=typeof e.baseBranch=="string"?e.baseBranch:void 0;try{if(i){let u=await
|
|
1115
|
+
`),...a.exitCode!==0&&{error:a.exitCode===124?`Agent "${s}" timed out`:`Agent "${s}" exited with code ${a.exitCode}`}}}async orchestrateTask(e,t){if(!this.llm)return{success:!1,error:"Orchestration requires an LLM provider but none was configured."};let s=e.task;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task" for orchestrate action.'};let r=[...this.agents.values()],n=e.agents;if(Array.isArray(n)&&n.length>0&&(r=n.map(d=>this.agents.get(d)).filter(d=>d!==void 0),r.length===0))return{success:!1,error:`None of the specified agents exist. Available: ${[...this.agents.keys()].join(", ")}`};let o=typeof e.maxIterations=="number"?e.maxIterations:void 0,i=e.git===!0,a=typeof e.prTitle=="string"?e.prTitle:void 0,c=typeof e.baseBranch=="string"?e.baseBranch:void 0;try{if(i){let u=await Qr(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress,forge:this.forgeConfig,prTitle:a,baseBranch:c});return this.formatGitOrchestrationResult(u)}let d=await zt(s,r,this.llm,{maxIterations:o,onProgress:t.onProgress});return this.formatOrchestrationResult(d)}catch(d){return{success:!1,error:`Orchestration failed: ${d instanceof Error?d.message:String(d)}`}}}formatOrchestrationResult(e){let t=[];t.push(`**Orchestration completed in ${e.iterations} iteration(s)**`),t.push(`**Plan:** ${e.plan.reasoning}`),t.push(`**Duration:** ${(e.totalDurationMs/1e3).toFixed(1)}s`);for(let r of e.subtaskResults){let n=r.execution.exitCode===0?"OK":`FAIL (exit ${r.execution.exitCode})`;t.push(`- **${r.subtask.id}** [${r.subtask.agent}]: ${r.subtask.description} \u2014 ${n}`)}return e.allModifiedFiles.length>0&&t.push(`
|
|
1100
1116
|
**Modified files:**
|
|
1101
1117
|
${e.allModifiedFiles.map(r=>`- ${r}`).join(`
|
|
1102
1118
|
`)}`),e.summary&&t.push(`
|
|
@@ -1105,7 +1121,7 @@ ${e.allModifiedFiles.map(r=>`- ${r}`).join(`
|
|
|
1105
1121
|
|
|
1106
1122
|
**Git:**
|
|
1107
1123
|
${s.join(`
|
|
1108
|
-
`)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+n}}}});var
|
|
1124
|
+
`)}`:"";return{...t,data:{...t.data,git:{branch:r.branch,commit:r.commit,pullRequest:r.pullRequest,warnings:r.warnings}},display:(t.display??"")+n}}}});var ju=T(()=>{"use strict";Fu();Io();Ma();xa();La()});var le={};fe(le,{ActivityTracker:()=>Ot,BMWSkill:()=>yo,BackgroundTaskSkill:()=>Ts,BriefingSkill:()=>vo,BrowserSkill:()=>gs,CalculatorSkill:()=>ss,CalendarProvider:()=>He,CalendarSkill:()=>Pt,ClipboardSkill:()=>hs,CodeAgentSkill:()=>en,CodeExecutionSkill:()=>Hr,CodeExecutor:()=>jt,ConfigureSkill:()=>As,ContactsProvider:()=>qe,ContactsSkill:()=>qr,CrossPlatformSkill:()=>ws,DelegateSkill:()=>ds,DockerSkill:()=>fo,DocumentSkill:()=>ks,EmailProvider:()=>it,EmailSkill:()=>ut,EnergyPriceSkill:()=>To,FeedReaderSkill:()=>Cs,FileSkill:()=>ms,ForgeClient:()=>Wt,HomeAssistantSkill:()=>lo,HttpSkill:()=>us,ImageGenerateSkill:()=>bs,MCPClient:()=>Ut,MCPManager:()=>Br,MCPSkillAdapter:()=>Ft,MarketplaceSkill:()=>Vr,MemorySkill:()=>ls,MicrosoftTodoSkill:()=>ko,MonitorSkill:()=>_o,NoteSkill:()=>is,PluginLoader:()=>Qn,ProfileSkill:()=>ys,ProxmoxSkill:()=>ao,ReminderSkill:()=>os,RoutingSkill:()=>wo,ScheduledTaskSkill:()=>_s,ScreenshotSkill:()=>fs,ShellSkill:()=>cs,Skill:()=>x,SkillRegistry:()=>es,SkillSandbox:()=>ts,SystemInfoSkill:()=>rs,TTSSkill:()=>Es,TodoSkill:()=>Ss,TransitSkill:()=>$s,UniFiSkill:()=>co,WatchSkill:()=>Rs,WeatherSkill:()=>as,WebSearchSkill:()=>ns,WorkflowSkill:()=>xs,allUserIds:()=>K,createCalendarProvider:()=>jr,createContactsProvider:()=>pa,createEmailProvider:()=>Pr,createForgeClient:()=>Ds,effectiveUserId:()=>de,gitAddRemote:()=>Zr,gitGetRemoteUrl:()=>Ns,gitInitRepo:()=>Jr,orchestrate:()=>zt,orchestrateWithGit:()=>Qr,parseRemoteUrl:()=>Ls});var ae=T(()=>{"use strict";W();Me();Zl();Ql();Ji();ed();rd();nd();od();id();ad();cd();ud();md();pd();yd();Td();kd();Ed();Sd();$d();Id();Ld();Dd();Md();Od();Ud();jd();Bd();Hd();Wd();zd();qd();Gd();Zd();Qd();nu();uu();mu();Tu();_u();bu();Su();vu();$u();Iu();xu();Cu();Nu();ju()});var tn,Oa=T(()=>{"use strict";tn=class{static{m(this,"ConversationManager")}conversations;constructor(e){this.conversations=e}getOrCreateConversation(e,t,s){let r=this.conversations.findByPlatformChat(e,t);return r?(this.conversations.updateTimestamp(r.id),r):this.conversations.create(e,t,s)}addMessage(e,t,s,r){return this.conversations.addMessage(e,t,s,r)}getHistory(e,t=20){return this.conversations.getMessages(e,t)}pruneMessages(e,t){return this.conversations.pruneMessages(e,t)}}});function $e(l,e){let t;if(e.platformUserId)t=l.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=l.findById(e.userId)??l.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in l?l.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in l&&(r=l.getLinkedUsers(s).map(a=>a.platformUserId));let n;try{"getProfile"in l?n=l.getProfile(s)?.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone:n=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{n=Intl.DateTimeFormat().resolvedOptions().timeZone}return{context:{userId:t.platformUserId,masterUserId:s,linkedPlatformUserIds:r,chatId:e.chatId,chatType:e.chatType,platform:e.platform,conversationId:e.conversationId??"",timezone:n},user:t,masterUserId:s,linkedPlatformUserIds:r}}var pt=T(()=>{"use strict";m($e,"buildSkillContext")});function Bu(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(bf))e.has(r)&&n.test(l)&&(t.add(r),s=!0);if(t.has("automation")){for(let r of e)t.add(r);return t}if(!s){let r=["productivity","information","media","automation","files"];for(let n of r)e.has(n)&&t.add(n)}return t}function Hu(l,e){return l.filter(t=>e.has(t.category??"core"))}var bf,Wu=T(()=>{"use strict";bf={productivity:/\b(todo|note|notiz|remind|erinner|calendar|kalender|termin|event|email|e-mail|mail|contact|kontakt|briefing|morgenbriefing|tagesbriefing)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info|transit|bahn|zug|bus|tram|u.?bahn|s.?bahn|abfahrt|verbindung|haltestelle|öffi|fahrplan|strom|energy|preis|price|kwh|awattar|marktpreis|spot|günstig|cheapest|netzentgelt|rss|feed|atom|news|nachricht|schlagzeil|headline)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows|bild|image|generier|photo|foto)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|script|skript|befehl|kommando|tägliche?r?s?|stündliche?r?s?|wöchentliche?r?s?|monatliche?r?s?|jeden\s+(tag|morgen|abend|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag)|um\s+\d{1,2}\s*(uhr|:|h)|alle\s+\d+\s*(min|stund|sekund)|in\s+\d+\s*(minuten?|stunden?|sekunden?|hours?|minutes?|seconds?|min)|daily|hourly|weekly|every\s+(day|hour|morning|evening|night|\d+\s*min)|führ.{0,5}aus|execut|ausführ)\b/i,files:/\b(file|datei|document|dokument|pdf|http|download|upload|herunterlad|hochlad|anhang|attachment)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|netzwerk|network|homeassistant|home.?assistant|smarthome|smart.?home|licht|light|schalter|switch|solar|photovoltaik|pv|wechselrichter|inverter|batterie.?speicher|wallbox|energieverbrauch|stromverbrauch|verbrauch.{0,5}kwh|einspeis|netzeinspeis|autarkie|eigenverbrauch|bmw|auto|fahrzeug|ladestand|reichweite|laden(?!e)|charging|vehicle|soc|ladehistorie|ladesession|ladevorgang|ladezyklus|ladekurve|km|kilometer|kilometerstand|mileage|tachostand)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};m(Bu,"selectCategories");m(Hu,"filterSkills")});import Pa from"node:fs";import zu from"node:path";function Af(l,e){if(l.length<=e)return l;let t=l.split(`
|
|
1109
1125
|
`);if(t.length<=10)return l.slice(0,e)+`
|
|
1110
1126
|
|
|
1111
1127
|
[... truncated, total `+l.length+" chars]";let s=Math.floor(t.length*.7),r=Math.max(Math.floor(t.length*.2),5),n=t.length-s-r,o=t.slice(0,s),i=t.slice(t.length-r),a=`
|
|
@@ -1116,15 +1132,15 @@ ${s.join(`
|
|
|
1116
1132
|
|
|
1117
1133
|
[... truncated, total `+l.length+` chars]
|
|
1118
1134
|
|
|
1119
|
-
`+l.slice(l.length-Math.floor(e*.2))}return c}var
|
|
1135
|
+
`+l.slice(l.length-Math.floor(e*.2))}return c}var Sf,qu,vf,$f,If,Gu,Rf,xf,Cf,Xu,Nf,sn,Ua=T(()=>{"use strict";Vi();pt();Wu();Sf=900*1e3,qu=50,vf=2,$f=12e3,If=3,Gu=.85;m(Af,"truncateToolResult");Rf=1e5,xf=2e3,Cf=.1,Xu=3,Nf=10,sn=class{static{m(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;confirmationQueue;activityLogger;skillHealthTracker;activeAgents=new Map;agentIdCounter=0;metrics={requestsTotal:0,requestsSuccess:0,requestsFailed:0,avgDurationMs:0,totalInputTokens:0,totalOutputTokens:0,totalCostUsd:0};getMetrics(){return{...this.metrics}}setConfirmationQueue(e){this.confirmationQueue=e}setActivityLogger(e){this.activityLogger=e}setSkillHealthTracker(e){this.skillHealthTracker=e}recordMetric(e,t,s){this.metrics.requestsTotal++,e?this.metrics.requestsSuccess++:this.metrics.requestsFailed++,this.metrics.avgDurationMs=Math.round(this.metrics.avgDurationMs+(t-this.metrics.avgDurationMs)/this.metrics.requestsTotal),this.metrics.lastRequestAt=new Date().toISOString(),s&&(this.metrics.totalInputTokens+=s.input,this.metrics.totalOutputTokens+=s.output,this.metrics.totalCostUsd+=s.costUsd)}constructor(e){this.llm=e.llm,this.conversationManager=e.conversationManager,this.users=e.users,this.logger=e.logger,this.skillRegistry=e.skillRegistry,this.skillSandbox=e.skillSandbox,this.securityManager=e.securityManager,this.memoryRepo=e.memoryRepo,this.speechTranscriber=e.speechTranscriber,this.inboxPath=e.inboxPath,this.embeddingService=e.embeddingService,this.activeLearning=e.activeLearning,this.memoryRetriever=e.memoryRetriever,this.maxHistoryMessages=e.maxHistoryMessages??30,this.documentProcessor=e.documentProcessor,this.conversationSummarizer=e.conversationSummarizer,this.promptBuilder=new Lr}async process(e,t){let s=Date.now();if(this.logger.info({platform:e.platform,userId:e.userId,chatId:e.chatId},"Processing message"),this.confirmationQueue&&e.text){let{context:r}=$e(this.users,{platformUserId:e.userId,platform:e.platform,chatId:e.chatId,chatType:e.chatType,userName:e.userName,displayName:e.displayName});if(await this.confirmationQueue.checkForConfirmation(e.chatId,e.platform,e.text,r))return{text:""}}try{let r=e.metadata?.originalChatId??e.chatId,{user:n,masterUserId:o,linkedPlatformUserIds:i,context:a}=$e(this.users,{platformUserId:e.userId,platform:e.platform,chatId:r,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),c=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,n.id),d=!e.metadata?.skipHistory&&this.conversationSummarizer?this.conversationSummarizer.getSummary(c.id):void 0,u=d?Nf:this.maxHistoryMessages,p=e.metadata?.skipHistory?[]:this.conversationManager.getHistory(c.id,u);this.conversationManager.addMessage(c.id,"user",e.text);let h,f=this.isSyntheticLabel(e.text),g=e.attachments?.some(q=>q.type==="audio")??!1,y=f&&!g;if(this.memoryRetriever&&e.text&&!y)try{h=await this.memoryRetriever.retrieve(o,e.text,15,i)}catch(q){this.logger.debug({err:q},"Hybrid memory retrieval failed")}if(!h&&this.memoryRepo&&!y)try{let q=[o,...(i??[]).filter(z=>z!==o)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let z=new Set;h=[];for(let C of q)for(let H of await this.embeddingService.semanticSearch(C,e.text,10))z.has(H.key)||(z.add(H.key),h.push(H));for(let C of q)for(let H of this.memoryRepo.getRecentForPrompt(C,5))z.has(H.key)||(z.add(H.key),h.push(H))}else{let z=new Set;h=[];for(let C of q)for(let H of this.memoryRepo.getRecentForPrompt(C,20))z.has(H.key)||(z.add(H.key),h.push(H))}}catch(q){this.logger.debug({err:q},"Memory loading failed")}h&&h.length>0&&(h=this.applyMemoryBudget(h));let _;try{"getProfile"in this.users&&(_=this.users.getProfile(o),_&&!_.displayName&&(_.displayName=n.displayName??n.username))}catch(q){this.logger.debug({err:q},"Profile loading failed")}let S=a.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,b=this.skillRegistry?this.skillRegistry.getAll().map(q=>q.metadata):void 0,$=b;if(b&&e.text){let q=new Set(b.map(Q=>Q.category??"core")),z=p.filter(Q=>Q.role==="user").slice(-3).map(Q=>Q.content).join(" "),C=z?`${e.text} ${z}`:e.text,H=Bu(C,q);$=Hu(b,H)}let N=$?this.promptBuilder.buildTools($):void 0,M=this.promptBuilder.buildSystemPrompt({memories:h,skills:$,userProfile:_,conversationSummary:d?.summary}),J=this.buildActiveAgentStatus();J&&(M+=`
|
|
1120
1136
|
|
|
1121
|
-
`+
|
|
1137
|
+
`+J);let V=this.promptBuilder.buildMessages(p),P=this.collapseRepeatedToolErrors(V),ee=Ki(P),ue=P.reduce((q,z)=>q+Mt(z),0)-ee.reduce((q,z)=>q+Mt(z),0);ue>100&&this.logger.debug(`Tool result trimming saved ~${ue} tokens`);let L=await this.buildUserContent(e,t);ee.push({role:"user",content:L});let se=N?Be(JSON.stringify(N)):0,ne=1,Z=this.trimToContextWindow(M,ee,se,ne),j,pe=0,Xe=Date.now(),ce="",be=0,me=0,Oe=0,Je=[],Ke=[],Ze=[];for(t?.("Thinking...");;){pe>0&&this.compressToolLoop(Z,M,se);try{j=await this.llm.complete({messages:Z,system:M,tools:N&&N.length>0?N:void 0,tier:e.metadata?.tier}),me+=j.usage?.inputTokens??0,Oe+=j.usage?.outputTokens??0}catch(oe){if((oe instanceof Error?oe.message:String(oe)).includes("prompt is too long")&&ne>.3){ne*=.5,this.logger.warn({budgetMultiplier:ne},"Prompt too long, retrimming with reduced budget"),Z=this.trimToContextWindow(M,ee,se,ne);continue}throw oe}if(j.stopReason==="max_tokens"&&j.toolCalls?.length&&(this.logger.warn({toolCallCount:j.toolCalls.length},"Discarding truncated tool calls due to max_tokens"),j={...j,toolCalls:[]}),!j.toolCalls||j.toolCalls.length===0){if(j.stopReason==="max_tokens"){let oe=0,Ae=j.content??"";for(;j.stopReason==="max_tokens"&&oe<If;){oe++,this.logger.info({continuationRounds:oe,textLength:Ae.length},"Output truncated, requesting continuation"),Ae?(Z.push({role:"assistant",content:Ae}),Z.push({role:"user",content:"Fahre exakt dort fort wo du aufgeh\xF6rt hast. Keine Wiederholung, nur der Rest."})):Z.push({role:"user",content:"Deine Antwort war zu lang und wurde abgeschnitten. Bitte antworte k\xFCrzer und kompakter. Fasse zusammen statt alles aufzulisten."});try{j=await this.llm.complete({messages:Z,system:M,tools:N&&N.length>0?N:void 0,tier:e.metadata?.tier}),me+=j.usage?.inputTokens??0,Oe+=j.usage?.outputTokens??0,j.content&&(Ae+=j.content)}catch{break}}j={...j,content:Ae,stopReason:"end_turn"}}break}let q=Date.now()-Xe;if(q>=Sf){let oe=Math.round(q/6e4);this.logger.warn({iteration:pe,elapsedMin:oe,pendingToolCalls:j.toolCalls.length},"Tool loop timeout reached"),j=await this.abortToolLoop(Z,j,c.id,M,`Das Zeitlimit von ${oe} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(pe>=qu){this.logger.warn({iteration:pe,pendingToolCalls:j.toolCalls.length},"Tool loop iteration cap reached"),j=await this.abortToolLoop(Z,j,c.id,M,`Das Iterationslimit von ${qu} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}pe++,this.logger.info({iteration:pe,toolCalls:j.toolCalls.length},"Processing tool calls");let z=[];j.content&&z.push({type:"text",text:j.content});for(let oe of j.toolCalls)z.push({type:"tool_use",id:oe.id,name:oe.name,input:oe.input});Z.push({role:"assistant",content:z});let C=await this.executeToolCallsParallel(j.toolCalls,{...a,conversationId:c.id,timezone:S},t),H=C.blocks;C.attachments.length>0&&Je.push(...C.attachments),Ke.push(...j.toolCalls),Ze.push(...H);let Q=this.buildErrorSignature(H);if(Q){if(Q===ce?be++:(be=1,ce=Q),be>=vf){this.logger.warn({iteration:pe,consecutiveErrors:be,errorSignature:Q},"Tool loop aborted: same error repeated consecutively"),j=await this.abortToolLoop(Z,j,c.id,M,`Der gleiche Tool-Fehler ist ${be}x hintereinander aufgetreten: "${ce.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else be=0,ce="";Z.push({role:"user",content:H}),t?.("Thinking...")}let De=j.content;if(!De)for(let q=Z.length-1;q>=0;q--){let z=Z[q];if(z.role==="assistant"&&Array.isArray(z.content)){let C=z.content.find(H=>H.type==="text");if(C&&"text"in C&&C.text){De=C.text;break}}}if(De||(De="(no response)"),Ke.length>0&&(this.conversationManager.addMessage(c.id,"assistant","",JSON.stringify(Ke)),this.conversationManager.addMessage(c.id,"user","",JSON.stringify(Ze))),this.conversationManager.addMessage(c.id,"assistant",De),this.activeLearning&&this.activeLearning.onMessageProcessed(o,e.text,De),this.conversationSummarizer&&!e.metadata?.skipHistory){let q=p.slice(-8).map(z=>({role:z.role,content:z.content}));this.conversationSummarizer.onMessageProcessed(c.id,p.length+2,e.text,De,q)}let wt=Date.now()-s,Tt=j.model??"unknown",Qe=Yn(Tt,{inputTokens:me,outputTokens:Oe});return this.logger.info({duration:wt,model:Tt,tokens:j.usage,totalTokens:{inputTokens:me,outputTokens:Oe},costUsd:Math.round(Qe*1e6)/1e6,stopReason:j.stopReason,toolIterations:pe},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:me,output:Oe,costUsd:Qe}),{text:De,attachments:Je.length>0?Je:void 0}}catch(r){throw this.recordMetric(!1,Date.now()-s),this.logger.error({err:r},"Failed to process message"),r}}async abortToolLoop(e,t,s,r,n,o=!1,i){if(!o){let d=[];t.content&&d.push({type:"text",text:t.content});for(let u of t.toolCalls)d.push({type:"tool_use",id:u.id,name:u.name,input:u.input});e.push({role:"assistant",content:d})}let a=t.toolCalls.map(d=>({type:"tool_result",tool_use_id:d.id,content:`Error: tool loop aborted \u2014 ${n}`,is_error:!0}));e.push({role:"user",content:a}),o||this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),this.conversationManager.addMessage(s,"user","",JSON.stringify(a));let c=e[e.length-1];return c&&c.role==="user"&&Array.isArray(c.content)?c.content.push({type:"text",text:`[System: ${n} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}):e.push({role:"user",content:`[System: ${n} Fasse dem User kurz zusammen was du bisher geschafft hast und was noch offen ist.]`}),await this.llm.complete({messages:e,system:r,tier:i})}buildErrorSignature(e){let t=[];for(let s of e)s.type==="tool_result"&&s.is_error&&t.push(s.content);return t.length>0?t.join("|"):""}collapseRepeatedToolErrors(e){let t=[],s=0;for(;s<e.length;){let r=e[s];if(r.role==="assistant"&&Array.isArray(r.content)&&r.content.some(n=>n.type==="tool_use")){let n=s+1<e.length?e[s+1]:null;if(n&&n.role==="user"&&Array.isArray(n.content)&&n.content.every(o=>o.type==="tool_result"&&o.is_error)){let o=this.toolPairSignature(r,n),i=1,a=s+2;for(;a+1<e.length;){let c=e[a],d=e[a+1];if(c.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(c,d)===o)i++,a+=2;else break}if(i>1){t.push(r),t.push(n),t.push({role:"user",content:`[System: The above tool error repeated ${i} times with identical input. The loop was aborted.]`}),s=a;continue}}}t.push(r),s++}return t}toolPairSignature(e,t){let s=Array.isArray(e.content)?e.content.filter(n=>n.type==="tool_use").map(n=>`${n.name}:${JSON.stringify(n.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(n=>n.type==="tool_result").map(n=>n.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],n=m((u,p)=>{let h=p.content;if(p.attachments&&p.attachments.length>0){r.push(...p.attachments);let f=p.attachments.map(g=>g.fileName).join(", ");h+=`
|
|
1122
1138
|
|
|
1123
|
-
[${p.attachments.length} Datei(en) werden dem User gesendet: ${
|
|
1124
|
-
`)}applyMemoryBudget(e){let t=e.some(o=>o.score!=null&&o.score>0),s=e;t&&(s=e.filter(o=>(o.score??1)>=
|
|
1139
|
+
[${p.attachments.length} Datei(en) werden dem User gesendet: ${f}]`}return h=Af(h,$f),{type:"tool_result",tool_use_id:u.id,content:h,is_error:p.isError}},"buildBlock");if(e.length===1){let u=e[0],p=this.getToolLabel(u.name,u.input);s?.(p);let h=await this.executeToolCall(u,t,s);return{blocks:[n(u,h)],attachments:r}}let o=3;s?.(`Running ${e.length} tools...`);let i=new Map;for(let u=0;u<e.length;u++){let p=e[u].name,h=i.get(p);h||(h=[],i.set(p,h)),h.push(u)}let a=[...i.values()].some(u=>u.length>o),c;if(a){c=new Map;let u=[...i.entries()].map(async([p,h])=>{for(let f=0;f<h.length;f+=o){let g=h.slice(f,f+o),y=await Promise.allSettled(g.map(_=>this.executeToolCall(e[_],t,s)));for(let _=0;_<g.length;_++)c.set(g[_],y[_])}});await Promise.all(u)}else{let u=await Promise.allSettled(e.map(p=>this.executeToolCall(p,t,s)));c=new Map(u.map((p,h)=>[h,p]))}return{blocks:e.map((u,p)=>{let h=c.get(p);return h.status==="fulfilled"?n(u,h.value):{type:"tool_result",tool_use_id:u.id,content:`Tool execution failed: ${h.reason}`,is_error:!0}}),attachments:r}}async executeToolCall(e,t,s){let r=this.skillRegistry?.get(e.name);if(!r)return this.logger.warn({tool:e.name},"Unknown skill requested"),{content:`Error: Unknown tool "${e.name}"`,isError:!0};if(this.skillHealthTracker){let n=this.skillHealthTracker.isDisabled(e.name);if(n){let o=n.disabledUntil?new Date(n.disabledUntil).toISOString():"unknown";return this.logger.warn({tool:e.name,disabledUntil:o,consecutiveFails:n.consecutiveFails},"Skill is auto-disabled due to repeated failures"),{content:`Skill "${e.name}" is temporarily disabled due to repeated failures (${n.consecutiveFails} consecutive). Re-enabled at ${o}.`,isError:!0}}}if(this.securityManager){let n=this.securityManager.evaluate({userId:t.userId,action:e.name,riskLevel:r.metadata.riskLevel,platform:t.platform,chatId:t.chatId,chatType:t.chatType});if(!n.allowed)return this.logger.warn({tool:e.name,reason:n.reason,rule:n.matchedRule?.id},"Skill execution denied by security rules"),this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:"denied",error:n.reason}),{content:`Access denied: ${n.reason}`,isError:!0}}if(this.skillSandbox){let n,o;if(e.name==="delegate"){let{ActivityTracker:c}=await Promise.resolve().then(()=>(ae(),le));n=new c(s),o=`agent-${++this.agentIdCounter}`,this.activeAgents.set(o,{chatId:t.chatId,task:String(e.input.task??"").slice(0,200),tracker:n,startedAt:Date.now()})}let i=e.name==="delegate"?{...t,tracker:n,onProgress:s}:s?{...t,onProgress:s}:t,a=Date.now();try{let c=await this.skillSandbox.execute(r,e.input,i,void 0,n);return this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:c.success?"success":"error",durationMs:Date.now()-a,error:c.error}),this.skillHealthTracker&&(c.success?this.skillHealthTracker.recordSuccess(e.name):this.skillHealthTracker.recordFailure(e.name,c.error??"Unknown error")),{content:c.display??(c.success?JSON.stringify(c.data):c.error??"Unknown error"),isError:!c.success,attachments:c.attachments}}catch(c){let d=c instanceof Error?c.message:String(c);throw this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:"error",durationMs:Date.now()-a,error:d}),this.skillHealthTracker?.recordFailure(e.name,d),c}finally{o&&this.activeAgents.delete(o)}}try{let n=await r.execute(e.input,t);return n.success?this.skillHealthTracker?.recordSuccess(e.name):this.skillHealthTracker?.recordFailure(e.name,n.error??"Unknown error"),{content:n.display??(n.success?JSON.stringify(n.data):n.error??"Unknown error"),isError:!n.success,attachments:n.attachments}}catch(n){let o=n instanceof Error?n.message:String(n);return this.skillHealthTracker?.recordFailure(e.name,o),{content:`Skill execution failed: ${o}`,isError:!0}}}getToolLabel(e,t){switch(e){case"shell":return`Running: ${String(t.command??"").slice(0,60)}`;case"web_search":return`Searching: ${String(t.query??"")}`;case"email":return`Email: ${String(t.action??"")}`;case"memory":return`Memory: ${String(t.action??"")}`;case"reminder":return`Reminder: ${String(t.action??"")}`;case"calculator":return"Calculating...";case"system_info":return"Getting system info...";case"delegate":return"Delegating sub-task...";case"http":return`Fetching: ${String(t.url??"").slice(0,60)}`;case"file":return`File: ${String(t.action??"")} ${String(t.path??"").slice(0,50)}`;case"clipboard":return`Clipboard: ${String(t.action??"")}`;case"screenshot":return"Taking screenshot...";case"browser":return`Browser: ${String(t.action??"")} ${String(t.url??"").slice(0,50)}`;case"weather":return`Weather: ${String(t.location??"")}`;case"note":return`Note: ${String(t.action??"")}`;case"profile":return`Profile: ${String(t.action??"")}`;case"calendar":return`Calendar: ${String(t.action??"")}`;case"background_task":return`Background task: ${String(t.action??"")}`;case"scheduled_task":return`Scheduled task: ${String(t.action??"")}`;case"cross_platform":return`Cross-platform: ${String(t.action??"")}`;case"code_sandbox":return"Running code...";case"document":return`Document: ${String(t.action??"")}`;default:return`Using ${e}...`}}buildActiveAgentStatus(){if(this.activeAgents.size===0)return;let e=["## Currently running sub-agents"];for(let[t,s]of this.activeAgents){let r=s.tracker.getSnapshot(),n=Math.round(r.totalElapsedMs/1e3);e.push(`- **${t}**: "${s.task}"`,` Status: ${s.tracker.formatStatus()}`,` Running for ${n}s | Last activity ${Math.round(r.idleMs/1e3)}s ago`)}return e.push(""),e.push("If the user asks what you or the agent is doing, describe the above status in natural language."),e.join(`
|
|
1140
|
+
`)}applyMemoryBudget(e){let t=e.some(o=>o.score!=null&&o.score>0),s=e;t&&(s=e.filter(o=>(o.score??1)>=Cf));let r=0,n=[];for(let o of s){let i=Be(`[${o.category}] ${o.key}: ${o.value}`);if(r+i>xf)break;r+=i,n.push(o)}return n.length<e.length&&this.logger.info({original:e.length,kept:n.length,tokenCount:r,droppedByScore:e.length-s.length},"Memory budget applied"),n}compressToolLoop(e,t,s=0){let r=this.llm.getContextWindow(),n=Math.floor(r.maxInputTokens*Gu);if(Be(t)+s+e.reduce((g,y)=>g+Mt(y),0)<=n)return;let a=[];for(let g=0;g<e.length-1;g++){let y=e[g],_=e[g+1];y.role==="assistant"&&Array.isArray(y.content)&&y.content.some(S=>S.type==="tool_use")&&_.role==="user"&&Array.isArray(_.content)&&_.content.some(S=>S.type==="tool_result")&&a.push({start:g,end:g+1})}if(a.length<=Xu)return;let c=a.length-Xu,d=a.slice(0,c),u=[];for(let g of d){let y=e[g.start],_=[];if(Array.isArray(y.content))for(let $ of y.content)$.type==="tool_use"&&_.push($.name);let S=e[g.end],b="ok";Array.isArray(S.content)&&S.content.some(N=>N.type==="tool_result"&&N.is_error)&&(b="error"),u.push(`- ${_.join(", ")}: ${b}`)}let p=d[0].start,f=d[d.length-1].end-p+1;e.splice(p,f,{role:"assistant",content:`[Earlier tool interactions compressed (${d.length} pairs):
|
|
1125
1141
|
${u.join(`
|
|
1126
1142
|
`)}
|
|
1127
|
-
]`},{role:"user",content:"[Context compressed to fit context window. Continue with the current task.]"}),this.logger.info({compressedPairs:d.length,removedMessages:
|
|
1143
|
+
]`},{role:"user",content:"[Context compressed to fit context window. Continue with the current task.]"}),this.logger.info({compressedPairs:d.length,removedMessages:f-2},"Compressed tool loop to fit context window")}trimToContextWindow(e,t,s=0,r=1){let n=this.llm.getContextWindow(),o=Math.floor(n.maxInputTokens*Gu*r),i=Be(e)+s,a=t[t.length-1],c=Mt(a),u=i+c+200+500,p=o-u;if(p<=0)return this.logger.warn({maxInputTokens:o,systemTokens:i,latestTokens:c},"Context window very tight, sending only latest message"),[a];let h=t.slice(0,-1),f=this.groupToolPairs(h),g=[];for(let S=f.length-1;S>=0;S--){let b=f[S].reduce(($,N)=>$+Mt(N),0);if(b>p)break;p-=b,g.unshift(f[S])}let y=g.flat(),_=h.length-y.length;if(_>0){this.logger.info({trimmedCount:_,totalMessages:t.length,maxInputTokens:o},"Trimmed conversation history to fit context window");let S=h.slice(0,h.length-y.length),b=this.summarizeTrimmedMessages(S);y.unshift({role:"user",content:`[Earlier conversation summary \u2014 ${_} messages were trimmed to fit the context window:
|
|
1128
1144
|
${b}
|
|
1129
1145
|
|
|
1130
1146
|
The conversation continues below with the most recent messages.]`})}return y.push(a),this.promptBuilder.sanitizeToolMessages(y)}summarizeTrimmedMessages(e){let t=[];for(let r of e){let n=this.extractMessageText(r);if(!n)continue;let o=n.length>150?n.slice(0,150)+"...":n,i=r.role==="user"?"User":"Assistant";if(t.push(`- ${i}: ${o}`),r.role==="assistant"&&Array.isArray(r.content)){for(let a of r.content)if(a.type==="tool_use"){let c=JSON.stringify(a.input).slice(0,80);t.push(` \u2192 Tool: ${a.name}(${c})`)}}}let s=40;if(t.length>s){let r=t.slice(0,s);return r.push(` ... and ${t.length-s} more interactions`),r.join(`
|
|
@@ -1132,32 +1148,32 @@ The conversation continues below with the most recent messages.]`})}return y.pus
|
|
|
1132
1148
|
`)}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(n=>n.type==="tool_use")){let n=[r];if(s+1<e.length&&e[s+1].role==="user"){let o=e[s+1];if(Array.isArray(o.content)&&o.content.some(i=>i.type==="tool_result")){n.push(o),s+=2,t.push(n);continue}}if(n.length===1&&s+1<e.length&&e[s+1].role==="user"){n.push(e[s+1]),s+=2,t.push(n);continue}t.push(n),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"),c=e.text==="[Voice message]"?"":`${e.text}
|
|
1133
1149
|
|
|
1134
1150
|
`;if(r.push({type:"text",text:`${c}[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 c=this.isTextMimeType(i.mimeType),d=`[File received: "${i.fileName??"unknown"}" (${this.formatBytes(i.data.length)}, ${i.mimeType??"unknown type"})]
|
|
1135
|
-
[Saved to: ${a}]`;if(c&&i.data.length<=
|
|
1151
|
+
[Saved to: ${a}]`;if(c&&i.data.length<=Rf){let u=i.data.toString("utf-8");d+=`
|
|
1136
1152
|
[File content]:
|
|
1137
|
-
${u}`}if(this.documentProcessor&&this.isIngestable(i.mimeType))try{let u=await this.documentProcessor.ingest(e.userId,a,i.fileName??"unknown",i.mimeType??"application/octet-stream");if(u.existing){try{
|
|
1153
|
+
${u}`}if(this.documentProcessor&&this.isIngestable(i.mimeType))try{let u=await this.documentProcessor.ingest(e.userId,a,i.fileName??"unknown",i.mimeType??"application/octet-stream");if(u.existing){try{Pa.unlinkSync(a)}catch{}d=`[File received: "${i.fileName??"unknown"}" (duplicate, not saved again)]
|
|
1138
1154
|
[IMPORTANT: This document is already indexed (${u.chunkCount} chunks). To read or answer questions about it, use the "document" skill with action "search" and a relevant query. Do NOT use shell/file tools to read the PDF.]`}else d+=`
|
|
1139
|
-
[IMPORTANT: Document has been indexed (${u.chunkCount} chunks). To read or answer questions about it, use the "document" skill with action "search" and a relevant query. Do NOT use shell/file tools to read the PDF.]`}catch(u){this.logger.warn({err:u,fileName:i.fileName},"Auto-ingest failed")}r.push({type:"text",text:d}),this.logger.info({fileName:i.fileName,savedPath:a,size:i.data.length},"File saved to inbox")}}let n=this.isSyntheticLabel(e.text);e.text&&!n&&r.push({type:"text",text:e.text});let o=r.some(i=>i.type==="text");if(r.some(i=>i.type==="image")&&!o)r.push({type:"text",text:"What do you see in this image?"});else if(n&&r.some(i=>i.type==="text"&&i.text.startsWith("[File received:"))){let i=r.some(c=>c.type==="text"&&c.text.includes("document is already indexed")),a=r.some(c=>c.type==="text"&&c.text.includes("Document has been indexed"));i||a?r.push({type:"text",text:"The user sent this document. It has been automatically indexed. Acknowledge receipt and tell the user the document is ready \u2014 they can ask questions about its content anytime."}):r.push({type:"text",text:"The user sent this file without any instructions. Ask them what they would like you to do with it. Do NOT take any other actions, do NOT use any tools, and do NOT act on conversation history or memories. ONLY ask what the user wants."})}else r.length===0&&r.push({type:"text",text:e.text||"(empty message)"});return r}isSyntheticLabel(e){return e?["[Photo","[Voice message","[Video","[Document","[File","[Sticker","[Audio"].some(s=>e.startsWith(s)):!0}saveToInbox(e){if(!e.data)return;let t=this.inboxPath??Ru.resolve("./data/inbox");try{Aa.mkdirSync(t,{recursive:!0})}catch{this.logger.error({inboxDir:t},"Cannot create inbox directory");return}let s=new Date().toISOString().replace(/[:.]/g,"-"),n=(e.fileName??`file_${s}`).replace(/[<>:"/\\|?*]/g,"_"),o=`${s}_${n}`,i=Ru.join(t,o);try{return Aa.writeFileSync(i,e.data),i}catch(a){this.logger.error({err:a,filePath:i},"Failed to save file to inbox");return}}isIngestable(e){return e?["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword","text/plain","text/csv","text/markdown","text/html","application/json","application/xml"].includes(e)||e.startsWith("text/"):!1}isTextMimeType(e){return e?["text/","application/json","application/xml","application/javascript","application/typescript","application/x-yaml","application/yaml","application/toml","application/x-sh","application/sql","application/csv","application/x-csv"].some(s=>e.startsWith(s)):!1}formatBytes(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var Jr,xa=T(()=>{"use strict";Jr=class l{static{m(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;failCounts=new Map;static MAX_SEND_RETRIES=5;constructor(e,t,s,r=15e3,n){this.reminderRepo=e,this.sendMessage=t,this.logger=s,this.linkedUsers=n,this.checkIntervalMs=r}start(){this.logger.info("Reminder scheduler started"),this.intervalId=setInterval(()=>this.checkDueReminders(),this.checkIntervalMs),this.checkDueReminders()}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=void 0),this.failCounts.clear(),this.logger.info("Reminder scheduler stopped")}async checkDueReminders(){try{let e=this.reminderRepo.getDue();for(let t of e)try{let s=`\u23F0 Reminder: ${t.message}`,r=!1;try{await this.sendMessage(t.platform,t.chatId,s),r=!0}catch(n){this.logger.warn({err:n,reminderId:t.id},"Primary platform delivery failed, trying cross-platform")}if(this.linkedUsers)try{let n=this.linkedUsers.getMasterUserId(t.userId),o=this.linkedUsers.getLinkedUsers(n);for(let i of o){if(i.platform===t.platform)continue;let a=this.linkedUsers.findConversation(i.platform,i.id);if(a)try{await this.sendMessage(i.platform,a.chatId,s),r=!0}catch(c){this.logger.debug({err:c,reminderId:t.id,platform:i.platform},"Cross-platform delivery failed")}}}catch(n){this.logger.debug({err:n,reminderId:t.id},"Cross-platform user lookup failed")}if(!r)throw new Error("No platform could deliver reminder");this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.info({reminderId:t.id},"Reminder fired")}catch(s){let r=(this.failCounts.get(t.id)??0)+1;this.failCounts.set(t.id,r),r>=l.MAX_SEND_RETRIES?(this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.error({reminderId:t.id,attempts:r,chatId:t.chatId},"Reminder abandoned after max retries \u2014 marked as fired")):this.logger.warn({err:s,reminderId:t.id,attempt:r,maxRetries:l.MAX_SEND_RETRIES},"Failed to send reminder, will retry")}}catch(e){this.logger.error({err:e},"Error checking due reminders")}}}});var Zr,Ca=T(()=>{"use strict";Zr=class{static{m(this,"SpeechTranscriber")}logger;apiKey;baseUrl;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,e.provider==="groq"?this.baseUrl=e.baseUrl??"https://api.groq.com/openai/v1":this.baseUrl=e.baseUrl??"https://api.openai.com/v1"}async transcribe(e,t){let s=this.mimeToExtension(t),r=new FormData;r.append("file",new Blob([e],{type:t}),`audio.${s}`),r.append("model","whisper-1");try{let n=await fetch(`${this.baseUrl}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:r});if(!n.ok){let i=await n.text();throw new Error(`Whisper API ${n.status}: ${i}`)}let o=await n.json();return this.logger.info({textLength:o.text.length},"Voice transcribed"),o.text}catch(n){throw this.logger.error({err:n},"Voice transcription failed"),n}}mimeToExtension(e){return{"audio/ogg":"ogg","audio/mpeg":"mp3","audio/mp4":"m4a","audio/wav":"wav","audio/webm":"webm","audio/x-m4a":"m4a"}[e]??"ogg"}}});var Qr,La=T(()=>{"use strict";Qr=class{static{m(this,"SpeechSynthesizer")}logger;apiKey;baseUrl;model;voice;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,this.baseUrl=e.baseUrl??"https://api.openai.com/v1",this.model=e.ttsModel??"tts-1",this.voice=e.ttsVoice??"alloy"}async synthesize(e){this.logger.info({textLength:e.length,model:this.model,voice:this.voice},"Synthesizing speech");let t=await fetch(`${this.baseUrl}/audio/speech`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:this.model,input:e,voice:this.voice,response_format:"opus"})});if(!t.ok){let r=await t.text();throw new Error(`TTS failed: ${t.status} ${r}`)}let s=Buffer.from(await t.arrayBuffer());return this.logger.info({audioBytes:s.length},"Speech synthesized"),s}}});var en,Na=T(()=>{"use strict";en=class{static{m(this,"ImageGenerator")}config;logger;constructor(e,t){this.config=e,this.logger=t}async generate(e,t={}){return this.logger.info({provider:this.config.provider,model:t.model,size:t.size},"Generating image"),this.config.provider==="openai"?this.generateOpenAI(e,t):this.generateGoogle(e,t)}async generateOpenAI(e,t){let{default:s}=await import("openai"),r=new s({apiKey:this.config.apiKey,...this.config.baseUrl&&{baseURL:this.config.baseUrl}}),n=t.model??"gpt-image-1",i=(await r.images.generate({model:n,prompt:e,n:1,size:t.size??"1024x1024",quality:t.quality??"medium"})).data?.[0]?.b64_json;if(!i)throw new Error("OpenAI image generation returned no data");let a=Buffer.from(i,"base64");return this.logger.info({model:n,bytes:a.length},"Image generated via OpenAI"),{data:a,mimeType:"image/png"}}async generateGoogle(e,t){let{GoogleGenAI:s}=await import("@google/genai"),r=new s({apiKey:this.config.apiKey}),n=t.model??"gemini-2.0-flash-exp",a=(await r.models.generateContent({model:n,contents:[{role:"user",parts:[{text:e}]}],config:{responseModalities:["IMAGE","TEXT"]}})).candidates?.[0]?.content?.parts?.find(u=>u.inlineData?.mimeType?.startsWith("image/"));if(!a?.inlineData)throw new Error("Google image generation returned no image data");let c=Buffer.from(a.inlineData.data,"base64"),d=a.inlineData.mimeType??"image/png";return this.logger.info({model:n,bytes:c.length,mimeType:d},"Image generated via Google"),{data:c,mimeType:d}}}});var tn,Da=T(()=>{"use strict";tn=class{static{m(this,"TransitClient")}logger;hafasClient;constructor(e){this.logger=e}async getClient(){if(this.hafasClient)return this.hafasClient;let{createClient:e}=await import("hafas-client"),{profile:t}=await import("hafas-client/p/oebb/index.js");return this.hafasClient=e(t,"alfred-ai-assistant"),this.hafasClient}async searchStops(e){return(await(await this.getClient()).locations(e,{results:10})).filter(r=>r.type==="stop"||r.type==="station").map(r=>({id:r.id,name:r.name,location:r.location?{latitude:r.location.latitude,longitude:r.location.longitude}:void 0}))}async journeys(e,t,s){let r=await this.getClient(),n={results:s?.results??3};return s?.departure&&(n.departure=s.departure),s?.arrival&&(n.arrival=s.arrival),((await r.journeys(e,t,n)).journeys||[]).map(i=>{let a=(i.legs||[]).map(g=>({origin:g.origin?.name||g.origin?.id||"Unknown",destination:g.destination?.name||g.destination?.id||"Unknown",departure:g.departure||g.plannedDeparture||"",arrival:g.arrival||g.plannedArrival||"",line:g.line?.name,direction:g.direction,mode:g.line?.mode||(g.walking?"walking":"unknown"),walking:g.walking===!0})),c=a[0]?.departure||"",d=a[a.length-1]?.arrival||"",u=c&&d?Math.round((new Date(d).getTime()-new Date(c).getTime())/6e4):0,p=a.filter(g=>!g.walking),h=Math.max(0,p.length-1);return{legs:a,departure:c,arrival:d,duration:u,transfers:h}})}async departures(e,t){let s=await this.getClient(),r={duration:t?.duration??30};t?.when&&(r.when=t.when);let n=await s.departures(e,r);return(n.departures||n||[]).map(o=>{let i=o.plannedWhen?new Date(o.plannedWhen):null,a=o.when?new Date(o.when):null,c=i&&a?Math.round((a.getTime()-i.getTime())/6e4):o.delay!=null?Math.round(o.delay/60):void 0;return{line:o.line?.name||o.line?.fahrtNr||"Unknown",direction:o.direction||o.destination?.name||"Unknown",when:o.when||o.plannedWhen||"",delay:c&&c>0?c:void 0,platform:o.platform||void 0}})}}});var sn,Ma=T(()=>{"use strict";sn=class{static{m(this,"ResponseFormatter")}format(e,t){switch(t){case"telegram":return{text:this.toTelegramHTML(e),parseMode:"html"};case"discord":return{text:this.toMarkdown(e),parseMode:"markdown"};case"matrix":return{text:this.toTelegramHTML(e),parseMode:"html"};case"whatsapp":return{text:this.toWhatsApp(e),parseMode:"text"};case"signal":return{text:this.stripFormatting(e),parseMode:"text"};default:return{text:e,parseMode:"text"}}}toTelegramHTML(e){let t=e,s=[];t=t.replace(/```(\w*)\n([\s\S]*?)```/g,(n,o,i)=>(s.push(`<pre>${this.escapeHTML(i.trimEnd())}</pre>`),`\0CB${s.length-1}\0`));let r=[];t=t.replace(/`([^`]+)`/g,(n,o)=>(r.push(`<code>${this.escapeHTML(o)}</code>`),`\0IC${r.length-1}\0`)),t=t.replace(/^#{1,6}\s+(.+)$/gm,"<b>$1</b>"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"<b>$1</b>"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"<i>$1</i>"),t=t.replace(/~~(.+?)~~/g,"<s>$1</s>"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2">$1</a>'),t=t.replace(/<(\/?)(?:strong)>/gi,"<$1b>"),t=t.replace(/<(\/?)(?:em)>/gi,"<$1i>"),t=t.replace(/<(\/?)(?:del|strike)>/gi,"<$1s>");for(let n of["b","i","s","u"]){let o="";for(;o!==t;)o=t,t=this.flattenNestedTag(t,n)}return t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))[^>]*>/gi,""),t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))/gi,"<"),t=t.replace(/\x00CB(\d+)\x00/g,(n,o)=>s[parseInt(o)]),t=t.replace(/\x00IC(\d+)\x00/g,(n,o)=>r[parseInt(o)]),t=t.replace(/\n{3,}/g,`
|
|
1155
|
+
[IMPORTANT: Document has been indexed (${u.chunkCount} chunks). To read or answer questions about it, use the "document" skill with action "search" and a relevant query. Do NOT use shell/file tools to read the PDF.]`}catch(u){this.logger.warn({err:u,fileName:i.fileName},"Auto-ingest failed")}r.push({type:"text",text:d}),this.logger.info({fileName:i.fileName,savedPath:a,size:i.data.length},"File saved to inbox")}}let n=this.isSyntheticLabel(e.text);e.text&&!n&&r.push({type:"text",text:e.text});let o=r.some(i=>i.type==="text");if(r.some(i=>i.type==="image")&&!o)r.push({type:"text",text:"What do you see in this image?"});else if(n&&r.some(i=>i.type==="text"&&i.text.startsWith("[File received:"))){let i=r.some(c=>c.type==="text"&&c.text.includes("document is already indexed")),a=r.some(c=>c.type==="text"&&c.text.includes("Document has been indexed"));i||a?r.push({type:"text",text:"The user sent this document. It has been automatically indexed. Acknowledge receipt and tell the user the document is ready \u2014 they can ask questions about its content anytime."}):r.push({type:"text",text:"The user sent this file without any instructions. Ask them what they would like you to do with it. Do NOT take any other actions, do NOT use any tools, and do NOT act on conversation history or memories. ONLY ask what the user wants."})}else r.length===0&&r.push({type:"text",text:e.text||"(empty message)"});return r}isSyntheticLabel(e){return e?["[Photo","[Voice message","[Video","[Document","[File","[Sticker","[Audio"].some(s=>e.startsWith(s)):!0}saveToInbox(e){if(!e.data)return;let t=this.inboxPath??zu.resolve("./data/inbox");try{Pa.mkdirSync(t,{recursive:!0})}catch{this.logger.error({inboxDir:t},"Cannot create inbox directory");return}let s=new Date().toISOString().replace(/[:.]/g,"-"),n=(e.fileName??`file_${s}`).replace(/[<>:"/\\|?*]/g,"_"),o=`${s}_${n}`,i=zu.join(t,o);try{return Pa.writeFileSync(i,e.data),i}catch(a){this.logger.error({err:a,filePath:i},"Failed to save file to inbox");return}}isIngestable(e){return e?["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword","text/plain","text/csv","text/markdown","text/html","application/json","application/xml"].includes(e)||e.startsWith("text/"):!1}isTextMimeType(e){return e?["text/","application/json","application/xml","application/javascript","application/typescript","application/x-yaml","application/yaml","application/toml","application/x-sh","application/sql","application/csv","application/x-csv"].some(s=>e.startsWith(s)):!1}formatBytes(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});var rn,Fa=T(()=>{"use strict";rn=class l{static{m(this,"ReminderScheduler")}reminderRepo;sendMessage;logger;linkedUsers;intervalId;checkIntervalMs;failCounts=new Map;static MAX_SEND_RETRIES=5;constructor(e,t,s,r=15e3,n){this.reminderRepo=e,this.sendMessage=t,this.logger=s,this.linkedUsers=n,this.checkIntervalMs=r}start(){this.logger.info("Reminder scheduler started"),this.intervalId=setInterval(()=>this.checkDueReminders(),this.checkIntervalMs),this.checkDueReminders()}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=void 0),this.failCounts.clear(),this.logger.info("Reminder scheduler stopped")}async checkDueReminders(){try{let e=this.reminderRepo.getDue();for(let t of e)try{let s=`\u23F0 Reminder: ${t.message}`,r=!1;try{await this.sendMessage(t.platform,t.chatId,s),r=!0}catch(n){this.logger.warn({err:n,reminderId:t.id},"Primary platform delivery failed, trying cross-platform")}if(this.linkedUsers)try{let n=this.linkedUsers.getMasterUserId(t.userId),o=this.linkedUsers.getLinkedUsers(n);for(let i of o){if(i.platform===t.platform)continue;let a=this.linkedUsers.findConversation(i.platform,i.id);if(a)try{await this.sendMessage(i.platform,a.chatId,s),r=!0}catch(c){this.logger.debug({err:c,reminderId:t.id,platform:i.platform},"Cross-platform delivery failed")}}}catch(n){this.logger.debug({err:n,reminderId:t.id},"Cross-platform user lookup failed")}if(!r)throw new Error("No platform could deliver reminder");this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.info({reminderId:t.id},"Reminder fired")}catch(s){let r=(this.failCounts.get(t.id)??0)+1;this.failCounts.set(t.id,r),r>=l.MAX_SEND_RETRIES?(this.reminderRepo.markFired(t.id),this.failCounts.delete(t.id),this.logger.error({reminderId:t.id,attempts:r,chatId:t.chatId},"Reminder abandoned after max retries \u2014 marked as fired")):this.logger.warn({err:s,reminderId:t.id,attempt:r,maxRetries:l.MAX_SEND_RETRIES},"Failed to send reminder, will retry")}}catch(e){this.logger.error({err:e},"Error checking due reminders")}}}});var nn,ja=T(()=>{"use strict";nn=class{static{m(this,"SpeechTranscriber")}logger;apiKey;baseUrl;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,e.provider==="groq"?this.baseUrl=e.baseUrl??"https://api.groq.com/openai/v1":this.baseUrl=e.baseUrl??"https://api.openai.com/v1"}async transcribe(e,t){let s=this.mimeToExtension(t),r=new FormData;r.append("file",new Blob([e],{type:t}),`audio.${s}`),r.append("model","whisper-1");try{let n=await fetch(`${this.baseUrl}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:r});if(!n.ok){let i=await n.text();throw new Error(`Whisper API ${n.status}: ${i}`)}let o=await n.json();return this.logger.info({textLength:o.text.length},"Voice transcribed"),o.text}catch(n){throw this.logger.error({err:n},"Voice transcription failed"),n}}mimeToExtension(e){return{"audio/ogg":"ogg","audio/mpeg":"mp3","audio/mp4":"m4a","audio/wav":"wav","audio/webm":"webm","audio/x-m4a":"m4a"}[e]??"ogg"}}});var on,Ba=T(()=>{"use strict";on=class{static{m(this,"SpeechSynthesizer")}logger;apiKey;baseUrl;model;voice;constructor(e,t){this.logger=t,this.apiKey=e.apiKey,this.baseUrl=e.baseUrl??"https://api.openai.com/v1",this.model=e.ttsModel??"tts-1",this.voice=e.ttsVoice??"alloy"}async synthesize(e){this.logger.info({textLength:e.length,model:this.model,voice:this.voice},"Synthesizing speech");let t=await fetch(`${this.baseUrl}/audio/speech`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:this.model,input:e,voice:this.voice,response_format:"opus"})});if(!t.ok){let r=await t.text();throw new Error(`TTS failed: ${t.status} ${r}`)}let s=Buffer.from(await t.arrayBuffer());return this.logger.info({audioBytes:s.length},"Speech synthesized"),s}}});var an,Ha=T(()=>{"use strict";an=class{static{m(this,"ImageGenerator")}config;logger;constructor(e,t){this.config=e,this.logger=t}async generate(e,t={}){return this.logger.info({provider:this.config.provider,model:t.model,size:t.size},"Generating image"),this.config.provider==="openai"?this.generateOpenAI(e,t):this.generateGoogle(e,t)}async generateOpenAI(e,t){let{default:s}=await import("openai"),r=new s({apiKey:this.config.apiKey,...this.config.baseUrl&&{baseURL:this.config.baseUrl}}),n=t.model??"gpt-image-1",i=(await r.images.generate({model:n,prompt:e,n:1,size:t.size??"1024x1024",quality:t.quality??"medium"})).data?.[0]?.b64_json;if(!i)throw new Error("OpenAI image generation returned no data");let a=Buffer.from(i,"base64");return this.logger.info({model:n,bytes:a.length},"Image generated via OpenAI"),{data:a,mimeType:"image/png"}}async generateGoogle(e,t){let{GoogleGenAI:s}=await import("@google/genai"),r=new s({apiKey:this.config.apiKey}),n=t.model??"gemini-2.0-flash-exp",a=(await r.models.generateContent({model:n,contents:[{role:"user",parts:[{text:e}]}],config:{responseModalities:["IMAGE","TEXT"]}})).candidates?.[0]?.content?.parts?.find(u=>u.inlineData?.mimeType?.startsWith("image/"));if(!a?.inlineData)throw new Error("Google image generation returned no image data");let c=Buffer.from(a.inlineData.data,"base64"),d=a.inlineData.mimeType??"image/png";return this.logger.info({model:n,bytes:c.length,mimeType:d},"Image generated via Google"),{data:c,mimeType:d}}}});var cn,Wa=T(()=>{"use strict";cn=class{static{m(this,"TransitClient")}logger;hafasClient;constructor(e){this.logger=e}async getClient(){if(this.hafasClient)return this.hafasClient;let{createClient:e}=await import("hafas-client"),{profile:t}=await import("hafas-client/p/oebb/index.js");return this.hafasClient=e(t,"alfred-ai-assistant"),this.hafasClient}async searchStops(e){return(await(await this.getClient()).locations(e,{results:10})).filter(r=>r.type==="stop"||r.type==="station").map(r=>({id:r.id,name:r.name,location:r.location?{latitude:r.location.latitude,longitude:r.location.longitude}:void 0}))}async journeys(e,t,s){let r=await this.getClient(),n={results:s?.results??3};return s?.departure&&(n.departure=s.departure),s?.arrival&&(n.arrival=s.arrival),((await r.journeys(e,t,n)).journeys||[]).map(i=>{let a=(i.legs||[]).map(f=>({origin:f.origin?.name||f.origin?.id||"Unknown",destination:f.destination?.name||f.destination?.id||"Unknown",departure:f.departure||f.plannedDeparture||"",arrival:f.arrival||f.plannedArrival||"",line:f.line?.name,direction:f.direction,mode:f.line?.mode||(f.walking?"walking":"unknown"),walking:f.walking===!0})),c=a[0]?.departure||"",d=a[a.length-1]?.arrival||"",u=c&&d?Math.round((new Date(d).getTime()-new Date(c).getTime())/6e4):0,p=a.filter(f=>!f.walking),h=Math.max(0,p.length-1);return{legs:a,departure:c,arrival:d,duration:u,transfers:h}})}async departures(e,t){let s=await this.getClient(),r={duration:t?.duration??30};t?.when&&(r.when=t.when);let n=await s.departures(e,r);return(n.departures||n||[]).map(o=>{let i=o.plannedWhen?new Date(o.plannedWhen):null,a=o.when?new Date(o.when):null,c=i&&a?Math.round((a.getTime()-i.getTime())/6e4):o.delay!=null?Math.round(o.delay/60):void 0;return{line:o.line?.name||o.line?.fahrtNr||"Unknown",direction:o.direction||o.destination?.name||"Unknown",when:o.when||o.plannedWhen||"",delay:c&&c>0?c:void 0,platform:o.platform||void 0}})}}});var ln,za=T(()=>{"use strict";ln=class{static{m(this,"ResponseFormatter")}format(e,t){switch(t){case"telegram":return{text:this.toTelegramHTML(e),parseMode:"html"};case"discord":return{text:this.toMarkdown(e),parseMode:"markdown"};case"matrix":return{text:this.toTelegramHTML(e),parseMode:"html"};case"whatsapp":return{text:this.toWhatsApp(e),parseMode:"text"};case"signal":return{text:this.stripFormatting(e),parseMode:"text"};default:return{text:e,parseMode:"text"}}}toTelegramHTML(e){let t=e,s=[];t=t.replace(/```(\w*)\n([\s\S]*?)```/g,(n,o,i)=>(s.push(`<pre>${this.escapeHTML(i.trimEnd())}</pre>`),`\0CB${s.length-1}\0`));let r=[];t=t.replace(/`([^`]+)`/g,(n,o)=>(r.push(`<code>${this.escapeHTML(o)}</code>`),`\0IC${r.length-1}\0`)),t=t.replace(/^#{1,6}\s+(.+)$/gm,"<b>$1</b>"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"<b>$1</b>"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"<i>$1</i>"),t=t.replace(/~~(.+?)~~/g,"<s>$1</s>"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2">$1</a>'),t=t.replace(/<(\/?)(?:strong)>/gi,"<$1b>"),t=t.replace(/<(\/?)(?:em)>/gi,"<$1i>"),t=t.replace(/<(\/?)(?:del|strike)>/gi,"<$1s>");for(let n of["b","i","s","u"]){let o="";for(;o!==t;)o=t,t=this.flattenNestedTag(t,n)}return t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))[^>]*>/gi,""),t=t.replace(/<(?!\/?(?:b|i|s|u|a|pre|code|tg-spoiler|tg-emoji|blockquote)(?:[\s>\/]|$))/gi,"<"),t=t.replace(/\x00CB(\d+)\x00/g,(n,o)=>s[parseInt(o)]),t=t.replace(/\x00IC(\d+)\x00/g,(n,o)=>r[parseInt(o)]),t=t.replace(/\n{3,}/g,`
|
|
1140
1156
|
|
|
1141
|
-
`),t}flattenNestedTag(e,t){let s=`<${t}>`,r=`</${t}>`,n=0,o="",i=0;for(;i<e.length;){if(e.slice(i,i+s.length).toLowerCase()===s){n++,n===1&&(o+=s),i+=s.length;continue}if(e.slice(i,i+r.length).toLowerCase()===r){n--,n<=0&&(o+=r,n=0),i+=r.length;continue}o+=e[i],i++}return o}toMarkdown(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<code>([^<]*)<\/code>/gi,"`$1`"),t=t.replace(/<pre>([^<]*)<\/pre>/gi,"```\n$1\n```"),t=t.replace(/<a\s+href="([^"]*)"[^>]*>([^<]*)<\/a>/gi,"[$2]($1)"),t=t.replace(/<[^>]+>/g,""),t}toWhatsApp(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<[^>]+>/g,""),t=t.replace(/^#{1,6}\s+(.+)$/gm,"*$1*"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"*$1*"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"_$1_"),t=t.replace(/~~(.+?)~~/g,"~$1~"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}stripFormatting(e){let t=e;return t=t.replace(/<[^>]+>/g,""),t=t.replace(/```\w*\n?/g,""),t=t.replace(/`([^`]+)`/g,"$1"),t=t.replace(/^#{1,6}\s+/gm,""),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"$1"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"$1"),t=t.replace(/~~(.+?)~~/g,"$1"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}escapeHTML(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}}});var
|
|
1157
|
+
`),t}flattenNestedTag(e,t){let s=`<${t}>`,r=`</${t}>`,n=0,o="",i=0;for(;i<e.length;){if(e.slice(i,i+s.length).toLowerCase()===s){n++,n===1&&(o+=s),i+=s.length;continue}if(e.slice(i,i+r.length).toLowerCase()===r){n--,n<=0&&(o+=r,n=0),i+=r.length;continue}o+=e[i],i++}return o}toMarkdown(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<code>([^<]*)<\/code>/gi,"`$1`"),t=t.replace(/<pre>([^<]*)<\/pre>/gi,"```\n$1\n```"),t=t.replace(/<a\s+href="([^"]*)"[^>]*>([^<]*)<\/a>/gi,"[$2]($1)"),t=t.replace(/<[^>]+>/g,""),t}toWhatsApp(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<[^>]+>/g,""),t=t.replace(/^#{1,6}\s+(.+)$/gm,"*$1*"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"*$1*"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"_$1_"),t=t.replace(/~~(.+?)~~/g,"~$1~"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}stripFormatting(e){let t=e;return t=t.replace(/<[^>]+>/g,""),t=t.replace(/```\w*\n?/g,""),t=t.replace(/`([^`]+)`/g,"$1"),t=t.replace(/^#{1,6}\s+/gm,""),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"$1"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"$1"),t=t.replace(/~~(.+?)~~/g,"$1"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}escapeHTML(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}}});var dn,qa=T(()=>{"use strict";dn=class{static{m(this,"EmbeddingService")}llm;embeddingRepo;logger;constructor(e,t,s){this.llm=e,this.embeddingRepo=t,this.logger=s}async embedAndStore(e,t,s,r){if(this.llm.supportsEmbeddings())try{let n=await this.llm.embed(t);if(!n)return;let o=this.embeddingRepo.store({userId:e,sourceType:s,sourceId:r,content:t,embedding:n.embedding,model:n.model,dimensions:n.dimensions});return this.logger.debug({userId:e,sourceType:s,sourceId:r},"Embedding stored"),o.id}catch(n){this.logger.error({err:n,userId:e,sourceType:s,sourceId:r},"Failed to embed content");return}}async semanticSearch(e,t,s=10){if(!this.llm.supportsEmbeddings())return[];try{let r=await this.llm.embed(t);if(!r)return[];let n=this.embeddingRepo.findByUser(e);if(n.length===0)return[];let o=n.map(a=>{let c=this.cosineSimilarity(r.embedding,a.embedding);return{...a,score:c}});return o.sort((a,c)=>c.score-a.score),o.slice(0,s).map(a=>({key:a.sourceId,value:a.content,category:a.sourceType,score:a.score}))}catch(r){return this.logger.error({err:r},"Semantic search failed"),[]}}cosineSimilarity(e,t){if(e.length!==t.length)return 0;let s=0,r=0,n=0;for(let i=0;i<e.length;i++)s+=e[i]*t[i],r+=e[i]*e[i],n+=t[i]*t[i];let o=Math.sqrt(r)*Math.sqrt(n);return o===0?0:s/o}}});import{createHash as Lf}from"node:crypto";var un,Ga=T(()=>{"use strict";un=class{static{m(this,"DocumentProcessor")}docRepo;embeddingService;logger;constructor(e,t,s){this.docRepo=e,this.embeddingService=t,this.logger=s}async ingest(e,t,s,r){let n=await import("node:fs"),o=n.readFileSync(t),i=Lf("sha256").update(o).digest("hex"),a=this.docRepo.findByContentHash(e,i);if(a&&a.chunkCount>0)return this.logger.info({documentId:a.id,filename:s,contentHash:i.slice(0,12)},"Document already ingested (duplicate)"),{documentId:a.id,chunkCount:a.chunkCount,existing:!0};a&&a.chunkCount===0&&(this.logger.info({documentId:a.id,filename:s},"Removing failed previous ingest attempt"),this.docRepo.deleteDocument(a.id));let c=await this.extractText(t,r),d=n.statSync(t),u=this.docRepo.createDocument(e,s,r,d.size,i),p=this.chunkText(c,500,50);for(let h=0;h<p.length;h++){let f;try{f=await this.embeddingService.embedAndStore(e,p[h],"document",`${u.id}:${h}`)}catch(g){this.logger.warn({documentId:u.id,chunkIndex:h,err:g},"Embedding failed for chunk, continuing")}this.docRepo.addChunk(u.id,h,p[h],f)}return this.docRepo.updateChunkCount(u.id,p.length),this.logger.info({documentId:u.id,filename:s,chunkCount:p.length},"Document ingested"),{documentId:u.id,chunkCount:p.length}}async extractText(e,t){let s=await import("node:fs");if(t==="application/pdf")try{let r=(await import("pdf-parse")).default,n=s.readFileSync(e);return(await r(n)).text}catch(r){throw this.logger.error({err:r},"PDF parsing failed"),new Error("Failed to parse PDF")}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")try{return(await(await import("mammoth")).extractRawText({path:e})).value}catch(r){throw this.logger.error({err:r},"DOCX parsing failed"),new Error("Failed to parse DOCX")}return s.readFileSync(e,"utf-8")}chunkText(e,t,s){let n=Math.round(t*3.5),o=Math.round(s*3.5),i=[],a=0;for(;a<e.length;){let c=a+n;if(c>=e.length){i.push(e.slice(a).trim());break}let d=Math.max(c-200,a),u=e.slice(d,c+200),p=u.lastIndexOf(`
|
|
1142
1158
|
|
|
1143
|
-
`);if(p>0)c=d+p;else{let
|
|
1159
|
+
`);if(p>0)c=d+p;else{let f=u.lastIndexOf(". ");f>0&&(c=d+f+1)}let h=e.slice(a,c).trim();h&&i.push(h),a=c-o}return i.filter(c=>c.length>0)}}});var mn,Xa=T(()=>{"use strict";pt();mn=class{static{m(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;skillHealthTracker;pollTimer;running=0;polling=!1;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;persistentRunner;constructor(e,t,s,r,n,o,i,a){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o,this.activityLogger=i,this.skillHealthTracker=a}setPersistentRunner(e){this.persistentRunner=e}start(){this.pollTimer=setInterval(()=>this.poll(),this.pollIntervalMs),this.logger.info("Background task runner started"),this.persistentRunner?.recoverInterrupted().catch(e=>{this.logger.error({err:e},"Failed to recover interrupted persistent tasks")})}stop(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0),this.logger.info("Background task runner stopped")}async poll(){if(!(this.polling||this.running>=this.maxConcurrent)){this.polling=!0;try{let e=this.maxConcurrent-this.running,t=this.taskRepo.claimPending(e);for(let s of t)this.running++,this.runTask(s).finally(()=>{this.running--})}catch(e){this.logger.error({err:e},"Error polling for background tasks")}finally{this.polling=!1}}}async runTask(e){if(e.maxDurationHours&&this.persistentRunner){await this.persistentRunner.runPersistent(e);return}let t=Date.now();try{let s=this.skillRegistry.get(e.skillName);if(!s){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}if(this.skillHealthTracker?.isDisabled(e.skillName)){this.taskRepo.updateStatus(e.id,"failed",void 0,`Skill "${e.skillName}" is temporarily disabled due to repeated failures`);return}let r;try{r=JSON.parse(e.skillInput)}catch(u){this.logger.warn({taskId:e.id,err:u},"Malformed skill input JSON"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:n}=$e(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o,i=new Promise((u,p)=>{o=setTimeout(()=>p(new Error("Background task timed out")),this.taskTimeoutMs)}),a=await Promise.race([this.skillSandbox.execute(s,r,n),i]).finally(()=>{o&&clearTimeout(o)}),c=JSON.stringify(a.data??a.display??a.error);this.taskRepo.updateStatus(e.id,a.success?"completed":"failed",c,a.error),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:a.success?"success":"error",durationMs:Date.now()-t,error:a.error}),this.skillHealthTracker&&(a.success?this.skillHealthTracker.recordSuccess(e.skillName):this.skillHealthTracker.recordFailure(e.skillName,a.error??"Unknown error"));let d=this.adapters.get(e.platform);if(d){let u=a.success?`\u2705 Background task completed: ${e.description}
|
|
1144
1160
|
|
|
1145
1161
|
Result: ${a.display??JSON.stringify(a.data)}`:`\u274C Background task failed: ${e.description}
|
|
1146
1162
|
|
|
1147
1163
|
Error: ${a.error}`;await d.sendMessage(e.chatId,u)}}catch(s){let r=s instanceof Error?s.message:String(s);this.taskRepo.updateStatus(e.id,"failed",void 0,r),this.logger.error({taskId:e.id,err:s},"Background task failed"),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:"error",durationMs:Date.now()-t,error:r}),this.skillHealthTracker?.recordFailure(e.skillName,r);let n=this.adapters.get(e.platform);n&&await n.sendMessage(e.chatId,`\u274C Background task failed: ${e.description}
|
|
1148
1164
|
|
|
1149
|
-
Error: ${r}`)}}}});var
|
|
1165
|
+
Error: ${r}`)}}}});var Df,pn,Ka=T(()=>{"use strict";pt();Df=5,pn=class{static{m(this,"PersistentAgentRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;activeAbortControllers=new Map;constructor(e,t,s,r,n,o,i){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=o,this.activityLogger=i}async recoverInterrupted(){try{let e=this.taskRepo.getInterrupted();for(let t of e)t.agentState?(this.logger.info({taskId:t.id,resumeCount:t.resumeCount},"Recovering interrupted persistent task"),this.resume(t).catch(s=>{this.logger.error({err:s,taskId:t.id},"Failed to recover interrupted task")})):(this.taskRepo.updateStatus(t.id,"failed",void 0,"Process restarted without checkpoint"),this.logger.warn({taskId:t.id},"Interrupted task without checkpoint marked as failed"),this.notifyUser(t,"\u274C Hintergrund-Task abgebrochen (Prozess-Neustart ohne Checkpoint)"))}catch(e){this.logger.error({err:e},"Failed to recover interrupted tasks")}}async runPersistent(e){if(!this.taskRepo.claimTask(e.id)){this.logger.info({taskId:e.id},"Task already claimed by another runner, skipping");return}let t=(e.maxDurationHours??24)*36e5,s=new AbortController;this.activeAbortControllers.set(e.id,s);try{let r=this.skillRegistry.get(e.skillName);if(!r){this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}let n;try{n=JSON.parse(e.skillInput)}catch{this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:o}=$e(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),i=Date.now()-new Date(e.createdAt).getTime();if(i>t){this.taskRepo.updateStatus(e.id,"failed",void 0,`Max duration of ${e.maxDurationHours}h exceeded`),this.notifyUser(e,`\u274C Persistenter Task "${e.description}" abgebrochen: maximale Laufzeit \xFCberschritten.`),this.logLifecycle(e,"expired");return}let a;if(e.agentState)try{let y=JSON.parse(e.agentState);y.conversationHistory?.length>0&&(a={conversationHistory:y.conversationHistory,currentIteration:y.currentIteration,totalIterations:y.totalIterations,dataStore:y.dataStore},this.logger.info({taskId:e.id,iteration:y.currentIteration,totalIterations:y.totalIterations},"Resuming persistent task from checkpoint"))}catch(y){this.logger.warn({taskId:e.id,err:y},"Failed to parse checkpoint, starting fresh")}let c=a?.currentIteration??0,d={...o,resumeState:a,abortSignal:s.signal,onIteration:m(y=>{if(y.iteration-c>=Df||s.signal.aborted){c=y.iteration;let _={conversationHistory:y.messages,partialResults:[],currentIteration:y.iteration,totalIterations:y.maxIterations,startedAt:e.startedAt??e.createdAt,lastActivityAt:new Date().toISOString(),dataStore:y.dataStore};try{this.taskRepo.checkpoint(e.id,JSON.stringify(_)),this.logLifecycle(e,"checkpoint"),this.logger.debug({taskId:e.id,iteration:y.iteration},"Persistent task checkpointed")}catch(S){this.logger.warn({err:S,taskId:e.id},"Failed to write checkpoint, retrying once");try{this.taskRepo.checkpoint(e.id,JSON.stringify(_)),this.logger.info({taskId:e.id},"Checkpoint retry succeeded")}catch(b){this.logger.error({err:b,taskId:e.id},"Checkpoint retry failed, aborting task"),this.taskRepo.updateStatus(e.id,"failed",void 0,"Checkpoint write failed after retry"),s.abort()}}}},"onIteration")},u=t-i,p,h=new Promise((y,_)=>{p=setTimeout(()=>_(new Error(`Max duration of ${e.maxDurationHours}h exceeded`)),u)}),f=await Promise.race([this.skillSandbox.execute(r,n,d),h]).finally(()=>{p&&clearTimeout(p)});if(this.activeAbortControllers.delete(e.id),s.signal.aborted){this.logger.info({taskId:e.id},"Persistent task paused via abort"),this.notifyUser(e,`\u23F8\uFE0F Persistenter Task pausiert: ${e.description}`);return}let g=JSON.stringify(f.data??f.display??f.error);this.taskRepo.updateStatus(e.id,f.success?"completed":"failed",g,f.error),this.notifyUser(e,f.success?`\u2705 Persistenter Task abgeschlossen: ${e.description}
|
|
1150
1166
|
|
|
1151
|
-
Ergebnis: ${
|
|
1167
|
+
Ergebnis: ${f.display??JSON.stringify(f.data)}`:`\u274C Persistenter Task fehlgeschlagen: ${e.description}
|
|
1152
1168
|
|
|
1153
|
-
Fehler: ${
|
|
1169
|
+
Fehler: ${f.error}`)}catch(r){this.activeAbortControllers.delete(e.id);let n=r instanceof Error?r.message:String(r);if(s.signal.aborted){this.logger.info({taskId:e.id},"Persistent task paused via abort"),this.notifyUser(e,`\u23F8\uFE0F Persistenter Task pausiert: ${e.description}`);return}this.taskRepo.updateStatus(e.id,"failed",void 0,n),this.logger.error({taskId:e.id,err:r},"Persistent task failed"),this.notifyUser(e,`\u274C Persistenter Task fehlgeschlagen: ${e.description}
|
|
1154
1170
|
|
|
1155
|
-
Fehler: ${n}`)}}async resume(e){this.taskRepo.markResuming(e.id),this.logLifecycle(e,"resume");let t=this.taskRepo.getById(e.id);if(!t){this.logger.warn({taskId:e.id},"Task disappeared during resume");return}await this.runPersistent(t)}async pause(e){this.taskRepo.updateStatus(e,"checkpointed");let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.logLifecycle({id:e,skillName:"",platform:"",chatId:"",userId:""},"pause"),this.logger.info({taskId:e},"Persistent task paused")}async cancel(e){let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.taskRepo.cancelTask(e),this.logger.info({taskId:e},"Persistent task cancelled")}async notifyUser(e,t){let s=this.adapters.get(e.platform);if(s)try{await s.sendMessage(e.chatId,t)}catch{}}logLifecycle(e,t){this.activityLogger?.logAgentLifecycle({taskId:e.id,skillName:e.skillName,event:t,platform:e.platform,chatId:e.chatId,userId:e.userId})}}});import
|
|
1156
|
-
${r}`;this.conversationManager.addMessage(
|
|
1171
|
+
Fehler: ${n}`)}}async resume(e){this.taskRepo.markResuming(e.id),this.logLifecycle(e,"resume");let t=this.taskRepo.getById(e.id);if(!t){this.logger.warn({taskId:e.id},"Task disappeared during resume");return}await this.runPersistent(t)}async pause(e){this.taskRepo.updateStatus(e,"checkpointed");let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.logLifecycle({id:e,skillName:"",platform:"",chatId:"",userId:""},"pause"),this.logger.info({taskId:e},"Persistent task paused")}async cancel(e){let t=this.activeAbortControllers.get(e);t&&(t.abort(),this.activeAbortControllers.delete(e)),this.taskRepo.cancelTask(e),this.logger.info({taskId:e},"Persistent task cancelled")}async notifyUser(e,t){let s=this.adapters.get(e.platform);if(s)try{await s.sendMessage(e.chatId,t)}catch{}}logLifecycle(e,t){this.activityLogger?.logAgentLifecycle({taskId:e.id,skillName:e.skillName,event:t,platform:e.platform,chatId:e.chatId,userId:e.userId})}}});import Mf from"node:crypto";var hn,Va=T(()=>{"use strict";Mi();pt();hn=class{static{m(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;activityLogger;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,n,o,i,a,c,d,u){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=n,this.users=o,this.logger=i,this.pipeline=a,this.formatter=c,this.conversationManager=d,this.activityLogger=u}start(){this.tickTimer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Proactive scheduler started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0),this.logger.info("Proactive scheduler stopped")}async tick(){try{let e=this.actionRepo.getDue();for(let t of e)try{await this.executeAction(t)}catch(s){this.logger.error({err:s,actionId:t.id},"Failed to execute scheduled action")}}catch(e){this.logger.error({err:e},"Error during proactive scheduler tick")}}async executeAction(e){let t=new Date().toISOString(),s=Date.now();this.logger.info({actionId:e.id,name:e.name},"Executing scheduled action");let r,n="text";if(e.skillName&&this.skillRegistry.has(e.skillName)){let h=this.skillRegistry.get(e.skillName);try{let f;try{f=JSON.parse(e.skillInput)}catch{f={},this.logger.warn({actionId:e.id},"Invalid skillInput JSON, using empty input")}let{context:g}=$e(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),y=await this.skillSandbox.execute(h,f,g);if(y.success){let _=y.display??JSON.stringify(y.data);if(this.formatter){let S=this.formatter.format(_,e.platform);r=S.text,n=S.parseMode}else r=_}else r=`\u274C Scheduled action "${e.name}" failed: ${y.error}`}catch(f){let g=f instanceof Error?f.message:String(f);r=`\u274C Scheduled action "${e.name}" failed: ${g}`}}else if(e.promptTemplate&&this.pipeline)try{let h=`scheduled-${e.id}`,f=this.users.findById(e.userId),g=f?.platformUserId??e.userId,y={id:`scheduled-${Mf.randomUUID()}`,platform:e.platform,chatId:h,chatType:"dm",userId:g,userName:f?.username??g,text:e.promptTemplate+"\n\n[Format: Use only Markdown (**, *, ~~, `, ```). Do NOT use HTML tags like <b>, <i>, <code>. The system converts Markdown to platform-specific formatting automatically.]",timestamp:new Date,metadata:{scheduled:!0,skipHistory:!0,tier:"fast",originalChatId:e.chatId}},_=await this.pipeline.process(y),S=this.formatter?this.formatter.format(_.text,e.platform):{text:_.text,parseMode:"text"};r=S.text,n=S.parseMode;let b=this.adapters.get(e.platform);if(b&&_.attachments)for(let $ of _.attachments)try{let N=$.mimeType.startsWith("image/"),M=$.mimeType==="audio/ogg"||$.mimeType==="audio/opus";N?await b.sendPhoto(e.chatId,$.data,$.fileName):M?await b.sendVoice(e.chatId,$.data):await b.sendFile(e.chatId,$.data,$.fileName)}catch(N){this.logger.warn({err:N,fileName:$.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(h){let f=h instanceof Error?h.message:String(h);this.logger.error({actionId:e.id,err:h},"Pipeline execution failed for scheduled action"),r=`Scheduled action "${e.name}" failed: ${f}`}else if(e.promptTemplate)try{r=(await this.llm.complete({messages:[{role:"user",content:e.promptTemplate}],maxTokens:1024,tier:"fast"})).content}catch(h){let f=h instanceof Error?h.message:String(h);this.logger.error({actionId:e.id,err:h},"LLM call failed for scheduled action"),r=`Scheduled action "${e.name}" failed: ${f}`}else this.logger.warn({actionId:e.id,skillName:e.skillName},"Unknown skill for scheduled action"),r=`Scheduled action "${e.name}" failed: unknown skill "${e.skillName}"`;let o=r.startsWith("\u274C");this.activityLogger?.logScheduledExec({actionId:e.id,actionName:e.name,skillName:e.skillName??void 0,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:o?"error":"success",durationMs:Date.now()-s,error:o?r:void 0});let i=r.trim(),a=(e.promptTemplate??"").toLowerCase(),c=/nichts|silent|no\s*output|don't\s*respond|do\s*not\s*respond/i.test(a),d=/offline|down|fehler|error|warn|critical|alert|fail|nicht\s+(erreichbar|verf[uü]gbar|gefunden|online)|ausgefallen|stopped|unreachable|unavailable|⚠|❌|🚨|🔴/i.test(i)&&!/keine\s+(probleme|fehler|auff[aä]lligkeiten)/i.test(i);if(!i||i.length<3||c&&!d)this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let h=this.adapters.get(e.platform);if(h)try{if(await h.sendMessage(e.chatId,r,{parseMode:n!=="text"?n:void 0}),e.promptTemplate&&this.conversationManager){let f=this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),g=`[Automated Scheduled Alert: ${e.name}]
|
|
1172
|
+
${r}`;this.conversationManager.addMessage(f.id,"assistant",g)}}catch(f){this.logger.error({err:f,actionId:e.id},"Failed to send scheduled action result")}}if(e.promptTemplate&&this.conversationManager)try{let h=`scheduled-${e.id}`,f=this.conversationManager.getOrCreateConversation(e.platform,h,e.userId);this.conversationManager.pruneMessages(f.id,20)}catch{}let p=this.calculateNextRun(e);p?this.actionRepo.updateLastRun(e.id,t,p):(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 Vn(e.scheduleValue,t)?.toISOString()??null;default:return null}}}});function ht(l,e){let t=e.split("."),s=l;for(let r of t){if(s==null)return;if(typeof s=="object"){if(r==="length"&&Array.isArray(s)){s=s.length;continue}s=s[r]}else return}return s}function Ro(l,e,t,s){let r=Of(l);if(s===null)return{triggered:!1,displayValue:r};switch(e){case"lt":case"gt":case"lte":case"gte":{let n=Ne(l),o=Ne(t);if(n===null||o===null)return{triggered:!1,displayValue:r};if(!(e==="lt"?n<o:e==="gt"?n>o:e==="lte"?n<=o:n>=o))return{triggered:!1,displayValue:r};let a=Ne(s);return a!==null&&(e==="lt"?a<o:e==="gt"?a>o:e==="lte"?a<=o:a>=o)?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"eq":{let n=Ne(l),o=Ne(t);if(n!==null&&o!==null){if(n!==o)return{triggered:!1,displayValue:r};let c=Ne(s);return c!==null&&c===o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let i=String(l),a=String(t);return i!==a?{triggered:!1,displayValue:r}:String(s)===a?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"neq":{let n=Ne(l),o=Ne(t);if(n!==null&&o!==null){if(n===o)return{triggered:!1,displayValue:r};let c=Ne(s);return c!==null&&c!==o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let i=String(l),a=String(t);return i===a?{triggered:!1,displayValue:r}:String(s)!==a?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"contains":return String(l).includes(String(t??""))?String(s).includes(String(t??""))?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}:{triggered:!1,displayValue:r};case"not_contains":return String(l).includes(String(t??""))?{triggered:!1,displayValue:r}:String(s).includes(String(t??""))?{triggered:!0,displayValue:r}:{triggered:!1,displayValue:r};case"changed":return{triggered:JSON.stringify(l)!==JSON.stringify(s),displayValue:r};case"increased":{let n=Ne(l),o=Ne(s);return n===null||o===null?{triggered:!1,displayValue:r}:{triggered:n>o,displayValue:r}}case"decreased":{let n=Ne(l),o=Ne(s);return n===null||o===null?{triggered:!1,displayValue:r}:{triggered:n<o,displayValue:r}}default:return{triggered:!1,displayValue:r}}}function Ya(l,e,t){let s={},r={},n=[];for(let i of e.conditions){let a=ht(l,i.field),c=t?.[i.field]??null,{triggered:d,displayValue:u}=Ro(a,i.operator,i.value,c);n.push(d),s[i.field]=u,r[i.field]=a}return{triggered:e.logic==="and"?n.every(Boolean):n.some(Boolean),displayValues:s,newLastValues:r}}function Ne(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}function Of(l){return l==null?"null":typeof l=="object"?JSON.stringify(l):String(l)}var fn=T(()=>{"use strict";m(ht,"extractField");m(Ro,"evaluateCondition");m(Ya,"evaluateCompositeCondition");m(Ne,"toNumber");m(Of,"formatValue")});function gn(l,e){return l.replace(/\{\{([^}]+)\}\}/g,(t,s)=>{let r=ht(e,s.trim());return r==null?"":typeof r=="object"?JSON.stringify(r):String(r)})}function qt(l,e){let t={};for(let[s,r]of Object.entries(l))typeof r=="string"?t[s]=gn(r,e):r!==null&&typeof r=="object"&&!Array.isArray(r)?t[s]=qt(r,e):Array.isArray(r)?t[s]=r.map(n=>typeof n=="string"?gn(n,e):n!==null&&typeof n=="object"&&!Array.isArray(n)?qt(n,e):n):t[s]=r;return t}var xo=T(()=>{"use strict";fn();m(gn,"resolveTemplates");m(qt,"resolveTemplatesInObject")});var Pf,Uf,Co,Ku=T(()=>{"use strict";fn();xo();pt();Pf=5,Uf={lt:"<",gt:">",lte:"<=",gte:">=",eq:"=",neq:"!=",contains:"contains",not_contains:"not contains",changed:"changed",increased:"increased",decreased:"decreased"},Co=class{static{m(this,"WatchEngine")}watchRepo;skillRegistry;skillSandbox;adapters;users;logger;confirmationQueue;activityLogger;skillHealthTracker;llmProvider;timer=null;tickIntervalMs=6e4;constructor(e,t,s,r,n,o,i,a,c,d){this.watchRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.users=n,this.logger=o,this.confirmationQueue=i,this.activityLogger=a,this.skillHealthTracker=c,this.llmProvider=d}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info("Watch engine started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Watch engine stopped")}async triggerWatch(e){let t=this.watchRepo.getById(e);if(!t)throw new Error(`Watch ${e} not found`);if(!t.enabled)throw new Error(`Watch ${e} is disabled`);this.logger.info({watchId:e,name:t.name},"Watch triggered via webhook"),await this.checkWatch(t)}async tick(){try{let e=this.watchRepo.getDue();for(let t of e)try{await this.checkWatch(t)}catch(s){this.logger.error({err:s,watchId:t.id},"Failed to check watch")}}catch(e){this.logger.error({err:e},"Error during watch engine tick")}}async checkWatch(e,t=0){let s=new Date().toISOString();this.logger.debug({watchId:e.id,name:e.name,skill:e.skillName},"Checking watch");let r=this.skillRegistry.get(e.skillName);if(!r){this.logger.warn({watchId:e.id,skillName:e.skillName},"Unknown skill for watch"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}if(this.skillHealthTracker?.isDisabled(e.skillName)){this.logger.debug({watchId:e.id,skillName:e.skillName},"Watch poll skill is auto-disabled, skipping"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}let{context:n}=$e(this.users,{platformUserId:e.chatId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),o=await this.skillSandbox.execute(r,e.skillParams,n);if(!o.success){this.logger.warn({watchId:e.id,error:o.error},"Watch skill execution failed"),this.skillHealthTracker?.recordFailure(e.skillName,o.error??"Watch poll failed"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}this.skillHealthTracker?.recordSuccess(e.skillName);let i,a,c;if(e.compositeCondition){let d=null;if(e.lastValue!==null)try{let p=JSON.parse(e.lastValue);d=p!==null&&typeof p=="object"&&!Array.isArray(p)?p:null}catch{}let u=Ya(o.data,e.compositeCondition,d);i=u.triggered,c=JSON.stringify(u.newLastValues),a=Object.entries(u.displayValues).map(([p,h])=>`${p}=${h}`).join(", ")}else{let d=ht(o.data,e.condition.field),u=null;if(e.lastValue!==null)try{u=JSON.parse(e.lastValue)}catch{}let p=Ro(d,e.condition.operator,e.condition.value,u);i=p.triggered,a=p.displayValue,c=JSON.stringify(d)}if(i&&this.isCooldownExpired(e)){let d=e.actionOnTrigger??"alert",u={result:o.data,currentValue:a,watchName:e.name},p=e.actionSkillParams?qt(e.actionSkillParams,u):{},h=e.messageTemplate?gn(e.messageTemplate,u):void 0;if(e.requiresConfirmation&&this.confirmationQueue&&(d==="action_only"||d==="alert_and_action")&&e.actionSkillName){if(await this.confirmationQueue.enqueue({chatId:e.chatId,platform:e.platform,source:"watch",sourceId:e.id,description:`Watch "${e.name}": ${e.actionSkillName} ausf\xFChren`,skillName:e.actionSkillName,skillParams:p}),d==="alert_and_action"){let g=await this.buildAlertText(e,a,o.data,h);g+=`
|
|
1157
1173
|
|
|
1158
|
-
(Aktion wartet auf Best\xE4tigung)`;let
|
|
1174
|
+
(Aktion wartet auf Best\xE4tigung)`;let y=this.adapters.get(e.platform);if(y)try{await y.sendMessage(e.chatId,g)}catch(_){this.logger.error({err:_,watchId:e.id,chatId:e.chatId},"Failed to send watch alert message")}}this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}if(d==="trigger_watch"&&e.triggerWatchId){if(t>=Pf){this.logger.warn({watchId:e.id,targetId:e.triggerWatchId,chainDepth:t},"Watch chain depth limit reached, aborting chain"),this.activityLogger?.logWatchChain({watchId:e.id,watchName:e.name,targetWatchId:e.triggerWatchId,platform:e.platform,chatId:e.chatId,outcome:"depth_limit",chainDepth:t}),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}let g=this.watchRepo.getById(e.triggerWatchId);if(!g){this.logger.warn({watchId:e.id,targetId:e.triggerWatchId},"Chained watch not found"),this.watchRepo.updateActionError(e.id,`Chained watch "${e.triggerWatchId}" not found`),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}if(!g.enabled){this.logger.warn({watchId:e.id,targetId:g.id},"Chained watch is disabled, skipping"),this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}this.activityLogger?.logWatchChain({watchId:e.id,watchName:e.name,targetWatchId:g.id,targetWatchName:g.name,platform:e.platform,chatId:e.chatId,outcome:"success",chainDepth:t}),this.logger.info({watchId:e.id,targetId:g.id,targetName:g.name,chainDepth:t+1},"Watch chain: triggering downstream watch");try{await this.checkWatch(g,t+1),this.watchRepo.updateActionError(e.id,null)}catch(y){let _=y instanceof Error?y.message:String(y);this.watchRepo.updateActionError(e.id,_),this.logger.warn({watchId:e.id,targetId:g.id,err:y},"Watch chain execution failed")}this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}let f=null;if((d==="action_only"||d==="alert_and_action")&&e.actionSkillName)if(this.skillHealthTracker?.isDisabled(e.actionSkillName))f=`Action skill "${e.actionSkillName}" is temporarily disabled due to repeated failures`,this.watchRepo.updateActionError(e.id,f),this.logger.warn({watchId:e.id,skillName:e.actionSkillName},"Watch action skill is auto-disabled");else{let g=this.skillRegistry.get(e.actionSkillName);if(g)try{await this.skillSandbox.execute(g,p,n),this.watchRepo.updateActionError(e.id,null),this.skillHealthTracker?.recordSuccess(e.actionSkillName),this.activityLogger?.logWatchAction({watchId:e.id,watchName:e.name,skillName:e.actionSkillName,platform:e.platform,chatId:e.chatId,outcome:"success"})}catch(y){f=y instanceof Error?y.message:String(y),this.watchRepo.updateActionError(e.id,f),this.skillHealthTracker?.recordFailure(e.actionSkillName,f),this.logger.warn({watchId:e.id,err:y},"Watch action failed"),this.activityLogger?.logWatchAction({watchId:e.id,watchName:e.name,skillName:e.actionSkillName,platform:e.platform,chatId:e.chatId,outcome:"error",error:f})}else f=`Action skill "${e.actionSkillName}" not found`,this.watchRepo.updateActionError(e.id,f),this.logger.warn({watchId:e.id,skillName:e.actionSkillName},"Unknown action skill for watch")}if(d==="alert"||d==="alert_and_action"){let g=await this.buildAlertText(e,a,o.data,h);f&&(g+=`
|
|
1159
1175
|
|
|
1160
|
-
\u26A0\uFE0F Aktion fehlgeschlagen: `+
|
|
1176
|
+
\u26A0\uFE0F Aktion fehlgeschlagen: `+f);let y=this.adapters.get(e.platform);if(y)try{await y.sendMessage(e.chatId,g),this.logger.info({watchId:e.id,name:e.name,value:a},"Watch alert sent"),this.activityLogger?.logWatchTrigger({watchId:e.id,watchName:e.name,value:a,platform:e.platform,chatId:e.chatId,outcome:"success"})}catch(_){this.logger.error({err:_,watchId:e.id},"Failed to send watch alert"),this.activityLogger?.logWatchTrigger({watchId:e.id,watchName:e.name,value:a,platform:e.platform,chatId:e.chatId,outcome:"error",error:_ instanceof Error?_.message:String(_)})}else this.logger.warn({watchId:e.id,platform:e.platform},"Watch alert skipped \u2014 no adapter for platform")}this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s})}else this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c})}isCooldownExpired(e){if(!e.lastTriggeredAt)return!0;let t=e.cooldownMinutes*6e4;return Date.now()-new Date(e.lastTriggeredAt).getTime()>=t}formatAlert(e,t,s){let r=Uf[e.condition.operator]??e.condition.operator,n=e.condition.value!=null?` ${r} ${e.condition.value}`:` ${r}`,o=[`\u26A1 Watch Alert: ${e.name}`,`Bedingung erf\xFCllt: ${e.condition.field}${n}`,`Aktueller Wert: ${t}`];if(s&&typeof s=="object"){let i=s,a=this.formatResultContext(i,e.condition.field);a&&o.push("",a)}return o.join(`
|
|
1161
1177
|
`)}async formatAlertWithLLM(e,t,s){if(!this.llmProvider)return null;try{let r=t;if(t&&typeof t=="object"&&!Array.isArray(t)){let a=t;if(Array.isArray(a.listings)&&a.listings.length>0){let c=e.match(/(\d+)\s*(günstigst|teuerst|billigst|Angebot|Listing|Ergebnis)/i),d=c?Math.max(parseInt(c[1],10),10):10,u=Math.max(d,10);a.listings.length>u&&(r={...a,listings:a.listings.slice(0,u)})}}let n=JSON.stringify(r,null,2),o=n.length>8e3?n.slice(0,8e3)+`
|
|
1162
1178
|
... (truncated)`:n;return(await this.llmProvider.complete({messages:[{role:"user",content:`Du bist ein Watch-Alert-Formatter. Formatiere die folgenden Daten als kurze, \xFCbersichtliche Benachrichtigung f\xFCr den User.
|
|
1163
1179
|
|
|
@@ -1180,10 +1196,10 @@ Regeln:
|
|
|
1180
1196
|
Insgesamt: ${e.count} Inserate`),n.join(`
|
|
1181
1197
|
`)}if(Array.isArray(e.cheapest)&&e.cheapest.length>0){let s=e.cheapest,r=[`G\xFCnstigste ${s.length}:`];for(let n of s){let o=String(n.title??"").slice(0,60),i=typeof n.price=="number"?`${n.price}\xA0\u20AC`:"k.A.",a=n.url?`
|
|
1182
1198
|
${n.url}`:"";r.push(`\u2022 ${o} \u2014 ${i}${a}`)}return r.join(`
|
|
1183
|
-
`)}return null}}});var
|
|
1199
|
+
`)}return null}}});var yn,Ja=T(()=>{"use strict";yn=class{static{m(this,"ConfirmationQueue")}confirmRepo;skillRegistry;skillSandbox;adapters;logger;activityLogger;expireTimer=null;feedbackService;constructor(e,t,s,r,n,o){this.confirmRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.logger=n,this.activityLogger=o}setFeedbackService(e){this.feedbackService=e}start(){this.expireTimer=setInterval(()=>this.expireTick(),6e4)}stop(){this.expireTimer&&(clearInterval(this.expireTimer),this.expireTimer=null)}async enqueue(e){let t=new Date(Date.now()+(e.timeoutMinutes??30)*6e4).toISOString(),s=this.confirmRepo.create({chatId:e.chatId,platform:e.platform,source:e.source,sourceId:e.sourceId,description:e.description,skillName:e.skillName,skillParams:e.skillParams,expiresAt:t}),r=this.adapters.get(e.platform);if(r){let n=s.id,o=`\u2753 Best\xE4tigung erforderlich:
|
|
1184
1200
|
${e.description}
|
|
1185
1201
|
|
|
1186
|
-
Antworte "ja" oder "nein".`;try{e.platform==="telegram"&&n?await r.sendMessage(e.chatId,o,{replyMarkup:{inlineKeyboard:[[{text:"\u2705 Approve",callbackData:`confirm:${n}:approve`},{text:"\u274C Reject",callbackData:`confirm:${n}:reject`}]]}}):await r.sendMessage(e.chatId,o)}catch(i){this.logger.error({err:i},"Failed to send confirmation request")}}}async checkForConfirmation(e,t,s,r){let n=s.trim().toLowerCase(),o=/^confirm:([^:]+):(approve|reject)$/.exec(n),i=o?o[2]==="approve":["ja","ok","yes","best\xE4tigen","j"].includes(n),a=o?o[2]==="reject":["nein","no","abbrechen","n","n\xF6"].includes(n);if(!i&&!a)return!1;let c=this.confirmRepo.findPending(e,t);if(!c)return!1;let d=this.adapters.get(t);if(i){this.confirmRepo.resolve(c.id,"approved");let u=this.skillRegistry.get(c.skillName);if(u)try{await this.skillSandbox.execute(u,c.skillParams,r),d&&await d.sendMessage(e,`\u2705 Aktion ausgef\xFChrt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"approved",userId:r.userId,platform:t,chatId:e})}catch(p){this.logger.error({err:p,confirmationId:c.id},"Confirmed action failed"),d&&await d.sendMessage(e,`\u274C Aktion fehlgeschlagen: ${p instanceof Error?p.message:String(p)}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"error",userId:r.userId,platform:t,chatId:e,error:p instanceof Error?p.message:String(p)})}else d&&await d.sendMessage(e,`\u274C Skill "${c.skillName}" nicht gefunden.`)}else this.confirmRepo.resolve(c.id,"rejected"),d&&await d.sendMessage(e,`\u274C Aktion abgelehnt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"rejected",userId:r.userId,platform:t,chatId:e});return!0}async expireTick(){try{let e=this.confirmRepo.expireOld();for(let t of e){this.activityLogger?.logConfirmation({confirmationId:t.id,skillName:t.skillName,description:t.description,source:t.source,sourceId:t.sourceId,outcome:"expired",platform:t.platform,chatId:t.chatId});let s=this.adapters.get(t.platform);if(s)try{await s.sendMessage(t.chatId,`\u23F0 Best\xE4tigung abgelaufen: ${t.description}`)}catch{}}}catch(e){this.logger.error({err:e},"Confirmation expire tick failed")}}}});function
|
|
1202
|
+
Antworte "ja" oder "nein".`;try{e.platform==="telegram"&&n?await r.sendMessage(e.chatId,o,{replyMarkup:{inlineKeyboard:[[{text:"\u2705 Approve",callbackData:`confirm:${n}:approve`},{text:"\u274C Reject",callbackData:`confirm:${n}:reject`}]]}}):await r.sendMessage(e.chatId,o)}catch(i){this.logger.error({err:i},"Failed to send confirmation request")}}}async checkForConfirmation(e,t,s,r){let n=s.trim().toLowerCase(),o=/^confirm:([^:]+):(approve|reject)$/.exec(n),i=o?o[2]==="approve":["ja","ok","yes","best\xE4tigen","j"].includes(n),a=o?o[2]==="reject":["nein","no","abbrechen","n","n\xF6"].includes(n);if(!i&&!a)return!1;let c=this.confirmRepo.findPending(e,t);if(!c)return!1;let d=this.adapters.get(t);if(i){this.confirmRepo.resolve(c.id,"approved");let u=this.skillRegistry.get(c.skillName);if(u)try{await this.skillSandbox.execute(u,c.skillParams,r),d&&await d.sendMessage(e,`\u2705 Aktion ausgef\xFChrt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"approved",userId:r.userId,platform:t,chatId:e})}catch(p){this.logger.error({err:p,confirmationId:c.id},"Confirmed action failed"),d&&await d.sendMessage(e,`\u274C Aktion fehlgeschlagen: ${p instanceof Error?p.message:String(p)}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"error",userId:r.userId,platform:t,chatId:e,error:p instanceof Error?p.message:String(p)})}else d&&await d.sendMessage(e,`\u274C Skill "${c.skillName}" nicht gefunden.`)}else this.confirmRepo.resolve(c.id,"rejected"),d&&await d.sendMessage(e,`\u274C Aktion abgelehnt: ${c.description}`),this.activityLogger?.logConfirmation({confirmationId:c.id,skillName:c.skillName,description:c.description,source:c.source,sourceId:c.sourceId,outcome:"rejected",userId:r.userId,platform:t,chatId:e}),this.feedbackService?.onWatchRejected({userId:r.userId,watchId:c.sourceId,watchName:c.description,skillName:c.skillName,skillParams:c.skillParams??{},description:c.description});return!0}async expireTick(){try{let e=this.confirmRepo.expireOld();for(let t of e){this.activityLogger?.logConfirmation({confirmationId:t.id,skillName:t.skillName,description:t.description,source:t.source,sourceId:t.sourceId,outcome:"expired",platform:t.platform,chatId:t.chatId});let s=this.adapters.get(t.platform);if(s)try{await s.sendMessage(t.chatId,`\u23F0 Best\xE4tigung abgelaufen: ${t.description}`)}catch{}}}catch(e){this.logger.error({err:e},"Confirmation expire tick failed")}}}});function Za(l){let e=l.trim();if(e.length<10)return{level:"low",matchedPatterns:[]};for(let s of Ff)if(s.test(e))return{level:"low",matchedPatterns:[]};let t=[];for(let s of jf)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 Ff,jf,Qa=T(()=>{"use strict";Ff=[/^(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],jf=[{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]}];m(Za,"scanSignal")});var Bf,Hf,wn,ec=T(()=>{"use strict";Bf=["fact","preference","correction","entity","decision","relationship","principle","commitment","moment","skill"],Hf=`You are a memory extraction system. Analyze the user message and extract personal facts about the USER (not about what they're asking).
|
|
1187
1203
|
|
|
1188
1204
|
Rules:
|
|
1189
1205
|
- Only extract information the user STATES about themselves
|
|
@@ -1203,7 +1219,7 @@ Extract memories from this conversation:
|
|
|
1203
1219
|
User: {USER_MESSAGE}
|
|
1204
1220
|
Assistant: {ASSISTANT_RESPONSE}
|
|
1205
1221
|
|
|
1206
|
-
Return ONLY a valid JSON array, no explanation:`,
|
|
1222
|
+
Return ONLY a valid JSON array, no explanation:`,wn=class{static{m(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,n=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=n}async extract(e,t,s){try{let r=Hf.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),n=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),o=this.parseResponse(n.content);if(o.length===0)return 0;let i=0;for(let a of o)if(!(a.confidence<this.minConfidence))try{let c=this.memoryRepo.saveWithMetadata(e,a.key,a.value,a.category,a.type,a.confidence,"auto");this.embeddingService&&this.embeddingService.embedAndStore(e,`${a.key}: ${a.value}`,"memory",c.id).catch(d=>this.logger.debug({err:d},"Auto-embed failed")),i++,this.logger.info({key:a.key,type:a.type,confidence:a.confidence},"Auto-extracted memory saved")}catch(c){this.logger.warn({err:c,key:a.key},"Failed to save extracted memory")}return i}catch(r){return this.logger.error({err:r},"Memory extraction failed"),0}}parseResponse(e){try{let t=e.match(/\[[\s\S]*\]/);if(!t)return[];let s=JSON.parse(t[0]);return Array.isArray(s)?s.filter(r=>typeof r=="object"&&r!==null).map(r=>({key:String(r.key||""),value:String(r.value||""),type:this.validateType(String(r.type||"fact")),confidence:this.clampConfidence(Number(r.confidence)||.5),category:String(r.category||"general")})).filter(r=>r.key&&r.value):[]}catch{return this.logger.debug({content:e.slice(0,200)},"Failed to parse extraction response"),[]}}validateType(e){return Bf.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});function No(l){let e=l.trim();if(e.length<8)return{level:"low"};for(let t of Wf)if(t.test(e))return{level:"high"};return{level:"low"}}var Wf,tc=T(()=>{"use strict";Wf=[/\b(nein,?\s*(nicht so|das ist falsch|das stimmt nicht|anders))\b/i,/\b(das war falsch|das ist falsch|das solltest du nicht)\b/i,/\b(ich meinte|ich wollte|ich habe gemeint)\b/i,/\b(tu das nicht|mach das nicht|lass das)\b/i,/\b(beim nächsten [Mm]al|in [Zz]ukunft|ab jetzt|ab sofort)\b/i,/\b(nicht wenn|nur wenn|nur falls|nur dann)\b/i,/\b(hör auf|stop|stopp).*\b(damit|das|mit)\b/i,/\b(das will ich nicht|das brauche ich nicht)\b/i,/\b(falsche?r?\s+(antwort|ergebnis|aktion|reaktion))\b/i,/\b(zu (oft|viel|aggressiv|häufig|früh|spät))\b/i,/\b(schwellenwert|threshold|grenzwert).*(ändern|anpassen|erhöhen|senken)\b/i,/\b(no,?\s*(not like that|that's wrong|don't do that))\b/i,/\b(that was wrong|that's incorrect|that's not what I)\b/i,/\b(I meant|I wanted|what I meant was)\b/i,/\b(don't do that|stop doing|never do)\b/i,/\b(next time|from now on|in the future|going forward)\b/i,/\b(not when|only when|only if|only then)\b/i,/\b(too (often|much|aggressive|frequent|early|late))\b/i];m(No,"scanCorrectionSignal")});var Tn,sc=T(()=>{"use strict";Qa();ec();tc();Tn=class{static{m(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;feedbackService;setFeedbackService(e){this.feedbackService=e}constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new wn(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;this.feedbackService&&No(t).level==="high"&&this.feedbackService.onConversationCorrection({userId:e,userMessage:t,assistantResponse:s});let r=Za(t);if(r.level==="low"){this.logger.debug({signal:"low"},"Skipping extraction \u2014 low signal");return}if(!this.checkRateLimit(e)){this.logger.debug({userId:e},"Skipping extraction \u2014 rate limit reached");return}this.logger.info({signal:r.level,patterns:r.matchedPatterns},"High signal detected, triggering extraction"),this.extractor.extract(e,t,s).then(n=>{n>0&&this.logger.info({userId:e,extractedCount:n},"Auto-extraction complete")}).catch(n=>{this.logger.error({err:n},"Auto-extraction failed")})}checkRateLimit(e){let t=Date.now(),s=t-6e4,r=this.extractionTimestamps.get(e);r||(r=[],this.extractionTimestamps.set(e,r));let n=r.filter(o=>o>s);return n.length===0?(this.extractionTimestamps.delete(e),!0):(this.extractionTimestamps.set(e,n),n.length>=this.maxExtractionsPerMinute?!1:(n.push(t),!0))}}});var Ms,rc=T(()=>{"use strict";Ms=class{static{m(this,"FeedbackService")}feedbackRepo;memoryRepo;logger;threshold;staleDays;constructor(e,t,s,r){this.feedbackRepo=e,this.memoryRepo=t,this.logger=s,this.threshold=r?.rejectionThreshold??3,this.staleDays=r?.staleDays??90}onWatchRejected(e){this.handleWatchRejection(e).catch(t=>{this.logger.error({err:t},"Feedback: watch rejection handling failed")})}onConversationCorrection(e){this.handleCorrection(e).catch(t=>{this.logger.error({err:t},"Feedback: conversation correction handling failed")})}async runMaintenance(){try{let e=this.feedbackRepo.pruneOldEvents(this.staleDays*2);e>0&&this.logger.info({pruned:e},"Feedback: pruned old events")}catch(e){this.logger.error({err:e},"Feedback: maintenance failed")}}async handleWatchRejection(e){let t=`watch:${e.watchName.toLowerCase().replace(/\s+/g,"_")}:${e.skillName}`;this.feedbackRepo.recordEvent(e.userId,"watch_rejection",e.watchId,t,e.description,{skillName:e.skillName,skillParams:e.skillParams});let s=this.feedbackRepo.countEvents(e.userId,t);if(this.logger.debug({contextKey:t,count:s,threshold:this.threshold},"Feedback: watch rejection recorded"),s>=this.threshold){let r=`feedback:${t}`,n=`Watch "${e.watchName}" wurde ${s}\xD7 abgelehnt. Schwellenwert oder Parameter \xFCberpr\xFCfen bevor diese Aktion vorgeschlagen wird.`;this.memoryRepo.saveWithMetadata(e.userId,r,n,"automation","feedback",.9,"auto"),this.logger.info({contextKey:t,count:s,memoryKey:r},"Feedback: watch rejection promoted to feedback memory")}}async handleCorrection(e){let t=new Date().toISOString().slice(0,10),s=`correction:${e.userId}:${t}`,r=this.extractCorrectionRule(e.userMessage);if(!r)return;this.feedbackRepo.recordEvent(e.userId,"conversation_correction",void 0,s,r,{userMessage:e.userMessage.slice(0,500)});let n=`feedback:correction:${Date.now()}`;this.memoryRepo.saveWithMetadata(e.userId,n,r,"general","feedback",.8,"auto"),this.logger.info({rule:r},"Feedback: conversation correction saved as feedback memory")}extractCorrectionRule(e){let t=e.trim();return t.length>10&&t.length<300?`Nutzer-Korrektur: ${t}`:t.length>=300?`Nutzer-Korrektur: ${t.slice(0,280)}...`:null}}});var zf,qf,Gf,Xf,_n,nc=T(()=>{"use strict";zf=Math.LN2,qf=.3,Gf=.7,Xf=3,_n=class{static{m(this,"MemoryRetriever")}memoryRepo;logger;embeddingService;constructor(e,t,s){this.memoryRepo=e,this.logger=t,this.embeddingService=s}async retrieve(e,t,s=15,r){let n=[e];if(r)for(let o of r)o!==e&&n.push(o);try{let o=new Set,i=[];for(let g of n)for(let y of this.memoryRepo.keywordSearch(g,t,30))o.has(y.id)||(o.add(y.id),i.push(y));let a=[],c=!1;if(this.embeddingService)try{let g=new Set;for(let y of n)for(let _ of await this.embeddingService.semanticSearch(y,t,30))g.has(_.key)||(g.add(_.key),a.push(_));c=a.length>0}catch(g){this.logger.debug({err:g},"Semantic search failed, falling back to keyword-only")}let d=new Map,u=i.length;for(let g=0;g<i.length;g++){let y=i[g],_=u>0?1-g/u:0,S=c?qf:1,b=this.applyBoosts(_*S,y);d.set(y.key,{memory:{key:y.key,value:y.value,category:y.category,type:y.type,score:b},score:b}),this.memoryRepo.recordAccess(y.id)}if(c)for(let g of a){let y=g.score*Gf,_=d.get(g.key);if(_)_.score+=y,_.memory.score=_.score;else{let S=this.memoryRepo.recall(e,g.key),b=this.applyBoosts(y,S||void 0);d.set(g.key,{memory:{key:g.key,value:g.value,category:g.category,type:S?.type||"general",score:b},score:b}),S&&this.memoryRepo.recordAccess(S.id)}}let p=Array.from(d.values()).sort((g,y)=>y.score-g.score),h=new Map,f=[];for(let{memory:g}of p){let y=h.get(g.type)||0;if(!(y>=Xf)&&(h.set(g.type,y+1),f.push(g),f.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:f.length,hasSemanticSearch:c},"Hybrid memory retrieval complete"),f}catch(o){this.logger.error({err:o},"Memory retrieval failed");let i=new Set,a=[];for(let c of n)for(let d of this.memoryRepo.getRecentForPrompt(c,s))i.has(d.key)||(i.add(d.key),a.push({key:d.key,value:d.value,category:d.category,type:d.type,score:0}));return a.slice(0,s)}}applyBoosts(e,t){let s=e;if(t){s*=.5+.5*t.confidence;let r=new Date(t.updatedAt).getTime(),n=Date.now()-r,o=Math.exp(-zf*n/2592e6);s*=o}return s}}});var kn,oc=T(()=>{"use strict";kn=class{static{m(this,"ConversationSummarizer")}llm;summaryRepo;logger;constructor(e,t,s){this.llm=e,this.summaryRepo=t,this.logger=s}getSummary(e){return this.summaryRepo.get(e)}onMessageProcessed(e,t,s,r,n){let o=this.summaryRepo.get(e);!o&&t<6||o&&t-o.messageCount<3||this.updateSummary(e,t,s,r,n,o).catch(i=>this.logger.warn({err:i,conversationId:e},"Failed to update conversation summary"))}async updateSummary(e,t,s,r,n,o){let i=this.buildSummaryPrompt(o?.summary,n,s,r),c=(await this.llm.complete({messages:[{role:"user",content:i}],temperature:.1,tier:"fast",maxTokens:512})).content?.trim();if(!c||c.length<10){this.logger.debug({conversationId:e},"Summary response too short, skipping upsert");return}this.summaryRepo.upsert({conversationId:e,summary:c,messageCount:t,lastUserMessage:s.slice(0,500),lastAssistantMessage:r.slice(0,500),updatedAt:new Date().toISOString()}),this.logger.debug({conversationId:e,messageCount:t,summaryLength:c.length},"Conversation summary updated")}buildSummaryPrompt(e,t,s,r){let n=`Du bist ein Zusammenfassungs-Assistent. Erstelle eine strukturierte Zusammenfassung des Gespr\xE4chsverlaufs.
|
|
1207
1223
|
`;if(e&&(n+=`
|
|
1208
1224
|
## Bisherige Zusammenfassung
|
|
1209
1225
|
${e}
|
|
@@ -1229,21 +1245,22 @@ Regeln:
|
|
|
1229
1245
|
- Maximal 120 W\xF6rter
|
|
1230
1246
|
- Nur relevante Fakten, kein Smalltalk
|
|
1231
1247
|
- Leere Punkte: "\u2014"
|
|
1232
|
-
- Sprache: Deutsch (oder Sprache des Gespr\xE4chs)`,n}}});var
|
|
1248
|
+
- Sprache: Deutsch (oder Sprache des Gespr\xE4chs)`,n}}});var En,ic=T(()=>{"use strict";En=class{static{m(this,"CalendarWatcher")}calendarProvider;notifRepo;adapters;defaultChatId;defaultPlatform;config;logger;activityLogger;timer=null;tickIntervalMs=6e4;minutesBefore;lastCleanup=0;constructor(e,t,s,r,n,o,i,a){this.calendarProvider=e,this.notifRepo=t,this.adapters=s,this.defaultChatId=r,this.defaultPlatform=n,this.config=o,this.logger=i,this.activityLogger=a,this.minutesBefore=o.minutesBefore??15}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info({minutesBefore:this.minutesBefore},"Calendar watcher started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Calendar watcher stopped")}async tick(){try{let e=Date.now();if(e-this.lastCleanup>36e5){let n=new Date(e-864e5).toISOString();this.notifRepo.cleanup(n),this.lastCleanup=e}let t=new Date,s=new Date(t.getTime()+this.minutesBefore*6e4),r=await this.calendarProvider.listEvents(t,s);for(let n of r)await this.processEvent(n)}catch(e){e instanceof Error&&(e.message.includes("Timeout")||e.message.includes("fetch failed")||e.message.includes("503")||e.message.includes("502")||e.message.includes("504"))?this.logger.warn({err:e},"Calendar watcher tick failed (transient)"):this.logger.error({err:e},"Calendar watcher tick failed")}}async processEvent(e){if(e.allDay||this.notifRepo.wasNotified(e.id,this.defaultChatId))return;let t=Date.now(),r=(e.start.getTime()-t)/6e4;if(r>this.minutesBefore||r<0)return;let n=[],o=Math.round(r),i=e.start.toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"});if(n.push(`\u{1F4C5} In ${o} Min: ${e.title}`),n.push(`Zeit: ${i} \u2013 ${e.end.toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"})}`),e.location&&n.push(`Ort: ${e.location}`),e.description){let c=e.description.replace(/<[^>]*>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/&#\d+;/g,"").replace(/\s+/g," ").trim();c.length>0&&n.push(`
|
|
1233
1249
|
${c.slice(0,200)}`)}let a=this.adapters.get(this.defaultPlatform);if(a)try{await a.sendMessage(this.defaultChatId,n.join(`
|
|
1234
|
-
`)),this.notifRepo.markNotified(e.id,this.defaultChatId,this.defaultPlatform,e.start.toISOString()),this.logger.info({eventId:e.id,title:e.title},"Calendar vorlauf notification sent"),this.activityLogger?.logCalendarNotify({eventId:e.id,eventTitle:e.title,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(c){this.logger.error({err:c,eventId:e.id},"Failed to send calendar notification"),this.activityLogger?.logCalendarNotify({eventId:e.id,eventTitle:e.title,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:c instanceof Error?c.message:String(c)})}}}});var
|
|
1235
|
-
`)),this.notifRepo.markNotified(i,this.defaultChatId,this.defaultPlatform,g),this.logger.info({todoId:e,title:t,kind:o},"Todo reminder sent"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(f){this.logger.error({err:f,todoId:e},"Failed to send todo reminder"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:f instanceof Error?f.message:String(f)})}}}});var yn,Ja=T(()=>{"use strict";yn=class{static{m(this,"ActivityLogger")}repo;logger;constructor(e,t){this.repo=e,this.logger=t}logSkillExec(e){this.safe(()=>this.repo.log({eventType:"skill_exec",source:"user",userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.details}))}logWatchTrigger(e){this.safe(()=>this.repo.log({eventType:"watch_trigger",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.watchName,outcome:e.outcome,errorMessage:e.error,details:{value:e.value}}))}logWatchAction(e){this.safe(()=>this.repo.log({eventType:"watch_action",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{watchName:e.watchName}}))}logConfirmation(e){this.safe(()=>this.repo.log({eventType:"confirmation",source:e.source,sourceId:e.sourceId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{confirmationId:e.confirmationId,description:e.description}}))}logScheduledExec(e){this.safe(()=>this.repo.log({eventType:"scheduled_exec",source:"scheduled",sourceId:e.actionId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.actionName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.skillName?{skillName:e.skillName}:void 0}))}logBackgroundTask(e){this.safe(()=>this.repo.log({eventType:"background_task",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error}))}logCalendarNotify(e){this.safe(()=>this.repo.log({eventType:"calendar_notify",source:"system",sourceId:e.eventId,platform:e.platform,chatId:e.chatId,action:e.eventTitle,outcome:e.outcome,errorMessage:e.error}))}logWorkflowExec(e){this.safe(()=>this.repo.log({eventType:"workflow_exec",source:"workflow",sourceId:e.chainId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.chainName,outcome:e.outcome,errorMessage:e.error,details:{executionId:e.executionId,...e.details}}))}logAgentLifecycle(e){this.safe(()=>this.repo.log({eventType:"agent_lifecycle",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.event,outcome:"success",details:{skillName:e.skillName,...e.details}}))}logSkillHealth(e){this.safe(()=>this.repo.log({eventType:"skill_health",source:"system",action:e.skillName,outcome:e.outcome,details:e.details}))}safe(e){try{e()}catch(t){this.logger.warn({err:t},"Failed to write activity log entry")}}}});var Af,wn,Za=T(()=>{"use strict";Af=[{fails:20,durationMinutes:1440},{fails:10,durationMinutes:120},{fails:5,durationMinutes:30}],wn=class{static{m(this,"SkillHealthTracker")}healthRepo;logger;activityLogger;constructor(e,t,s){this.healthRepo=e,this.logger=t,this.activityLogger=s}isDisabled(e){try{return this.healthRepo.isDisabled(e)?this.healthRepo.getByName(e):void 0}catch{return}}recordSuccess(e){try{this.healthRepo.recordSuccess(e)}catch(t){this.logger.debug({err:t,skillName:e},"Failed to record skill success")}}recordFailure(e,t){try{let s=this.healthRepo.recordFailure(e,t);for(let r of Af)if(s.consecutiveFails>=r.fails&&!s.disabledUntil){let n=new Date(Date.now()+r.durationMinutes*6e4).toISOString();this.healthRepo.disable(e,n),this.logger.warn({skillName:e,consecutiveFails:s.consecutiveFails,disabledUntil:n},"Skill auto-disabled due to repeated failures"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"disabled",details:{consecutiveFails:s.consecutiveFails,disabledUntil:n,lastError:t}});break}}catch(s){this.logger.debug({err:s,skillName:e},"Failed to record skill failure")}}forceEnable(e){try{this.healthRepo.enable(e),this.logger.info({skillName:e},"Skill force-enabled by user"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"re-enabled",details:{reason:"force-enable"}})}catch(t){this.logger.warn({err:t,skillName:e},"Failed to force-enable skill")}}getDashboard(){try{return this.healthRepo.getAll()}catch{return[]}}checkReEnables(){try{let e=this.healthRepo.getAll(),t=new Date;for(let s of e)s.disabledUntil&&new Date(s.disabledUntil)<=t&&(this.healthRepo.enable(s.skillName),this.logger.info({skillName:s.skillName},"Skill auto-re-enabled after cooldown"),this.activityLogger?.logSkillHealth({skillName:s.skillName,outcome:"re-enabled",details:{reason:"cooldown-expired"}}))}catch(e){this.logger.warn({err:e},"Failed to check re-enables")}}}});var Tn,Qa=T(()=>{"use strict";So();Tn=class{static{m(this,"WorkflowRunner")}workflowRepo;skillRegistry;skillSandbox;logger;activityLogger;healthTracker;constructor(e,t,s,r,n,o){this.workflowRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.logger=r,this.activityLogger=n,this.healthTracker=o}async run(e,t,s){let r=this.workflowRepo.createExecution(e.id,e.steps.length),n=[],o=s??{};for(let i=0;i<e.steps.length;i++){let a=e.steps[i];if(this.healthTracker?.isDisabled(a.skillName)){let f=`Skill "${a.skillName}" is temporarily disabled`;if(a.onError==="skip"){n.push({skillName:a.skillName,success:!1,error:f});continue}return this.finishExecution(r.id,"failed",i,n,f),{executionId:r.id,status:"failed",stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:f}}let c=this.skillRegistry.get(a.skillName);if(!c){let f=`Skill "${a.skillName}" not found`;if(a.onError==="skip"){n.push({skillName:a.skillName,success:!1,error:f});continue}return this.finishExecution(r.id,"failed",i,n,f),{executionId:r.id,status:"failed",stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:f}}let d={prev:o,steps:n.map(f=>f.data)};s&&(d.trigger=s);let u=Wt(a.inputMapping,d),p=a.onError==="retry"?(a.maxRetries??1)+1:1,h,g=!1;for(let f=0;f<p;f++)try{let y=await this.skillSandbox.execute(c,u,t);if(y.success){o=y.data,n.push({skillName:a.skillName,success:!0,data:y.data}),this.healthTracker?.recordSuccess(a.skillName),g=!0;break}else h=y.error??"Unknown error",this.healthTracker?.recordFailure(a.skillName,h)}catch(y){h=y instanceof Error?y.message:String(y),this.healthTracker?.recordFailure(a.skillName,h)}if(!g){if(n.push({skillName:a.skillName,success:!1,error:h}),a.onError==="skip")continue;let f=i>0?"partial":"failed";return this.finishExecution(r.id,f,i,n,h),this.logWorkflow(e,r.id,f,i,h),{executionId:r.id,status:f,stepsCompleted:i,totalSteps:e.steps.length,stepResults:n,error:h}}this.workflowRepo.updateExecution(r.id,{stepsCompleted:i+1,stepResults:JSON.stringify(n)})}return this.finishExecution(r.id,"completed",e.steps.length,n),this.logWorkflow(e,r.id,"completed",e.steps.length),{executionId:r.id,status:"completed",stepsCompleted:e.steps.length,totalSteps:e.steps.length,stepResults:n}}finishExecution(e,t,s,r,n){this.workflowRepo.updateExecution(e,{status:t,stepsCompleted:s,stepResults:JSON.stringify(r),error:n,completedAt:new Date().toISOString()})}logWorkflow(e,t,s,r,n){this.activityLogger?.logWorkflowExec({chainId:e.id,chainName:e.name,executionId:t,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:s==="completed"?"success":"error",error:n,details:{stepsCompleted:r,totalSteps:e.steps.length}})}}});import Rf from"node:crypto";var xf,Cf,_n,ec=T(()=>{"use strict";mt();xf=[7,12,18],Cf=1024,_n=class{static{m(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;tickTimer;lastRunHour=-1;enabled;schedule;tier;deduplicationHours;constructor(e,t,s,r,n,o,i,a,c,d,u,p,h,g,f,y,k){this.calendarProvider=e,this.todoRepo=t,this.watchRepo=s,this.memoryRepo=r,this.activityRepo=n,this.skillHealthRepo=o,this.notifRepo=i,this.skillRegistry=a,this.skillSandbox=c,this.llm=d,this.adapters=u,this.userRepo=p,this.defaultChatId=h,this.defaultPlatform=g,this.logger=y,this.activityLogger=k,this.enabled=f?.enabled!==!1,this.schedule=f?.schedule??"morning_noon_evening",this.tier=f?.tier??"fast",this.deduplicationHours=f?.deduplicationHours??12}start(){if(!this.enabled){this.logger.info("Reasoning engine disabled");return}this.tickTimer=setInterval(()=>this.tick(),6e4),this.logger.info({schedule:this.schedule,tier:this.tier},"Reasoning engine started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0)}shouldRun(){let e=new Date,t=e.getHours(),s=e.getMinutes();switch(this.schedule){case"morning_noon_evening":return!!(xf.includes(t)&&s===0&&this.lastRunHour!==t);case"hourly":return s===0&&this.lastRunHour!==t;case"half_hourly":return(s<=1||s>=30&&s<=31)&&this.lastRunHour!==t*100+(s<2?0:30);default:return!1}}markRun(){let e=new Date;this.schedule==="half_hourly"?this.lastRunHour=e.getHours()*100+e.getMinutes():this.lastRunHour=e.getHours()}async tick(){if(this.shouldRun()){this.markRun();try{this.logger.info("Reasoning pass starting");let e=Date.now(),t=await this.collectContext(),s=this.buildPrompt(t),n=(await this.llm.complete({messages:[{role:"user",content:s}],maxTokens:Cf,tier:this.tier})).content.trim(),o=Date.now()-e;if(!n||n==="KEINE_INSIGHTS"||n.length<10){this.logger.info({durationMs:o},"Reasoning pass: no insights"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o});return}let i=this.parseInsights(n),a=i.filter(u=>!this.wasRecentlySent(u));if(a.length===0){this.logger.info({durationMs:o,total:i.length},"Reasoning pass: all insights deduplicated");return}let c=`\u{1F4A1} **Alfred Insights**
|
|
1250
|
+
`)),this.notifRepo.markNotified(e.id,this.defaultChatId,this.defaultPlatform,e.start.toISOString()),this.logger.info({eventId:e.id,title:e.title},"Calendar vorlauf notification sent"),this.activityLogger?.logCalendarNotify({eventId:e.id,eventTitle:e.title,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(c){this.logger.error({err:c,eventId:e.id},"Failed to send calendar notification"),this.activityLogger?.logCalendarNotify({eventId:e.id,eventTitle:e.title,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:c instanceof Error?c.message:String(c)})}}}});var bn,ac=T(()=>{"use strict";bn=class{static{m(this,"TodoWatcher")}todoRepo;notifRepo;adapters;defaultChatId;defaultPlatform;logger;activityLogger;timer=null;tickIntervalMs=6e4;minutesBefore;overdueCheck;lastOverdueCheck=0;constructor(e,t,s,r,n,o,i,a){this.todoRepo=e,this.notifRepo=t,this.adapters=s,this.defaultChatId=r,this.defaultPlatform=n,this.logger=i,this.activityLogger=a,this.minutesBefore=o.minutesBefore??30,this.overdueCheck=o.overdueCheck??!0}start(){this.timer=setInterval(()=>this.tick(),this.tickIntervalMs),this.logger.info({minutesBefore:this.minutesBefore},"Todo watcher started")}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.logger.info("Todo watcher stopped")}async tick(){try{let e=new Date(Date.now()+this.minutesBefore*6e4),t=this.todoRepo.getDueInWindow(e.toISOString());for(let r of t)await this.notify(r.id,r.title,r.dueDate,r.list,r.priority,"upcoming");let s=Date.now();if(this.overdueCheck&&s-this.lastOverdueCheck>36e5){this.lastOverdueCheck=s;let r=this.todoRepo.getOverdue();for(let n of r)await this.notify(n.id,n.title,n.dueDate,n.list,n.priority,"overdue")}}catch(e){this.logger.error({err:e},"Todo watcher tick failed")}}async notify(e,t,s,r,n,o){let i=o==="overdue"?`todo:${o}:${e}:${new Date().toISOString().slice(0,10)}`:`todo:${o}:${e}`;if(this.notifRepo.wasNotified(i,this.defaultChatId))return;let c=new Date(s).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}),p=[`${o==="overdue"?"\u26A0\uFE0F":"\u2705"} **${o==="overdue"?"\xDCberf\xE4llig":"Bald f\xE4llig"}:** ${t}`,`F\xE4llig: ${c}`];r!=="default"&&p.push(`Liste: ${r}`),n!=="normal"&&p.push(`Priorit\xE4t: ${n}`);let h=this.adapters.get(this.defaultPlatform);if(!h)return;let f=o==="overdue"?new Date().toISOString():s;try{await h.sendMessage(this.defaultChatId,p.join(`
|
|
1251
|
+
`)),this.notifRepo.markNotified(i,this.defaultChatId,this.defaultPlatform,f),this.logger.info({todoId:e,title:t,kind:o},"Todo reminder sent"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"success"})}catch(g){this.logger.error({err:g,todoId:e},"Failed to send todo reminder"),this.activityLogger?.logCalendarNotify({eventId:i,eventTitle:`[Todo] ${t}`,platform:this.defaultPlatform,chatId:this.defaultChatId,outcome:"error",error:g instanceof Error?g.message:String(g)})}}}});var Sn,cc=T(()=>{"use strict";Sn=class{static{m(this,"ActivityLogger")}repo;logger;constructor(e,t){this.repo=e,this.logger=t}logSkillExec(e){this.safe(()=>this.repo.log({eventType:"skill_exec",source:"user",userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.details}))}logWatchTrigger(e){this.safe(()=>this.repo.log({eventType:"watch_trigger",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.watchName,outcome:e.outcome,errorMessage:e.error,details:{value:e.value}}))}logWatchAction(e){this.safe(()=>this.repo.log({eventType:"watch_action",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{watchName:e.watchName}}))}logWatchChain(e){this.safe(()=>this.repo.log({eventType:"watch_chain",source:"watch",sourceId:e.watchId,platform:e.platform,chatId:e.chatId,action:`${e.watchName} -> ${e.targetWatchName??e.targetWatchId}`,outcome:e.outcome==="success"?"success":"error",errorMessage:e.error??(e.outcome==="depth_limit"?"Chain depth limit reached":void 0),details:{targetWatchId:e.targetWatchId,targetWatchName:e.targetWatchName,chainDepth:e.chainDepth}}))}logConfirmation(e){this.safe(()=>this.repo.log({eventType:"confirmation",source:e.source,sourceId:e.sourceId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,errorMessage:e.error,details:{confirmationId:e.confirmationId,description:e.description}}))}logScheduledExec(e){this.safe(()=>this.repo.log({eventType:"scheduled_exec",source:"scheduled",sourceId:e.actionId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.actionName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error,details:e.skillName?{skillName:e.skillName}:void 0}))}logBackgroundTask(e){this.safe(()=>this.repo.log({eventType:"background_task",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.skillName,outcome:e.outcome,durationMs:e.durationMs,errorMessage:e.error}))}logCalendarNotify(e){this.safe(()=>this.repo.log({eventType:"calendar_notify",source:"system",sourceId:e.eventId,platform:e.platform,chatId:e.chatId,action:e.eventTitle,outcome:e.outcome,errorMessage:e.error}))}logWorkflowExec(e){this.safe(()=>this.repo.log({eventType:"workflow_exec",source:"workflow",sourceId:e.chainId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.chainName,outcome:e.outcome,errorMessage:e.error,details:{executionId:e.executionId,...e.details}}))}logAgentLifecycle(e){this.safe(()=>this.repo.log({eventType:"agent_lifecycle",source:"background",sourceId:e.taskId,userId:e.userId,platform:e.platform,chatId:e.chatId,action:e.event,outcome:"success",details:{skillName:e.skillName,...e.details}}))}logSkillHealth(e){this.safe(()=>this.repo.log({eventType:"skill_health",source:"system",action:e.skillName,outcome:e.outcome,details:e.details}))}safe(e){try{e()}catch(t){this.logger.warn({err:t},"Failed to write activity log entry")}}}});var Kf,vn,lc=T(()=>{"use strict";Kf=[{fails:20,durationMinutes:1440},{fails:10,durationMinutes:120},{fails:5,durationMinutes:30}],vn=class{static{m(this,"SkillHealthTracker")}healthRepo;logger;activityLogger;constructor(e,t,s){this.healthRepo=e,this.logger=t,this.activityLogger=s}isDisabled(e){try{return this.healthRepo.isDisabled(e)?this.healthRepo.getByName(e):void 0}catch{return}}recordSuccess(e){try{this.healthRepo.recordSuccess(e)}catch(t){this.logger.debug({err:t,skillName:e},"Failed to record skill success")}}recordFailure(e,t){try{let s=this.healthRepo.recordFailure(e,t);for(let r of Kf)if(s.consecutiveFails>=r.fails&&!s.disabledUntil){let n=new Date(Date.now()+r.durationMinutes*6e4).toISOString();this.healthRepo.disable(e,n),this.logger.warn({skillName:e,consecutiveFails:s.consecutiveFails,disabledUntil:n},"Skill auto-disabled due to repeated failures"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"disabled",details:{consecutiveFails:s.consecutiveFails,disabledUntil:n,lastError:t}});break}}catch(s){this.logger.debug({err:s,skillName:e},"Failed to record skill failure")}}forceEnable(e){try{this.healthRepo.enable(e),this.logger.info({skillName:e},"Skill force-enabled by user"),this.activityLogger?.logSkillHealth({skillName:e,outcome:"re-enabled",details:{reason:"force-enable"}})}catch(t){this.logger.warn({err:t,skillName:e},"Failed to force-enable skill")}}getDashboard(){try{return this.healthRepo.getAll()}catch{return[]}}checkReEnables(){try{let e=this.healthRepo.getAll(),t=new Date;for(let s of e)s.disabledUntil&&new Date(s.disabledUntil)<=t&&(this.healthRepo.enable(s.skillName),this.logger.info({skillName:s.skillName},"Skill auto-re-enabled after cooldown"),this.activityLogger?.logSkillHealth({skillName:s.skillName,outcome:"re-enabled",details:{reason:"cooldown-expired"}}))}catch(e){this.logger.warn({err:e},"Failed to check re-enables")}}}});function dc(l,e){let t=ht(e,l.field);if(t==null)return!1;let s=l.value;switch(l.operator){case"eq":return String(t)===String(s);case"neq":return String(t)!==String(s);case"gt":case"gte":case"lt":case"lte":{let r=Vu(t),n=Vu(s);return r===null||n===null?!1:l.operator==="gt"?r>n:l.operator==="gte"?r>=n:l.operator==="lt"?r<n:r<=n}case"contains":return String(t).toLowerCase().includes(String(s??"").toLowerCase());case"not_contains":return!String(t).toLowerCase().includes(String(s??"").toLowerCase());case"changed":return!0;case"increased":case"decreased":return!1;default:return!1}}function Vu(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}var uc=T(()=>{"use strict";fn();m(dc,"evaluateWorkflowCondition");m(Vu,"toNumber")});var $n,mc=T(()=>{"use strict";xo();uc();$n=class{static{m(this,"WorkflowRunner")}workflowRepo;skillRegistry;skillSandbox;logger;activityLogger;healthTracker;constructor(e,t,s,r,n,o){this.workflowRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.logger=r,this.activityLogger=n,this.healthTracker=o}async run(e,t,s){let r=this.workflowRepo.createExecution(e.id,e.steps.length),n=[],o=s??{},i=0,a=0,c=new Map,d=e.steps.length+2;for(;i<e.steps.length;){let u=(c.get(i)??0)+1;if(c.set(i,u),u>d){let $=`Workflow cycle detected at step ${i} (visited ${u} times)`;return this.finishExecution(r.id,"failed",a,n,$),this.logWorkflow(e,r.id,"failed",a,$),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let p=e.steps[i];if(a++,p.type==="condition"){let $=p,N={prev:o,steps:n.map(P=>P.data)};s&&(N.trigger=s);let M=dc($.condition,N),J=M?"then":"else",V=M?$.then:$.else;if(n.push({skillName:$.label??"__condition__",success:!0,data:{branch:J,field:$.condition.field,conditionMet:M,target:V}}),this.logger.debug({workflowId:e.id,step:i,branch:J,target:V,field:$.condition.field,conditionMet:M},"Workflow condition evaluated"),V==="end")return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n};if(typeof V=="number"){if(V<0||V>=e.steps.length){let P=`Condition step ${i}: jump target ${V} is out of range (0-${e.steps.length-1})`;return this.finishExecution(r.id,"failed",a,n,P),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:P}}i=V}else i++;this.workflowRepo.updateExecution(r.id,{stepsCompleted:a,stepResults:JSON.stringify(n)});continue}let h=p;if(this.healthTracker?.isDisabled(h.skillName)){let $=`Skill "${h.skillName}" is temporarily disabled`;if(h.onError==="skip"){n.push({skillName:h.skillName,success:!1,error:$}),i++;continue}let N=a>1?"partial":"failed";return this.finishExecution(r.id,N,a,n,$),{executionId:r.id,status:N,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let f=this.skillRegistry.get(h.skillName);if(!f){let $=`Skill "${h.skillName}" not found`;if(h.onError==="skip"){n.push({skillName:h.skillName,success:!1,error:$}),i++;continue}let N=a>1?"partial":"failed";return this.finishExecution(r.id,N,a,n,$),{executionId:r.id,status:N,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}let g={prev:o,steps:n.map($=>$.data)};s&&(g.trigger=s);let y=qt(h.inputMapping,g),_=h.onError==="retry"?(h.maxRetries??1)+1:1,S,b=!1;for(let $=0;$<_;$++)try{let N=await this.skillSandbox.execute(f,y,t);if(N.success){o=N.data,n.push({skillName:h.skillName,success:!0,data:N.data}),this.healthTracker?.recordSuccess(h.skillName),b=!0;break}else S=N.error??"Unknown error",this.healthTracker?.recordFailure(h.skillName,S)}catch(N){S=N instanceof Error?N.message:String(N),this.healthTracker?.recordFailure(h.skillName,S)}if(!b){if(n.push({skillName:h.skillName,success:!1,error:S}),h.onError==="skip"){i++;continue}let $=a>1?"partial":"failed";return this.finishExecution(r.id,$,a,n,S),this.logWorkflow(e,r.id,$,a,S),{executionId:r.id,status:$,stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:S}}if(this.workflowRepo.updateExecution(r.id,{stepsCompleted:a,stepResults:JSON.stringify(n)}),h.jumpTo==="end")return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n};if(typeof h.jumpTo=="number"){if(h.jumpTo<0||h.jumpTo>=e.steps.length){let $=`Action step ${i}: jumpTo ${h.jumpTo} is out of range`;return this.finishExecution(r.id,"failed",a,n,$),{executionId:r.id,status:"failed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n,error:$}}i=h.jumpTo}else i++}return this.finishExecution(r.id,"completed",a,n),this.logWorkflow(e,r.id,"completed",a),{executionId:r.id,status:"completed",stepsCompleted:a,totalSteps:e.steps.length,stepResults:n}}finishExecution(e,t,s,r,n){this.workflowRepo.updateExecution(e,{status:t,stepsCompleted:s,stepResults:JSON.stringify(r),error:n,completedAt:new Date().toISOString()})}logWorkflow(e,t,s,r,n){this.activityLogger?.logWorkflowExec({chainId:e.id,chainName:e.name,executionId:t,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:s==="completed"?"success":"error",error:n,details:{stepsCompleted:r,totalSteps:e.steps.length}})}}});import Yu from"node:crypto";var Vf,Yf,In,An,pc=T(()=>{"use strict";pt();Vf=[7,12,18],Yf=1536,In="---ACTIONS---",An=class{static{m(this,"ReasoningEngine")}calendarProvider;todoRepo;watchRepo;memoryRepo;activityRepo;skillHealthRepo;notifRepo;skillRegistry;skillSandbox;llm;adapters;userRepo;defaultChatId;defaultPlatform;logger;activityLogger;defaultLocation;feedbackRepo;confirmationQueue;tickTimer;lastRunHour=-1;enabled;schedule;tier;deduplicationHours;constructor(e,t,s,r,n,o,i,a,c,d,u,p,h,f,g,y,_,S,b,$){this.calendarProvider=e,this.todoRepo=t,this.watchRepo=s,this.memoryRepo=r,this.activityRepo=n,this.skillHealthRepo=o,this.notifRepo=i,this.skillRegistry=a,this.skillSandbox=c,this.llm=d,this.adapters=u,this.userRepo=p,this.defaultChatId=h,this.defaultPlatform=f,this.logger=y,this.activityLogger=_,this.defaultLocation=S,this.feedbackRepo=b,this.confirmationQueue=$,this.enabled=g?.enabled!==!1,this.schedule=g?.schedule??"morning_noon_evening",this.tier=g?.tier??"fast",this.deduplicationHours=g?.deduplicationHours??12}start(){if(!this.enabled){this.logger.info("Reasoning engine disabled");return}this.tickTimer=setInterval(()=>this.tick(),6e4),this.logger.info({schedule:this.schedule,tier:this.tier},"Reasoning engine started")}stop(){this.tickTimer&&(clearInterval(this.tickTimer),this.tickTimer=void 0)}shouldRun(){let e=new Date,t=e.getHours(),s=e.getMinutes();switch(this.schedule){case"morning_noon_evening":return!!(Vf.includes(t)&&s===0&&this.lastRunHour!==t);case"hourly":return s===0&&this.lastRunHour!==t;case"half_hourly":return(s<=1||s>=30&&s<=31)&&this.lastRunHour!==t*100+(s<2?0:30);default:return!1}}markRun(){let e=new Date;this.schedule==="half_hourly"?this.lastRunHour=e.getHours()*100+e.getMinutes():this.lastRunHour=e.getHours()}async tick(){if(this.shouldRun()){this.markRun();try{this.logger.info("Reasoning pass starting");let e=Date.now(),t=await this.collectContext(),s=this.buildPrompt(t),n=(await this.llm.complete({messages:[{role:"user",content:s}],maxTokens:Yf,tier:this.tier})).content.trim(),o=Date.now()-e;if(!n||n==="KEINE_INSIGHTS"||n.length<10){this.logger.info({durationMs:o},"Reasoning pass: no insights"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o});return}let i=this.parseReasoningResponse(n),a=i.insights.filter(c=>!this.wasRecentlySent(c));if(a.length===0&&i.actions.length===0){this.logger.info({durationMs:o,total:i.insights.length},"Reasoning pass: all deduplicated");return}if(a.length>0){let c=`\u{1F4A1} **Alfred Insights**
|
|
1236
1252
|
|
|
1237
1253
|
${a.join(`
|
|
1238
1254
|
|
|
1239
|
-
`)}`,d=this.adapters.get(this.defaultPlatform);if(d){await d.sendMessage(this.defaultChatId,c);for(let u of a)this.markSent(u);this.logger.info({durationMs:o,insights:a.length},"Reasoning pass: insights sent")}this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o})}catch(e){this.logger.error({err:e},"Reasoning pass failed"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"error",error:e instanceof Error?e.message:String(e)})}}}async collectContext(){let e=new Date,t=e.toLocaleString("de-AT",{weekday:"long",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit"}),[s,r,n]=await Promise.all([this.fetchCalendar(e),this.fetchSkillData("weather",{}),this.fetchSkillData("energy_price",{action:"current"})]),o=this.fetchTodos(),i=this.fetchWatches(),a=this.fetchMemories(),c=this.fetchActivity(),d=this.fetchSkillHealth();return{dateTime:t,events:s,todos:o,watches:i,memories:a,activity:c,weather:r,energy:n,skillHealth:d}}async fetchCalendar(e){if(!this.calendarProvider)return"(Kalender nicht konfiguriert)";try{let t=e,s=new Date(e.getTime()+1440*60*1e3),r=await this.calendarProvider.listEvents(t,s);return r.length===0?"Keine Termine in den n\xE4chsten 24h.":r.map(n=>{let o=n.start instanceof Date?n.start.toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}):String(n.start),i=n.location?` (${n.location})`:"";return`- ${o}: ${n.title??"Termin"}${i}`}).join(`
|
|
1255
|
+
`)}`,d=this.adapters.get(this.defaultPlatform);if(d){await d.sendMessage(this.defaultChatId,c);for(let u of a)this.markSent(u);this.logger.info({durationMs:o,insights:a.length},"Reasoning pass: insights sent")}}i.actions.length>0&&await this.processActions(i.actions),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:o})}catch(e){this.logger.error({err:e},"Reasoning pass failed"),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"error",error:e instanceof Error?e.message:String(e)})}}}async collectContext(){let e=new Date,t=e.toLocaleString("de-AT",{weekday:"long",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit"}),[s,r,n]=await Promise.all([this.fetchCalendar(e),this.fetchSkillData("weather",{action:"current",...this.defaultLocation?{location:this.defaultLocation}:{}}),this.fetchSkillData("energy_price",{action:"current"})]),o=this.fetchTodos(),i=this.fetchWatches(),a=this.fetchMemories(),c=this.fetchActivity(),d=this.fetchSkillHealth(),u=this.fetchFeedback();return{dateTime:t,events:s,todos:o,watches:i,memories:a,activity:c,weather:r,energy:n,skillHealth:d,feedback:u}}async fetchCalendar(e){if(!this.calendarProvider)return"(Kalender nicht konfiguriert)";try{let t=e,s=new Date(e.getTime()+1440*60*1e3),r=await this.calendarProvider.listEvents(t,s);return r.length===0?"Keine Termine in den n\xE4chsten 24h.":r.map(n=>{let o=n.start instanceof Date?n.start.toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}):String(n.start),i=n.location?` (${n.location})`:"";return`- ${o}: ${n.title??"Termin"}${i}`}).join(`
|
|
1240
1256
|
`)}catch(t){return this.logger.warn({err:t},"Reasoning: calendar fetch failed"),"(Kalender-Abfrage fehlgeschlagen)"}}async fetchSkillData(e,t){let s=this.skillRegistry.get(e);if(!s)return`(${e} nicht verf\xFCgbar)`;try{let{context:r}=$e(this.userRepo,{userId:this.defaultChatId,platform:this.defaultPlatform,chatId:this.defaultChatId,chatType:"dm"}),n=await this.skillSandbox.execute(s,t,r);return n.success?n.display??JSON.stringify(n.data):`(${e}: ${n.error})`}catch(r){return this.logger.warn({err:r,skillName:e},"Reasoning: skill fetch failed"),`(${e}-Abfrage fehlgeschlagen)`}}fetchTodos(){try{let e=this.todoRepo.getOverdue(),t=new Date(Date.now()+1440*60*1e3).toISOString(),s=this.todoRepo.getDueInWindow(t),r=this.todoRepo.list(this.defaultChatId),n=[];if(e.length>0){n.push(`\xDCberf\xE4llig (${e.length}):`);for(let o of e.slice(0,10))n.push(` - [${o.priority}] ${o.title} (f\xE4llig: ${o.dueDate})`)}if(s.length>0){n.push(`Bald f\xE4llig (${s.length}):`);for(let o of s.slice(0,10))n.push(` - [${o.priority}] ${o.title} (f\xE4llig: ${o.dueDate})`)}return r.length>0&&n.push(`Gesamt offene Todos: ${r.length}`),n.length>0?n.join(`
|
|
1241
1257
|
`):"Keine offenen Todos."}catch(e){return this.logger.warn({err:e},"Reasoning: todo fetch failed"),"(Todo-Abfrage fehlgeschlagen)"}}fetchWatches(){try{let e=this.watchRepo.getEnabled();return e.length===0?"Keine aktiven Watches.":e.map(t=>{let s=t.lastValue?(()=>{try{let n=JSON.parse(t.lastValue);return typeof n=="object"?JSON.stringify(n).slice(0,200):String(n)}catch{return t.lastValue.slice(0,200)}})():"noch kein Ergebnis",r=t.lastTriggeredAt?`letzter Alert: ${new Date(t.lastTriggeredAt).toLocaleString("de-AT")}`:"noch nie ausgel\xF6st";return`- "${t.name}" (${t.skillName}, alle ${t.intervalMinutes} Min) \u2192 ${r}
|
|
1242
1258
|
Letzter Wert: ${s}`}).join(`
|
|
1243
1259
|
`)}catch(e){return this.logger.warn({err:e},"Reasoning: watch fetch failed"),"(Watch-Abfrage fehlgeschlagen)"}}fetchMemories(){try{let e=this.memoryRepo.getRecentForPrompt(this.defaultChatId,30);return e.length===0?"Keine gespeicherten Erinnerungen.":e.map(t=>`- [${t.type}] ${t.key}: ${t.value}`).join(`
|
|
1244
1260
|
`)}catch(e){return this.logger.warn({err:e},"Reasoning: memory fetch failed"),"(Memory-Abfrage fehlgeschlagen)"}}fetchActivity(){try{let e=new Date(Date.now()-864e5).toISOString(),t=this.activityRepo.stats(e);return t.length===0?"Keine Aktivit\xE4t in den letzten 24h.":t.map(s=>`- ${s.eventType} (${s.outcome}): ${s.count}\xD7`).join(`
|
|
1245
1261
|
`)}catch(e){return this.logger.warn({err:e},"Reasoning: activity fetch failed"),"(Aktivit\xE4ts-Abfrage fehlgeschlagen)"}}fetchSkillHealth(){try{let e=this.skillHealthRepo.getDisabled();return e.length===0?"Alle Skills aktiv.":e.map(t=>`- ${t.skillName}: deaktiviert bis ${t.disabledUntil} (${t.consecutiveFails} Fehler: ${t.lastError??"?"})`).join(`
|
|
1246
|
-
`)}catch(e){return this.logger.warn({err:e},"Reasoning: skill health fetch failed"),"(Skill-Health-Abfrage fehlgeschlagen)"}}
|
|
1262
|
+
`)}catch(e){return this.logger.warn({err:e},"Reasoning: skill health fetch failed"),"(Skill-Health-Abfrage fehlgeschlagen)"}}fetchFeedback(){if(!this.feedbackRepo)return"";try{let e=this.feedbackRepo.getRecentEvents(this.defaultChatId,20);return e.length===0?"Kein Feedback zu Watches oder Korrekturen.":e.map(t=>`- [${t.feedbackType}] ${t.description} (${t.occurredAt.slice(0,10)})`).join(`
|
|
1263
|
+
`)}catch(e){return this.logger.warn({err:e},"Reasoning: feedback fetch failed"),""}}buildPrompt(e){return`Du bist Alfreds Denk-Modul. Deine Aufgabe: Analysiere ALLE folgenden Daten und finde Zusammenh\xE4nge, Konflikte, Optimierungen oder Handlungsempfehlungen f\xFCr den User.
|
|
1247
1264
|
|
|
1248
1265
|
REGELN:
|
|
1249
1266
|
- Nur ECHTE, nicht-offensichtliche Erkenntnisse melden
|
|
@@ -1289,70 +1306,83 @@ ${e.weather}
|
|
|
1289
1306
|
${e.energy}
|
|
1290
1307
|
|
|
1291
1308
|
=== Skill-Status ===
|
|
1292
|
-
${e.skillHealth}
|
|
1293
|
-
|
|
1294
|
-
`);if(i>0&&(n=i),n<0){let c=r.slice(0,t).match(/.*[.!?]\s/s);c&&(n=c[0].length)}n<0&&(n=t),s.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return s}}});import{Bot as Nf,InputFile as tc}from"grammy";function Du(l){if(l==="markdown")return"MarkdownV2";if(l==="html")return"HTML"}var $o,Mu=T(()=>{"use strict";ot();m(Du,"mapParseMode");$o=class extends ge{static{m(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new Nf(e)}async connect(){this.status="connecting",this.bot.on("message:text",e=>{this.emit("message",this.normalizeMessage(e.message,e.message.text))}),this.bot.on("message:photo",async e=>{let t=e.message,r=(t.caption??"")||"[Photo]",n=t.photo[t.photo.length-1],o=await this.downloadAttachment(n.file_id,"image","image/jpeg"),i=this.normalizeMessage(t,r);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:voice",async e=>{let t=e.message,s=await this.downloadAttachment(t.voice.file_id,"audio",t.voice.mime_type??"audio/ogg"),r=this.normalizeMessage(t,"[Voice message]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:audio",async e=>{let t=e.message,r=(t.caption??"")||`[Audio: ${t.audio.file_name??"audio"}]`,n=await this.downloadAttachment(t.audio.file_id,"audio",t.audio.mime_type??"audio/mpeg"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:video",async e=>{let t=e.message,r=(t.caption??"")||"[Video]",n=await this.downloadAttachment(t.video.file_id,"video",t.video.mime_type??"video/mp4"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,n=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,o=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),i=this.normalizeMessage(t,n);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:video_note",async e=>{let t=e.message,s=await this.downloadAttachment(t.video_note.file_id,"video","video/mp4"),r=this.normalizeMessage(t,"[Video note]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:sticker",e=>{let t=e.message,s=t.sticker.emoji??"\u{1F3F7}\uFE0F";this.emit("message",this.normalizeMessage(t,`[Sticker: ${s}]`))}),this.bot.on("callback_query:data",e=>{let t=e.callbackQuery,s=t.from,r=t.message?.chat?.id;if(!r)return;e.answerCallbackQuery().catch(()=>{});let n={id:String(t.id),platform:"telegram",chatId:String(r),chatType:t.message?.chat?.type==="private"?"dm":"group",userId:String(s.id),userName:s.username??String(s.id),displayName:[s.first_name,s.last_name].filter(Boolean).join(" "),text:t.data,timestamp:new Date,metadata:{callbackQuery:!0}};this.emit("message",n)}),this.bot.catch(e=>{this.emit("error",e.error)}),this.bot.start({onStart:m(()=>{this.status="connected",this.emit("connected")},"onStart")})}async disconnect(){await this.bot.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,4096),n="";for(let o=0;o<r.length;o++){let a=o===r.length-1&&s?.replyMarkup?.inlineKeyboard?{inline_keyboard:s.replyMarkup.inlineKeyboard.map(d=>d.map(u=>({text:u.text,callback_data:u.callbackData})))}:void 0,c=await this.bot.api.sendMessage(Number(e),r[o],{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:Du(s?.parseMode),message_thread_id:s?.threadId?Number(s.threadId):void 0,reply_markup:a});n=String(c.message_id)}return n}async editMessage(e,t,s,r){await this.bot.api.editMessageText(Number(e),Number(t),s,{parse_mode:Du(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 tc(t,"image.png"),{caption:s});return String(r.message_id)}async sendFile(e,t,s,r){let n=await this.bot.api.sendDocument(Number(e),new tc(t,s),{caption:r});return String(n.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new tc(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,threadId:e.message_thread_id?String(e.message_thread_id):void 0}}async downloadAttachment(e,t,s,r){try{let o=(await this.bot.api.getFile(e)).file_path;if(!o)return;let i=`https://api.telegram.org/file/bot${this.bot.token}/${o}`,a=await fetch(i);if(!a.ok)return;let c=Buffer.from(await a.arrayBuffer());return{type:t,mimeType:s,fileName:r??o.split("/").pop(),size:c.length,data:c}}catch(n){console.error("[telegram] Failed to download file",e,n instanceof Error?n.message:"Unknown error");return}}}});import{Client as Df,GatewayIntentBits as Io,Events as sc}from"discord.js";var Ao,Ou=T(()=>{"use strict";ot();Ao=class extends ge{static{m(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new Df({intents:[Io.Guilds,Io.GuildMessages,Io.MessageContent,Io.DirectMessages]}),this.client.on(sc.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,threadId:e.channel.isThread()?e.channelId: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(sc.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(sc.Error,e=>{this.emit("error",e)}),await this.client.login(this.token)}async disconnect(){this.client?.destroy(),this.client=null,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){if(!this.client)throw new Error("Client is not connected");let r=await this.client.channels.fetch(e);if(!r?.isTextBased()||!("send"in r))throw new Error(`Channel ${e} is not a text channel`);let n=this.splitText(t,2e3),o="";for(let i=0;i<n.length;i++)i===0&&s?.replyToMessageId?o=(await(await r.messages.fetch(s.replyToMessageId)).reply(n[i])).id:o=(await r.send(n[i])).id;return o}async editMessage(e,t,s,r){if(!this.client)throw new Error("Client is not connected");let n=await this.client.channels.fetch(e);if(!n?.isTextBased()||!("messages"in n))throw new Error(`Channel ${e} is not a text channel`);await(await n.messages.fetch(t)).edit(s)}async deleteMessage(e,t){if(!this.client)throw new Error("Client is not connected");let s=await this.client.channels.fetch(e);if(!s?.isTextBased()||!("messages"in s))throw new Error(`Channel ${e} is not a text channel`);await(await s.messages.fetch(t)).delete()}async sendPhoto(e,t,s){if(!this.client)return;let r=await this.client.channels.fetch(e);return!r?.isTextBased()||!("send"in r)?void 0:(await r.send({content:s,files:[{attachment:t,name:"image.png"}]})).id}async sendFile(e,t,s,r){if(!this.client)return;let n=await this.client.channels.fetch(e);return!n?.isTextBased()||!("send"in n)?void 0:(await n.send({content:r,files:[{attachment:t,name:s}]})).id}async sendVoice(e,t,s){return this.sendFile(e,t,"voice.ogg",s)}async downloadAttachments(e){let t=[],s=e.attachments;if(!s||s.size===0)return t;let r=25*1024*1024;for(let[,n]of s)try{if(n.size&&n.size>r)continue;let o=await fetch(n.url);if(!o.ok)continue;let i=await o.arrayBuffer(),a=Buffer.from(i),c=this.classifyContentType(n.contentType);t.push({type:c,url:n.url,mimeType:n.contentType??void 0,fileName:n.name??void 0,size:n.size??a.length,data:a})}catch(o){console.error("[discord] Failed to download attachment",n.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]"}}});import{homedir as Mf}from"node:os";import{join as Of}from"node:path";var Ro,Pu=T(()=>{"use strict";ot();Ro=class extends ge{static{m(this,"MatrixAdapter")}platform="matrix";client;homeserverUrl;accessToken;botUserId;storagePath;constructor(e,t,s,r){super(),this.homeserverUrl=e.replace(/\/+$/,""),this.accessToken=t,this.botUserId=s,this.storagePath=r??Of(Mf(),".alfred","matrix-storage")}async connect(){this.status="connecting";let{MatrixClient:e,SimpleFsStorageProvider:t,AutojoinRoomsMixin:s}=await import("matrix-bot-sdk"),r=new t(this.storagePath);this.client=new e(this.homeserverUrl,this.accessToken,r),s.setupOnClient(this.client),this.client.on("room.message",async(n,o)=>{if(o.sender===this.botUserId)return;let i=o.content?.msgtype;if(i)try{let a=await this.normalizeEvent(n,o,i);a&&this.emit("message",a)}catch(a){this.emit("error",a instanceof Error?a:new Error(String(a)))}}),await this.client.start(),this.status="connected",this.emit("connected")}async disconnect(){this.client.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,32e3),n="";for(let o of r)s?.parseMode==="html"?n=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:o.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:o}):n=await this.client.sendText(e,o);return n}async editMessage(e,t,s,r){let n=r?.parseMode==="html",o={msgtype:"m.text",body:"* "+(n?s.replace(/<[^>]*>/g,""):s),"m.new_content":{msgtype:"m.text",body:n?s.replace(/<[^>]*>/g,""):s,...n?{format:"org.matrix.custom.html",formatted_body:s}:{}},"m.relates_to":{rel_type:"m.replace",event_id:t}};await this.client.sendEvent(e,"m.room.message",o)}async deleteMessage(e,t){await this.client.redactEvent(e,t)}async sendPhoto(e,t,s){let r=await this.client.uploadContent(t,"image/png","image.png"),n={msgtype:"m.image",body:s??"image.png",url:r,info:{mimetype:"image/png",size:t.length}};return await this.client.sendEvent(e,"m.room.message",n)}async sendFile(e,t,s,r){let n=this.guessMimeType(s),o=await this.client.uploadContent(t,n,s),i={msgtype:"m.file",body:r??s,filename:s,url:o,info:{mimetype:n,size:t.length}};return await this.client.sendEvent(e,"m.room.message",i)}async normalizeEvent(e,t,s){let r;try{r=(await this.client.getUserProfile(t.sender))?.displayname??void 0}catch{}let n={id:t.event_id,platform:"matrix",chatId:e,chatType:"group",userId:t.sender,userName:t.sender.split(":")[0].slice(1),displayName:r,timestamp:new Date(t.origin_server_ts),replyToMessageId:t.content["m.relates_to"]?.["m.in_reply_to"]?.event_id};switch(s){case"m.text":return{...n,text:t.content.body};case"m.image":{let o=await this.downloadAttachment(t.content,"image");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Photo]",attachments:o?[o]:void 0}}case"m.audio":{let o=await this.downloadAttachment(t.content,"audio");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Voice message]",attachments:o?[o]:void 0}}case"m.video":{let o=await this.downloadAttachment(t.content,"video");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Video]",attachments:o?[o]:void 0}}case"m.file":{let o=await this.downloadAttachment(t.content,"document");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Document]",attachments:o?[o]:void 0}}default:return t.content.body?{...n,text:t.content.body}:void 0}}async downloadAttachment(e,t){let s=e.url;if(!s||!s.startsWith("mxc://"))return;let r=e.info??{},n=r.mimetype,o=r.size,i=e.filename??e.body??"file",a=s.slice(6),c=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${a}`,`${this.homeserverUrl}/_matrix/media/v3/download/${a}`];for(let d of c)try{let u=await fetch(d,{headers:{Authorization:`Bearer ${this.accessToken}`}});if(u.status===404)continue;if(!u.ok){console.error(`[matrix] Download failed (${u.status})`,s,d);continue}let p=await u.arrayBuffer(),h=Buffer.from(p);return{type:t,mimeType:n,fileName:i,size:o??h.length,data:h}}catch(u){console.error("[matrix] Download error",s,d,u);continue}console.error("[matrix] All download endpoints failed for",s)}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var xo,Uu=T(()=>{"use strict";ot();xo=class extends ge{static{m(this,"WhatsAppAdapter")}platform="whatsapp";socket;downloadMedia;dataPath;reconnectAttempts=0;reconnectTimer;constructor(e){super(),this.dataPath=e}async connect(){this.status="connecting";let{makeWASocket:e,useMultiFileAuthState:t,DisconnectReason:s,downloadMediaMessage:r}=await import("@whiskeysockets/baileys");this.downloadMedia=r;let{state:n,saveCreds:o}=await t(this.dataPath);this.socket=e({auth:n,printQRInTerminal:!0}),this.socket.ev.on("creds.update",o),this.socket.ev.on("connection.update",i=>{if(i.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),i.connection==="close"){let c=i.lastDisconnect?.error?.output?.statusCode!==s.loggedOut;if(this.status="disconnected",this.emit("disconnected"),c){let d=Math.min(1e3*Math.pow(2,this.reconnectAttempts),6e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>this.connect(),d)}}}),this.socket.ev.on("messages.upsert",({messages:i,type:a})=>{if(a==="notify")for(let c of i)c.message&&(c.key.fromMe||this.processMessage(c).catch(d=>{this.emit("error",d instanceof Error?d:new Error(String(d)))}))})}async disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.reconnectAttempts=0,this.socket?.end(void 0),this.socket=void 0,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,65e3),n="";for(let o=0;o<r.length;o++)n=(await this.socket.sendMessage(e,{text:r[o]},o===0&&s?.replyToMessageId?{quoted:{key:{remoteJid:e,id:s.replyToMessageId},message:{}}}:void 0))?.key?.id??"";return n}async editMessage(e,t,s,r){await this.socket.sendMessage(e,{text:s,edit:{remoteJid:e,id:t,fromMe:!0}})}async deleteMessage(e,t){await this.socket.sendMessage(e,{delete:{remoteJid:e,id:t,fromMe:!0}})}async sendPhoto(e,t,s){return(await this.socket.sendMessage(e,{image:t,caption:s}))?.key?.id}async sendFile(e,t,s,r){return(await this.socket.sendMessage(e,{document:t,fileName:s,caption:r,mimetype:this.guessMimeType(s)}))?.key?.id}async processMessage(e){let t=e.message,s=t.conversation??t.extendedTextMessage?.text??t.imageMessage?.caption??t.videoMessage?.caption??t.documentMessage?.caption??"",r=[],n=s;if(t.imageMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.imageMessage.mimetype??"image/jpeg";r.push({type:"image",mimeType:a,fileName:t.imageMessage.fileName??`image.${a.split("/")[1]??"jpeg"}`,size:t.imageMessage.fileLength??i.length,data:i})}n||(n="[Photo]")}else if(t.audioMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.audioMessage.mimetype??"audio/ogg";r.push({type:"audio",mimeType:a,fileName:t.audioMessage.fileName??`audio.${a.split("/")[1]??"ogg"}`,size:t.audioMessage.fileLength??i.length,data:i})}n||(n="[Voice message]")}else if(t.videoMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"video",mimeType:t.videoMessage.mimetype??"video/mp4",size:t.videoMessage.fileLength??i.length,data:i}),n||(n="[Video]")}else if(t.documentMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"document",mimeType:t.documentMessage.mimetype??"application/octet-stream",fileName:t.documentMessage.fileName??"document",size:t.documentMessage.fileLength??i.length,data:i}),n||(n="[Document]")}else if(t.stickerMessage&&!s)return;if(!n&&r.length===0)return;let o={id:e.key.id??"",platform:"whatsapp",chatId:e.key.remoteJid??"",chatType:e.key.remoteJid?.endsWith("@g.us")?"group":"dm",userId:e.key.participant??e.key.remoteJid??"",userName:e.pushName??e.key.participant??e.key.remoteJid??"",displayName:e.pushName??void 0,text:n,timestamp:new Date(e.messageTimestamp*1e3),replyToMessageId:t.extendedTextMessage?.contextInfo?.stanzaId??void 0,attachments:r.length>0?r:void 0};this.emit("message",o)}async downloadMediaSafe(e){try{if(!this.downloadMedia)return;let t=await this.downloadMedia(e,"buffer",{});return Buffer.isBuffer(t)?t:Buffer.from(t)}catch(t){console.error("[whatsapp] Failed to download media",t);return}}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Co,Fu=T(()=>{"use strict";ot();Co=class extends ge{static{m(this,"SignalAdapter")}apiUrl;phoneNumber;platform="signal";pollingInterval;consecutiveErrors=0;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.schedulePoll(),this.status="connected",this.emit("connected");return}catch(r){if(t=r instanceof Error?r:new Error(String(r)),s<e){let n=1e3*Math.pow(2,s);await new Promise(o=>setTimeout(o,n))}}this.status="error",this.emit("error",t)}schedulePoll(e=2e3){this.pollingInterval=setTimeout(async()=>{try{await this.pollMessages(),this.consecutiveErrors=0,this.schedulePoll(2e3)}catch(t){if(this.consecutiveErrors++,this.emit("error",t instanceof Error?t:new Error(String(t))),this.consecutiveErrors>=50){this.status="error",this.emit("error",new Error(`Signal polling stopped after ${this.consecutiveErrors} consecutive errors`));return}let s=Math.min(this.consecutiveErrors*2e3,6e4);this.schedulePoll(s)}},e)}async disconnect(){this.pollingInterval&&(clearTimeout(this.pollingInterval),this.pollingInterval=void 0),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,6e3),n="";for(let o of r){let i=e.startsWith("group."),a={message:o,number:this.phoneNumber};i?a.recipients=[e.replace("group.","")]:a.recipients=[e];let c=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!c.ok)throw new Error(`Signal send failed: ${c.status} ${await c.text()}`);let d=await c.json();n=String(d.timestamp??Date.now())}return n}async editMessage(e,t,s,r){throw new Error("Signal does not support message editing")}async deleteMessage(e,t){let s={number:this.phoneNumber,recipients:[e],timestamp:Number(t)},r=await fetch(`${this.apiUrl}/v1/deleteMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!r.ok)throw new Error(`Signal delete failed: ${r.status} ${await r.text()}`)}async pollMessages(){let e=await fetch(`${this.apiUrl}/v1/receive/${this.phoneNumber}`);if(!e.ok)return;let t=await e.json();for(let s of t){let r=s.envelope?.dataMessage;if(!r||!r.message&&(!r.attachments||r.attachments.length===0))continue;let n=s.envelope,o=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:n.sourceNumber??n.source??"",i=[];if(r.attachments)for(let d of r.attachments){let u=await this.downloadAttachment(d);u&&i.push(u)}let a=r.message||this.inferTextFromAttachments(i)||"";if(!a&&i.length===0)continue;let c={id:String(r.timestamp??Date.now()),platform:"signal",chatId:o,chatType:r.groupInfo?"group":"dm",userId:n.sourceNumber??n.source??"",userName:n.sourceName??n.sourceNumber??n.source??"",displayName:n.sourceName,text:a,timestamp:new Date(r.timestamp??Date.now()),attachments:i.length>0?i:void 0};this.emit("message",c)}}async downloadAttachment(e){if(e.id)try{let t=await fetch(`${this.apiUrl}/v1/attachments/${e.id}`);if(!t.ok)return;let s=await t.arrayBuffer(),r=Buffer.from(s);return{type:this.classifyContentType(e.contentType),mimeType:e.contentType??void 0,fileName:e.filename??void 0,size:e.size??r.length,data:r}}catch(t){console.error("[signal] Failed to download attachment",e.id,t);return}}classifyContentType(e){return e?e.startsWith("image/")?"image":e.startsWith("audio/")?"audio":e.startsWith("video/")?"video":"document":"other"}inferTextFromAttachments(e){if(e.length===0)return"";let t=e.map(s=>s.type);return t.includes("image")?"[Photo]":t.includes("audio")?"[Voice message]":t.includes("video")?"[Video]":t.includes("document")?"[Document]":"[File]"}}});import rc from"node:readline";var Lo,ju=T(()=>{"use strict";ot();Lo=class extends ge{static{m(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=rc.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
|
|
1309
|
+
${e.skillHealth}
|
|
1310
|
+
${e.feedback?`
|
|
1311
|
+
=== Nutzer-Feedback & Korrekturen ===
|
|
1312
|
+
${e.feedback}`:""}
|
|
1313
|
+
${this.confirmationQueue?`
|
|
1314
|
+
=== AKTIONEN ===
|
|
1315
|
+
Wenn du eine sinnvolle, sofort ausf\xFChrbare Aktion erkennst, kannst du sie vorschlagen.
|
|
1316
|
+
Regeln: Max 2 Aktionen, nur wenn JETZT sinnvoll (nicht hypothetisch).
|
|
1317
|
+
Aktionstypen: "execute_skill" (Skill ausf\xFChren) oder "create_reminder" (Erinnerung anlegen).
|
|
1318
|
+
Format: nach deinen Text-Insights, trenne mit "${In}", dann ein JSON-Array:
|
|
1319
|
+
${In}
|
|
1320
|
+
[{"type":"execute_skill","description":"Wallbox ein (Strom <5ct, BMW 45%)","skillName":"homeassistant","skillParams":{"action":"turn_on","entity_id":"switch.wallbox"}}]
|
|
1321
|
+
Wenn keine Aktionen sinnvoll: lass den ${In} Block weg.`:""}`}parseInsights(e){let t=e.split(/\n{2,}|\n(?=\d+\.\s)/).map(s=>s.trim()).filter(s=>s.length>10);return t.length<=1?[e.trim()]:t}insightHash(e){let t=e.slice(0,100).toLowerCase().replace(/\s+/g," ");return Yu.createHash("sha256").update(t).digest("hex").slice(0,16)}wasRecentlySent(e){let s=`reasoning:${this.insightHash(e)}`;return this.notifRepo.wasNotified(s,this.defaultChatId)}markSent(e){let s=`reasoning:${this.insightHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}parseReasoningResponse(e){let t=e.indexOf(In);if(t===-1)return{insights:this.parseInsights(e),actions:[]};let s=e.slice(0,t).trim(),r=e.slice(t+In.length).trim(),n=s?this.parseInsights(s):[],o=[];try{let i=JSON.parse(r);Array.isArray(i)&&(o=i.filter(a=>a&&typeof a=="object"&&typeof a.type=="string"&&typeof a.description=="string"&&typeof a.skillName=="string"&&typeof a.skillParams=="object"&&a.skillParams!==null))}catch{this.logger.warn("Reasoning: failed to parse actions JSON, ignoring")}return{insights:n,actions:o}}actionHash(e){let t=`${e.type}:${e.skillName}:${JSON.stringify(e.skillParams)}`.slice(0,150).toLowerCase().replace(/\s+/g," ");return Yu.createHash("sha256").update(t).digest("hex").slice(0,16)}actionWasRecentlyProposed(e){let t=this.actionHash(e);return this.notifRepo.wasNotified(`reasoning-action:${t}`,this.defaultChatId)}markActionProposed(e){let s=`reasoning-action:${this.actionHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}async processActions(e){if(!this.confirmationQueue||e.length===0)return;let t=e.slice(0,2);for(let s of t){if(this.actionWasRecentlyProposed(s)){this.logger.info({action:s.description},"Reasoning: action deduplicated, skipping");continue}try{await this.confirmationQueue.enqueue({chatId:this.defaultChatId,platform:this.defaultPlatform,source:"reasoning",sourceId:"reasoning-engine",description:s.description,skillName:s.skillName,skillParams:s.skillParams,timeoutMinutes:60}),this.markActionProposed(s),this.logger.info({action:s.description},"Reasoning: action enqueued for confirmation")}catch(r){this.logger.error({err:r,action:s.description},"Reasoning: failed to enqueue action")}}}}});import{EventEmitter as Jf}from"node:events";var ye,at=T(()=>{"use strict";ye=class extends Jf{static{m(this,"MessagingAdapter")}status="disconnected";async sendPhoto(e,t,s){}async sendFile(e,t,s,r){}async sendVoice(e,t,s){}endStream(e){}getStatus(){return this.status}splitText(e,t){if(e.length<=t)return[e];let s=[],r=e;for(;r.length>0;){if(r.length<=t){s.push(r);break}let n=-1,i=r.slice(0,t).lastIndexOf(`
|
|
1322
|
+
|
|
1323
|
+
`);if(i>0&&(n=i),n<0){let c=r.slice(0,t).match(/.*[.!?]\s/s);c&&(n=c[0].length)}n<0&&(n=t),s.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return s}}});import{Bot as Zf,InputFile as hc}from"grammy";function Ju(l){if(l==="markdown")return"MarkdownV2";if(l==="html")return"HTML"}var Lo,Zu=T(()=>{"use strict";at();m(Ju,"mapParseMode");Lo=class extends ye{static{m(this,"TelegramAdapter")}platform="telegram";bot;constructor(e){super(),this.bot=new Zf(e)}async connect(){this.status="connecting",this.bot.on("message:text",e=>{this.emit("message",this.normalizeMessage(e.message,e.message.text))}),this.bot.on("message:photo",async e=>{let t=e.message,r=(t.caption??"")||"[Photo]",n=t.photo[t.photo.length-1],o=await this.downloadAttachment(n.file_id,"image","image/jpeg"),i=this.normalizeMessage(t,r);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:voice",async e=>{let t=e.message,s=await this.downloadAttachment(t.voice.file_id,"audio",t.voice.mime_type??"audio/ogg"),r=this.normalizeMessage(t,"[Voice message]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:audio",async e=>{let t=e.message,r=(t.caption??"")||`[Audio: ${t.audio.file_name??"audio"}]`,n=await this.downloadAttachment(t.audio.file_id,"audio",t.audio.mime_type??"audio/mpeg"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:video",async e=>{let t=e.message,r=(t.caption??"")||"[Video]",n=await this.downloadAttachment(t.video.file_id,"video",t.video.mime_type??"video/mp4"),o=this.normalizeMessage(t,r);o.attachments=n?[n]:void 0,this.emit("message",o)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,n=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,o=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),i=this.normalizeMessage(t,n);i.attachments=o?[o]:void 0,this.emit("message",i)}),this.bot.on("message:video_note",async e=>{let t=e.message,s=await this.downloadAttachment(t.video_note.file_id,"video","video/mp4"),r=this.normalizeMessage(t,"[Video note]");r.attachments=s?[s]:void 0,this.emit("message",r)}),this.bot.on("message:sticker",e=>{let t=e.message,s=t.sticker.emoji??"\u{1F3F7}\uFE0F";this.emit("message",this.normalizeMessage(t,`[Sticker: ${s}]`))}),this.bot.on("callback_query:data",e=>{let t=e.callbackQuery,s=t.from,r=t.message?.chat?.id;if(!r)return;e.answerCallbackQuery().catch(()=>{});let n={id:String(t.id),platform:"telegram",chatId:String(r),chatType:t.message?.chat?.type==="private"?"dm":"group",userId:String(s.id),userName:s.username??String(s.id),displayName:[s.first_name,s.last_name].filter(Boolean).join(" "),text:t.data,timestamp:new Date,metadata:{callbackQuery:!0}};this.emit("message",n)}),this.bot.catch(e=>{this.emit("error",e.error)}),this.bot.start({onStart:m(()=>{this.status="connected",this.emit("connected")},"onStart")})}async disconnect(){await this.bot.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,4096),n="";for(let o=0;o<r.length;o++){let a=o===r.length-1&&s?.replyMarkup?.inlineKeyboard?{inline_keyboard:s.replyMarkup.inlineKeyboard.map(d=>d.map(u=>({text:u.text,callback_data:u.callbackData})))}:void 0,c=await this.bot.api.sendMessage(Number(e),r[o],{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:Ju(s?.parseMode),message_thread_id:s?.threadId?Number(s.threadId):void 0,reply_markup:a});n=String(c.message_id)}return n}async editMessage(e,t,s,r){await this.bot.api.editMessageText(Number(e),Number(t),s,{parse_mode:Ju(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 hc(t,"image.png"),{caption:s});return String(r.message_id)}async sendFile(e,t,s,r){let n=await this.bot.api.sendDocument(Number(e),new hc(t,s),{caption:r});return String(n.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new hc(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,threadId:e.message_thread_id?String(e.message_thread_id):void 0}}async downloadAttachment(e,t,s,r){try{let o=(await this.bot.api.getFile(e)).file_path;if(!o)return;let i=`https://api.telegram.org/file/bot${this.bot.token}/${o}`,a=await fetch(i);if(!a.ok)return;let c=Buffer.from(await a.arrayBuffer());return{type:t,mimeType:s,fileName:r??o.split("/").pop(),size:c.length,data:c}}catch(n){console.error("[telegram] Failed to download file",e,n instanceof Error?n.message:"Unknown error");return}}}});import{Client as Qf,GatewayIntentBits as Do,Events as fc}from"discord.js";var Mo,Qu=T(()=>{"use strict";at();Mo=class extends ye{static{m(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new Qf({intents:[Do.Guilds,Do.GuildMessages,Do.MessageContent,Do.DirectMessages]}),this.client.on(fc.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,threadId:e.channel.isThread()?e.channelId: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(fc.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(fc.Error,e=>{this.emit("error",e)}),await this.client.login(this.token)}async disconnect(){this.client?.destroy(),this.client=null,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){if(!this.client)throw new Error("Client is not connected");let r=await this.client.channels.fetch(e);if(!r?.isTextBased()||!("send"in r))throw new Error(`Channel ${e} is not a text channel`);let n=this.splitText(t,2e3),o="";for(let i=0;i<n.length;i++)i===0&&s?.replyToMessageId?o=(await(await r.messages.fetch(s.replyToMessageId)).reply(n[i])).id:o=(await r.send(n[i])).id;return o}async editMessage(e,t,s,r){if(!this.client)throw new Error("Client is not connected");let n=await this.client.channels.fetch(e);if(!n?.isTextBased()||!("messages"in n))throw new Error(`Channel ${e} is not a text channel`);await(await n.messages.fetch(t)).edit(s)}async deleteMessage(e,t){if(!this.client)throw new Error("Client is not connected");let s=await this.client.channels.fetch(e);if(!s?.isTextBased()||!("messages"in s))throw new Error(`Channel ${e} is not a text channel`);await(await s.messages.fetch(t)).delete()}async sendPhoto(e,t,s){if(!this.client)return;let r=await this.client.channels.fetch(e);return!r?.isTextBased()||!("send"in r)?void 0:(await r.send({content:s,files:[{attachment:t,name:"image.png"}]})).id}async sendFile(e,t,s,r){if(!this.client)return;let n=await this.client.channels.fetch(e);return!n?.isTextBased()||!("send"in n)?void 0:(await n.send({content:r,files:[{attachment:t,name:s}]})).id}async sendVoice(e,t,s){return this.sendFile(e,t,"voice.ogg",s)}async downloadAttachments(e){let t=[],s=e.attachments;if(!s||s.size===0)return t;let r=25*1024*1024;for(let[,n]of s)try{if(n.size&&n.size>r)continue;let o=await fetch(n.url);if(!o.ok)continue;let i=await o.arrayBuffer(),a=Buffer.from(i),c=this.classifyContentType(n.contentType);t.push({type:c,url:n.url,mimeType:n.contentType??void 0,fileName:n.name??void 0,size:n.size??a.length,data:a})}catch(o){console.error("[discord] Failed to download attachment",n.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]"}}});import{homedir as eg}from"node:os";import{join as tg}from"node:path";var Oo,em=T(()=>{"use strict";at();Oo=class extends ye{static{m(this,"MatrixAdapter")}platform="matrix";client;homeserverUrl;accessToken;botUserId;storagePath;constructor(e,t,s,r){super(),this.homeserverUrl=e.replace(/\/+$/,""),this.accessToken=t,this.botUserId=s,this.storagePath=r??tg(eg(),".alfred","matrix-storage")}async connect(){this.status="connecting";let{MatrixClient:e,SimpleFsStorageProvider:t,AutojoinRoomsMixin:s}=await import("matrix-bot-sdk"),r=new t(this.storagePath);this.client=new e(this.homeserverUrl,this.accessToken,r),s.setupOnClient(this.client),this.client.on("room.message",async(n,o)=>{if(o.sender===this.botUserId)return;let i=o.content?.msgtype;if(i)try{let a=await this.normalizeEvent(n,o,i);a&&this.emit("message",a)}catch(a){this.emit("error",a instanceof Error?a:new Error(String(a)))}}),await this.client.start(),this.status="connected",this.emit("connected")}async disconnect(){this.client.stop(),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,32e3),n="";for(let o of r)s?.parseMode==="html"?n=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:o.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:o}):n=await this.client.sendText(e,o);return n}async editMessage(e,t,s,r){let n=r?.parseMode==="html",o={msgtype:"m.text",body:"* "+(n?s.replace(/<[^>]*>/g,""):s),"m.new_content":{msgtype:"m.text",body:n?s.replace(/<[^>]*>/g,""):s,...n?{format:"org.matrix.custom.html",formatted_body:s}:{}},"m.relates_to":{rel_type:"m.replace",event_id:t}};await this.client.sendEvent(e,"m.room.message",o)}async deleteMessage(e,t){await this.client.redactEvent(e,t)}async sendPhoto(e,t,s){let r=await this.client.uploadContent(t,"image/png","image.png"),n={msgtype:"m.image",body:s??"image.png",url:r,info:{mimetype:"image/png",size:t.length}};return await this.client.sendEvent(e,"m.room.message",n)}async sendFile(e,t,s,r){let n=this.guessMimeType(s),o=await this.client.uploadContent(t,n,s),i={msgtype:"m.file",body:r??s,filename:s,url:o,info:{mimetype:n,size:t.length}};return await this.client.sendEvent(e,"m.room.message",i)}async normalizeEvent(e,t,s){let r;try{r=(await this.client.getUserProfile(t.sender))?.displayname??void 0}catch{}let n={id:t.event_id,platform:"matrix",chatId:e,chatType:"group",userId:t.sender,userName:t.sender.split(":")[0].slice(1),displayName:r,timestamp:new Date(t.origin_server_ts),replyToMessageId:t.content["m.relates_to"]?.["m.in_reply_to"]?.event_id};switch(s){case"m.text":return{...n,text:t.content.body};case"m.image":{let o=await this.downloadAttachment(t.content,"image");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Photo]",attachments:o?[o]:void 0}}case"m.audio":{let o=await this.downloadAttachment(t.content,"audio");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Voice message]",attachments:o?[o]:void 0}}case"m.video":{let o=await this.downloadAttachment(t.content,"video");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Video]",attachments:o?[o]:void 0}}case"m.file":{let o=await this.downloadAttachment(t.content,"document");return o&&t.content.body&&(o.fileName=t.content.body),{...n,text:"[Document]",attachments:o?[o]:void 0}}default:return t.content.body?{...n,text:t.content.body}:void 0}}async downloadAttachment(e,t){let s=e.url;if(!s||!s.startsWith("mxc://"))return;let r=e.info??{},n=r.mimetype,o=r.size,i=e.filename??e.body??"file",a=s.slice(6),c=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${a}`,`${this.homeserverUrl}/_matrix/media/v3/download/${a}`];for(let d of c)try{let u=await fetch(d,{headers:{Authorization:`Bearer ${this.accessToken}`}});if(u.status===404)continue;if(!u.ok){console.error(`[matrix] Download failed (${u.status})`,s,d);continue}let p=await u.arrayBuffer(),h=Buffer.from(p);return{type:t,mimeType:n,fileName:i,size:o??h.length,data:h}}catch(u){console.error("[matrix] Download error",s,d,u);continue}console.error("[matrix] All download endpoints failed for",s)}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Po,tm=T(()=>{"use strict";at();Po=class extends ye{static{m(this,"WhatsAppAdapter")}platform="whatsapp";socket;downloadMedia;dataPath;reconnectAttempts=0;reconnectTimer;constructor(e){super(),this.dataPath=e}async connect(){this.status="connecting";let{makeWASocket:e,useMultiFileAuthState:t,DisconnectReason:s,downloadMediaMessage:r}=await import("@whiskeysockets/baileys");this.downloadMedia=r;let{state:n,saveCreds:o}=await t(this.dataPath);this.socket=e({auth:n,printQRInTerminal:!0}),this.socket.ev.on("creds.update",o),this.socket.ev.on("connection.update",i=>{if(i.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),i.connection==="close"){let c=i.lastDisconnect?.error?.output?.statusCode!==s.loggedOut;if(this.status="disconnected",this.emit("disconnected"),c){let d=Math.min(1e3*Math.pow(2,this.reconnectAttempts),6e4);this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>this.connect(),d)}}}),this.socket.ev.on("messages.upsert",({messages:i,type:a})=>{if(a==="notify")for(let c of i)c.message&&(c.key.fromMe||this.processMessage(c).catch(d=>{this.emit("error",d instanceof Error?d:new Error(String(d)))}))})}async disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.reconnectAttempts=0,this.socket?.end(void 0),this.socket=void 0,this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,65e3),n="";for(let o=0;o<r.length;o++)n=(await this.socket.sendMessage(e,{text:r[o]},o===0&&s?.replyToMessageId?{quoted:{key:{remoteJid:e,id:s.replyToMessageId},message:{}}}:void 0))?.key?.id??"";return n}async editMessage(e,t,s,r){await this.socket.sendMessage(e,{text:s,edit:{remoteJid:e,id:t,fromMe:!0}})}async deleteMessage(e,t){await this.socket.sendMessage(e,{delete:{remoteJid:e,id:t,fromMe:!0}})}async sendPhoto(e,t,s){return(await this.socket.sendMessage(e,{image:t,caption:s}))?.key?.id}async sendFile(e,t,s,r){return(await this.socket.sendMessage(e,{document:t,fileName:s,caption:r,mimetype:this.guessMimeType(s)}))?.key?.id}async processMessage(e){let t=e.message,s=t.conversation??t.extendedTextMessage?.text??t.imageMessage?.caption??t.videoMessage?.caption??t.documentMessage?.caption??"",r=[],n=s;if(t.imageMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.imageMessage.mimetype??"image/jpeg";r.push({type:"image",mimeType:a,fileName:t.imageMessage.fileName??`image.${a.split("/")[1]??"jpeg"}`,size:t.imageMessage.fileLength??i.length,data:i})}n||(n="[Photo]")}else if(t.audioMessage){let i=await this.downloadMediaSafe(e);if(i){let a=t.audioMessage.mimetype??"audio/ogg";r.push({type:"audio",mimeType:a,fileName:t.audioMessage.fileName??`audio.${a.split("/")[1]??"ogg"}`,size:t.audioMessage.fileLength??i.length,data:i})}n||(n="[Voice message]")}else if(t.videoMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"video",mimeType:t.videoMessage.mimetype??"video/mp4",size:t.videoMessage.fileLength??i.length,data:i}),n||(n="[Video]")}else if(t.documentMessage){let i=await this.downloadMediaSafe(e);i&&r.push({type:"document",mimeType:t.documentMessage.mimetype??"application/octet-stream",fileName:t.documentMessage.fileName??"document",size:t.documentMessage.fileLength??i.length,data:i}),n||(n="[Document]")}else if(t.stickerMessage&&!s)return;if(!n&&r.length===0)return;let o={id:e.key.id??"",platform:"whatsapp",chatId:e.key.remoteJid??"",chatType:e.key.remoteJid?.endsWith("@g.us")?"group":"dm",userId:e.key.participant??e.key.remoteJid??"",userName:e.pushName??e.key.participant??e.key.remoteJid??"",displayName:e.pushName??void 0,text:n,timestamp:new Date(e.messageTimestamp*1e3),replyToMessageId:t.extendedTextMessage?.contextInfo?.stanzaId??void 0,attachments:r.length>0?r:void 0};this.emit("message",o)}async downloadMediaSafe(e){try{if(!this.downloadMedia)return;let t=await this.downloadMedia(e,"buffer",{});return Buffer.isBuffer(t)?t:Buffer.from(t)}catch(t){console.error("[whatsapp] Failed to download media",t);return}}guessMimeType(e){let t=e.split(".").pop()?.toLowerCase();return{pdf:"application/pdf",txt:"text/plain",json:"application/json",csv:"text/csv",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",mp3:"audio/mpeg",ogg:"audio/ogg",mp4:"video/mp4",zip:"application/zip",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t??""]??"application/octet-stream"}}});var Uo,sm=T(()=>{"use strict";at();Uo=class extends ye{static{m(this,"SignalAdapter")}apiUrl;phoneNumber;platform="signal";pollingInterval;consecutiveErrors=0;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.schedulePoll(),this.status="connected",this.emit("connected");return}catch(r){if(t=r instanceof Error?r:new Error(String(r)),s<e){let n=1e3*Math.pow(2,s);await new Promise(o=>setTimeout(o,n))}}this.status="error",this.emit("error",t)}schedulePoll(e=2e3){this.pollingInterval=setTimeout(async()=>{try{await this.pollMessages(),this.consecutiveErrors=0,this.schedulePoll(2e3)}catch(t){if(this.consecutiveErrors++,this.emit("error",t instanceof Error?t:new Error(String(t))),this.consecutiveErrors>=50){this.status="error",this.emit("error",new Error(`Signal polling stopped after ${this.consecutiveErrors} consecutive errors`));return}let s=Math.min(this.consecutiveErrors*2e3,6e4);this.schedulePoll(s)}},e)}async disconnect(){this.pollingInterval&&(clearTimeout(this.pollingInterval),this.pollingInterval=void 0),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=this.splitText(t,6e3),n="";for(let o of r){let i=e.startsWith("group."),a={message:o,number:this.phoneNumber};i?a.recipients=[e.replace("group.","")]:a.recipients=[e];let c=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!c.ok)throw new Error(`Signal send failed: ${c.status} ${await c.text()}`);let d=await c.json();n=String(d.timestamp??Date.now())}return n}async editMessage(e,t,s,r){throw new Error("Signal does not support message editing")}async deleteMessage(e,t){let s={number:this.phoneNumber,recipients:[e],timestamp:Number(t)},r=await fetch(`${this.apiUrl}/v1/deleteMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!r.ok)throw new Error(`Signal delete failed: ${r.status} ${await r.text()}`)}async pollMessages(){let e=await fetch(`${this.apiUrl}/v1/receive/${this.phoneNumber}`);if(!e.ok)return;let t=await e.json();for(let s of t){let r=s.envelope?.dataMessage;if(!r||!r.message&&(!r.attachments||r.attachments.length===0))continue;let n=s.envelope,o=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:n.sourceNumber??n.source??"",i=[];if(r.attachments)for(let d of r.attachments){let u=await this.downloadAttachment(d);u&&i.push(u)}let a=r.message||this.inferTextFromAttachments(i)||"";if(!a&&i.length===0)continue;let c={id:String(r.timestamp??Date.now()),platform:"signal",chatId:o,chatType:r.groupInfo?"group":"dm",userId:n.sourceNumber??n.source??"",userName:n.sourceName??n.sourceNumber??n.source??"",displayName:n.sourceName,text:a,timestamp:new Date(r.timestamp??Date.now()),attachments:i.length>0?i:void 0};this.emit("message",c)}}async downloadAttachment(e){if(e.id)try{let t=await fetch(`${this.apiUrl}/v1/attachments/${e.id}`);if(!t.ok)return;let s=await t.arrayBuffer(),r=Buffer.from(s);return{type:this.classifyContentType(e.contentType),mimeType:e.contentType??void 0,fileName:e.filename??void 0,size:e.size??r.length,data:r}}catch(t){console.error("[signal] Failed to download attachment",e.id,t);return}}classifyContentType(e){return e?e.startsWith("image/")?"image":e.startsWith("audio/")?"audio":e.startsWith("video/")?"video":"document":"other"}inferTextFromAttachments(e){if(e.length===0)return"";let t=e.map(s=>s.type);return t.includes("image")?"[Photo]":t.includes("audio")?"[Voice message]":t.includes("video")?"[Video]":t.includes("document")?"[Document]":"[File]"}}});import gc from"node:readline";var Fo,rm=T(()=>{"use strict";at();Fo=class extends ye{static{m(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=gc.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
|
|
1295
1324
|
Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leave.
|
|
1296
1325
|
`),this.rl.on("line",e=>{let t=e.trim();if(!t){this.prompt();return}if(t==="/quit"||t==="/exit"){console.log(`
|
|
1297
1326
|
Goodbye!
|
|
1298
1327
|
`),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(`
|
|
1299
1328
|
Alfred: ${t}
|
|
1300
|
-
`),this.prompt(),r}async editMessage(e,t,s,r){
|
|
1329
|
+
`),this.prompt(),r}async editMessage(e,t,s,r){gc.clearLine(process.stdout,0),gc.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import sg from"node:http";import Os from"node:fs";import Ps from"node:path";import jo from"node:crypto";var rg,nm,Bo,om=T(()=>{"use strict";at();rg={".html":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"application/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".txt":"text/plain; charset=utf-8"},nm=1048576,Bo=class extends ye{static{m(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;dashboardFn;webUiPath;webhooks=new Map;constructor(e,t,s){if(super(),this.port=e,this.host=t,this.apiToken=s?.apiToken,this.corsOrigin=s?.corsOrigin??"http://localhost:3420",this.healthCheckFn=s?.healthCheck,this.metricsFn=s?.metricsCallback,this.dashboardFn=s?.dashboardCallback,this.webUiPath=s?.webUiPath,s?.webhooks)for(let r of s.webhooks)this.webhooks.set(r.name,r)}addWebhook(e){this.webhooks.set(e.name,e)}async connect(){this.status="connecting",this.server=sg.createServer((e,t)=>{this.handleRequest(e,t)}),await new Promise((e,t)=>{this.server.listen(this.port,this.host,()=>{e()}),this.server.once("error",t)}),this.status="connected",this.emit("connected")}async disconnect(){for(let[e,t]of this.streams)this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e);this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),r}async editMessage(e,t,s,r){let n=this.streams.get(e);n&&this.writeSseEvent(n,"status",{type:"status",text:s})}async deleteMessage(e,t){}async sendPhoto(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,r){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:r}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"voice",data:t.toString("base64"),caption:s}),`api-voice-${++this.messageCounter}`}endStream(e){let t=this.streams.get(e);t&&(this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e))}handleRequest(e,t){if(t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Access-Control-Allow-Origin",this.corsOrigin),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.method==="OPTIONS"){t.writeHead(204),t.end();return}let s=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`);if(s.pathname==="/api/health"&&e.method==="GET")this.handleHealth(t);else if(s.pathname==="/api/metrics"&&e.method==="GET")this.handleMetrics(t);else if(s.pathname==="/api/message"&&e.method==="POST")this.handleMessage(e,t);else if(s.pathname==="/api/dashboard"&&e.method==="GET")this.handleDashboard(e,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let r=s.pathname.slice(13);this.handleWebhook(e,t,r)}else this.webUiPath&&s.pathname.startsWith("/alfred/")&&e.method==="GET"?this.serveStaticFile(s.pathname,t):this.webUiPath&&s.pathname==="/alfred"&&e.method==="GET"?(t.writeHead(302,{Location:"/alfred/"}),t.end()):(t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"})))}checkAuth(e,t){if(!this.apiToken)return!0;let s=e.headers.authorization,r=`Bearer ${this.apiToken}`;return!s||s.length!==r.length||!jo.timingSafeEqual(Buffer.from(s),Buffer.from(r))?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleDashboard(e,t){if(this.checkAuth(e,t)){if(!this.dashboardFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard not configured"}));return}try{let s=this.dashboardFn();t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}catch{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard data fetch failed"}))}}}serveStaticFile(e,t){if(!this.webUiPath){t.writeHead(404),t.end();return}let s=e.replace(/^\/alfred/,"");(!s||s==="/")&&(s="/index.html");let r=Ps.resolve(this.webUiPath,"."+s);if(!r.startsWith(Ps.resolve(this.webUiPath))){t.writeHead(403),t.end();return}let n=r;if(!Os.existsSync(n))if(Os.existsSync(n+".html"))n=n+".html";else if(Os.existsSync(Ps.join(n,"index.html")))n=Ps.join(n,"index.html");else{t.writeHead(404,{"Content-Type":"text/html"}),t.end("Not found");return}let o=Os.statSync(n);if(o.isDirectory()){let d=Ps.join(n,"index.html");if(Os.existsSync(d))n=d;else{t.writeHead(404),t.end();return}}let i=Ps.extname(n).toLowerCase(),a=rg[i]??"application/octet-stream",c=i===".html"?"no-cache":"public, max-age=31536000, immutable";t.writeHead(200,{"Content-Type":a,"Content-Length":o.size,"Cache-Control":c}),Os.createReadStream(n).pipe(t)}handleHealth(e){let t=this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",r=s==="ok"?200:503;e.writeHead(r,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(this.metricsFn())):this.handleHealth(e)}handleMessage(e,t){if(!this.checkAuth(e,t))return;let s="",r=0,n=!1;e.on("data",o=>{if(!n){if(r+=o.length,r>nm){n=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}s+=o.toString()}}),e.on("end",()=>{if(!n)try{let o=JSON.parse(s),i=o.text;if(!i||typeof i!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:'Missing or invalid "text" field'}));return}let a=o.chatId??`api-chat-${jo.randomUUID()}`,c=o.userId??"api-user",d=this.streams.get(a);d&&(this.writeSseEvent(d,"done",{type:"done"}),d.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this.streams.set(a,t),e.on("close",()=>{this.streams.delete(a)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:a,chatType:"dm",userId:c,userName:c,displayName:"API User",text:i,timestamp:new Date};this.emit("message",u)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON body"}))}})}handleWebhook(e,t,s){let r=this.webhooks.get(s);if(!r){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`Webhook "${s}" not found`}));return}let n="",o=0,i=!1;e.on("data",a=>{if(!i){if(o+=a.length,o>nm){i=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}n+=a.toString()}}),e.on("end",async()=>{if(i)return;let a=e.headers["x-webhook-signature"];if(!a){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing X-Webhook-Signature header"}));return}let c=jo.createHmac("sha256",r.secret).update(n).digest(),d=Buffer.from(a,"hex");if(d.length!==c.length||!jo.timingSafeEqual(d,c)){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid signature"}));return}try{let u=JSON.parse(n);await r.callback(u),t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({ok:!0}))}catch(u){t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:u instanceof Error?u.message:"Internal error"}))}})}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
|
|
1301
1330
|
data: ${JSON.stringify(s)}
|
|
1302
1331
|
|
|
1303
|
-
`)}}});var pt={};he(pt,{CLIAdapter:()=>Lo,DiscordAdapter:()=>Ao,HttpAdapter:()=>Do,MatrixAdapter:()=>Ro,MessagingAdapter:()=>ge,SignalAdapter:()=>Co,TelegramAdapter:()=>$o,WhatsAppAdapter:()=>xo});var ht=T(()=>{"use strict";ot();Mu();Ou();Pu();Uu();Fu();ju();Hu()});import kn from"node:fs";import Mo from"node:path";import Uf from"js-yaml";var zt,Wu=T(()=>{"use strict";bi();Ii();tt();ji();qn();se();Ia();Ra();xa();Ca();La();Na();Da();Ma();Oa();Pa();Ua();Fa();ja();Nu();Ha();Ga();Xa();Ka();Va();Ya();Ja();Za();Qa();ec();zt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new sn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=tr("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new At(this.config.storage.path);let e=this.database.getDb(),t=new rr(e),s=new nr(e);this.userRepo=s;let r=new Rt(e);this.auditRepo=r;let n=new or(e);this.memoryRepo=n;let o=new ir(e),i=new ar(e),a=new cr(e),c=new lr(e),d=new dr(e),u=new ur(e);this.scheduledActionRepo=u;let p=new Ct(e);this.activityRepo=p;let h=new yn(p,this.logger.child({component:"activity"})),g=new wr(e),f=new wn(g,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=f,this.logger.info("Storage initialized");let y=new Rr,k=this.loadSecurityRules();y.loadRules(k);let S=new xr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:k.length},"Security engine initialized");let b=Ui(this.config.llm,this.logger.child({component:"llm"}));await b.initialize(),this.llmProvider=b;let C=new yr(e);this.usageRepo=C,b.setPersist((v,M,V,Y,ye,me)=>{C.record(v,M,V,Y,ye,me)});let D=new rn(b,a,this.logger.child({component:"embeddings"})),P=this.config.activeLearning?.enabled!==!1,Q,ae;P&&(Q=new mn({llm:b,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:D,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),ae=new pn(n,this.logger.child({component:"memory-retriever"}),D),this.logger.info("Active learning & memory retriever initialized"));let j=new gr(e);this.summaryRepo=j;let z=new hn(b,j,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let re=new Qt(this.logger.child({component:"sandbox"})),N=this.skillRegistry=new Zt;N.register(new es),N.register(new ts),N.register(new ss(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),N.register(new rs(o)),N.register(new ns(i));let ie=new pr(e);if(N.register(new Es(ie)),N.register(new os),N.register(new is),N.register(new as(n,D)),N.register(new cs(b,N,re,S)),this.config.email?.accounts?.length){let v=new Map;for(let V of this.config.email.accounts)try{V.provider==="microsoft"&&!V.microsoft?.clientId&&this.config.calendar?.microsoft&&(V.microsoft={...this.config.calendar.microsoft});let Y=await Cr(V);v.set(V.name,Y),this.logger.info({account:V.name,provider:V.provider??"imap-smtp"},"Email account initialized")}catch(Y){this.logger.warn({err:Y,account:V.name},"Email account initialization failed, skipping")}let M=v.size>0?new dt(v):new dt;M.setLLM(b),N.register(M)}else{let v=new dt;v.setLLM(b),N.register(v)}N.register(new ls),N.register(new ds);let ce=new $s;ce.setReloadCallback(v=>this.reloadService(v)),N.register(ce),N.register(new ms),N.register(new ps),N.register(new hs),N.register(new fs(s)),N.register(new gs(s,c,this.adapters,(v,M)=>t.findByPlatformAndUser(v,M)));let J=new ys(d);N.register(J),N.register(new ws(u));let B=new mr(e),ue=new nn(B,D,this.logger.child({component:"documents"}));N.register(new Ts(B,ue,D));let Xe,ne;if(this.config.calendar)try{ne=await Dr(this.config.calendar),Xe=new Mt(ne),N.register(Xe),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(v){this.logger.warn({err:v},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Xe,ne&&this.config.calendar?.vorlauf?.enabled){let v=new xt(e),M=this.config.security?.ownerUserId;M&&(this.calendarWatcher=new fn(ne,v,this.adapters,M,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let v=this.config.security?.ownerUserId;if(v){let M=new xt(e);this.todoWatcher=new gn(ie,M,this.adapters,v,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:v}=await Promise.resolve().then(()=>(se(),oe));this.mcpManager=new v(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let M of this.mcpManager.getSkills())N.register(M);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},b)),this.logger.info({agents:this.config.codeAgents.agents.map(M=>M.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:v,createContactsProvider:M}=await Promise.resolve().then(()=>(se(),oe)),V=await M(this.config.contacts);N.register(new v(V)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(v){this.logger.warn({err:v},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant,proxmoxBackup:this.config.proxmoxBackup})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:v}=await Promise.resolve().then(()=>(se(),oe));N.register(new v(N,this.config,n)),this.logger.info("Briefing skill registered")}N.register(new Rs(n)),this.logger.info("Feed reader skill registered"),this.logger.info({skills:N.getAll().map(v=>v.metadata.name)},"Skills registered");let be;if(this.config.speech?.apiKey&&(be=new Zr(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let v=new Qr(this.config.speech,this.logger.child({component:"tts"}));N.register(new _s(v)),this.logger.info("Text-to-speech skill registered")}let de=this.detectImageGenProvider();if(de){let v=new en(de,this.logger.child({component:"image-gen"}));N.register(new ks(v)),this.logger.info({provider:de.provider},"Image generation skill registered")}try{let v=new tn(this.logger.child({component:"transit"}));N.register(new Ss(v)),this.logger.info("Public transit skill registered")}catch(v){this.logger.warn({err:v},"Failed to register transit skill")}let Me=new Vr(t),Ye=Mo.resolve(Mo.dirname(this.config.storage.path),"inbox");this.pipeline=new Yr({llm:b,conversationManager:Me,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:N,skillSandbox:re,securityManager:S,memoryRepo:n,speechTranscriber:be,inboxPath:Ye,embeddingService:D,activeLearning:Q,memoryRetriever:ae,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:ue,conversationSummarizer:z}),this.reminderScheduler=new Jr(o,async(v,M,V)=>{let Y=this.adapters.get(v);Y?await Y.sendMessage(M,V):this.logger.warn({platform:v,chatId:M},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(v=>s.getMasterUserId(v),"getMasterUserId"),getLinkedUsers:m(v=>s.getLinkedUsers(v),"getLinkedUsers"),findConversation:m((v,M)=>t.findByPlatformAndUser(v,M),"findConversation")}),this.backgroundTaskRunner=new on(N,re,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,f);let Ke=new an(N,re,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ke),J.setPersistentRunner(Ke),this.proactiveScheduler=new cn(u,N,re,b,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Me,h);let Je=new hr(e);this.watchRepo=Je,N.register(new Is(Je,N));let Ne=new fr(e);this.confirmationQueue=new dn(Ne,N,re,this.adapters,this.logger.child({component:"confirmation-queue"}),h),this.watchEngine=new vo(Je,N,re,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,f,b);let gt=new Tr(e),yt=new As(gt);N.register(yt);let at=new Tn(gt,N,re,this.logger.child({component:"workflow-runner"}),h,f);yt.setRunner(at);{let v=this.config.security?.ownerUserId;if(v&&this.config.reasoning?.enabled!==!1){let M=new xt(e);this.reasoningEngine=new _n(ne,ie,Je,n,p,g,M,N,re,b,this.adapters,s,v,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(f),await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("telegram",new t(e.telegram.token)),this.logger.info("Telegram adapter registered")}if(e.discord?.enabled&&e.discord.token){let{DiscordAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("discord",new t(e.discord.token)),this.logger.info("Discord adapter registered")}if(e.whatsapp?.enabled){let{WhatsAppAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("whatsapp",new t(e.whatsapp.dataPath)),this.logger.info("WhatsApp adapter registered")}if(e.matrix?.enabled&&e.matrix.accessToken){let{MatrixAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("matrix",new t(e.matrix.homeserverUrl,e.matrix.accessToken,e.matrix.userId)),this.logger.info("Matrix adapter registered")}if(e.signal?.enabled&&e.signal.phoneNumber){let{SignalAdapter:t}=await Promise.resolve().then(()=>(ht(),pt));this.adapters.set("signal",new t(e.signal.apiUrl,e.signal.phoneNumber)),this.logger.info("Signal adapter registered")}if(e.api?.enabled!==!1){let{HttpAdapter:t}=await Promise.resolve().then(()=>(ht(),pt)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>{let n;try{let o=this.config.storage.path,i=kn.statSync(o);n={path:o,sizeBytes:i.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([o,i])=>[o,i.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:this.watchRepo?.countEnabled()??0,schedulersActive:this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback")})),this.logger.info({port:s,host:r},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:m(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let o=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,o)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:this.auditRepo?.cleanup(90)??0,summaries:this.summaryRepo?.cleanup(180)??0,activity:this.activityRepo?.cleanup(90)??0,usage:this.usageRepo?.cleanup(365)??0,expiredMemories:this.memoryRepo?.cleanupExpired()??0};(e.audit||e.summaries||e.activity||e.usage)&&this.logger.info(e,"Startup DB cleanup completed")}catch(e){this.logger.warn({err:e},"Startup DB cleanup failed")}this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.adapters.size===0&&this.logger.warn("No messaging adapters enabled. Configure at least one platform."),this.logger.info(`Alfred is running with ${this.adapters.size} adapter(s)`)}async startWithCLI(){this.adapters.clear();let{CLIAdapter:e}=await Promise.resolve().then(()=>(ht(),pt)),t=new e;this.adapters.set("cli",t),t.on("disconnected",()=>{this.stop().then(()=>process.exit(0))}),await this.start()}async stop(){this.logger.info("Stopping Alfred..."),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(r=>setTimeout(r,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(r){this.logger.error({platform:t,err:r},"Failed to disconnect adapter")}try{this.database&&(this.database.getDb().pragma("wal_checkpoint(TRUNCATE)"),this.database.close())}catch{}this.logger.info("Alfred stopped")}async reloadService(e){try{ki();let t=new pe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(se(),oe)),n=await r(t.contacts);this.skillRegistry.register(new s(n)),this.config.contacts=t.contacts,this.logger.info({provider:t.contacts.provider},"Contacts skill hot-reloaded")}if(e==="docker"&&t.docker){let{DockerSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(se(),oe));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),o=this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${o.totalCostUsd}`),e.push("# HELP alfred_llm_today_calls Total LLM calls today (persisted)"),e.push("# TYPE alfred_llm_today_calls gauge"),e.push(`alfred_llm_today_calls ${o.totalCalls}`)}return e.push(""),e.join(`
|
|
1304
|
-
`)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async a=>{if(a!==n){n=a;try{r?await t.editMessage(s.chatId,r,a):r=await t.sendMessage(s.chatId,a)}catch(c){this.logger.debug({err:c,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o);if(i.text){let a=this.formatter.format(i.text,s.platform),c=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,c)}catch(d){this.logger.debug({err:d,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,a.text,c)}else await t.sendMessage(s.chatId,a.text,c)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let u=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,u.text)}}if(i.attachments)for(let a of i.attachments)try{let c=a.mimeType?.startsWith("image/")??!1,d=a.mimeType==="audio/ogg"||a.mimeType==="audio/opus";c?await t.sendPhoto(s.chatId,a.data,a.fileName):d?await t.sendVoice(s.chatId,a.data):await t.sendFile(s.chatId,a.data,a.fileName)}catch(c){this.logger.warn({err:c,fileName:a.fileName,chatId:s.chatId},"Failed to send attachment")}t.endStream(s.chatId)}catch(r){this.logger.error({platform:e,err:r,chatId:s.chatId},"Failed to handle message");try{await t.sendMessage(s.chatId,"Sorry, I encountered an error processing your message. Please try again.")}catch(n){this.logger.error({err:n},"Failed to send error message")}t.endStream(s.chatId)}}),t.on("error",s=>{this.logger.error({platform:e,err:s},"Adapter error")}),t.on("connected",()=>{this.logger.info({platform:e},"Adapter connected")}),t.on("disconnected",()=>{this.logger.warn({platform:e},"Adapter disconnected")})}detectImageGenProvider(){let e=["default","strong","fast","embeddings","local"];for(let t of["openai","google"])for(let s of e){let r=this.config.llm[s];if(r?.provider===t&&r.apiKey)return{provider:t,apiKey:r.apiKey,baseUrl:r.baseUrl}}}loadSecurityRules(){let e=
|
|
1332
|
+
`)}}});var ft={};fe(ft,{CLIAdapter:()=>Fo,DiscordAdapter:()=>Mo,HttpAdapter:()=>Bo,MatrixAdapter:()=>Oo,MessagingAdapter:()=>ye,SignalAdapter:()=>Uo,TelegramAdapter:()=>Lo,WhatsAppAdapter:()=>Po});var gt=T(()=>{"use strict";at();Zu();Qu();em();tm();sm();rm();om()});import Us from"node:fs";import Ye from"node:path";import ng from"js-yaml";var Gt,im=T(()=>{"use strict";Ni();Oi();rt();Vi();Zn();ae();Oa();Ua();Fa();ja();Ba();Ha();Wa();za();qa();Ga();Xa();Ka();Va();Ku();Ja();sc();rc();nc();oc();ic();ac();cc();lc();mc();pc();Gt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new ln;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=ir("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new xt(this.config.storage.path);let e=this.database.getDb(),t=new cr(e),s=new lr(e);this.userRepo=s;let r=new Ct(e);this.auditRepo=r;let n=new dr(e);this.memoryRepo=n;let o=new ur(e),i=new mr(e),a=new pr(e),c=new hr(e),d=new fr(e),u=new gr(e);this.scheduledActionRepo=u;let p=new Lt(e);this.activityRepo=p;let h=new Sn(p,this.logger.child({component:"activity"})),f=new br(e);this.skillHealthRepo=f;let g=new vn(f,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new Mr,_=this.loadSecurityRules();y.loadRules(_);let S=new Or(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:_.length},"Security engine initialized");let b=Xi(this.config.llm,this.logger.child({component:"llm"}));await b.initialize(),this.llmProvider=b;let $=new Er(e);this.usageRepo=$,b.setPersist((C,H,Q,oe,Ae,Xo)=>{$.record(C,H,Q,oe,Ae,Xo)});let N=new dn(b,a,this.logger.child({component:"embeddings"})),M=this.config.activeLearning?.enabled!==!1,J,V;M&&(J=new Tn({llm:b,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:N,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),V=new _n(n,this.logger.child({component:"memory-retriever"}),N),this.logger.info("Active learning & memory retriever initialized"));let P=new kr(e);this.summaryRepo=P;let ee=new kn(b,P,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ue=new ts(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new es;L.register(new ss),L.register(new rs),L.register(new ns(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new os(o)),L.register(new is(i));let se=new wr(e);if(L.register(new Ss(se)),L.register(new as),L.register(new cs),L.register(new ls(n,N)),L.register(new ds(b,L,ue,S)),this.config.email?.accounts?.length){let C=new Map;for(let Q of this.config.email.accounts)try{Q.provider==="microsoft"&&!Q.microsoft?.clientId&&this.config.calendar?.microsoft&&(Q.microsoft={...this.config.calendar.microsoft});let oe=await Pr(Q);C.set(Q.name,oe),this.logger.info({account:Q.name,provider:Q.provider??"imap-smtp"},"Email account initialized")}catch(oe){this.logger.warn({err:oe,account:Q.name},"Email account initialization failed, skipping")}let H=C.size>0?new ut(C):new ut;H.setLLM(b),L.register(H)}else{let C=new ut;C.setLLM(b),L.register(C)}L.register(new us),L.register(new ms);let ne=new As;ne.setReloadCallback(C=>this.reloadService(C)),L.register(ne),L.register(new hs),L.register(new fs),L.register(new gs),L.register(new ys(s)),L.register(new ws(s,c,this.adapters,(C,H)=>t.findByPlatformAndUser(C,H)));let Z=new Ts(d);L.register(Z),L.register(new _s(u));let j=new yr(e),pe=new un(j,N,this.logger.child({component:"documents"}));L.register(new ks(j,pe,N));let Xe,ce;if(this.config.calendar)try{ce=await jr(this.config.calendar),Xe=new Pt(ce),L.register(Xe),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=Xe,ce&&this.config.calendar?.vorlauf?.enabled){let C=new Nt(e),H=this.config.security?.ownerUserId;H&&(this.calendarWatcher=new En(ce,C,this.adapters,H,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let C=this.config.security?.ownerUserId;if(C){let H=new Nt(e);this.todoWatcher=new bn(se,H,this.adapters,C,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(ae(),le));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let H of this.mcpManager.getSkills())L.register(H);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(ae(),le));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(()=>(ae(),le));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},b)),this.logger.info({agents:this.config.codeAgents.agents.map(H=>H.name)},"Code agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(ae(),le));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(()=>(ae(),le));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(()=>(ae(),le));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:H}=await Promise.resolve().then(()=>(ae(),le)),Q=await H(this.config.contacts);L.register(new C(Q)),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(()=>(ae(),le));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(ae(),le));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(()=>(ae(),le));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(ae(),le));L.register(new C(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:C}=await Promise.resolve().then(()=>(ae(),le));L.register(new C({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant,proxmoxBackup:this.config.proxmoxBackup})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:C}=await Promise.resolve().then(()=>(ae(),le));L.register(new C(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:C}=await Promise.resolve().then(()=>(ae(),le));L.register(new C(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:C}=await Promise.resolve().then(()=>(ae(),le));L.register(new C(L,this.config,n)),this.logger.info("Briefing skill registered")}L.register(new Cs(n)),this.logger.info("Feed reader skill registered"),this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let be;if(this.config.speech?.apiKey&&(be=new nn(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 on(this.config.speech,this.logger.child({component:"tts"}));L.register(new Es(C)),this.logger.info("Text-to-speech skill registered")}let me=this.detectImageGenProvider();if(me){let C=new an(me,this.logger.child({component:"image-gen"}));L.register(new bs(C)),this.logger.info({provider:me.provider},"Image generation skill registered")}try{let C=new cn(this.logger.child({component:"transit"}));L.register(new $s(C)),this.logger.info("Public transit skill registered")}catch(C){this.logger.warn({err:C},"Failed to register transit skill")}let Oe=new tn(t),Je=Ye.resolve(Ye.dirname(this.config.storage.path),"inbox");this.pipeline=new sn({llm:b,conversationManager:Oe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:ue,securityManager:S,memoryRepo:n,speechTranscriber:be,inboxPath:Je,embeddingService:N,activeLearning:J,memoryRetriever:V,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:pe,conversationSummarizer:ee}),this.reminderScheduler=new rn(o,async(C,H,Q)=>{let oe=this.adapters.get(C);oe?await oe.sendMessage(H,Q):this.logger.warn({platform:C,chatId:H},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:m(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:m((C,H)=>t.findByPlatformAndUser(C,H),"findConversation")}),this.backgroundTaskRunner=new mn(L,ue,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,g);let Ke=new pn(L,ue,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ke),Z.setPersistentRunner(Ke),this.proactiveScheduler=new hn(u,L,ue,b,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Oe,h);let Ze=new Tr(e);this.watchRepo=Ze,L.register(new Rs(Ze,L));let De=new _r(e);this.confirmationQueue=new yn(De,L,ue,this.adapters,this.logger.child({component:"confirmation-queue"}),h);let wt=new vr(e),Tt=new Ms(wt,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(Tt),J&&J.setFeedbackService(Tt),this.watchEngine=new Co(Ze,L,ue,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,g,b);let Qe=new Sr(e),q=new xs(Qe);L.register(q);let z=new $n(Qe,L,ue,this.logger.child({component:"workflow-runner"}),h,g);q.setRunner(z);{let C=this.config.security?.ownerUserId;if(C&&this.config.reasoning?.enabled!==!1){let H=new Nt(e);this.reasoningEngine=new An(ce,se,Ze,n,p,f,H,L,ue,b,this.adapters,s,C,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h,this.config.briefing?.location,wt,this.confirmationQueue)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(g),await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(gt(),ft));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(()=>(gt(),ft));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(()=>(gt(),ft));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(()=>(gt(),ft));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(()=>(gt(),ft));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(()=>(gt(),ft)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>{let n;try{let o=this.config.storage.path,i=Us.statSync(o);n={path:o,sizeBytes:i.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([o,i])=>[o,i.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:this.watchRepo?.countEnabled()??0,schedulersActive:this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:m(()=>({watches:this.watchRepo?.getEnabled()??[],scheduled:this.scheduledActionRepo?.getAll()??[],skillHealth:this.skillHealthRepo?.getAll()??[]}),"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:r,webUi:e.api?.webUi!==!1},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:m(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let o=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,o)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:this.auditRepo?.cleanup(90)??0,summaries:this.summaryRepo?.cleanup(180)??0,activity:this.activityRepo?.cleanup(90)??0,usage:this.usageRepo?.cleanup(365)??0,expiredMemories:this.memoryRepo?.cleanupExpired()??0};(e.audit||e.summaries||e.activity||e.usage)&&this.logger.info(e,"Startup DB cleanup completed")}catch(e){this.logger.warn({err:e},"Startup DB cleanup failed")}this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.adapters.size===0&&this.logger.warn("No messaging adapters enabled. Configure at least one platform."),this.logger.info(`Alfred is running with ${this.adapters.size} adapter(s)`)}async startWithCLI(){this.adapters.clear();let{CLIAdapter:e}=await Promise.resolve().then(()=>(gt(),ft)),t=new e;this.adapters.set("cli",t),t.on("disconnected",()=>{this.stop().then(()=>process.exit(0))}),await this.start()}async stop(){this.logger.info("Stopping Alfred..."),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(r=>setTimeout(r,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(r){this.logger.error({platform:t,err:r},"Failed to disconnect adapter")}try{this.database&&(this.database.getDb().pragma("wal_checkpoint(TRUNCATE)"),this.database.close())}catch{}this.logger.info("Alfred stopped")}async reloadService(e){try{xi();let t=new he().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(ae(),le));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(()=>(ae(),le));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(()=>(ae(),le));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(()=>(ae(),le)),n=await r(t.contacts);this.skillRegistry.register(new s(n)),this.config.contacts=t.contacts,this.logger.info({provider:t.contacts.provider},"Contacts skill hot-reloaded")}if(e==="docker"&&t.docker){let{DockerSkill:s}=await Promise.resolve().then(()=>(ae(),le));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(()=>(ae(),le));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(()=>(ae(),le));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(()=>(ae(),le));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}resolveWebUiPath(){let e=[Ye.join(process.cwd(),"web-ui"),Ye.join(__dirname,"..","..","web-ui"),Ye.join(__dirname,"..","..","..","web-ui"),Ye.join(__dirname,"..","..","apps","web","out")];for(let t of e)try{let s=Ye.resolve(t);if(Us.existsSync(Ye.join(s,"index.html")))return this.logger.info({path:s},"Web UI found"),s}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),o=this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${o.totalCostUsd}`),e.push("# HELP alfred_llm_today_calls Total LLM calls today (persisted)"),e.push("# TYPE alfred_llm_today_calls gauge"),e.push(`alfred_llm_today_calls ${o.totalCalls}`)}return e.push(""),e.join(`
|
|
1333
|
+
`)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async a=>{if(a!==n){n=a;try{r?await t.editMessage(s.chatId,r,a):r=await t.sendMessage(s.chatId,a)}catch(c){this.logger.debug({err:c,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o);if(i.text){let a=this.formatter.format(i.text,s.platform),c=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,c)}catch(d){this.logger.debug({err:d,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,a.text,c)}else await t.sendMessage(s.chatId,a.text,c)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let u=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,u.text)}}if(i.attachments)for(let a of i.attachments)try{let c=a.mimeType?.startsWith("image/")??!1,d=a.mimeType==="audio/ogg"||a.mimeType==="audio/opus";c?await t.sendPhoto(s.chatId,a.data,a.fileName):d?await t.sendVoice(s.chatId,a.data):await t.sendFile(s.chatId,a.data,a.fileName)}catch(c){this.logger.warn({err:c,fileName:a.fileName,chatId:s.chatId},"Failed to send attachment")}t.endStream(s.chatId)}catch(r){this.logger.error({platform:e,err:r,chatId:s.chatId},"Failed to handle message");try{await t.sendMessage(s.chatId,"Sorry, I encountered an error processing your message. Please try again.")}catch(n){this.logger.error({err:n},"Failed to send error message")}t.endStream(s.chatId)}}),t.on("error",s=>{this.logger.error({platform:e,err:s},"Adapter error")}),t.on("connected",()=>{this.logger.info({platform:e},"Adapter connected")}),t.on("disconnected",()=>{this.logger.warn({platform:e},"Adapter disconnected")})}detectImageGenProvider(){let e=["default","strong","fast","embeddings","local"];for(let t of["openai","google"])for(let s of e){let r=this.config.llm[s];if(r?.provider===t&&r.apiKey)return{provider:t,apiKey:r.apiKey,baseUrl:r.baseUrl}}}loadSecurityRules(){let e=Ye.resolve(this.config.security.rulesPath),t=[];if(!Us.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!Us.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=Us.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=Ye.join(e,n),i=Us.readFileSync(o,"utf-8"),a=ng.load(i);if(a?.rules&&Array.isArray(a.rules)){let d=new ot().loadFromObject({rules:a.rules});t.push(...d),this.logger.info({file:n,count:d.length},"Loaded security rules")}}catch(o){this.logger.error({err:o,file:n},"Failed to load security rules file")}return t}}});var am=T(()=>{"use strict"});var yc=T(()=>{"use strict";rc();tc()});var wc=T(()=>{"use strict";im();Ua();Oa();Fa();ja();Ba();za();qa();Xa();Ka();Va();pt();Ga();Ha();Wa();sc();nc();ec();am();Qa();oc();fn();uc();Ja();yc();yc();ic();ac();cc();xo();lc();mc();pc()});import Ho from"node:fs";import cm from"node:path";import og from"node:os";function lm(){try{let l=Ho.readFileSync(Tc,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function dm(l){try{let e=cm.dirname(Tc);Ho.existsSync(e)||Ho.mkdirSync(e,{recursive:!0}),Ho.writeFileSync(Tc,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Xt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),ag);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function um(l,e,t){switch(l){case"anthropic":{let s=await Xt("https://api.anthropic.com/v1/models",{headers:{"x-api-key":e??"","anthropic-version":"2023-06-01"}});return s.ok?((await s.json()).data??[]).map(n=>({id:n.id,name:n.display_name})):[]}case"openai":{let s=t?`${t.replace(/\/+$/,"")}/models`:"https://api.openai.com/v1/models",r=await Xt(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await Xt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await Xt("https://api.mistral.ai/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(n=>({id:n.id,name:n.name})):[]}case"openrouter":{let s=await Xt("https://openrouter.ai/api/v1/models",{headers:{Authorization:`Bearer ${e??""}`}});return s.ok?((await s.json()).data??[]).map(n=>({id:n.id,name:n.name})):[]}case"ollama":{let s=(t??"http://localhost:11434").replace(/\/+$/,""),r=await Xt(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await Xt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function _c(l,e,t){let s=lm(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<ig)return r.models;try{let n=await um(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},dm(s),n}catch{}return r?r.models:[]}function Wo(l,e,t){um(l,e,t).then(s=>{if(s.length>0){let r=lm();r.providers[l]={fetchedAt:Date.now(),models:s},dm(r)}}).catch(()=>{})}function kc(l,e){let t=new Set,s=[];for(let r of l)if(!t.has(r.id)){t.add(r.id);let n=e.find(o=>o.id===r.id);s.push({id:r.id,name:r.name,desc:n?.desc})}for(let r of e)t.has(r.id)||(t.add(r.id),s.push({id:r.id,desc:r.desc}));return s}var ig,ag,Tc,Ec=T(()=>{"use strict";ig=1440*60*1e3,ag=5e3,Tc=cm.join(og.homedir(),".alfred","model-cache.json");m(lm,"readCache");m(dm,"writeCache");m(Xt,"fetchWithTimeout");m(um,"fetchModelsFromAPI");m(_c,"getModels");m(Wo,"refreshCacheInBackground");m(kc,"mergeModels")});var mm={};fe(mm,{startCommand:()=>cg});async function cg(){let l=new he,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=ir("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new Gt(e),r=!1,n=m(async o=>{if(!r){r=!0,t.info({signal:o},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(i){t.error({error:i},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",o=>{t.fatal({error:o},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",o=>{t.fatal({reason:o},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let o=e.llm;o?.default?.provider?Wo(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&Wo(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&Wo(a.provider,a.apiKey,a.baseUrl)}}catch(o){let i=o instanceof Error?o:new Error(String(o));t.fatal({err:i},"Failed to start Alfred"),process.exit(1)}}var pm=T(()=>{"use strict";rt();Ni();wc();Ec();m(cg,"startCommand")});var fm={};fe(fm,{chatCommand:()=>ug});import hm from"node:http";import Rn from"node:readline";function lg(l,e){return new Promise(t=>{let s=hm.get(`http://${l}:${e}/api/health`,{timeout:2e3},r=>{let n="";r.on("data",o=>{n+=o.toString()}),r.on("end",()=>{try{let o=JSON.parse(n);t(o.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function dg(l,e){let t=Rn.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
|
|
1305
1334
|
Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
|
|
1306
1335
|
`),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
|
|
1307
1336
|
Goodbye!
|
|
1308
|
-
`),t.close(),process.exit(0));let n=JSON.stringify({text:r,chatId:"api-chat",userId:"api-user"}),o=
|
|
1337
|
+
`),t.close(),process.exit(0));let n=JSON.stringify({text:r,chatId:"api-chat",userId:"api-user"}),o=hm.request({hostname:l,port:e,path:"/api/message",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n)}},i=>{let a="";i.on("data",c=>{a+=c.toString();let d=a.split(`
|
|
1309
1338
|
|
|
1310
1339
|
`);a=d.pop()??"";for(let u of d){let p=u.split(`
|
|
1311
|
-
`).find(h=>h.startsWith("data: "));if(p)try{let h=JSON.parse(p.slice(6));switch(h.type){case"status":
|
|
1340
|
+
`).find(h=>h.startsWith("data: "));if(p)try{let h=JSON.parse(p.slice(6));switch(h.type){case"status":Rn.clearLine(process.stdout,0),Rn.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${h.text??""}`);break;case"response":Rn.clearLine(process.stdout,0),Rn.cursorTo(process.stdout,0),process.stdout.write(`
|
|
1312
1341
|
Alfred: ${h.text??""}
|
|
1313
|
-
`);break;case"attachment":{let
|
|
1342
|
+
`);break;case"attachment":{let f=h.fileName??h.attachmentType??"file";process.stdout.write(`[Attachment: ${f}]
|
|
1314
1343
|
`);break}case"done":t.prompt();break;case"error":process.stdout.write(`
|
|
1315
1344
|
Error: ${h.text??"Unknown error"}
|
|
1316
1345
|
`),t.prompt();break}}catch{}}}),i.on("end",()=>{if(a.length>0){let c=a.split(`
|
|
1317
1346
|
`).find(d=>d.startsWith("data: "));if(c)try{let d=JSON.parse(c.slice(6));(d.type==="done"||d.type==="error")&&t.prompt()}catch{}}}),i.on("error",c=>{console.error(`
|
|
1318
1347
|
Connection error: ${c.message}`),t.prompt()})});o.on("error",i=>{console.error(`
|
|
1319
|
-
Failed to send message: ${i.message}`),t.prompt()}),o.write(n),o.end()}),t.on("close",()=>{process.exit(0)})}async function
|
|
1320
|
-
`);for(let
|
|
1321
|
-
${
|
|
1322
|
-
`:`${
|
|
1323
|
-
${
|
|
1324
|
-
${
|
|
1325
|
-
`);let r=await
|
|
1326
|
-
${
|
|
1327
|
-
${
|
|
1328
|
-
${
|
|
1329
|
-
${E("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${E("Using single model for all tasks.")}`);let
|
|
1330
|
-
${
|
|
1331
|
-
${
|
|
1332
|
-
${
|
|
1333
|
-
${
|
|
1334
|
-
${
|
|
1335
|
-
${
|
|
1336
|
-
${
|
|
1337
|
-
${
|
|
1338
|
-
${
|
|
1339
|
-
${
|
|
1340
|
-
${
|
|
1341
|
-
${E("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let
|
|
1342
|
-
${
|
|
1343
|
-
${
|
|
1344
|
-
${
|
|
1345
|
-
${
|
|
1346
|
-
${
|
|
1347
|
-
${
|
|
1348
|
-
${
|
|
1349
|
-
${
|
|
1350
|
-
${
|
|
1351
|
-
${
|
|
1352
|
-
${
|
|
1353
|
-
${
|
|
1354
|
-
${
|
|
1355
|
-
`)
|
|
1348
|
+
Failed to send message: ${i.message}`),t.prompt()}),o.write(n),o.end()}),t.on("close",()=>{process.exit(0)})}async function ug(l){let e=new he,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 lg(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),dg(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let i=t.llm[l.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let o=new Gt(t);try{await o.initialize(),await o.startWithCLI()}catch(i){console.error("Failed to start chat:",i.message),process.exit(1)}}var gm=T(()=>{"use strict";rt();wc();m(lg,"checkHealth");m(dg,"startClientMode");m(ug,"chatCommand")});var Tm={};fe(Tm,{setupCommand:()=>Eg});import{createInterface as mg}from"node:readline/promises";import{stdin as pg,stdout as hg}from"node:process";import{execFileSync as fg}from"node:child_process";import Ee from"node:fs";import gg from"node:os";import Ie from"node:path";import bc from"js-yaml";function U(l){return`${zo}${l}${I}`}function Tg(l){return`${F}${l}${I}`}function _e(l){return`${qo}${l}${I}`}function wm(l){return`${yg}${l}${I}`}function D(l){return`${Y}${l}${I}`}function E(l){return`${yt}${l}${I}`}function ke(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function _g(l){let e=process.platform==="win32",t=e?"where":"which";try{let n=fg(t,[l],{stdio:"pipe"}).toString().trim();if(n)return n.split(/\r?\n/)[0]}catch{}let s=gg.homedir(),r=e?[Ie.join(s,".local","bin",`${l}.exe`),Ie.join(s,"AppData","Roaming","npm",`${l}.cmd`),Ie.join(s,"AppData","Roaming","npm",`${l}`)]:[Ie.join(s,".local","bin",l),"/usr/local/bin/"+l,"/opt/homebrew/bin/"+l,Ie.join(s,".npm-global","bin",l)];for(let n of r)try{return Ee.accessSync(n,Ee.constants.X_OK),n}catch{}return null}function kg(l){let e={},t={},s=!1,r=!1,n=30,o=Ie.join(l,"config","default.yml");if(Ee.existsSync(o))try{let h=bc.load(Ee.readFileSync(o,"utf-8"));h&&typeof h=="object"&&Object.assign(e,h)}catch{}let i=Ie.join(l,".env");if(Ee.existsSync(i))try{let h=Ee.readFileSync(i,"utf-8").split(`
|
|
1349
|
+
`);for(let f of h){let g=f.trim();if(!g||g.startsWith("#"))continue;let y=g.indexOf("=");y>0&&(t[g.slice(0,y)]=g.slice(y+1))}}catch{}let a=Ie.join(l,"config","rules","default-rules.yml");if(Ee.existsSync(a))try{let h=bc.load(Ee.readFileSync(a,"utf-8"));if(h?.rules){s=h.rules.some(y=>y.id==="allow-owner-admin"&&y.effect==="allow"),h.rules.find(y=>y.id==="allow-write-for-dm"||y.id==="allow-write-all")?.id==="allow-write-all"&&(r=!0);let g=h.rules.find(y=>y.id==="rate-limit-write");g?.rateLimit?.maxInvocations&&(n=g.rateLimit.maxInvocations)}}catch{}let c=!!e.codeSandbox?.enabled,d=e.api?.webUi!==!1,u=e.llm,p={};if(u){for(let h of["strong","fast","embeddings","local"])u[h]?.provider&&u[h]?.model&&(p[h]=u[h]);u.default?.provider&&(e.llm={...e.llm,provider:u.default.provider,model:u.default.model,baseUrl:u.default.baseUrl})}return{config:e,env:t,shellEnabled:s,writeInGroups:r,rateLimit:n,codeSandboxEnabled:c,webUiEnabled:d,multiModelTiers:p}}async function Eg(){let l=mg({input:pg,output:hg}),e=process.cwd(),t=kg(e),s=Object.keys(t.config).length>0;try{bg(),console.log(s?`${qo}Existing configuration found \u2014 press Enter to keep current values.${I}
|
|
1350
|
+
${yt}Only change what you need to update.${I}
|
|
1351
|
+
`:`${qo}Welcome to the Alfred setup wizard!${I}
|
|
1352
|
+
${yt}This will walk you through configuring your AI assistant.${I}
|
|
1353
|
+
${yt}Press Enter to accept defaults shown in [brackets].${I}
|
|
1354
|
+
`);let r=await B(l,"What should your bot be called?",t.config.name??"Alfred"),n=t.config.llm?.provider?ct.findIndex(k=>k.name===t.config.llm?.provider):-1,o=n>=0?n+1:1;console.log(`
|
|
1355
|
+
${D("Which LLM provider would you like to use?")}`);for(let k=0;k<ct.length;k++){let v=k===n?` ${E("(current)")}`:"";console.log(` ${_e(String(k+1)+")")} ${ct[k].label}${v}`)}let i=await xn(l,"> ",1,ct.length,o),a=ct[i-1];console.log(` ${U(">")} Selected: ${D(a.label)}`);let c="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?c=await B(l,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):c=await Le(l,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${U(">")} API key set: ${E(ke(c))}`));let u=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let v=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if(v){let R={ollama:"Ollama URL (use a remote address if Ollama runs on another machine)",openwebui:"OpenWebUI URL",openai:"OpenAI-compatible API URL (leave default for official API)",openrouter:"OpenRouter API URL",google:"Google Gemini API URL (leave default for official API)"};console.log(""),u=await B(l,R[a.name]??"API Base URL",v.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${U(">")} URL: ${E(u)}`)}}let h=t.config.llm?.model??a.defaultModel;console.log("");let f,g=await _c(a.name,c,u),y=kc(g,a.models??[]);if(y.length>0){console.log(`${D("Available models:")}`);for(let R=0;R<y.length;R++){let X=y[R],O=X.desc??X.name??"",G=X.id===h?` ${U("(current)")}`:"";console.log(` ${_e(`${R+1})`)} ${X.id}${O?` ${E(`\u2014 ${O}`)}`:""}${G}`)}console.log(` ${_e(`${y.length+1})`)} ${E("Other (enter manually)")}`);let k=await B(l,"Choose model","1"),v=parseInt(k,10)-1;v>=0&&v<y.length?f=y[v].id:f=await B(l,"Model ID",h)}else f=await B(l,"Which model?",h);let _=Object.keys(t.multiModelTiers).length>0,S=_?"Y/n":"y/N";console.log(`
|
|
1356
|
+
${D("Configure additional model tiers for specialized tasks?")}`),console.log(`${E("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let b=(await l.question(`${F}> ${I}${E(`[${S}] `)}`)).trim().toLowerCase(),$=b===""?_:b==="y"||b==="yes",N={};if($){let k=[{key:"strong",label:"Strong",hint:"complex reasoning, coding, long documents",defaultModel:"claude-opus-4-20250514"},{key:"fast",label:"Fast",hint:"quick responses, simple tasks",defaultModel:"claude-haiku-4-5-20251001"},{key:"embeddings",label:"Embeddings",hint:"semantic search & memory",defaultModel:"text-embedding-3-small"},{key:"local",label:"Local",hint:"offline fallback via Ollama",defaultModel:"llama3.2"}];for(let v of k){let R=t.multiModelTiers[v.key],X=!!R?.model;console.log(`
|
|
1357
|
+
${D(`${v.label} model`)} ${E(`(${v.hint})`)}`),X&&console.log(` ${E(`Current: ${R.provider}/${R.model}`)}`);let O=R?.provider??a.name,G=ct.map(xe=>xe.name).join(", ");console.log(` ${E(`Providers: ${G}`)}`);let Se=(await l.question(` ${F}Provider: ${I}${E(`[${O}] `)}`)).trim()||O;if(!Se&&!X){console.log(` ${E("Skipped.")}`);continue}let te=Se,ve,Fe;if(te!==a.name){let xe=R?.apiKey??t.env[`ALFRED_LLM_${v.key.toUpperCase()}_API_KEY`]??"";if(xe?ve=await B(l,` API key for ${te}`,xe):(ct.find(st=>st.name===te)?.needsApiKey??!0)&&(ve=await Le(l,` API key for ${te}`)),["ollama","openwebui"].includes(te)){let st=(R?.baseUrl??"")||ct.find(Gn=>Gn.name===te)?.baseUrl||"";st&&(Fe=await B(l,` ${te} URL`,st))}}let At=ve??(te===a.name?c:void 0),or=Fe??(te===a.name?u:void 0),bi=ct.find(xe=>xe.name===te),Si=await _c(te,At,or),dt=kc(Si,bi?.models??[]),tt;if(dt.length>0){console.log(` ${D("Available models:")}`);for(let Yt=0;Yt<dt.length;Yt++){let st=dt[Yt],Gn=st.desc??st.name??"",lp=st.id===R?.model?` ${U("(current)")}`:"";console.log(` ${_e(`${Yt+1})`)} ${st.id}${Gn?` ${E(`\u2014 ${Gn}`)}`:""}${lp}`)}console.log(` ${_e(`${dt.length+1})`)} ${E("Other (enter manually)")}`),console.log(` ${_e("0)")} ${E("Skip this tier")}`);let xe=(await l.question(` ${F}> ${I}${X?E(`[${R.model}] `):""}`)).trim();if(xe==="0"){console.log(` ${E("Skipped.")}`);continue}let qn=parseInt(xe,10)-1;qn>=0&&qn<dt.length?tt=dt[qn].id:!xe&&X?tt=R.model:tt=await B(l," Model ID",X?R.model:v.defaultModel)}else if(console.log(` ${E("Press Enter to skip.")}`),tt=(await l.question(` ${F}Model: ${I}${X?E(`[${R.model}] `):""}`)).trim()||(X?R.model:""),!tt){console.log(` ${E("Skipped.")}`);continue}N[v.key]={provider:te,model:tt,...ve?{apiKey:ve}:{},...Fe?{baseUrl:Fe}:{}},console.log(` ${U(">")} ${v.label}: ${D(te)}/${D(tt)}`)}Object.keys(N).length===0&&console.log(`
|
|
1358
|
+
${E("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${E("Using single model for all tasks.")}`);let M=["brave","tavily","duckduckgo","searxng"],J=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",V=M.indexOf(J),P=V>=0?V+1:0;console.log(`
|
|
1359
|
+
${D("Web Search provider (for searching the internet):")}`);let ee=["Brave Search \u2014 recommended, free tier (2,000/month)","Tavily \u2014 built for AI agents, free tier (1,000/month)","DuckDuckGo \u2014 free, no API key needed","SearXNG \u2014 self-hosted, no API key needed"],ue=m(k=>V===k?` ${E("(current)")}`:"","mark");console.log(` ${_e("0)")} None (disable web search)${V===-1&&J===""?` ${E("(current)")}`:""}`);for(let k=0;k<ee.length;k++)console.log(` ${_e(String(k+1)+")")} ${ee[k]}${ue(k)}`);let L=await xn(l,"> ",0,M.length,P),se,ne="",Z="";if(L>=1&&L<=M.length&&(se=M[L-1]),se==="brave"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ne=await B(l," Brave Search API key",k):(console.log(` ${E("Get your free API key at: https://brave.com/search/api/")}`),ne=await Le(l," Brave Search API key")),console.log(` ${U(">")} Brave Search: ${E(ke(ne))}`)}else if(se==="tavily"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ne=await B(l," Tavily API key",k):(console.log(` ${E("Get your free API key at: https://tavily.com/")}`),ne=await Le(l," Tavily API key")),console.log(` ${U(">")} Tavily: ${E(ke(ne))}`)}else if(se==="duckduckgo")console.log(` ${U(">")} DuckDuckGo: ${E("no API key needed")}`);else if(se==="searxng"){let k=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";Z=await B(l," SearXNG URL",k),Z=Z.replace(/\/+$/,""),console.log(` ${U(">")} SearXNG: ${E(Z)}`)}else console.log(` ${E("Web search disabled \u2014 you can configure it later.")}`);let j=[];for(let k=0;k<Fs.length;k++){let v=Fs[k];t.config[v.configKey]?.enabled&&j.push(k+1)}let pe=j.length>0?j.join(","):"";console.log(`
|
|
1360
|
+
${D("Which messaging platforms do you want to enable?")}`),console.log(`${E("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let k=0;k<Fs.length;k++){let v=j.includes(k+1)?` ${E("(enabled)")}`:"";console.log(` ${_e(String(k+1)+")")} ${Fs[k].label}${v}`)}console.log(` ${_e("0)")} None (configure later)`);let Xe=(await l.question(`${F}> ${I}${pe?E(`[${pe}] `):""}`)).trim(),ce=[],be=Xe||pe;if(be&&be!=="0"){let k=be.split(",").map(v=>parseInt(v.trim(),10));for(let v of k)if(v>=1&&v<=Fs.length){let R=Fs[v-1];ce.includes(R)||ce.push(R)}}ce.length>0?console.log(` ${U(">")} Enabling: ${ce.map(k=>D(k.label)).join(", ")}`):console.log(` ${E("No platforms selected \u2014 you can configure them later.")}`);let me={},Oe={};for(let k of ce){if(k.credentials.length===0){k.name==="whatsapp"&&console.log(`
|
|
1361
|
+
${Tg("i")} WhatsApp: a QR code will be displayed on first start.`);continue}console.log(`
|
|
1362
|
+
${D(k.label+" configuration:")}`);let v={};for(let R of k.credentials){let X=t.env[R.envKey]??"",O;X?O=await B(l,` ${R.prompt}`,X):R.defaultValue?O=await B(l,` ${R.prompt}`,R.defaultValue):R.required?O=await Le(l,` ${R.prompt}`):(O=(await l.question(` ${R.prompt}: ${F}`)).trim(),process.stdout.write(I)),v[R.configField]=O,Oe[R.envKey]=O,R.configField==="token"||R.configField==="accessToken"?console.log(` ${U(">")} Set: ${E(ke(O))}`):console.log(` ${U(">")} Set: ${E(O)}`)}me[k.configKey]=v}let Je=t.config.email?.accounts??[],Ke=Je[0],Ze=Ke?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",De=Ke?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",wt=Je.length>0||!!Ze||De==="microsoft",Tt=wt?"Y/n":"y/N";console.log(`
|
|
1363
|
+
${D("Email access (read & send emails)?")}`),console.log(`${E("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let Qe=(await l.question(`${F}> ${I}${E(`[${Tt}] `)}`)).trim().toLowerCase(),q=Qe===""?wt:Qe==="y"||Qe==="yes",z=[],C={"gmail.com":{imap:"imap.gmail.com",smtp:"smtp.gmail.com"},"googlemail.com":{imap:"imap.gmail.com",smtp:"smtp.gmail.com"},"outlook.com":{imap:"outlook.office365.com",smtp:"smtp.office365.com"},"hotmail.com":{imap:"outlook.office365.com",smtp:"smtp.office365.com"},"live.com":{imap:"outlook.office365.com",smtp:"smtp.office365.com"},"yahoo.com":{imap:"imap.mail.yahoo.com",smtp:"smtp.mail.yahoo.com"},"icloud.com":{imap:"imap.mail.me.com",smtp:"smtp.mail.me.com"},"me.com":{imap:"imap.mail.me.com",smtp:"smtp.mail.me.com"},"gmx.de":{imap:"imap.gmx.net",smtp:"mail.gmx.net"},"gmx.net":{imap:"imap.gmx.net",smtp:"mail.gmx.net"},"web.de":{imap:"imap.web.de",smtp:"smtp.web.de"},"posteo.de":{imap:"posteo.de",smtp:"posteo.de"},"mailbox.org":{imap:"imap.mailbox.org",smtp:"smtp.mailbox.org"},"protonmail.com":{imap:"127.0.0.1",smtp:"127.0.0.1"},"proton.me":{imap:"127.0.0.1",smtp:"127.0.0.1"}},H=m(async(k,v)=>{let R={name:k,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},X=v?.provider??"",O=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],G=X==="microsoft"?1:0;console.log("");for(let te=0;te<O.length;te++){let ve=te===G?` ${E("(current)")}`:"";console.log(` ${_e(`${te+1})`)} ${O[te]}${ve}`)}let re=(await l.question(`${F}> ${I}${E(`[${G+1}] `)}`)).trim(),Se=re===""?G:parseInt(re,10)-1;if(R.provider=Se===1?"microsoft":"imap-smtp",R.provider==="microsoft"){let te=t.config.calendar?.microsoft,ve=v?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Fe=v?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",At=v?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(te&&!ve)console.log(` ${U(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${E("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${E("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${E("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),R.msClientId=await B(l," Client ID",ve),R.msClientId||(R.msClientId=await Le(l," Client ID"));let or=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";R.msClientSecret=await B(l," Client Secret",or),R.msClientSecret||(R.msClientSecret=await Le(l," Client Secret")),R.msTenantId=await B(l," Tenant ID",Fe),R.msTenantId||(R.msTenantId=await Le(l," Tenant ID")),console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),R.msRefreshToken=await B(l," Refresh Token",At),R.msRefreshToken||(R.msRefreshToken=await Le(l," Refresh Token"))}console.log(` ${U(">")} Email [${k}]: Microsoft 365 (Graph API)`)}else{let te=v?.auth?.user??"";console.log(""),R.user=await B(l," Email address",te||""),R.user||(R.user=await Le(l," Email address"));let ve=v?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";ve?R.pass=await B(l," Password / App password",ve):(console.log(` ${E("For Gmail: use an App Password (not your regular password)")}`),console.log(` ${E(" \u2192 Google Account \u2192 Security \u2192 2-Step \u2192 App passwords")}`),R.pass=await Le(l," Password / App password"));let Fe=R.user.split("@")[1]?.toLowerCase()??"",At=C[Fe],or=v?.imap?.host??At?.imap??`imap.${Fe}`,bi=v?.smtp?.host??At?.smtp??`smtp.${Fe}`,Si=v?.imap?.port??993,dt=v?.smtp?.port??587;At&&console.log(` ${U(">")} Detected ${Fe} \u2014 using preset server settings`),R.imapHost=await B(l," IMAP server",or);let tt=await B(l," IMAP port",String(Si));R.imapPort=parseInt(tt,10)||993,R.smtpHost=await B(l," SMTP server",bi);let xe=await B(l," SMTP port",String(dt));R.smtpPort=parseInt(xe,10)||587,console.log(` ${U(">")} Email [${k}]: ${E(R.user)} via ${E(R.imapHost)}`)}return R},"configureEmailAccount");if(q){let k=Ke??(t.config.email?.auth?{provider:t.config.email.provider,auth:t.config.email.auth,imap:t.config.email.imap,smtp:t.config.email.smtp,microsoft:t.config.email.microsoft}:void 0);z.push(await H("default",k));let v=!0;for(;v;){let R=(await l.question(`
|
|
1364
|
+
${D("Add another email account?")} ${E("[y/N]")} `)).trim().toLowerCase();if(R==="y"||R==="yes"){let O=(await l.question(` ${D("Account name:")} `)).trim()||`account${z.length+1}`,G=Je.find(re=>re.name===O);z.push(await H(O,G))}else v=!1}}else console.log(` ${E("Email disabled \u2014 you can configure it later.")}`);let Q=["openai","groq"],oe=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",Ae=Q.indexOf(oe),Xo=Ae>=0?Ae+1:0;console.log(`
|
|
1365
|
+
${D("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${E("Transcribes voice messages from Telegram, Discord, etc.")}`);let Ic=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${_e("0)")} None (disable voice transcription)${Ae===-1?` ${E("(current)")}`:""}`);for(let k=0;k<Ic.length;k++){let v=Ae===k?` ${E("(current)")}`:"";console.log(` ${_e(String(k+1)+")")} ${Ic[k]}${v}`)}let Ko=await xn(l,"> ",0,Q.length,Xo),Ve,lt="",js="";if(Ko>=1&&Ko<=Q.length&&(Ve=Q[Ko-1]),Ve==="openai"){let k=t.env.ALFRED_SPEECH_API_KEY??"";k?lt=await B(l," OpenAI API key (for Whisper)",k):(console.log(` ${E("Uses your OpenAI API key for Whisper transcription.")}`),lt=await Le(l," OpenAI API key")),console.log(` ${U(">")} OpenAI Whisper: ${E(ke(lt))}`)}else if(Ve==="groq"){let k=t.env.ALFRED_SPEECH_API_KEY??"";k?lt=await B(l," Groq API key",k):(console.log(` ${E("Get your free API key at: https://console.groq.com/")}`),lt=await Le(l," Groq API key"));let v=t.env.ALFRED_SPEECH_BASE_URL??"";v&&(js=await B(l," Groq API URL",v)),console.log(` ${U(">")} Groq Whisper: ${E(ke(lt))}`)}else console.log(` ${E("Voice transcription disabled \u2014 you can configure it later.")}`);let Bs=!1,Hs="alloy";if(Ve){let k=t.config.speech?.ttsEnabled??!1,v=k?"Y/n":"y/N";console.log(`
|
|
1366
|
+
${D("Voice responses (Text-to-Speech)?")}`),console.log(`${E("Alfred can reply as a voice message when the user asks for it.")}`);let R=(await l.question(`${F}> ${I}${E(`[${v}] `)}`)).trim().toLowerCase();if(Bs=R===""?k:R==="y"||R==="yes",Bs){let X=["alloy","echo","fable","onyx","nova","shimmer"],O=t.config.speech?.ttsVoice??"alloy",G=X.indexOf(O),re=G>=0?G+1:1;console.log(`
|
|
1367
|
+
${D("Which voice?")}`);for(let te=0;te<X.length;te++){let ve=G===te?` ${E("(current)")}`:"";console.log(` ${_e(String(te+1)+")")} ${X[te]}${ve}`)}let Se=await xn(l," > ",1,X.length,re);Hs=X[Se-1],console.log(` ${U(">")} TTS voice: ${D(Hs)}`)}else console.log(` ${E("Voice responses disabled.")}`)}let Om=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
|
|
1368
|
+
${D("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${E("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let Vo=(await l.question(`${F}> ${I}${E(`[${Om}] `)}`)).trim().toLowerCase(),Yo=Vo===""?t.codeSandboxEnabled:Vo==="y"||Vo==="yes";console.log(Yo?` ${U(">")} Code Sandbox ${D("enabled")} (JavaScript + Python)`:` ${E("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
|
|
1369
|
+
${D("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${E("Scanning for known coding agents on this system...")}`);let Jo=[];for(let k of ym){let v=_g(k.whichCmd);v?(Jo.push({...k,resolvedPath:v}),console.log(` ${U("\u2713")} ${D(k.label)} ${E(`(${v})`)}`)):console.log(` ${E("\xB7")} ${E(k.label)} ${E("\u2014 not found")}`)}let Zo=(t.config.codeAgents?.agents??[]).filter(k=>!ym.some(v=>v.name===k.name));for(let k of Zo)console.log(` ${U("\u2713")} ${D(k.name)} ${E(`(${k.command}) \u2014 from existing config`)}`);let _t=[];if(Jo.length===0&&Zo.length===0)console.log(`
|
|
1370
|
+
${E("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let k=[...Jo.map(O=>({name:O.name,command:O.resolvedPath??O.command,argsTemplate:O.argsTemplate,promptVia:O.promptVia,label:O.label,detected:!0})),...Zo.map(O=>({name:O.name,command:O.command,argsTemplate:O.argsTemplate,promptVia:O.promptVia??"arg",label:O.name,detected:!1}))];console.log(`
|
|
1371
|
+
${D("Which agents should Alfred use?")} ${E("(comma-separated, e.g. 1,2)")}`);let v=new Set((t.config.codeAgents?.agents??[]).map(O=>O.name));for(let O=0;O<k.length;O++){let G=k[O],re=v.has(G.name)?` ${E("(current)")}`:"";console.log(` ${F}${O+1}${I}) ${G.label}${re}`)}console.log(` ${F}0${I}) None`);let R=k.map((O,G)=>v.size>0?v.has(O.name)?String(G+1):null:O.detected?String(G+1):null).filter(Boolean).join(",")||"0",X=(await l.question(` ${F}> ${I}${E(`[${R}] `)}`)).trim()||R;X!=="0"&&(_t=X.split(",").map(G=>parseInt(G.trim(),10)).filter(G=>!isNaN(G)&&G>=1&&G<=k.length).map(G=>{let re=k[G-1];return{name:re.name,command:re.command,argsTemplate:re.argsTemplate,promptVia:re.promptVia}})),_t.length>0?console.log(` ${U(">")} ${D(String(_t.length))} agent(s) selected: ${_t.map(O=>O.name).join(", ")}`):console.log(` ${E("No agents selected.")}`)}let Qo=t.config.codeAgents?.forge,ei=Qo?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
|
|
1372
|
+
${D("Forge Integration (auto-create PRs/MRs after code agent orchestration)?")}`),console.log(`${E("Connects to GitHub or GitLab to push branches and create pull/merge requests.")}`),console.log(`${E("Owner/repo are detected automatically from the git remote at runtime.")}`);let Ac=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let k of Ac){let v=k.name===ei?` ${E("(current)")}`:"";console.log(` ${F}${k.num}${I}) ${k.label}${v}`)}let Rc=ei==="github"?"2":ei==="gitlab"?"3":"1",Pm=(await l.question(`${F}> ${I}${E(`[${Rc}] `)}`)).trim()||Rc,kt=Ac.find(k=>k.num===Pm)?.name??"",Ws="",zs="";if(kt==="github"){console.log(` ${U(">")} Forge: ${D("GitHub")}`);let k=t.env.ALFRED_GITHUB_TOKEN??Qo?.github?.token??"";k&&console.log(` ${E(`Current token: ${ke(k)}`)}`),console.log(` ${E("Create a token at https://github.com/settings/tokens (scope: repo)")}`),Ws=(await l.question(` ${Y}GitHub Token${I}: ${F}`)).trim(),process.stdout.write(I),!Ws&&k&&(Ws=k)}else if(kt==="gitlab"){console.log(` ${U(">")} Forge: ${D("GitLab")}`);let k=t.env.ALFRED_GITLAB_TOKEN??Qo?.gitlab?.token??"";k&&console.log(` ${E(`Current token: ${ke(k)}`)}`),console.log(` ${E("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),zs=(await l.question(` ${Y}GitLab Token${I}: ${F}`)).trim(),process.stdout.write(I),!zs&&k&&(zs=k)}else console.log(` ${E("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);let Um=t.webUiEnabled!==!1?"Y/n":"y/N";console.log(`
|
|
1373
|
+
${D("Web Chat UI (browser-based chat interface)?")}`),console.log(`${E("Serves a web UI at http://host:port/alfred/ \u2014 chat, dashboard, skill health.")}`);let ti=(await l.question(`${F}> ${I}${E(`[${Um}] `)}`)).trim().toLowerCase(),si=ti===""?t.webUiEnabled!==!1:ti==="y"||ti==="yes";console.log(si?` ${U(">")} Web Chat UI ${D("enabled")} \u2014 accessible at /alfred/`:` ${E("Web Chat UI disabled.")}`),console.log(`
|
|
1374
|
+
${D("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${E("Control VMs, containers, network devices, and smart home through Alfred.")}`);let qs=t.config.proxmox,ri=t.env.ALFRED_PROXMOX_BASE_URL??qs?.baseUrl??"",Fm=ri?"Y/n":"y/N",xc=(await l.question(` ${Y}Enable Proxmox VE?${I} ${E(`[${Fm}]`)}: ${F}`)).trim().toLowerCase()||(ri?"y":"n");process.stdout.write(I);let Nn=xc==="y"||xc==="yes",Gs="",ni="",Xs="",oi=!0;if(Nn){Gs=await B(l," Proxmox URL (e.g. https://pve.local:8006)",ri||"https://pve.local:8006");let k=t.env.ALFRED_PROXMOX_TOKEN_ID??qs?.tokenId??"";k&&console.log(` ${E(`Current token ID: ${k}`)}`),console.log(` ${E("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),ni=await B(l," API Token ID (user@realm!name)",k);let v=t.env.ALFRED_PROXMOX_TOKEN_SECRET??qs?.tokenSecret??"";v&&console.log(` ${E(`Current secret: ${ke(v)}`)}`),Xs=(await l.question(` ${Y}API Token Secret${I}: ${F}`)).trim(),process.stdout.write(I),!Xs&&v&&(Xs=v);let R=qs?.verifyTls===!1?"y/N":"Y/n",X=(await l.question(` ${Y}Verify TLS?${I} ${E(`(self-signed? \u2192 no) [${R}]`)}: ${F}`)).trim().toLowerCase()||(qs?.verifyTls===!1?"n":"y");process.stdout.write(I),oi=X==="y"||X==="yes",console.log(` ${U(">")} Proxmox: ${D(Gs)} ${E(`(TLS verify: ${oi?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox disabled.")}`);let Kt=t.config.proxmoxBackup,ii=t.env.ALFRED_PBS_BASE_URL??Kt?.baseUrl??"",jm=ii?"Y/n":"y/N",Cc=(await l.question(`
|
|
1375
|
+
${Y}Enable Proxmox Backup Server?${I} ${E(`[${jm}]`)}: ${F}`)).trim().toLowerCase()||(ii?"y":"n");process.stdout.write(I);let Ln=Cc==="y"||Cc==="yes",Ks="",ai="",Vs="",Ys=24,Dn=!0;if(Ln){Ks=await B(l," PBS URL (e.g. https://pbs.local:8007)",ii||"https://pbs.local:8007");let k=t.env.ALFRED_PBS_TOKEN_ID??Kt?.tokenId??"";k&&console.log(` ${E(`Current token ID: ${k}`)}`),console.log(` ${E("Create: Configuration \u2192 Access Control \u2192 API Token")}`),ai=await B(l," API Token ID (user@realm!name)",k);let v=t.env.ALFRED_PBS_TOKEN_SECRET??Kt?.tokenSecret??"";v&&console.log(` ${E(`Current secret: ${ke(v)}`)}`),Vs=(await l.question(` ${Y}API Token Secret${I}: ${F}`)).trim(),process.stdout.write(I),!Vs&&v&&(Vs=v);let R=t.env.ALFRED_PBS_MAX_AGE_HOURS??Kt?.maxAgeHours?.toString()??"24";Ys=parseInt(await B(l," Max backup age (hours, alert if older)",R),10)||24;let X=Kt?.verifyTls===!1?"y/N":"Y/n",O=(await l.question(` ${Y}Verify TLS?${I} ${E(`(self-signed? \u2192 no) [${X}]`)}: ${F}`)).trim().toLowerCase()||(Kt?.verifyTls===!1?"n":"y");process.stdout.write(I),Dn=O==="y"||O==="yes",console.log(` ${U(">")} PBS: ${D(Ks)} ${E(`(max age: ${Ys}h, TLS verify: ${Dn?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox Backup Server disabled.")}`);let Et=t.config.unifi,ci=t.env.ALFRED_UNIFI_BASE_URL??Et?.baseUrl??"",Bm=ci?"Y/n":"y/N",Nc=(await l.question(`
|
|
1376
|
+
${Y}Enable UniFi Network?${I} ${E(`[${Bm}]`)}: ${F}`)).trim().toLowerCase()||(ci?"y":"n");process.stdout.write(I);let Js=Nc==="y"||Nc==="yes",Vt="",bt="",li="",Zs="",di=!0;if(Js){Vt=await B(l," UniFi URL (e.g. https://unifi.local)",ci||"https://unifi.local"),console.log(` ${E("Auth: API Key (recommended) or Username/Password")}`);let k=t.env.ALFRED_UNIFI_API_KEY??Et?.apiKey??"",v=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],R=k?"1":Et?.username?"2":"1";for(let re of v)console.log(` ${F}${re.num}${I}) ${re.label}`);if(((await l.question(` ${F}> ${I}${E(`[${R}] `)}`)).trim()||R)==="1")k&&console.log(` ${E(`Current key: ${ke(k)}`)}`),console.log(` ${E("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),bt=(await l.question(` ${Y}API Key${I}: ${F}`)).trim(),process.stdout.write(I),!bt&&k&&(bt=k);else{let re=t.env.ALFRED_UNIFI_USERNAME??Et?.username??"";li=await B(l," Username",re||"alfred");let Se=t.env.ALFRED_UNIFI_PASSWORD??Et?.password??"";Se&&console.log(` ${E(`Current password: ${ke(Se)}`)}`),Zs=(await l.question(` ${Y}Password${I}: ${F}`)).trim(),process.stdout.write(I),!Zs&&Se&&(Zs=Se)}let O=Et?.verifyTls===!1?"y/N":"Y/n",G=(await l.question(` ${Y}Verify TLS?${I} ${E(`(self-signed? \u2192 no) [${O}]`)}: ${F}`)).trim().toLowerCase()||(Et?.verifyTls===!1?"n":"y");process.stdout.write(I),di=G==="y"||G==="yes",console.log(` ${U(">")} UniFi: ${D(Vt)} ${E(`(TLS verify: ${di?"yes":"no"})`)}`)}else console.log(` ${E("UniFi disabled.")}`);let Mn=t.config.homeassistant,ui=t.env.ALFRED_HOMEASSISTANT_URL??Mn?.baseUrl??"",Hm=ui?"Y/n":"y/N",Lc=(await l.question(`
|
|
1377
|
+
${Y}Enable Home Assistant?${I} ${E(`[${Hm}]`)}: ${F}`)).trim().toLowerCase()||(ui?"y":"n");process.stdout.write(I);let On=Lc==="y"||Lc==="yes",Qs="",er="",mi=!0;if(On){Qs=await B(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",ui||"http://homeassistant.local:8123");let k=t.env.ALFRED_HOMEASSISTANT_TOKEN??Mn?.accessToken??"";k&&console.log(` ${E(`Current token: ${ke(k)}`)}`),console.log(` ${E("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),er=(await l.question(` ${Y}Long-Lived Access Token${I}: ${F}`)).trim(),process.stdout.write(I),!er&&k&&(er=k);let v=Mn?.verifyTls===!1?"y/N":"Y/n",R=(await l.question(` ${Y}Verify TLS?${I} ${E(`(self-signed? \u2192 no) [${v}]`)}: ${F}`)).trim().toLowerCase()||(Mn?.verifyTls===!1?"n":"y");process.stdout.write(I),mi=R==="y"||R==="yes",console.log(` ${U(">")} Home Assistant: ${D(Qs)} ${E(`(TLS verify: ${mi?"yes":"no"})`)}`)}else console.log(` ${E("Home Assistant disabled.")}`);let Pe=t.config.contacts,pi=t.env.ALFRED_CONTACTS_PROVIDER??Pe?.provider??"",Wm=pi?"Y/n":"y/N",Dc=(await l.question(`
|
|
1378
|
+
${Y}Enable Contacts management?${I} ${E(`[${Wm}]`)}: ${F}`)).trim().toLowerCase()||(pi?"y":"n");process.stdout.write(I);let Pn=Dc==="y"||Dc==="yes",Ue="",we={};if(Pn){let k=["carddav","google","microsoft"],v=k.indexOf(pi),R=v>=0?v+1:1;console.log(` ${_e("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${_e("2)")} Google Contacts`),console.log(` ${_e("3)")} Microsoft 365`);let X=await xn(l," > ",1,3,R);if(Ue=k[X-1],we.ALFRED_CONTACTS_PROVIDER=Ue,Ue==="carddav"){let O=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Pe?.carddav?.serverUrl??"";we.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await B(l," CardDAV Server URL",O||"https://cloud.example.com/remote.php/dav");let G=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Pe?.carddav?.username??"";we.ALFRED_CARDDAV_CONTACTS_USERNAME=await B(l," Username",G);let re=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Pe?.carddav?.password??"";re&&console.log(` ${E(`Current password: ${ke(re)}`)}`);let Se=(await l.question(` ${Y}Password${I}: ${F}`)).trim();process.stdout.write(I),we.ALFRED_CARDDAV_CONTACTS_PASSWORD=Se||re}else if(Ue==="google"){let O=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Pe?.google?.clientId??"";O&&console.log(` ${E(`Current client ID: ${ke(O)}`)}`),we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${Y}Google Client ID${I}: ${F}`)).trim()||O,process.stdout.write(I);let G=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Pe?.google?.clientSecret??"";we.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${Y}Google Client Secret${I}: ${F}`)).trim()||G,process.stdout.write(I);let re=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Pe?.google?.refreshToken??"";we.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${Y}Refresh Token${I}: ${F}`)).trim()||re,process.stdout.write(I)}else if(Ue==="microsoft"){let O=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Pe?.microsoft?.clientId??"";O&&console.log(` ${E(`Current client ID: ${ke(O)}`)}`),we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${Y}Microsoft Client ID${I}: ${F}`)).trim()||O,process.stdout.write(I);let G=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Pe?.microsoft?.clientSecret??"";we.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${Y}Microsoft Client Secret${I}: ${F}`)).trim()||G,process.stdout.write(I);let re=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Pe?.microsoft?.tenantId??"";we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await B(l," Tenant ID",re||"common");let Se=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Pe?.microsoft?.refreshToken??"";console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),we.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${Y}Refresh Token${I}: ${F}`)).trim()||Se,process.stdout.write(I)}console.log(` ${U(">")} Contacts: ${D(Ue)}`)}else console.log(` ${E("Contacts disabled.")}`);let Mc=t.config.docker,hi=t.env.ALFRED_DOCKER_SOCKET_PATH??Mc?.socketPath??"",fi=t.env.ALFRED_DOCKER_HOST??Mc?.host??"",zm=hi||fi?"Y/n":"y/N",Oc=(await l.question(`
|
|
1379
|
+
${Y}Enable Docker management?${I} ${E(`[${zm}]`)}: ${F}`)).trim().toLowerCase()||(hi||fi?"y":"n");process.stdout.write(I);let Un=Oc==="y"||Oc==="yes",St="",vt="";if(Un){let k=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${E("Use socket path for local Docker, or host URL for remote.")}`),St=await B(l," Docker socket path",hi||k);let v=(await l.question(` ${Y}Docker host URL (optional, for remote)${I}: ${F}`)).trim();process.stdout.write(I),vt=v||fi,console.log(` ${U(">")} Docker: ${D(vt||St)}`)}else console.log(` ${E("Docker disabled.")}`);let qm=t.config.bmw,gi=t.env.ALFRED_BMW_CLIENT_ID??qm?.clientId??"",Gm=gi?"Y/n":"y/N",Pc=(await l.question(`
|
|
1380
|
+
${Y}Enable BMW CarData (vehicle status, charging)?${I} ${E(`[${Gm}]`)}: ${F}`)).trim().toLowerCase()||(gi?"y":"n");process.stdout.write(I);let Fn=Pc==="y"||Pc==="yes",yi="";Fn?(console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://bmw-cardata.bmwgroup.com/customer")}`),console.log(` ${E(" 2. Login mit deinem MyBMW-Account")}`),console.log(` ${E(" 3. Client-ID generieren")}`),console.log(` ${E(' 4. Scope "CarData API" aktivieren (ca. 60s warten)')}`),yi=await B(l," BMW CarData Client ID",gi),console.log(` ${U(">")} BMW CarData: ${D("enabled")}`)):console.log(` ${E("BMW CarData disabled.")}`);let Xm=t.config.routing,wi=t.env.ALFRED_ROUTING_API_KEY??Xm?.apiKey??"",Km=wi?"Y/n":"y/N",Uc=(await l.question(`
|
|
1381
|
+
${Y}Enable route planning with live traffic (Google Routes)?${I} ${E(`[${Km}]`)}: ${F}`)).trim().toLowerCase()||(wi?"y":"n");process.stdout.write(I);let jn=Uc==="y"||Uc==="yes",Ti="";jn?(console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${E(" 2. Routes API aktivieren")}`),console.log(` ${E(" 3. API Key erstellen")}`),Ti=await B(l," Google Maps API Key",wi),console.log(` ${U(">")} Routing: ${D("enabled")}`)):console.log(` ${E("Routing disabled.")}`);let et=t.config.energy,Vm=t.env.ALFRED_ENERGY_GRID_NAME??et?.gridName??"",_i=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(et?.gridUsageCt!=null?String(et.gridUsageCt):""),Ym=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(et?.gridLossCt!=null?String(et.gridLossCt):""),Jm=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(et?.gridCapacityFee!=null?String(et.gridCapacityFee):""),Zm=t.env.ALFRED_ENERGY_GRID_METER_FEE??(et?.gridMeterFee!=null?String(et.gridMeterFee):""),Qm=_i?"Y/n":"y/N",Fc=(await l.question(`
|
|
1382
|
+
${Y}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${I} ${E(`[${Qm}]`)}: ${F}`)).trim().toLowerCase()||(_i?"y":"n");process.stdout.write(I);let Bn=Fc==="y"||Fc==="yes",$t="",It="",Hn="",tr="",sr="";Bn?(console.log(` ${E('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${E("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),$t=await B(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",Vm),It=await B(l," Netznutzungsentgelt (ct/kWh netto)",_i),Hn=await B(l," Netzverlustentgelt (ct/kWh netto)",Ym||"0.38"),tr=await B(l," Leistungspauschale (\u20AC/Monat netto)",Jm),sr=await B(l," Messentgelt (\u20AC/Monat netto)",Zm||"2.22"),console.log(` ${U(">")} Energy: ${D($t||"enabled")} (${It} + ${Hn} ct/kWh)`)):console.log(` ${E("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
|
|
1383
|
+
${D("Security configuration:")}`);let jc=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",Re;if(jc)Re=await B(l,"Owner user ID (for elevated permissions)",jc);else{let k=(await l.question(`${Y}Owner user ID${I} ${E("(optional, for elevated permissions)")}: ${F}`)).trim();process.stdout.write(I),Re=k}let rr=!1;if(Re){let k=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${D("Enable shell access (admin commands) for the owner?")}`),console.log(` ${E("Allows Alfred to execute shell commands. Only for the owner.")}`);let v=(await l.question(` ${F}> ${I}${E(`[${k}] `)}`)).trim().toLowerCase();v===""?rr=t.shellEnabled:rr=v==="y"||v==="yes",console.log(rr?` ${U(">")} Shell access ${D("enabled")} for owner ${E(Re)}`:` ${E("Shell access disabled.")}`)}let ep=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${D("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${E("By default, write actions are only allowed in DMs.")}`);let ki=(await l.question(` ${F}> ${I}${E(`[${ep}] `)}`)).trim().toLowerCase(),nr;ki===""?nr=t.writeInGroups:nr=ki==="y"||ki==="yes",console.log(nr?` ${U(">")} Write actions ${D("enabled")} in groups`:` ${E("Write actions only in DMs (default).")}`);let tp=t.rateLimit??30;console.log("");let sp=await B(l," Rate limit (max write actions per hour per user)",String(tp)),Wn=Math.max(1,parseInt(sp,10)||30);console.log(` ${U(">")} Rate limit: ${D(String(Wn))} per hour`),console.log(`
|
|
1384
|
+
${D("Writing configuration files...")}`);let A=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let k=a.envKeyName||"ALFRED_OLLAMA_API_KEY";A.push(`${k}=${c}`)}if(f!==a.defaultModel&&A.push(`ALFRED_LLM_MODEL=${f}`),u&&A.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(N).length>0){A.push("","# === Additional Model Tiers ===");for(let[k,v]of Object.entries(N)){let R=`ALFRED_LLM_${k.toUpperCase()}`;A.push(""),A.push(`${R}_PROVIDER=${v.provider}`),A.push(`${R}_MODEL=${v.model}`),v.apiKey&&A.push(`${R}_API_KEY=${v.apiKey}`),v.baseUrl&&A.push(`${R}_BASE_URL=${v.baseUrl}`)}}A.push("","# === Messaging Platforms ===","");for(let[k,v]of Object.entries(Oe))A.push(`${k}=${v}`);if(A.push("","# === Web Search ===",""),se?(A.push(`ALFRED_SEARCH_PROVIDER=${se}`),ne&&A.push(`ALFRED_SEARCH_API_KEY=${ne}`),Z&&A.push(`ALFRED_SEARCH_BASE_URL=${Z}`)):(A.push("# ALFRED_SEARCH_PROVIDER=brave"),A.push("# ALFRED_SEARCH_API_KEY=")),A.push("","# === Email ===",""),q&&z.length>0){let k=z[0];k.provider==="microsoft"?(A.push("ALFRED_EMAIL_PROVIDER=microsoft"),k.msClientId?(A.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${k.msClientId}`),A.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${k.msClientSecret}`),A.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${k.msTenantId}`),A.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${k.msRefreshToken}`)):A.push("# Microsoft email credentials shared from calendar config")):(A.push(`ALFRED_EMAIL_USER=${k.user}`),A.push(`ALFRED_EMAIL_PASS=${k.pass}`)),z.length>1&&A.push("# Additional email accounts configured in config/default.yml")}else A.push("# ALFRED_EMAIL_USER="),A.push("# ALFRED_EMAIL_PASS=");if(A.push("","# === Speech ===",""),Ve?(A.push(`ALFRED_SPEECH_PROVIDER=${Ve}`),A.push(`ALFRED_SPEECH_API_KEY=${lt}`),js&&A.push(`ALFRED_SPEECH_BASE_URL=${js}`),Bs&&(A.push("ALFRED_TTS_ENABLED=true"),A.push(`ALFRED_TTS_VOICE=${Hs}`))):(A.push("# ALFRED_SPEECH_PROVIDER=groq"),A.push("# ALFRED_SPEECH_API_KEY=")),A.push("","# === Forge (GitHub / GitLab) ===",""),kt==="github"?(A.push("ALFRED_FORGE_PROVIDER=github"),A.push(`ALFRED_GITHUB_TOKEN=${Ws}`)):kt==="gitlab"?(A.push("ALFRED_FORGE_PROVIDER=gitlab"),A.push(`ALFRED_GITLAB_TOKEN=${zs}`)):(A.push("# ALFRED_FORGE_PROVIDER=github"),A.push("# ALFRED_GITHUB_TOKEN=")),A.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),Nn?(A.push(`ALFRED_PROXMOX_BASE_URL=${Gs}`),A.push(`ALFRED_PROXMOX_TOKEN_ID=${ni}`),A.push(`ALFRED_PROXMOX_TOKEN_SECRET=${Xs}`)):(A.push("# ALFRED_PROXMOX_BASE_URL="),A.push("# ALFRED_PROXMOX_TOKEN_ID="),A.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),Ln?(A.push(`ALFRED_PBS_BASE_URL=${Ks}`),A.push(`ALFRED_PBS_TOKEN_ID=${ai}`),A.push(`ALFRED_PBS_TOKEN_SECRET=${Vs}`),A.push(`ALFRED_PBS_MAX_AGE_HOURS=${Ys}`),Dn||A.push("ALFRED_PBS_VERIFY_TLS=false")):(A.push("# ALFRED_PBS_BASE_URL="),A.push("# ALFRED_PBS_TOKEN_ID="),A.push("# ALFRED_PBS_TOKEN_SECRET=")),Js&&bt?(A.push(`ALFRED_UNIFI_BASE_URL=${Vt}`),A.push(`ALFRED_UNIFI_API_KEY=${bt}`)):Js?(A.push(`ALFRED_UNIFI_BASE_URL=${Vt}`),A.push(`ALFRED_UNIFI_USERNAME=${li}`),A.push(`ALFRED_UNIFI_PASSWORD=${Zs}`)):(A.push("# ALFRED_UNIFI_BASE_URL="),A.push("# ALFRED_UNIFI_API_KEY=")),On?(A.push(`ALFRED_HOMEASSISTANT_URL=${Qs}`),A.push(`ALFRED_HOMEASSISTANT_TOKEN=${er}`)):(A.push("# ALFRED_HOMEASSISTANT_URL="),A.push("# ALFRED_HOMEASSISTANT_TOKEN=")),A.push("","# === Contacts ===",""),Pn)for(let[k,v]of Object.entries(we))A.push(`${k}=${v}`);else A.push("# ALFRED_CONTACTS_PROVIDER=carddav");A.push("","# === Docker ===",""),Un?(St&&A.push(`ALFRED_DOCKER_SOCKET_PATH=${St}`),vt&&A.push(`ALFRED_DOCKER_HOST=${vt}`)):(A.push("# ALFRED_DOCKER_SOCKET_PATH="),A.push("# ALFRED_DOCKER_HOST=")),A.push("","# === BMW CarData ===",""),Fn?A.push(`ALFRED_BMW_CLIENT_ID=${yi}`):A.push("# ALFRED_BMW_CLIENT_ID="),A.push("","# === Routing ===",""),jn?A.push(`ALFRED_ROUTING_API_KEY=${Ti}`):A.push("# ALFRED_ROUTING_API_KEY="),A.push("","# === Energy / aWATTar ===",""),Bn&&It?($t&&A.push(`ALFRED_ENERGY_GRID_NAME=${$t}`),A.push(`ALFRED_ENERGY_GRID_USAGE_CT=${It}`),A.push(`ALFRED_ENERGY_GRID_LOSS_CT=${Hn}`),tr&&A.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${tr}`),sr&&A.push(`ALFRED_ENERGY_GRID_METER_FEE=${sr}`)):(A.push("# ALFRED_ENERGY_GRID_NAME="),A.push("# ALFRED_ENERGY_GRID_USAGE_CT="),A.push("# ALFRED_ENERGY_GRID_LOSS_CT="),A.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),A.push("# ALFRED_ENERGY_GRID_METER_FEE=")),A.push("","# === Security ===",""),Re?A.push(`ALFRED_OWNER_USER_ID=${Re}`):A.push("# ALFRED_OWNER_USER_ID="),A.push("");let rp=Ie.join(e,".env");Ee.writeFileSync(rp,A.join(`
|
|
1385
|
+
`),"utf-8"),console.log(` ${U("+")} ${E(".env")} written`);let zn=Ie.join(e,"config");Ee.existsSync(zn)||Ee.mkdirSync(zn,{recursive:!0});let Bc={name:r,telegram:{token:me.telegram?.token??"",enabled:ce.some(k=>k.name==="telegram")},discord:{token:me.discord?.token??"",enabled:ce.some(k=>k.name==="discord")},whatsapp:{enabled:ce.some(k=>k.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:me.matrix?.homeserverUrl??"https://matrix.org",accessToken:me.matrix?.accessToken??"",userId:me.matrix?.userId??"",enabled:ce.some(k=>k.name==="matrix")},signal:{apiUrl:me.signal?.apiUrl??"http://localhost:8080",phoneNumber:me.signal?.phoneNumber??"",enabled:ce.some(k=>k.name==="signal")},llm:Object.keys(N).length>0?{default:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...N}:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...se?{search:{provider:se,...ne?{apiKey:ne}:{},...Z?{baseUrl:Z}:{}}}:{},...q&&z.length>0?{email:{accounts:z.map(k=>k.provider==="microsoft"?{name:k.name,provider:"microsoft",...k.msClientId?{microsoft:{clientId:k.msClientId,clientSecret:k.msClientSecret,tenantId:k.msTenantId,refreshToken:k.msRefreshToken}}:{}}:{name:k.name,imap:{host:k.imapHost,port:k.imapPort,secure:k.imapPort===993},smtp:{host:k.smtpHost,port:k.smtpPort,secure:k.smtpPort===465},auth:{user:k.user,pass:k.pass}})}}:{},...Ve?{speech:{provider:Ve,apiKey:lt,...js?{baseUrl:js}:{},...Bs?{ttsEnabled:!0,ttsVoice:Hs}:{}}}:{},...Yo?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},..._t.length>0||kt?{codeAgents:{enabled:_t.length>0,agents:_t,...kt==="github"?{forge:{provider:"github",github:{token:Ws}}}:kt==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:zs}}}:{}}}:{},...Nn?{proxmox:{baseUrl:Gs,tokenId:ni,tokenSecret:Xs,verifyTls:oi}}:{},...Ln?{proxmoxBackup:{baseUrl:Ks,tokenId:ai,tokenSecret:Vs,maxAgeHours:Ys,verifyTls:Dn}}:{},...Js?{unifi:{baseUrl:Vt,...bt?{apiKey:bt}:{username:li,password:Zs},site:"default",verifyTls:di}}:{},...On?{homeassistant:{baseUrl:Qs,accessToken:er,verifyTls:mi}}:{},...Pn?{contacts:{provider:Ue,...Ue==="carddav"?{carddav:{serverUrl:we.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:we.ALFRED_CARDDAV_CONTACTS_USERNAME}}:Ue==="google"?{google:{clientId:we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:Ue==="microsoft"?{microsoft:{clientId:we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Un?{docker:{...St?{socketPath:St}:{},...vt?{host:vt}:{}}}:{},...Fn?{bmw:{clientId:yi}}:{},...jn?{routing:{apiKey:Ti}}:{},...Bn&&It?{energy:{...$t?{gridName:$t}:{},gridUsageCt:parseFloat(It),gridLossCt:parseFloat(Hn||"0"),...tr?{gridCapacityFee:parseFloat(tr)}:{},...sr?{gridMeterFee:parseFloat(sr)}:{}}}:{},api:{enabled:!0,port:3420,host:"127.0.0.1",webUi:si},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};Re&&(Bc.security.ownerUserId=Re);let np="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+bc.dump(Bc,{lineWidth:120,noRefs:!0,sortKeys:!1}),op=Ie.join(zn,"default.yml");Ee.writeFileSync(op,np,"utf-8"),console.log(` ${U("+")} ${E("config/default.yml")} written`);let Ei=Ie.join(zn,"rules");Ee.existsSync(Ei)||Ee.mkdirSync(Ei,{recursive:!0});let ip=rr&&Re?`
|
|
1356
1386
|
# Allow admin actions (shell, etc.) for the owner only
|
|
1357
1387
|
- id: allow-owner-admin
|
|
1358
1388
|
effect: allow
|
|
@@ -1361,7 +1391,7 @@ ${L("Writing configuration files...")}`);let I=["# Alfred Environment Variables"
|
|
|
1361
1391
|
actions: ["*"]
|
|
1362
1392
|
riskLevels: [admin, destructive]
|
|
1363
1393
|
conditions:
|
|
1364
|
-
users: ["${
|
|
1394
|
+
users: ["${Re}"]
|
|
1365
1395
|
`:`
|
|
1366
1396
|
# Allow admin actions (shell, etc.) for the owner only
|
|
1367
1397
|
# Uncomment and set your user ID to enable:
|
|
@@ -1372,8 +1402,8 @@ ${L("Writing configuration files...")}`);let I=["# Alfred Environment Variables"
|
|
|
1372
1402
|
# actions: ["*"]
|
|
1373
1403
|
# riskLevels: [admin, destructive]
|
|
1374
1404
|
# conditions:
|
|
1375
|
-
# users: ["${
|
|
1376
|
-
`,
|
|
1405
|
+
# users: ["${Re||"YOUR_USER_ID_HERE"}"]
|
|
1406
|
+
`,ap=`# Alfred \u2014 Default Security Rules
|
|
1377
1407
|
# Rules are evaluated in priority order (lower number = higher priority).
|
|
1378
1408
|
# First matching rule wins.
|
|
1379
1409
|
|
|
@@ -1386,7 +1416,7 @@ rules:
|
|
|
1386
1416
|
actions: ["*"]
|
|
1387
1417
|
riskLevels: [read]
|
|
1388
1418
|
|
|
1389
|
-
${
|
|
1419
|
+
${nr?` # Allow write-level skills everywhere (DMs and groups)
|
|
1390
1420
|
- id: allow-write-all
|
|
1391
1421
|
effect: allow
|
|
1392
1422
|
priority: 200
|
|
@@ -1402,7 +1432,7 @@ ${Qs?` # Allow write-level skills everywhere (DMs and groups)
|
|
|
1402
1432
|
conditions:
|
|
1403
1433
|
chatType: dm`}
|
|
1404
1434
|
|
|
1405
|
-
# Rate-limit write actions: max ${
|
|
1435
|
+
# Rate-limit write actions: max ${Wn} per hour per user
|
|
1406
1436
|
- id: rate-limit-write
|
|
1407
1437
|
effect: allow
|
|
1408
1438
|
priority: 250
|
|
@@ -1410,9 +1440,9 @@ ${Qs?` # Allow write-level skills everywhere (DMs and groups)
|
|
|
1410
1440
|
actions: ["*"]
|
|
1411
1441
|
riskLevels: [write]
|
|
1412
1442
|
rateLimit:
|
|
1413
|
-
maxInvocations: ${
|
|
1443
|
+
maxInvocations: ${Wn}
|
|
1414
1444
|
windowSeconds: 3600
|
|
1415
|
-
${
|
|
1445
|
+
${ip}
|
|
1416
1446
|
# Deny destructive and admin actions by default
|
|
1417
1447
|
- id: deny-destructive
|
|
1418
1448
|
effect: deny
|
|
@@ -1428,24 +1458,24 @@ ${Wm}
|
|
|
1428
1458
|
scope: global
|
|
1429
1459
|
actions: ["*"]
|
|
1430
1460
|
riskLevels: [read, write, destructive, admin]
|
|
1431
|
-
`,
|
|
1432
|
-
${
|
|
1461
|
+
`,cp=Ie.join(Ei,"default-rules.yml");Ee.writeFileSync(cp,ap,"utf-8"),console.log(` ${U("+")} ${E("config/rules/default-rules.yml")} written`);let Hc=Ie.join(e,"data");Ee.existsSync(Hc)||(Ee.mkdirSync(Hc,{recursive:!0}),console.log(` ${U("+")} ${E("data/")} directory created`)),console.log(""),console.log(`${zo}${"=".repeat(52)}${I}`),console.log(`${zo}${Y} Setup complete!${I}`),console.log(`${zo}${"=".repeat(52)}${I}`),console.log(""),console.log(` ${D("Bot name:")} ${r}`),console.log(` ${D("LLM default:")} ${a.name} (${f})`),c&&console.log(` ${D("API key:")} ${ke(c)}`);for(let[k,v]of Object.entries(N)){let R=k.charAt(0).toUpperCase()+k.slice(1);console.log(` ${D(`LLM ${R}:`)}${" ".repeat(Math.max(1,10-R.length))}${v.provider} (${v.model})`)}if(ce.length>0?console.log(` ${D("Platforms:")} ${ce.map(k=>k.label).join(", ")}`):console.log(` ${D("Platforms:")} none (configure later)`),se){let k={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${Z})`};console.log(` ${D("Web search:")} ${k[se]}`)}else console.log(` ${D("Web search:")} ${E("disabled")}`);if(q&&z.length>0){let k=z.map(v=>v.provider==="microsoft"?`${v.name} (Microsoft 365)${v.msClientId?"":" \u2014 shared from Calendar"}`:`${v.name} (${v.imapHost})`);console.log(` ${D("Email:")} ${k.join(", ")}`)}else console.log(` ${D("Email:")} ${E("disabled")}`);if(Ve){let k={openai:"OpenAI Whisper",groq:"Groq Whisper"},v=Bs?`, TTS: ${Hs}`:"";console.log(` ${D("Voice:")} ${k[Ve]}${v}`)}else console.log(` ${D("Voice:")} ${E("disabled")}`);console.log(` ${D("Code Sandbox:")} ${Yo?U("enabled"):E("disabled")}`),console.log(` ${D("Web Chat UI:")} ${si?U("enabled (/alfred/)"):E("disabled")}`),Nn&&console.log(` ${D("Proxmox:")} ${U(Gs)}`),Ln&&console.log(` ${D("PBS:")} ${U(Ks)} ${E(`(max age: ${Ys}h)`)}`),Js&&console.log(` ${D("UniFi:")} ${U(Vt)}`),On&&console.log(` ${D("Home Assist.:")} ${U(Qs)}`),Pn&&console.log(` ${D("Contacts:")} ${U(Ue)}`),Un&&console.log(` ${D("Docker:")} ${U(vt||St)}`),Fn&&console.log(` ${D("BMW CarData:")} ${U("enabled")}`),jn&&console.log(` ${D("Routing:")} ${U("enabled")}`),Bn&&console.log(` ${D("Energy:")} ${U($t||"enabled")} ${E(`(${It} ct/kWh)`)}`),Re&&(console.log(` ${D("Owner ID:")} ${Re}`),console.log(` ${D("Shell access:")} ${rr?U("enabled"):E("disabled")}`)),console.log(` ${D("Write scope:")} ${nr?"DMs + Groups":"DMs only"}`),console.log(` ${D("Rate limit:")} ${Wn}/hour per user`),console.log(""),console.log(`${qo}Next steps:${I}`),console.log(` ${D("alfred start")} Start Alfred`),console.log(` ${D("alfred status")} Check configuration`),console.log(` ${D("alfred --help")} Show all commands`),console.log(""),console.log(`${yt}Edit ${D(".env")}${yt} or ${D("config/default.yml")}${yt} for manual configuration.${I}`),console.log("")}finally{l.close()}}async function B(l,e,t){let s=(await l.question(`${Y}${e}${I} ${E(`[${t}]`)}: ${F}`)).trim();return process.stdout.write(I),s||t}async function Le(l,e){for(;;){let t=(await l.question(`${Y}${e}${I}: ${F}`)).trim();if(process.stdout.write(I),t)return t;console.log(` ${wm("!")} This field is required. Please enter a value.`)}}async function xn(l,e,t,s,r){for(;;){let n=(await l.question(`${F}${e}${I}`)).trim();if(!n)return r;let o=parseInt(n,10);if(!Number.isNaN(o)&&o>=t&&o<=s)return o;console.log(` ${wm("!")} Please enter a number between ${t} and ${s}.`)}}function bg(){console.log(`
|
|
1462
|
+
${wg}${Y} _ _ _____ ____ _____ ____
|
|
1433
1463
|
/ \\ | | | ___| _ \\| ____| _ \\
|
|
1434
1464
|
/ _ \\ | | | |_ | |_) | _| | | | |
|
|
1435
1465
|
/ ___ \\| |___| _| | _ <| |___| |_| |
|
|
1436
|
-
/_/ \\_\\_____|_| |_| \\_\\_____|____/ ${
|
|
1437
|
-
${
|
|
1438
|
-
`)}var A,K,ft,Uo,F,Fo,Jf,Zf,it,Ds,em,rm=T(()=>{"use strict";cc();A="\x1B[0m",K="\x1B[1m",ft="\x1B[2m",Uo="\x1B[32m",F="\x1B[33m",Fo="\x1B[36m",Jf="\x1B[31m",Zf="\x1B[35m";m(U,"green");m(Qf,"yellow");m(_e,"cyan");m(tm,"red");m(L,"bold");m(E,"dim");m(ke,"maskKey");it=[{name:"anthropic",label:"Anthropic (Claude) \u2014 recommended",defaultModel:"claude-sonnet-4-20250514",envKeyName:"ALFRED_ANTHROPIC_API_KEY",needsApiKey:!0,models:[{id:"claude-sonnet-4-20250514",desc:"Sonnet 4 \u2014 fast, smart, recommended"},{id:"claude-opus-4-20250514",desc:"Opus 4 \u2014 most capable, slower"},{id:"claude-haiku-4-5-20251001",desc:"Haiku 4.5 \u2014 fastest, cheapest"}]},{name:"openai",label:"OpenAI (GPT)",defaultModel:"gpt-4o",envKeyName:"ALFRED_OPENAI_API_KEY",needsApiKey:!0,models:[{id:"gpt-4o",desc:"GPT-4o \u2014 flagship, 128k context"},{id:"gpt-4o-mini",desc:"GPT-4o Mini \u2014 fast, cheap, 128k context"},{id:"o3-mini",desc:"o3-mini \u2014 reasoning, 200k context"}]},{name:"openrouter",label:"OpenRouter (multiple providers)",defaultModel:"anthropic/claude-sonnet-4-20250514",envKeyName:"ALFRED_OPENROUTER_API_KEY",needsApiKey:!0,baseUrl:"https://openrouter.ai/api/v1"},{name:"ollama",label:"Ollama (local, no API key needed)",defaultModel:"llama3.2",envKeyName:"",needsApiKey:!1,baseUrl:"http://localhost:11434"},{name:"openwebui",label:"OpenWebUI (local OpenAI-compatible UI)",defaultModel:"llama3.2",envKeyName:"ALFRED_OPENWEBUI_API_KEY",needsApiKey:!0,baseUrl:"http://localhost:3000/api/v1"},{name:"google",label:"Google (Gemini)",defaultModel:"gemini-2.0-flash",envKeyName:"ALFRED_GOOGLE_API_KEY",needsApiKey:!0,models:[{id:"gemini-2.0-flash",desc:"Flash 2.0 \u2014 fast, 1M context"},{id:"gemini-2.0-pro",desc:"Pro 2.0 \u2014 capable, 1M context"},{id:"gemini-1.5-pro",desc:"Pro 1.5 \u2014 2M context"},{id:"gemini-1.5-flash",desc:"Flash 1.5 \u2014 fast, 1M context"}]},{name:"mistral",label:"Mistral AI",defaultModel:"mistral-small-latest",envKeyName:"ALFRED_MISTRAL_API_KEY",needsApiKey:!0,models:[{id:"mistral-small-latest",desc:"Small 3.2 \u2014 fast, 128k context, best value"},{id:"mistral-medium-latest",desc:"Medium 3.1 \u2014 balanced, 128k context"},{id:"mistral-large-latest",desc:"Large 3 \u2014 flagship, 256k context"},{id:"codestral-latest",desc:"Codestral \u2014 code-optimized, 256k context"},{id:"magistral-medium-latest",desc:"Magistral Medium \u2014 reasoning, 40k context"},{id:"magistral-small-latest",desc:"Magistral Small \u2014 reasoning (light), 40k context"},{id:"ministral-8b-latest",desc:"Ministral 8B \u2014 edge/tiny, 128k context"}]}],Ds=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];m(eg,"findCommand");em=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];m(tg,"loadExistingConfig");m(sg,"setupCommand");m(H,"askWithDefault");m(Le,"askRequired");m(bn,"askNumber");m(rg,"printBanner")});var om={};he(om,{configCommand:()=>ag});function og(l){let e=l.toLowerCase();return ng.some(t=>e.includes(t))}function ig(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function nm(l){let e={};for(let[t,s]of Object.entries(l))og(t)?e[t]=ig(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=nm(s):e[t]=s;return e}async function ag(){let l=new pe,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=nm(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var ng,im=T(()=>{"use strict";tt();ng=["token","apikey","api_key","accesstoken","secret","password"];m(og,"isSensitiveKey");m(ig,"redactValue");m(nm,"redactObject");m(ag,"configCommand")});var cm={};he(cm,{rulesCommand:()=>lg});import jo from"node:fs";import am from"node:path";import cg from"js-yaml";async function lg(){let l=new pe,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=am.resolve(e.security.rulesPath);if(!jo.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}jo.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=jo.readdirSync(t).filter(a=>a.endsWith(".yml")||a.endsWith(".yaml"));if(r.length===0){console.log(`No YAML rule files found in: ${t}`);return}let n=new rt,o=[],i=[];for(let a of r){let c=am.join(t,a);try{let d=jo.readFileSync(c,"utf-8"),u=cg.load(d),p=n.loadFromObject(u);o.push(...p)}catch(d){i.push(` ${a}: ${d.message}`)}}if(console.log("Alfred \u2014 Security Rules"),console.log("======================="),console.log(`Rules directory: ${t}`),console.log(`Rule files found: ${r.length}`),console.log(`Total rules loaded: ${o.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(o.length!==0){o.sort((a,c)=>a.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of o){let c=a.rateLimit?` | rate-limit: ${a.rateLimit.maxInvocations}/${a.rateLimit.windowSeconds}s`:"";console.log(` [${a.priority}] ${a.id}`),console.log(` effect: ${a.effect} | scope: ${a.scope}`),console.log(` actions: ${a.actions.join(", ")}`),console.log(` risk levels: ${a.riskLevels.join(", ")}${c}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var lm=T(()=>{"use strict";tt();qn();m(lg,"rulesCommand")});var dm={};he(dm,{statusCommand:()=>ug});import Sn from"node:fs";import dc from"node:path";import dg from"js-yaml";async function ug(){let l=new pe,e;try{e=l.loadConfig()}catch(c){console.error("Failed to load configuration:",c.message),process.exit(1)}console.log("Alfred \u2014 Status"),console.log("================"),console.log("");let t=[{name:"Telegram",enabled:e.telegram.enabled,configured:!!e.telegram.token},{name:"Discord",enabled:!!e.discord?.enabled,configured:!!e.discord?.token},{name:"WhatsApp",enabled:!!e.whatsapp?.enabled,configured:!!e.whatsapp?.dataPath},{name:"Matrix",enabled:!!e.matrix?.enabled,configured:!!e.matrix?.accessToken},{name:"Signal",enabled:!!e.signal?.enabled,configured:!!e.signal?.phoneNumber}];console.log("Messaging Adapters:");for(let c of t){let d=c.enabled?"enabled":c.configured?"configured (disabled)":"not configured",u=c.enabled?"+":"-";console.log(` [${u}] ${c.name}: ${d}`)}console.log(""),console.log("LLM Provider:");let s=e.llm.default;console.log(` Provider: ${s.provider}`),console.log(` Model: ${s.model}`),console.log(` API Key: ${s.apiKey?"set":"not set"}`),s.baseUrl&&console.log(` Base URL: ${s.baseUrl}`);for(let c of["strong","fast","embeddings","local"]){let d=e.llm[c];d&&console.log(` ${c}: ${d.provider}/${d.model}`)}console.log(""),console.log("Storage:");let r=dc.resolve(e.storage.path),n=Sn.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=dc.resolve(e.security.rulesPath),i=0,a=0;if(Sn.existsSync(o)&&Sn.statSync(o).isDirectory()){let c=Sn.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new rt;for(let u of c){let p=dc.join(o,u);try{let h=Sn.readFileSync(p,"utf-8"),g=dg.load(h),f=d.loadFromObject(g);i+=f.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${o}`),console.log(` Rule files: ${a}`),console.log(` Rules loaded: ${i}`),console.log(` Default effect: ${e.security.defaultEffect}`),e.security.ownerUserId&&console.log(` Owner user ID: ${e.security.ownerUserId}`),console.log(""),console.log("Logger:"),console.log(` Level: ${e.logger.level}`),console.log(` Pretty: ${e.logger.pretty}`)}var um=T(()=>{"use strict";tt();qn();m(ug,"statusCommand")});var hm={};he(hm,{authCommand:()=>Ig});import{createServer as mg}from"node:http";import{exec as pg}from"node:child_process";import{readFileSync as hg,writeFileSync as fg,existsSync as gg}from"node:fs";import{createInterface as yg}from"node:readline";import{resolve as wg}from"node:path";async function uc(l){let e=yg({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function _g(){let l={};try{let s=new pe().loadConfig();for(let o of["email","calendar","contacts"]){let i=s[o];if(!i)continue;let a=i.microsoft;a&&(!l.clientId&&a.clientId&&(l.clientId=a.clientId),!l.clientSecret&&a.clientSecret&&(l.clientSecret=a.clientSecret),!l.tenantId&&a.tenantId&&(l.tenantId=a.tenantId))}let r=s.todo;r&&(!l.clientId&&r.clientId&&(l.clientId=r.clientId),!l.clientSecret&&r.clientSecret&&(l.clientSecret=r.clientSecret),!l.tenantId&&r.tenantId&&(l.tenantId=r.tenantId));let n=s.email;if(n?.accounts&&Array.isArray(n.accounts))for(let o of n.accounts){let i=o.microsoft;i&&(!l.clientId&&i.clientId&&(l.clientId=i.clientId),!l.clientSecret&&i.clientSecret&&(l.clientSecret=i.clientSecret),!l.tenantId&&i.tenantId&&(l.tenantId=i.tenantId))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS","ALFRED_MICROSOFT_TODO"];for(let t of e)l.clientId||(l.clientId=process.env[`${t}_CLIENT_ID`]),l.clientSecret||(l.clientSecret=process.env[`${t}_CLIENT_SECRET`]),l.tenantId||(l.tenantId=process.env[`${t}_TENANT_ID`]);return l}async function kg(){let l=_g(),e=l.clientId||await uc(" Client ID: "),t=l.clientSecret||await uc(" Client Secret: "),s=l.tenantId||await uc(' Tenant ID (oder "common"): ');return(!e||!t||!s)&&(console.error("Fehler: Client ID, Client Secret und Tenant ID werden ben\xF6tigt."),process.exit(1)),{clientId:e,clientSecret:t,tenantId:s}}function Eg(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:mm,response_mode:"query",scope:pm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function bg(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:mm,grant_type:"authorization_code",scope:pm}),s=await fetch(`https://login.microsoftonline.com/${e.tenantId}/oauth2/v2.0/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t});if(!s.ok){let n=await s.text();throw new Error(`Token-Austausch fehlgeschlagen (${s.status}): ${n}`)}let r=await s.json();if(!r.refresh_token)throw new Error('Kein Refresh Token in der Antwort. Stelle sicher, dass "offline_access" als Scope erlaubt ist.');return r.refresh_token}function Sg(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&pg(t,()=>{})}function vg(l,e){let t=wg(process.cwd(),".env"),s=[];gg(t)&&(s=hg(t,"utf-8").split(`
|
|
1466
|
+
/_/ \\_\\_____|_| |_| \\_\\_____|____/ ${I}
|
|
1467
|
+
${yt} Personal AI Assistant \u2014 Setup Wizard${I}
|
|
1468
|
+
`)}var I,Y,yt,zo,F,qo,yg,wg,ct,Fs,ym,_m=T(()=>{"use strict";Ec();I="\x1B[0m",Y="\x1B[1m",yt="\x1B[2m",zo="\x1B[32m",F="\x1B[33m",qo="\x1B[36m",yg="\x1B[31m",wg="\x1B[35m";m(U,"green");m(Tg,"yellow");m(_e,"cyan");m(wm,"red");m(D,"bold");m(E,"dim");m(ke,"maskKey");ct=[{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"}]}],Fs=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];m(_g,"findCommand");ym=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["exec","--dangerously-bypass-approvals-and-sandbox","{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];m(kg,"loadExistingConfig");m(Eg,"setupCommand");m(B,"askWithDefault");m(Le,"askRequired");m(xn,"askNumber");m(bg,"printBanner")});var Em={};fe(Em,{configCommand:()=>Ig});function vg(l){let e=l.toLowerCase();return Sg.some(t=>e.includes(t))}function $g(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function km(l){let e={};for(let[t,s]of Object.entries(l))vg(t)?e[t]=$g(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=km(s):e[t]=s;return e}async function Ig(){let l=new he,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=km(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var Sg,bm=T(()=>{"use strict";rt();Sg=["token","apikey","api_key","accesstoken","secret","password"];m(vg,"isSensitiveKey");m($g,"redactValue");m(km,"redactObject");m(Ig,"configCommand")});var vm={};fe(vm,{rulesCommand:()=>Rg});import Go from"node:fs";import Sm from"node:path";import Ag from"js-yaml";async function Rg(){let l=new he,e;try{e=l.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let t=Sm.resolve(e.security.rulesPath);if(!Go.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}Go.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=Go.readdirSync(t).filter(a=>a.endsWith(".yml")||a.endsWith(".yaml"));if(r.length===0){console.log(`No YAML rule files found in: ${t}`);return}let n=new ot,o=[],i=[];for(let a of r){let c=Sm.join(t,a);try{let d=Go.readFileSync(c,"utf-8"),u=Ag.load(d),p=n.loadFromObject(u);o.push(...p)}catch(d){i.push(` ${a}: ${d.message}`)}}if(console.log("Alfred \u2014 Security Rules"),console.log("======================="),console.log(`Rules directory: ${t}`),console.log(`Rule files found: ${r.length}`),console.log(`Total rules loaded: ${o.length}`),console.log(""),i.length>0){console.log("Errors:");for(let a of i)console.log(a);console.log("")}if(o.length!==0){o.sort((a,c)=>a.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let a of o){let c=a.rateLimit?` | rate-limit: ${a.rateLimit.maxInvocations}/${a.rateLimit.windowSeconds}s`:"";console.log(` [${a.priority}] ${a.id}`),console.log(` effect: ${a.effect} | scope: ${a.scope}`),console.log(` actions: ${a.actions.join(", ")}`),console.log(` risk levels: ${a.riskLevels.join(", ")}${c}`),a.conditions&&console.log(` conditions: ${JSON.stringify(a.conditions)}`),console.log("")}}}var $m=T(()=>{"use strict";rt();Zn();m(Rg,"rulesCommand")});var Im={};fe(Im,{statusCommand:()=>Cg});import Cn from"node:fs";import Sc from"node:path";import xg from"js-yaml";async function Cg(){let l=new he,e;try{e=l.loadConfig()}catch(c){console.error("Failed to load configuration:",c.message),process.exit(1)}console.log("Alfred \u2014 Status"),console.log("================"),console.log("");let t=[{name:"Telegram",enabled:e.telegram.enabled,configured:!!e.telegram.token},{name:"Discord",enabled:!!e.discord?.enabled,configured:!!e.discord?.token},{name:"WhatsApp",enabled:!!e.whatsapp?.enabled,configured:!!e.whatsapp?.dataPath},{name:"Matrix",enabled:!!e.matrix?.enabled,configured:!!e.matrix?.accessToken},{name:"Signal",enabled:!!e.signal?.enabled,configured:!!e.signal?.phoneNumber}];console.log("Messaging Adapters:");for(let c of t){let d=c.enabled?"enabled":c.configured?"configured (disabled)":"not configured",u=c.enabled?"+":"-";console.log(` [${u}] ${c.name}: ${d}`)}console.log(""),console.log("LLM Provider:");let s=e.llm.default;console.log(` Provider: ${s.provider}`),console.log(` Model: ${s.model}`),console.log(` API Key: ${s.apiKey?"set":"not set"}`),s.baseUrl&&console.log(` Base URL: ${s.baseUrl}`);for(let c of["strong","fast","embeddings","local"]){let d=e.llm[c];d&&console.log(` ${c}: ${d.provider}/${d.model}`)}console.log(""),console.log("Storage:");let r=Sc.resolve(e.storage.path),n=Cn.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let o=Sc.resolve(e.security.rulesPath),i=0,a=0;if(Cn.existsSync(o)&&Cn.statSync(o).isDirectory()){let c=Cn.readdirSync(o).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));a=c.length;let d=new ot;for(let u of c){let p=Sc.join(o,u);try{let h=Cn.readFileSync(p,"utf-8"),f=xg.load(h),g=d.loadFromObject(f);i+=g.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${o}`),console.log(` Rule files: ${a}`),console.log(` Rules loaded: ${i}`),console.log(` Default effect: ${e.security.defaultEffect}`),e.security.ownerUserId&&console.log(` Owner user ID: ${e.security.ownerUserId}`),console.log(""),console.log("Logger:"),console.log(` Level: ${e.logger.level}`),console.log(` Pretty: ${e.logger.pretty}`)}var Am=T(()=>{"use strict";rt();Zn();m(Cg,"statusCommand")});var Cm={};fe(Cm,{authCommand:()=>Xg});import{createServer as Ng}from"node:http";import{exec as Lg}from"node:child_process";import{readFileSync as Dg,writeFileSync as Mg,existsSync as Og}from"node:fs";import{createInterface as Pg}from"node:readline";import{resolve as Ug}from"node:path";async function vc(l){let e=Pg({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function jg(){let l={};try{let s=new he().loadConfig();for(let o of["email","calendar","contacts"]){let i=s[o];if(!i)continue;let a=i.microsoft;a&&(!l.clientId&&a.clientId&&(l.clientId=a.clientId),!l.clientSecret&&a.clientSecret&&(l.clientSecret=a.clientSecret),!l.tenantId&&a.tenantId&&(l.tenantId=a.tenantId))}let r=s.todo;r&&(!l.clientId&&r.clientId&&(l.clientId=r.clientId),!l.clientSecret&&r.clientSecret&&(l.clientSecret=r.clientSecret),!l.tenantId&&r.tenantId&&(l.tenantId=r.tenantId));let n=s.email;if(n?.accounts&&Array.isArray(n.accounts))for(let o of n.accounts){let i=o.microsoft;i&&(!l.clientId&&i.clientId&&(l.clientId=i.clientId),!l.clientSecret&&i.clientSecret&&(l.clientSecret=i.clientSecret),!l.tenantId&&i.tenantId&&(l.tenantId=i.tenantId))}}catch{}let e=["ALFRED_MICROSOFT_EMAIL","ALFRED_MICROSOFT_CALENDAR","ALFRED_MICROSOFT_CONTACTS","ALFRED_MICROSOFT_TODO"];for(let t of e)l.clientId||(l.clientId=process.env[`${t}_CLIENT_ID`]),l.clientSecret||(l.clientSecret=process.env[`${t}_CLIENT_SECRET`]),l.tenantId||(l.tenantId=process.env[`${t}_TENANT_ID`]);return l}async function Bg(){let l=jg(),e=l.clientId||await vc(" Client ID: "),t=l.clientSecret||await vc(" Client Secret: "),s=l.tenantId||await vc(' 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 Hg(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:Rm,response_mode:"query",scope:xm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function Wg(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:Rm,grant_type:"authorization_code",scope:xm}),s=await fetch(`https://login.microsoftonline.com/${e.tenantId}/oauth2/v2.0/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t});if(!s.ok){let n=await s.text();throw new Error(`Token-Austausch fehlgeschlagen (${s.status}): ${n}`)}let r=await s.json();if(!r.refresh_token)throw new Error('Kein Refresh Token in der Antwort. Stelle sicher, dass "offline_access" als Scope erlaubt ist.');return r.refresh_token}function zg(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&Lg(t,()=>{})}function qg(l,e){let t=Ug(process.cwd(),".env"),s=[];Og(t)&&(s=Dg(t,"utf-8").split(`
|
|
1439
1469
|
`));let r={ALFRED_EMAIL_PROVIDER:"microsoft",ALFRED_CALENDAR_PROVIDER:"microsoft",ALFRED_CONTACTS_PROVIDER:"microsoft",ALFRED_MICROSOFT_EMAIL_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_EMAIL_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN:e,ALFRED_MICROSOFT_CALENDAR_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_CALENDAR_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_CALENDAR_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_CALENDAR_REFRESH_TOKEN:e,ALFRED_MICROSOFT_CONTACTS_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_CONTACTS_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN:e,ALFRED_MICROSOFT_TODO_CLIENT_ID:l.clientId,ALFRED_MICROSOFT_TODO_CLIENT_SECRET:l.clientSecret,ALFRED_MICROSOFT_TODO_TENANT_ID:l.tenantId,ALFRED_MICROSOFT_TODO_REFRESH_TOKEN:e},n=new Set(Object.keys(r));for(let i=0;i<s.length;i++){let a=s[i].match(/^#?\s*([A-Z_]+)=/);a&&n.has(a[1])&&(s[i]=`${a[1]}=${r[a[1]]}`,n.delete(a[1]))}if(n.size>0){s.length>0&&s[s.length-1]!==""&&s.push("");for(let i of n)s.push(`${i}=${r[i]}`)}let o=s.join(`
|
|
1440
1470
|
`).replace(/\n*$/,`
|
|
1441
|
-
`);
|
|
1442
|
-
Fehler: ${s.message}`),process.exit(1)}process.exit(0)}var
|
|
1471
|
+
`);Mg(t,o)}function Gg(l){return new Promise((e,t)=>{let s=Ng(async(r,n)=>{let o=new URL(r.url??"/","http://localhost:3000");if(o.pathname!=="/callback"){n.writeHead(404),n.end("Not found");return}let i=o.searchParams.get("code"),a=o.searchParams.get("error");if(a){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>Fehler: ${a}</h1><p>${o.searchParams.get("error_description")??""}</p>`),s.close(),t(new Error(`OAuth-Fehler: ${a}`));return}if(!i){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>Fehler: Kein Auth-Code erhalten</h1>");return}try{let c=await Wg(i,l);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(Fg),s.close(),e(c)}catch(c){n.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>Fehler beim Token-Austausch</h1><p>${c.message}</p>`),s.close(),t(c)}});s.listen(3e3,()=>{console.log(" Callback-Server gestartet auf http://localhost:3000")}),s.on("error",r=>{t(new Error(`Server konnte nicht gestartet werden: ${r.message}`))})})}async function Xg(l){l||(console.error("Usage: alfred auth <provider>"),console.error(" Unterst\xFCtzte Provider: microsoft"),process.exit(1)),l!=="microsoft"&&(console.error(`Unbekannter Provider: ${l}`),console.error(" Unterst\xFCtzte Provider: microsoft"),process.exit(1)),console.log(""),console.log(" Microsoft 365 OAuth \u2014 Automatischer Token-Flow"),console.log(" ================================================"),console.log("");let e=await Bg(),t=Hg(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),zg(t);try{let s=await Gg(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),qg(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(`
|
|
1472
|
+
Fehler: ${s.message}`),process.exit(1)}process.exit(0)}var Rm,xm,Fg,Nm=T(()=>{"use strict";rt();Rm="http://localhost:3000/callback",xm=["offline_access","Mail.Read","Mail.ReadWrite","Mail.Send","Contacts.Read","Contacts.ReadWrite","Calendars.Read","Calendars.ReadWrite","Tasks.ReadWrite"].join(" "),Fg=`<!DOCTYPE html>
|
|
1443
1473
|
<html><head><meta charset="utf-8"><title>Alfred \u2014 Auth erfolgreich</title>
|
|
1444
1474
|
<style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0d1117;color:#e6edf3}
|
|
1445
1475
|
.card{text-align:center;padding:2rem;border:1px solid #30363d;border-radius:12px;background:#161b22}
|
|
1446
1476
|
h1{color:#3fb950;margin-bottom:.5rem}p{color:#8b949e}</style></head>
|
|
1447
|
-
<body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;m(
|
|
1448
|
-
Alfred CLI v${
|
|
1477
|
+
<body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;m(vc,"askQuestion");m(jg,"resolveCredentials");m(Bg,"ensureCredentials");m(Hg,"buildAuthUrl");m(Wg,"exchangeCode");m(zg,"openBrowser");m(qg,"updateEnvFile");m(Gg,"waitForCallback");m(Xg,"authCommand")});var Lm={};fe(Lm,{logsCommand:()=>Yg});import Kg from"node:fs";import Vg from"node:path";async function Yg(l,e){let t=new he,s;try{s=t.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let r=Vg.resolve(s.storage.path);if(!Kg.existsSync(r)){console.log(`Database not found at: ${r}`),console.log("No log entries. Alfred has not been run yet, or the database path is incorrect.");return}let n;try{n=new xt(r),e?.activity?Zg(n,l,e):Jg(n,l)}catch(o){console.error("Failed to read log:",o.message),process.exit(1)}finally{n&&n.close()}}function Jg(l,e){let t=new Ct(l.getDb()),s=t.count({}),r=t.query({limit:e});if(console.log("Alfred \u2014 Audit Log (Security)"),console.log("=============================="),console.log(`Total entries: ${s}`),console.log(`Showing last ${Math.min(e,s)} entries:`),console.log(""),r.length===0){console.log("No audit log entries found.");return}for(let n of r){let o=n.timestamp.toISOString(),i=n.effect==="allow"?"ALLOW":"DENY ";console.log(` ${o} [${i}] ${n.action}`),console.log(` user: ${n.userId} | platform: ${n.platform} | risk: ${n.riskLevel}`),n.ruleId&&console.log(` rule: ${n.ruleId}`),n.chatId&&console.log(` chat: ${n.chatId}`),n.context&&console.log(` context: ${JSON.stringify(n.context)}`),console.log("")}}function Zg(l,e,t){let s=new Lt(l.getDb());if(t.stats){let o=s.stats(t.since);if(console.log("Alfred \u2014 Activity Stats"),console.log("========================"),t.since&&console.log(`Since: ${t.since}`),console.log(""),o.length===0){console.log("No activity entries found.");return}let i=Math.max(...o.map(c=>c.eventType.length),10),a=Math.max(...o.map(c=>c.outcome.length),7);console.log(` ${"EVENT TYPE".padEnd(i)} ${"OUTCOME".padEnd(a)} COUNT`),console.log(` ${"\u2500".repeat(i)} ${"\u2500".repeat(a)} \u2500\u2500\u2500\u2500\u2500`);for(let c of o)console.log(` ${c.eventType.padEnd(i)} ${c.outcome.padEnd(a)} ${c.count}`);return}let r=s.count({eventType:t.type,source:t.source,outcome:t.outcome}),n=s.query({eventType:t.type,source:t.source,outcome:t.outcome,since:t.since,limit:e});if(console.log("Alfred \u2014 Activity Log"),console.log("======================"),console.log(`Total entries: ${r}`),t.type&&console.log(`Filter: type=${t.type}`),t.source&&console.log(`Filter: source=${t.source}`),t.outcome&&console.log(`Filter: outcome=${t.outcome}`),console.log(`Showing last ${Math.min(e,r)} entries:`),console.log(""),n.length===0){console.log("No activity entries found.");return}for(let o of n){let i=Qg(o.outcome),a=o.durationMs?` (${o.durationMs}ms)`:"";console.log(` ${o.timestamp} [${i}] ${o.eventType}: ${o.action}${a}`),console.log(` source: ${o.source}${o.sourceId?` (${o.sourceId.slice(0,8)})`:""} | platform: ${o.platform??"-"}`),o.userId&&console.log(` user: ${o.userId}`),o.errorMessage&&console.log(` error: ${o.errorMessage.slice(0,200)}`),o.details&&console.log(` details: ${JSON.stringify(o.details)}`),console.log("")}}function Qg(l){switch(l){case"success":return"\x1B[32mSUCCESS\x1B[0m";case"error":return"\x1B[31mERROR \x1B[0m";case"denied":return"\x1B[31mDENIED \x1B[0m";case"approved":return"\x1B[32mAPPROVED\x1B[0m";case"rejected":return"\x1B[33mREJECTED\x1B[0m";case"expired":return"\x1B[33mEXPIRED\x1B[0m";case"skipped":return"\x1B[90mSKIPPED\x1B[0m";default:return l.toUpperCase()}}var Dm=T(()=>{"use strict";rt();Oi();m(Yg,"logsCommand");m(Jg,"showAuditLog");m(Zg,"showActivityLog");m(Qg,"formatOutcome")});import{readFileSync as ey}from"node:fs";import{fileURLToPath as ty}from"node:url";import{dirname as sy,join as ry}from"node:path";function ny(){try{let l=sy(ty(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(ey(ry(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}m(ny,"getVersion");var Mm=ny(),$c=`
|
|
1478
|
+
Alfred CLI v${Mm}
|
|
1449
1479
|
Personal AI Assistant
|
|
1450
1480
|
|
|
1451
1481
|
Usage:
|
|
@@ -1470,4 +1500,4 @@ Commands:
|
|
|
1470
1500
|
Options:
|
|
1471
1501
|
--help, -h Show this help message
|
|
1472
1502
|
--version, -v Show version number
|
|
1473
|
-
`.trim();function
|
|
1503
|
+
`.trim();function oy(l){let e=l.slice(2),t=e.length>0&&!e[0].startsWith("-")?e[0]:"",s=t?e.slice(1):e,r={},n=[],o=0;for(;o<s.length;){let i=s[o];if(i.startsWith("--")){let a=i.slice(2);o+1<s.length&&!s[o+1].startsWith("-")?(r[a]=s[o+1],o+=2):(r[a]=!0,o+=1)}else if(i.startsWith("-")&&i.length===2){let a=i.slice(1);o+1<s.length&&!s[o+1].startsWith("-")?(r[a]=s[o+1],o+=2):(r[a]=!0,o+=1)}else n.push(i),o+=1}return{command:t,flags:r,positional:n}}m(oy,"parseArgs");async function iy(){let l=oy(process.argv);switch((l.flags.help||l.flags.h)&&(console.log($c),process.exit(0)),(l.flags.version||l.flags.v)&&(console.log(`alfred v${Mm}`),process.exit(0)),l.command){case"start":{let{startCommand:e}=await Promise.resolve().then(()=>(pm(),mm));await e();break}case"chat":{let{chatCommand:e}=await Promise.resolve().then(()=>(gm(),fm));await e({model:typeof l.flags.model=="string"?l.flags.model:void 0,tier:typeof l.flags.tier=="string"?l.flags.tier:void 0});break}case"setup":{let{setupCommand:e}=await Promise.resolve().then(()=>(_m(),Tm));await e();break}case"config":{let{configCommand:e}=await Promise.resolve().then(()=>(bm(),Em));await e();break}case"rules":{let{rulesCommand:e}=await Promise.resolve().then(()=>($m(),vm));await e();break}case"status":{let{statusCommand:e}=await Promise.resolve().then(()=>(Am(),Im));await e();break}case"auth":{let e=l.positional[0]??"",{authCommand:t}=await Promise.resolve().then(()=>(Nm(),Cm));await t(e);break}case"logs":{let e=l.flags.tail,t=20;if(typeof e=="string"){let r=parseInt(e,10);(Number.isNaN(r)||r<=0)&&(console.error("Error: --tail must be a positive integer"),process.exit(1)),t=r}let{logsCommand:s}=await Promise.resolve().then(()=>(Dm(),Lm));await s(t,{activity:!!l.flags.activity,type:typeof l.flags.type=="string"?l.flags.type:void 0,source:typeof l.flags.source=="string"?l.flags.source:void 0,outcome:typeof l.flags.outcome=="string"?l.flags.outcome:void 0,since:typeof l.flags.since=="string"?l.flags.since:void 0,stats:!!l.flags.stats});break}case"help":console.log($c);break;case"":console.log($c),process.exit(0);break;default:console.error(`Unknown command: ${l.command}`),console.error(""),console.error('Run "alfred --help" for usage information.'),process.exit(1)}}m(iy,"main");iy().catch(l=>{console.error("Fatal error:",l),process.exit(1)});
|