@madh-io/alfred-ai 0.19.0-multi-ha.21 → 0.19.0-multi-ha.23

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 CHANGED
@@ -1362,14 +1362,14 @@ CREATE TABLE IF NOT EXISTS adapter_claims (
1362
1362
  INSERT INTO shared_resources (id, resource_type, resource_id, owner_user_id, shared_with_user_id, shared_with_group_id, created_at)
1363
1363
  VALUES (?, ?, ?, ?, ?, ?, ?)
1364
1364
  ON CONFLICT DO NOTHING
1365
- `,[t,e.resourceType,e.resourceId,e.ownerUserId,e.sharedWithUserId??null,e.sharedWithGroupId??null,s]),{id:t,...e,createdAt:s}}async unshare(e,t,s,r){return s?(await this.adapter.execute("DELETE FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND shared_with_user_id = ?",[e,t,s])).changes>0:r?(await this.adapter.execute("DELETE FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND shared_with_group_id = ?",[e,t,r])).changes>0:!1}async hasAccess(e,t,s,r){if(await this.adapter.queryOne("SELECT 1 FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND (owner_user_id = ? OR shared_with_user_id = ?)",[e,t,s,s]))return!0;if(r&&r.length>0){let i=r.map(()=>"?").join(",");if(await this.adapter.queryOne(`SELECT 1 FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND shared_with_group_id IN (${i})`,[e,t,...r]))return!0}return!1}async getSharedWith(e,t,s){let r=[],n="SELECT * FROM shared_resources WHERE shared_with_user_id = ?",i=[e];t&&(n+=" AND resource_type = ?",i.push(t));let a=await this.adapter.query(n,i);if(r.push(...a.map(o=>this.mapRow(o))),s&&s.length>0){let c=`SELECT * FROM shared_resources WHERE shared_with_group_id IN (${s.map(()=>"?").join(",")})`,d=[...s];t&&(c+=" AND resource_type = ?",d.push(t));let u=await this.adapter.query(c,d);r.push(...u.map(h=>this.mapRow(h)))}return r}async getSharesForResource(e,t){return(await this.adapter.query("SELECT * FROM shared_resources WHERE resource_type = ? AND resource_id = ?",[e,t])).map(r=>this.mapRow(r))}mapRow(e){return{id:e.id,resourceType:e.resource_type,resourceId:e.resource_id,ownerUserId:e.owner_user_id,sharedWithUserId:e.shared_with_user_id,sharedWithGroupId:e.shared_with_group_id,createdAt:e.created_at}}}});import wt from"node:fs";import Ke from"node:path";function Ou(l){switch(l.backend){case"s3":return new sn(l);case"nfs":case"local":default:return new tn(l)}}var tn,sn,Du=w(()=>{"use strict";tn=class{static{p(this,"LocalFileStore")}backend;basePath;constructor(e){this.backend=e.backend==="nfs"?"nfs":"local",this.basePath=e.basePath??Ke.resolve("./data/files"),wt.mkdirSync(this.basePath,{recursive:!0})}async save(e,t,s){let r=Ke.join(this.basePath,this.sanitize(e));wt.mkdirSync(r,{recursive:!0});let n=new Date().toISOString().replace(/[:.]/g,"-"),i=this.sanitize(t),a=`${n}_${i}`,o=Ke.join(r,a);return wt.writeFileSync(o,s),{key:Ke.relative(this.basePath,o).replace(/\\/g,"/"),fileName:t,userId:e,size:s.length,createdAt:new Date().toISOString()}}async read(e,t){if(t){let r=this.sanitize(t);if(!e.startsWith(r+"/"))throw new Error("Access denied: file does not belong to this user")}let s=Ke.resolve(this.basePath,e);if(!s.startsWith(Ke.resolve(this.basePath)))throw new Error("Path traversal attempt blocked");return wt.readFileSync(s)}async list(e){let t=Ke.join(this.basePath,this.sanitize(e));return wt.existsSync(t)?wt.readdirSync(t).map(r=>{let n=Ke.join(t,r),i=wt.statSync(n);return{key:`${this.sanitize(e)}/${r}`,fileName:r.replace(/^\d{4}-\d{2}-\d{2}T[\d-]+_/,""),userId:e,size:i.size,createdAt:i.mtime.toISOString()}}):[]}async delete(e){let t=Ke.resolve(this.basePath,e);if(!t.startsWith(Ke.resolve(this.basePath)))return!1;try{return wt.unlinkSync(t),!0}catch{return!1}}async exists(e){let t=Ke.resolve(this.basePath,e);return t.startsWith(Ke.resolve(this.basePath))&&wt.existsSync(t)}sanitize(e){return e.replace(/[<>:"/\\|?*]/g,"_").slice(0,100)}},sn=class{static{p(this,"S3FileStore")}config;backend="s3";client;bucket;endpoint;constructor(e){this.config=e,this.bucket=e.s3Bucket??"alfred-files",this.endpoint=e.s3Endpoint}sanitize(e){return e.replace(/[<>:"/\\|?*]/g,"_").replace(/\.\./g,"_").slice(0,100)}async getClient(){if(this.client)return this.client;let{S3Client:e}=await Function('return import("@aws-sdk/client-s3")')();return this.client=new e({region:this.config.s3Region??"us-east-1",endpoint:this.endpoint,forcePathStyle:!!this.endpoint,credentials:this.config.s3AccessKey?{accessKeyId:this.config.s3AccessKey,secretAccessKey:this.config.s3SecretKey??""}:void 0}),this.client}async save(e,t,s){let r=await this.getClient(),{PutObjectCommand:n}=await Function('return import("@aws-sdk/client-s3")')(),i=new Date().toISOString().replace(/[:.]/g,"-"),a=`${this.sanitize(e)}/${i}_${this.sanitize(t)}`;return await r.send(new n({Bucket:this.bucket,Key:a,Body:s,ContentType:"application/octet-stream"})),{key:a,fileName:t,userId:e,size:s.length,createdAt:new Date().toISOString()}}async read(e,t){if(t){let a=this.sanitize(t);if(!e.startsWith(a+"/"))throw new Error("Access denied: file does not belong to this user")}let s=await this.getClient(),{GetObjectCommand:r}=await Function('return import("@aws-sdk/client-s3")')(),n=await s.send(new r({Bucket:this.bucket,Key:e})),i=[];for await(let a of n.Body)i.push(a);return Buffer.concat(i)}async list(e){let t=await this.getClient(),{ListObjectsV2Command:s}=await Function('return import("@aws-sdk/client-s3")')();return((await t.send(new s({Bucket:this.bucket,Prefix:`${this.sanitize(e)}/`}))).Contents??[]).map(n=>({key:n.Key,fileName:n.Key.split("/").pop()?.replace(/^\d{4}-\d{2}-\d{2}T[\d-]+_/,"")??n.Key,userId:e,size:n.Size??0,createdAt:n.LastModified?.toISOString()??new Date().toISOString()}))}async delete(e){let t=await this.getClient(),{DeleteObjectCommand:s}=await Function('return import("@aws-sdk/client-s3")')();try{return await t.send(new s({Bucket:this.bucket,Key:e})),!0}catch{return!1}}async exists(e){let t=await this.getClient(),{HeadObjectCommand:s}=await Function('return import("@aws-sdk/client-s3")')();try{return await t.send(new s({Bucket:this.bucket,Key:e})),!0}catch{return!1}}};p(Ou,"createFileStore")});import{randomUUID as zg}from"node:crypto";var Yi,Mu=w(()=>{"use strict";Yi=class{static{p(this,"ProjectAgentSessionRepository")}adapter;constructor(e){this.adapter=e}async create(e){let t=zg(),s=new Date().toISOString();return await this.adapter.execute(`
1365
+ `,[t,e.resourceType,e.resourceId,e.ownerUserId,e.sharedWithUserId??null,e.sharedWithGroupId??null,s]),{id:t,...e,createdAt:s}}async unshare(e,t,s,r){return s?(await this.adapter.execute("DELETE FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND shared_with_user_id = ?",[e,t,s])).changes>0:r?(await this.adapter.execute("DELETE FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND shared_with_group_id = ?",[e,t,r])).changes>0:!1}async hasAccess(e,t,s,r){if(await this.adapter.queryOne("SELECT 1 FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND (owner_user_id = ? OR shared_with_user_id = ?)",[e,t,s,s]))return!0;if(r&&r.length>0){let i=r.map(()=>"?").join(",");if(await this.adapter.queryOne(`SELECT 1 FROM shared_resources WHERE resource_type = ? AND resource_id = ? AND shared_with_group_id IN (${i})`,[e,t,...r]))return!0}return!1}async getSharedWith(e,t,s){let r=[],n="SELECT * FROM shared_resources WHERE shared_with_user_id = ?",i=[e];t&&(n+=" AND resource_type = ?",i.push(t));let a=await this.adapter.query(n,i);if(r.push(...a.map(o=>this.mapRow(o))),s&&s.length>0){let c=`SELECT * FROM shared_resources WHERE shared_with_group_id IN (${s.map(()=>"?").join(",")})`,d=[...s];t&&(c+=" AND resource_type = ?",d.push(t));let u=await this.adapter.query(c,d);r.push(...u.map(h=>this.mapRow(h)))}return r}async getSharesForResource(e,t){return(await this.adapter.query("SELECT * FROM shared_resources WHERE resource_type = ? AND resource_id = ?",[e,t])).map(r=>this.mapRow(r))}mapRow(e){return{id:e.id,resourceType:e.resource_type,resourceId:e.resource_id,ownerUserId:e.owner_user_id,sharedWithUserId:e.shared_with_user_id,sharedWithGroupId:e.shared_with_group_id,createdAt:e.created_at}}}});import wt from"node:fs";import ze from"node:path";function Ou(l){switch(l.backend){case"s3":return new sn(l);case"nfs":case"local":default:return new tn(l)}}var tn,sn,Du=w(()=>{"use strict";tn=class{static{p(this,"LocalFileStore")}backend;basePath;constructor(e){this.backend=e.backend==="nfs"?"nfs":"local",this.basePath=e.basePath??ze.resolve("./data/files"),wt.mkdirSync(this.basePath,{recursive:!0})}async save(e,t,s){let r=ze.join(this.basePath,this.sanitize(e));wt.mkdirSync(r,{recursive:!0});let n=new Date().toISOString().replace(/[:.]/g,"-"),i=this.sanitize(t),a=`${n}_${i}`,o=ze.join(r,a);return wt.writeFileSync(o,s),{key:ze.relative(this.basePath,o).replace(/\\/g,"/"),fileName:t,userId:e,size:s.length,createdAt:new Date().toISOString()}}async read(e,t){if(t){let r=this.sanitize(t);if(!e.startsWith(r+"/"))throw new Error("Access denied: file does not belong to this user")}let s=ze.resolve(this.basePath,e);if(!s.startsWith(ze.resolve(this.basePath)))throw new Error("Path traversal attempt blocked");return wt.readFileSync(s)}async list(e){let t=ze.join(this.basePath,this.sanitize(e));return wt.existsSync(t)?wt.readdirSync(t).map(r=>{let n=ze.join(t,r),i=wt.statSync(n);return{key:`${this.sanitize(e)}/${r}`,fileName:r.replace(/^\d{4}-\d{2}-\d{2}T[\d-]+_/,""),userId:e,size:i.size,createdAt:i.mtime.toISOString()}}):[]}async delete(e){let t=ze.resolve(this.basePath,e);if(!t.startsWith(ze.resolve(this.basePath)))return!1;try{return wt.unlinkSync(t),!0}catch{return!1}}async exists(e){let t=ze.resolve(this.basePath,e);return t.startsWith(ze.resolve(this.basePath))&&wt.existsSync(t)}sanitize(e){return e.replace(/[<>:"/\\|?*]/g,"_").slice(0,100)}},sn=class{static{p(this,"S3FileStore")}config;backend="s3";client;bucket;endpoint;constructor(e){this.config=e,this.bucket=e.s3Bucket??"alfred-files",this.endpoint=e.s3Endpoint}sanitize(e){return e.replace(/[<>:"/\\|?*]/g,"_").replace(/\.\./g,"_").slice(0,100)}async getClient(){if(this.client)return this.client;let{S3Client:e}=await Function('return import("@aws-sdk/client-s3")')();return this.client=new e({region:this.config.s3Region??"us-east-1",endpoint:this.endpoint,forcePathStyle:!!this.endpoint,credentials:this.config.s3AccessKey?{accessKeyId:this.config.s3AccessKey,secretAccessKey:this.config.s3SecretKey??""}:void 0}),this.client}async save(e,t,s){let r=await this.getClient(),{PutObjectCommand:n}=await Function('return import("@aws-sdk/client-s3")')(),i=new Date().toISOString().replace(/[:.]/g,"-"),a=`${this.sanitize(e)}/${i}_${this.sanitize(t)}`;return await r.send(new n({Bucket:this.bucket,Key:a,Body:s,ContentType:"application/octet-stream"})),{key:a,fileName:t,userId:e,size:s.length,createdAt:new Date().toISOString()}}async read(e,t){if(t){let a=this.sanitize(t);if(!e.startsWith(a+"/"))throw new Error("Access denied: file does not belong to this user")}let s=await this.getClient(),{GetObjectCommand:r}=await Function('return import("@aws-sdk/client-s3")')(),n=await s.send(new r({Bucket:this.bucket,Key:e})),i=[];for await(let a of n.Body)i.push(a);return Buffer.concat(i)}async list(e){let t=await this.getClient(),{ListObjectsV2Command:s}=await Function('return import("@aws-sdk/client-s3")')();return((await t.send(new s({Bucket:this.bucket,Prefix:`${this.sanitize(e)}/`}))).Contents??[]).map(n=>({key:n.Key,fileName:n.Key.split("/").pop()?.replace(/^\d{4}-\d{2}-\d{2}T[\d-]+_/,"")??n.Key,userId:e,size:n.Size??0,createdAt:n.LastModified?.toISOString()??new Date().toISOString()}))}async delete(e){let t=await this.getClient(),{DeleteObjectCommand:s}=await Function('return import("@aws-sdk/client-s3")')();try{return await t.send(new s({Bucket:this.bucket,Key:e})),!0}catch{return!1}}async exists(e){let t=await this.getClient(),{HeadObjectCommand:s}=await Function('return import("@aws-sdk/client-s3")')();try{return await t.send(new s({Bucket:this.bucket,Key:e})),!0}catch{return!1}}};p(Ou,"createFileStore")});import{randomUUID as zg}from"node:crypto";var Yi,Mu=w(()=>{"use strict";Yi=class{static{p(this,"ProjectAgentSessionRepository")}adapter;constructor(e){this.adapter=e}async create(e){let t=zg(),s=new Date().toISOString();return await this.adapter.execute(`
1366
1366
  INSERT INTO project_agent_sessions (id, task_id, goal, cwd, agent_name, created_at, updated_at)
1367
1367
  VALUES (?, ?, ?, ?, ?, ?, ?)
1368
1368
  `,[t,e.taskId,e.goal,e.cwd,e.agentName,s,s]),{id:t,taskId:e.taskId,goal:e.goal,cwd:e.cwd,agentName:e.agentName,currentPhase:"planning",currentIteration:0,totalFilesChanged:0,lastBuildPassed:!1,milestones:[],createdAt:s,updatedAt:s}}async getByTaskId(e){let t=await this.adapter.queryOne("SELECT * FROM project_agent_sessions WHERE task_id = ?",[e]);return t?this.mapRow(t):void 0}async updateProgress(e,t){let s=new Date().toISOString(),r=["updated_at = ?"],n=[s];t.currentPhase!==void 0&&(r.push("current_phase = ?"),n.push(t.currentPhase)),t.currentIteration!==void 0&&(r.push("current_iteration = ?"),n.push(t.currentIteration)),t.totalFilesChanged!==void 0&&(r.push("total_files_changed = ?"),n.push(t.totalFilesChanged)),t.lastBuildPassed!==void 0&&(r.push("last_build_passed = ?"),n.push(t.lastBuildPassed?1:0)),t.lastCommitSha!==void 0&&(r.push("last_commit_sha = ?"),n.push(t.lastCommitSha)),r.push("last_progress_at = ?"),n.push(s),n.push(e),await this.adapter.execute(`UPDATE project_agent_sessions SET ${r.join(", ")} WHERE task_id = ?`,n)}async addMilestone(e,t){let s=await this.getByTaskId(e);if(!s)return;let r=[...s.milestones,t],n=new Date().toISOString();await this.adapter.execute("UPDATE project_agent_sessions SET milestones = ?, updated_at = ? WHERE task_id = ?",[JSON.stringify(r),n,e])}mapRow(e){let t=[];try{t=JSON.parse(e.milestones)}catch{}return{id:e.id,taskId:e.task_id,goal:e.goal,cwd:e.cwd,agentName:e.agent_name,currentPhase:e.current_phase,currentIteration:e.current_iteration,totalFilesChanged:e.total_files_changed,lastBuildPassed:e.last_build_passed===1,lastCommitSha:e.last_commit_sha,lastProgressAt:e.last_progress_at,milestones:t,createdAt:e.created_at,updatedAt:e.updated_at}}}});var Vi,Uu=w(()=>{"use strict";Vi=class{static{p(this,"ProcessedMessageRepository")}adapter;constructor(e){this.adapter=e}async markProcessed(e,t,s=24){if(this.adapter.type==="sqlite")return!0;let r=new Date().toISOString(),n=new Date(Date.now()+s*36e5).toISOString();return(await this.adapter.execute(`INSERT INTO processed_messages (message_key, node_id, processed_at, expires_at)
1369
1369
  VALUES (?, ?, ?, ?)
1370
- ON CONFLICT (message_key) DO NOTHING`,[e,t,r,n])).changes>0}async cleanup(){let e=new Date().toISOString();return(await this.adapter.execute("DELETE FROM processed_messages WHERE expires_at < ?",[e])).changes}}});var dt={};ie(dt,{ActivityRepository:()=>Ot,AlfredUserRepository:()=>Ki,AuditRepository:()=>xt,BackgroundTaskRepository:()=>Ns,CalendarNotificationRepository:()=>Ct,ConfirmationRepository:()=>Ms,ConversationRepository:()=>Ss,Database:()=>lt,DatabaseConnectionRepository:()=>qi,DocumentRepository:()=>Cs,EmbeddingRepository:()=>$s,FeedbackRepository:()=>Bs,LinkTokenRepository:()=>Rs,LocalFileStore:()=>tn,MIGRATIONS:()=>Bi,MemoryRepository:()=>vs,Migrator:()=>rs,NoteRepository:()=>As,PG_MIGRATIONS:()=>Qd,PG_SCHEMA:()=>Qr,PgMigrator:()=>Hi,PostgresAsyncAdapter:()=>Tt,ProcessedMessageRepository:()=>Vi,ProjectAgentSessionRepository:()=>Yi,ReminderRepository:()=>Is,S3FileStore:()=>sn,SQLiteAsyncAdapter:()=>ns,ScheduledActionRepository:()=>xs,SharedResourceRepository:()=>Gi,SkillHealthRepository:()=>Fs,SummaryRepository:()=>Us,TodoRepository:()=>Os,UsageRepository:()=>Ps,UserRepository:()=>bs,WatchRepository:()=>Ds,WorkflowRepository:()=>js,createDbAdapter:()=>Hd,createFileStore:()=>Ou});var Xe=w(()=>{"use strict";zd();Gd();Yd();Vd();Jd();ji();Xo();qo();Zd();eu();tu();su();ru();iu();au();gu();Tu();wu();Eu();_u();ku();Su();bu();vu();Iu();$u();Ru();Nu();xu();Cu();Du();Wo();Mu();Uu()});function Et(l){if(Go[l])return Go[l];let e=Object.entries(Go).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Go,Kg,He,is=w(()=>{"use strict";Go={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Kg={maxInputTokens:128e3,maxOutputTokens:8192};p(Et,"lookupContextWindow");He=class{static{p(this,"LLMProvider")}config;contextWindow=Kg;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Gg from"@anthropic-ai/sdk";var rn,Yo=w(()=>{"use strict";is();rn=class extends He{static{p(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Gg({apiKey:this.config.apiKey,maxRetries:5});let e=Et(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 i=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(i)}}}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 Yg from"openai";var et,Xs=w(()=>{"use strict";is();et=class extends He{static{p(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Yg({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=Et(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,i,a="",o="",c=[],d=null,u=0,h=0;for await(let m of r){let f=m.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(o+=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 k;try{k=JSON.parse(a||"{}")}catch{k={}}c.push({id:n,name:i,input:k})}n=y.id,i=y.function?.name,a=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:i}}}else y.function?.arguments&&(a+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),m.usage&&(u=m.usage.prompt_tokens,h=m.usage.completion_tokens)}if(n){let m;try{m=JSON.parse(a||"{}")}catch{m={}}c.push({id:n,name:i,input:m})}yield{type:"message_complete",response:{content:o,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:h},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=[],i=[],a=[];for(let o of r.content)switch(o.type){case"text":n.push({type:"text",text:o.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${o.source.media_type};base64,${o.source.data}`}});break;case"tool_use":i.push({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.input)}});break;case"tool_result":a.push({tool_call_id:o.tool_use_id,content:o.content});break}if(r.role==="assistant"&&i.length>0){let o=n.map(c=>c.text).join("");s.push({role:"assistant",content:o||null,tool_calls:i})}else if(a.length>0)for(let o of a)s.push({role:"tool",tool_call_id:o.tool_call_id,content:o.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(o=>o.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(i=>({id:i.id,name:i.function.name,input:(()=>{try{return JSON.parse(i.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 nn,Vo=w(()=>{"use strict";Xs();nn=class extends et{static{p(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var an,Jo=w(()=>{"use strict";is();an=class extends He{static{p(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=Et(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(i=>i.includes("context_length")||i==="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 a=await n.text();throw new Error(`Ollama API error (${n.status}): ${a}`)}let i=await n.json();return this.mapResponse(i)}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 m=await n.text();throw new Error(`Ollama API error (${n.status}): ${m}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let i=n.body.getReader(),a=new TextDecoder,o="",c="",d=0,u=0,h=[];try{for(;;){let{done:m,value:f}=await i.read();if(m)break;o+=a.decode(f,{stream:!0});let g=o.split(`
1370
+ ON CONFLICT (message_key) DO NOTHING`,[e,t,r,n])).changes>0}async cleanup(){let e=new Date().toISOString();return(await this.adapter.execute("DELETE FROM processed_messages WHERE expires_at < ?",[e])).changes}}});var dt={};ie(dt,{ActivityRepository:()=>Ot,AlfredUserRepository:()=>Ki,AuditRepository:()=>xt,BackgroundTaskRepository:()=>Ns,CalendarNotificationRepository:()=>Ct,ConfirmationRepository:()=>Ms,ConversationRepository:()=>Ss,Database:()=>lt,DatabaseConnectionRepository:()=>qi,DocumentRepository:()=>Cs,EmbeddingRepository:()=>$s,FeedbackRepository:()=>Bs,LinkTokenRepository:()=>Rs,LocalFileStore:()=>tn,MIGRATIONS:()=>Bi,MemoryRepository:()=>vs,Migrator:()=>rs,NoteRepository:()=>As,PG_MIGRATIONS:()=>Qd,PG_SCHEMA:()=>Qr,PgMigrator:()=>Hi,PostgresAsyncAdapter:()=>Tt,ProcessedMessageRepository:()=>Vi,ProjectAgentSessionRepository:()=>Yi,ReminderRepository:()=>Is,S3FileStore:()=>sn,SQLiteAsyncAdapter:()=>ns,ScheduledActionRepository:()=>xs,SharedResourceRepository:()=>Gi,SkillHealthRepository:()=>Fs,SummaryRepository:()=>Us,TodoRepository:()=>Os,UsageRepository:()=>Ps,UserRepository:()=>bs,WatchRepository:()=>Ds,WorkflowRepository:()=>js,createDbAdapter:()=>Hd,createFileStore:()=>Ou});var Be=w(()=>{"use strict";zd();Gd();Yd();Vd();Jd();ji();Xo();qo();Zd();eu();tu();su();ru();iu();au();gu();Tu();wu();Eu();_u();ku();Su();bu();vu();Iu();$u();Ru();Nu();xu();Cu();Du();Wo();Mu();Uu()});function Et(l){if(Go[l])return Go[l];let e=Object.entries(Go).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Go,Kg,Xe,is=w(()=>{"use strict";Go={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Kg={maxInputTokens:128e3,maxOutputTokens:8192};p(Et,"lookupContextWindow");Xe=class{static{p(this,"LLMProvider")}config;contextWindow=Kg;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Gg from"@anthropic-ai/sdk";var rn,Yo=w(()=>{"use strict";is();rn=class extends Xe{static{p(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Gg({apiKey:this.config.apiKey,maxRetries:5});let e=Et(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 i=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(i)}}}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 Yg from"openai";var et,Xs=w(()=>{"use strict";is();et=class extends Xe{static{p(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Yg({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=Et(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,i,a="",o="",c=[],d=null,u=0,h=0;for await(let m of r){let f=m.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(o+=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 k;try{k=JSON.parse(a||"{}")}catch{k={}}c.push({id:n,name:i,input:k})}n=y.id,i=y.function?.name,a=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:i}}}else y.function?.arguments&&(a+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),m.usage&&(u=m.usage.prompt_tokens,h=m.usage.completion_tokens)}if(n){let m;try{m=JSON.parse(a||"{}")}catch{m={}}c.push({id:n,name:i,input:m})}yield{type:"message_complete",response:{content:o,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:h},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=[],i=[],a=[];for(let o of r.content)switch(o.type){case"text":n.push({type:"text",text:o.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${o.source.media_type};base64,${o.source.data}`}});break;case"tool_use":i.push({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.input)}});break;case"tool_result":a.push({tool_call_id:o.tool_use_id,content:o.content});break}if(r.role==="assistant"&&i.length>0){let o=n.map(c=>c.text).join("");s.push({role:"assistant",content:o||null,tool_calls:i})}else if(a.length>0)for(let o of a)s.push({role:"tool",tool_call_id:o.tool_call_id,content:o.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(o=>o.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(i=>({id:i.id,name:i.function.name,input:(()=>{try{return JSON.parse(i.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 nn,Vo=w(()=>{"use strict";Xs();nn=class extends et{static{p(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var an,Jo=w(()=>{"use strict";is();an=class extends Xe{static{p(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=Et(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(i=>i.includes("context_length")||i==="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 a=await n.text();throw new Error(`Ollama API error (${n.status}): ${a}`)}let i=await n.json();return this.mapResponse(i)}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 m=await n.text();throw new Error(`Ollama API error (${n.status}): ${m}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let i=n.body.getReader(),a=new TextDecoder,o="",c="",d=0,u=0,h=[];try{for(;;){let{done:m,value:f}=await i.read();if(m)break;o+=a.decode(f,{stream:!0});let g=o.split(`
1371
1371
  `);o=g.pop()??"";for(let y of g){let k=y.trim();if(!k)continue;let b;try{b=JSON.parse(k)}catch{continue}if(b.message?.content&&(c+=b.message.content,yield{type:"text_delta",text:b.message.content}),b.message?.tool_calls)for(let S of b.message.tool_calls){let I={id:`ollama_tool_${h.length}`,name:S.function.name,input:S.function.arguments};h.push(I),yield{type:"tool_use_start",toolCall:{id:I.id,name:I.name}},yield{type:"tool_use_delta",toolCall:{input:I.input}}}b.done&&(d=b.prompt_eval_count??0,u=b.eval_count??0,yield{type:"message_complete",response:{content:c,model:this.config.model,toolCalls:h.length>0?h:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:h.length>0?"tool_use":"end_turn"}})}}if(o.trim()){let m;try{m=JSON.parse(o.trim())}catch{return}if(m.message?.content&&(c+=m.message.content,yield{type:"text_delta",text:m.message.content}),m.message?.tool_calls)for(let f of m.message.tool_calls){let g={id:`ollama_tool_${h.length}`,name:f.function.name,input:f.function.arguments};h.push(g),yield{type:"tool_use_start",toolCall:{id:g.id,name:g.name}},yield{type:"tool_use_delta",toolCall:{input:g.input}}}m.done&&(d=m.prompt_eval_count??0,u=m.eval_count??0,yield{type:"message_complete",response:{content:c,toolCalls:h.length>0?h:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:h.length>0?"tool_use":"end_turn"}})}}finally{i.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 i of t)switch(i.type){case"text":s.push(i.text);break;case"image":r.push(i.source.data);break;case"tool_use":s.push(`[Tool call: ${i.name}(${JSON.stringify(i.input)})]`);break;case"tool_result":s.push(`[Tool result for ${i.tool_use_id}]: ${i.content}`);break}let n={role:e,content:s.join(`
1372
- `)};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 on,Zo=w(()=>{"use strict";Xs();on=class extends et{static{p(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as Vg}from"@google/genai";var cn,Qo=w(()=>{"use strict";is();cn=class extends He{static{p(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Vg({apiKey:this.config.apiKey});let e=Et(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="",i=[],a=0,o=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 h of d.functionCalls){let m={id:h.id??`google_tool_${i.length}`,name:h.name,input:h.args??{}};i.push(m),yield{type:"tool_use_start",toolCall:{id:m.id,name:m.name}}}d.usageMetadata&&(a=d.usageMetadata.promptTokenCount??0,o=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:i.length>0?i:void 0,usage:{inputTokens:a,outputTokens:o},stopReason:i.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 i=[],a=[],o=[];for(let c of r.content)switch(c.type){case"text":a.push({text:c.text});break;case"image":a.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":i.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 h=JSON.parse(c.content);u=typeof h=="object"&&h!==null?h:{result:h}}catch{u={result:c.content}}o.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&i.length>0){let c=this.buildCacheKeyFromBlocks(i),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...a];for(let h=0;h<i.length;h++){let m=i[h];u.push({functionCall:{id:m.id,name:m.name,args:m.input},...h===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else a.length>0&&s.push({role:n,parts:a});o.length>0&&s.push({role:"user",parts:o})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let a of e)if(a.role==="model"){for(let o of a.parts??[])if(o.functionCall){let c=o.functionCall.id??o.functionCall.name??"";c&&t.add(c)}s.push(a)}else{let o=(a.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});o.length>0&&s.push({role:a.role,parts:o})}let r=new Set;for(let a of s)if(a.role!=="model"){for(let o of a.parts??[])if(o.functionResponse){let c=o.functionResponse.id??o.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let a of s)if(a.role==="model"){let o=(a.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});o.length>0&&n.push({role:a.role,parts:o})}else n.push(a);if(n.length<=1)return n;let i=[n[0]];for(let a=1;a<n.length;a++){let o=i[i.length-1],c=n[a];o.role===c.role?o.parts=[...o.parts??[],...c.parts??[]]:i.push(c)}return i}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,i)=>({id:n.id??`google_tool_${i}`,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 ln,ec=w(()=>{"use strict";Xs();ln=class extends et{static{p(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function tc(l){switch(l.provider){case"anthropic":return new rn(l);case"openai":return new et(l);case"openrouter":return new nn(l);case"ollama":return new an(l);case"openwebui":return new on(l);case"google":return new cn(l);case"mistral":return new ln(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var sc=w(()=>{"use strict";Yo();Xs();Vo();Jo();Zo();Qo();ec();p(tc,"createLLMProvider")});function Pu(l){let e=l.toLowerCase();for(let[t,s]of Jg)if(e.startsWith(t.toLowerCase()))return s}function Ji(l,e){let t=Pu(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,i=e.cacheCreationTokens??0,a=Math.max(0,e.inputTokens-n);return r+=a/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),i>0&&t.cacheWrite&&(r+=i/s*t.cacheWrite),r}var Jg,dn,rc=w(()=>{"use strict";Jg=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];p(Pu,"getModelPricing");p(Ji,"calculateCost");dn=class{static{p(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=Ji(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 i=this.data.byModel[e];i||(i={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=i),i.calls++,i.inputTokens+=t.inputTokens,i.outputTokens+=t.outputTokens,i.cacheReadTokens+=r,i.cacheWriteTokens+=n,i.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 nc(l,e){return new Zi(l,e)}var Fu,Zi,ju=w(()=>{"use strict";is();sc();rc();Fu=["default","strong","fast","embeddings","local"],Zi=class extends He{static{p(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new dn;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of Fu){let t=this.multiConfig[e];if(t){let s=tc(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),i=n.model??r?.model??"unknown";n.model||(n.model=i);let a=this.costTracker.record(i,n.usage);return this.logger?.info({tier:t,model:i,costUsd:Math.round(a*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 i=this.providers.get(n);if(i)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(i,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 i=["default","strong","fast"].filter(a=>a!==s);for(let a of i){let o=this.providers.get(a);if(o)try{this.logger?.info({tier:a},"Stream fallback to tier"),yield*o.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 Fu){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};p(nc,"createModelRouter")});function tt(l){return Math.ceil(l.length/3.5)}function as(l){if(typeof l.content=="string")return tt(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=tt(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=tt(t.name)+tt(JSON.stringify(t.input));break;case"tool_result":e+=tt(t.content);break}return e}function ic(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let o of l)if(o.role==="assistant"&&Array.isArray(o.content))for(let c of o.content)c.type==="tool_use"&&n.set(c.id,c.name);let i=[];for(let o=0;o<l.length;o++){let c=l[o];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&i.push(o)}let a=new Set(i.slice(-t));return l.map((o,c)=>{if(a.has(c)||o.role!=="user"||!Array.isArray(o.content))return o;let d=!1,u=o.content.map(h=>{if(h.type!=="tool_result")return h;let m=h.content;if(typeof m!="string"||m.length<r)return h;d=!0;let f=n.get(h.tool_use_id)||"unknown",g=m.split(`
1372
+ `)};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 on,Zo=w(()=>{"use strict";Xs();on=class extends et{static{p(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as Vg}from"@google/genai";var cn,Qo=w(()=>{"use strict";is();cn=class extends Xe{static{p(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Vg({apiKey:this.config.apiKey});let e=Et(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="",i=[],a=0,o=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 h of d.functionCalls){let m={id:h.id??`google_tool_${i.length}`,name:h.name,input:h.args??{}};i.push(m),yield{type:"tool_use_start",toolCall:{id:m.id,name:m.name}}}d.usageMetadata&&(a=d.usageMetadata.promptTokenCount??0,o=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:i.length>0?i:void 0,usage:{inputTokens:a,outputTokens:o},stopReason:i.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 i=[],a=[],o=[];for(let c of r.content)switch(c.type){case"text":a.push({text:c.text});break;case"image":a.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":i.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 h=JSON.parse(c.content);u=typeof h=="object"&&h!==null?h:{result:h}}catch{u={result:c.content}}o.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&i.length>0){let c=this.buildCacheKeyFromBlocks(i),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...a];for(let h=0;h<i.length;h++){let m=i[h];u.push({functionCall:{id:m.id,name:m.name,args:m.input},...h===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else a.length>0&&s.push({role:n,parts:a});o.length>0&&s.push({role:"user",parts:o})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let a of e)if(a.role==="model"){for(let o of a.parts??[])if(o.functionCall){let c=o.functionCall.id??o.functionCall.name??"";c&&t.add(c)}s.push(a)}else{let o=(a.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});o.length>0&&s.push({role:a.role,parts:o})}let r=new Set;for(let a of s)if(a.role!=="model"){for(let o of a.parts??[])if(o.functionResponse){let c=o.functionResponse.id??o.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let a of s)if(a.role==="model"){let o=(a.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});o.length>0&&n.push({role:a.role,parts:o})}else n.push(a);if(n.length<=1)return n;let i=[n[0]];for(let a=1;a<n.length;a++){let o=i[i.length-1],c=n[a];o.role===c.role?o.parts=[...o.parts??[],...c.parts??[]]:i.push(c)}return i}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,i)=>({id:n.id??`google_tool_${i}`,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 ln,ec=w(()=>{"use strict";Xs();ln=class extends et{static{p(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function tc(l){switch(l.provider){case"anthropic":return new rn(l);case"openai":return new et(l);case"openrouter":return new nn(l);case"ollama":return new an(l);case"openwebui":return new on(l);case"google":return new cn(l);case"mistral":return new ln(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var sc=w(()=>{"use strict";Yo();Xs();Vo();Jo();Zo();Qo();ec();p(tc,"createLLMProvider")});function Pu(l){let e=l.toLowerCase();for(let[t,s]of Jg)if(e.startsWith(t.toLowerCase()))return s}function Ji(l,e){let t=Pu(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,i=e.cacheCreationTokens??0,a=Math.max(0,e.inputTokens-n);return r+=a/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),i>0&&t.cacheWrite&&(r+=i/s*t.cacheWrite),r}var Jg,dn,rc=w(()=>{"use strict";Jg=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];p(Pu,"getModelPricing");p(Ji,"calculateCost");dn=class{static{p(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=Ji(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 i=this.data.byModel[e];i||(i={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=i),i.calls++,i.inputTokens+=t.inputTokens,i.outputTokens+=t.outputTokens,i.cacheReadTokens+=r,i.cacheWriteTokens+=n,i.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 nc(l,e){return new Zi(l,e)}var Fu,Zi,ju=w(()=>{"use strict";is();sc();rc();Fu=["default","strong","fast","embeddings","local"],Zi=class extends Xe{static{p(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new dn;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of Fu){let t=this.multiConfig[e];if(t){let s=tc(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),i=n.model??r?.model??"unknown";n.model||(n.model=i);let a=this.costTracker.record(i,n.usage);return this.logger?.info({tier:t,model:i,costUsd:Math.round(a*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 i=this.providers.get(n);if(i)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(i,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 i=["default","strong","fast"].filter(a=>a!==s);for(let a of i){let o=this.providers.get(a);if(o)try{this.logger?.info({tier:a},"Stream fallback to tier"),yield*o.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 Fu){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};p(nc,"createModelRouter")});function tt(l){return Math.ceil(l.length/3.5)}function as(l){if(typeof l.content=="string")return tt(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=tt(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=tt(t.name)+tt(JSON.stringify(t.input));break;case"tool_result":e+=tt(t.content);break}return e}function ic(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let o of l)if(o.role==="assistant"&&Array.isArray(o.content))for(let c of o.content)c.type==="tool_use"&&n.set(c.id,c.name);let i=[];for(let o=0;o<l.length;o++){let c=l[o];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&i.push(o)}let a=new Set(i.slice(-t));return l.map((o,c)=>{if(a.has(c)||o.role!=="user"||!Array.isArray(o.content))return o;let d=!1,u=o.content.map(h=>{if(h.type!=="tool_result")return h;let m=h.content;if(typeof m!="string"||m.length<r)return h;d=!0;let f=n.get(h.tool_use_id)||"unknown",g=m.split(`
1373
1373
  `)[0].slice(0,s),y=h.is_error?"Fehler":"Ergebnis";return{...h,content:`[${y}: ${f} \u2014 ${g}]`}});return d?{...o,content:u}:o})}var un,Bu=w(()=>{"use strict";p(tt,"estimateTokens");p(as,"estimateMessageTokens");p(ic,"trimOldToolResults");un=class{static{p(this,"PromptBuilder")}buildSystemPrompt(e={}){let{memories:t,skills:s,userProfile:r,todayEvents:n,conversationSummary:i}=e,a=process.platform==="darwin"?"macOS":process.platform==="win32"?"Windows":"Linux",o=process.env.HOME||process.env.USERPROFILE||"~",c=`You are Alfred, a personal AI assistant. You run on ${a} (home: ${o}).
1374
1374
 
1375
1375
  ## Core principles
@@ -1443,40 +1443,40 @@ This summarizes the earlier conversation. Use it to maintain continuity. The mos
1443
1443
  `;c+=`
1444
1444
  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+=`
1445
1445
 
1446
- 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 a=r,o=[];s.content&&o.push({type:"text",text:s.content});for(let c of a)o.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return o.length===0&&o.push({type:"text",text:""}),{role:"assistant",content:o}}let n=r,i=[];for(let a of n)a.type==="tool_result"&&i.push(a);return i.length>0?{role:"user",content:i}:{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 c of e)if(c.role==="assistant"&&Array.isArray(c.content))for(let d of c.content)d.type==="tool_use"&&t.add(d.id);else if(c.role==="user"&&Array.isArray(c.content))for(let d of c.content)d.type==="tool_result"&&t.has(d.tool_use_id)&&s.add(d.tool_use_id);let r=new Set,n=new Set,i=[];for(let c of e){if(!Array.isArray(c.content)){i.push(c);continue}let d=c.content.filter(u=>u.type==="tool_use"?!s.has(u.id)||r.has(u.id)?!1:(r.add(u.id),!0):u.type==="tool_result"?!s.has(u.tool_use_id)||n.has(u.tool_use_id)?!1:(n.add(u.tool_use_id),!0):!0);d.length!==0&&i.push({...c,content:d})}let a=[];for(let c of i){let d=a[a.length-1];if(d&&d.role===c.role){let u=typeof d.content=="string"?[{type:"text",text:d.content}]:d.content,h=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content;a[a.length-1]={...d,content:[...u,...h]}}else a.push(c)}let o=[];for(let c=0;c<a.length;c++){let d=a[c],u=o[o.length-1];if(u&&u.role==="user"&&d.role==="user"&&o.push({role:"assistant",content:"(previous request failed)"}),u&&u.role==="assistant"&&Array.isArray(u.content)&&d.role==="user"){let h=u.content.some(f=>f.type==="tool_use"),m=Array.isArray(d.content)&&d.content.some(f=>f.type==="tool_result");if(h&&!m){let f=u.content.filter(g=>g.type==="text");o[o.length-1]={role:"assistant",content:f.length>0?f:"(tool execution failed)"}}}if(c===a.length-1&&d.role==="assistant"&&Array.isArray(d.content)&&d.content.some(m=>m.type==="tool_use")){let m=d.content.filter(f=>f.type==="text");o.push({role:"assistant",content:m.length>0?m:"(tool execution incomplete)"});continue}o.push(d)}return o}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var ac=w(()=>{"use strict";is();Yo();Xs();Vo();Jo();Zo();Qo();ec();sc();ju();Bu();rc()});var pn,oc=w(()=>{"use strict";pn=class{static{p(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let i=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:i,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 hn,Xu=w(()=>{"use strict";oc();hn=class{static{p(this,"RuleEngine")}rules=[];rateLimiter=new pn;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 Hu,Wu,qu,_t,zu=w(()=>{"use strict";Hu=["allow","deny"],Wu=["global","user","conversation","platform"],qu=["read","write","destructive","admin"],_t=class{static{p(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!Hu.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Hu.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"||!Wu.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Wu.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(!qu.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${qu.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 i=n.timeWindow;if(typeof i!="object"||i===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(i.startHour!==void 0&&(typeof i.startHour!="number"||i.startHour<0||i.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(i.endHour!==void 0&&(typeof i.endHour!="number"||i.endHour<0||i.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(i.daysOfWeek!==void 0&&(!Array.isArray(i.daysOfWeek)||!i.daysOfWeek.every(a=>typeof a=="number"&&a>=0&&a<=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 Zg from"node:crypto";var mn,Ku=w(()=>{"use strict";mn=class{static{p(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:Zg.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 Qi=w(()=>{"use strict";Xu();oc();zu();Ku()});var N,X=w(()=>{"use strict";N=class{static{p(this,"Skill")}}});function se(l){return l.masterUserId??l.userId}function ee(l){let e=new Set;if(e.add(se(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var We=w(()=>{"use strict";p(se,"effectiveUserId");p(ee,"allUserIds")});var Hs,Gu=w(()=>{"use strict";Hs=class{static{p(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var Ws,Yu=w(()=>{"use strict";Ws=class{static{p(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:i}=e.metadata;return this.logger.info({skill:i,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,i,r,n):this.executeWithHardTimeout(e,t,s,i,r)}async executeWithTracker(e,t,s,r,n,i){return new Promise(a=>{let o=!1,c,d,u,h=p(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),m=p(f=>{o||(o=!0,h(),a(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),m(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),m({success:!1,error:g})}),u=setTimeout(()=>{if(o)return;let f=i.getIdleMs();if(f>=12e4){let y=i.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),m({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=i.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(o){h();return}let y=i.getIdleMs(),k=i.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:k.state,iteration:k.iteration,totalMs:k.totalElapsedMs},"Agent went inactive \u2014 aborting"),m({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(o)return;let f=i.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),m({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 i,a=await Promise.race([e.execute(t,s),new Promise((o,c)=>{i=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{i&&clearTimeout(i)});return this.logger.info({skill:r,success:a.success,...a.success?{}:{error:a.error}},"Skill execution completed"),a}catch(i){let a=i instanceof Error?i.message:String(i);return this.logger.error({skill:r,error:a},"Skill execution failed"),{success:!1,error:a}}}}});var os,cc=w(()=>{"use strict";os=class{static{p(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import Qg from"node:fs";import lc from"node:path";var ea,Vu=w(()=>{"use strict";X();ea=class{static{p(this,"PluginLoader")}async loadFromDirectory(e){let t=lc.resolve(e),s;try{s=await Qg.promises.readdir(t)}catch(i){let a=i instanceof Error?i.message:String(i);return console.warn(`PluginLoader: failed to read directory "${t}": ${a}`),[]}let r=s.filter(i=>i.endsWith(".js")),n=[];for(let i of r){let a=lc.join(t,i);try{let o=await this.loadFromFile(a);n.push(o)}catch(o){let c=o instanceof Error?o.message:String(o);console.warn(`PluginLoader: skipping "${a}": ${c}`)}}return n}async loadFromFile(e){let t=lc.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 i=new n;if(!(i instanceof N))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(i,t),i}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 ey(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 Ju)e.push({type:"const",value:Ju[s]});else if(s in Zu)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 ty(l){let e=ey(l);if(e.length===0)throw new Error("Empty expression");return new dc(e).parse()}var Zu,Ju,dc,qs,Qu=w(()=>{"use strict";X();Zu={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},Ju={PI:Math.PI,E:Math.E};p(ey,"tokenize");dc=class{static{p(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return Zu[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};p(ty,"safeEval");qs=class extends N{static{p(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=ty(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 i=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${i}`}}}}});var zs,ep=w(()=>{"use strict";X();zs=class extends N{static{p(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=p(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var Ks,tp=w(()=>{"use strict";X();Ks=class extends N{static{p(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let i;switch(this.config.provider){case"brave":i=await this.searchBrave(s,r);break;case"searxng":i=await this.searchSearXNG(s,r);break;case"tavily":i=await this.searchTavily(s,r);break;case"duckduckgo":i=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(i.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let a=i.map((o,c)=>`${c+1}. **${o.title}**
1446
+ 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 a=r,o=[];s.content&&o.push({type:"text",text:s.content});for(let c of a)o.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return o.length===0&&o.push({type:"text",text:""}),{role:"assistant",content:o}}let n=r,i=[];for(let a of n)a.type==="tool_result"&&i.push(a);return i.length>0?{role:"user",content:i}:{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 c of e)if(c.role==="assistant"&&Array.isArray(c.content))for(let d of c.content)d.type==="tool_use"&&t.add(d.id);else if(c.role==="user"&&Array.isArray(c.content))for(let d of c.content)d.type==="tool_result"&&t.has(d.tool_use_id)&&s.add(d.tool_use_id);let r=new Set,n=new Set,i=[];for(let c of e){if(!Array.isArray(c.content)){i.push(c);continue}let d=c.content.filter(u=>u.type==="tool_use"?!s.has(u.id)||r.has(u.id)?!1:(r.add(u.id),!0):u.type==="tool_result"?!s.has(u.tool_use_id)||n.has(u.tool_use_id)?!1:(n.add(u.tool_use_id),!0):!0);d.length!==0&&i.push({...c,content:d})}let a=[];for(let c of i){let d=a[a.length-1];if(d&&d.role===c.role){let u=typeof d.content=="string"?[{type:"text",text:d.content}]:d.content,h=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content;a[a.length-1]={...d,content:[...u,...h]}}else a.push(c)}let o=[];for(let c=0;c<a.length;c++){let d=a[c],u=o[o.length-1];if(u&&u.role==="user"&&d.role==="user"&&o.push({role:"assistant",content:"(previous request failed)"}),u&&u.role==="assistant"&&Array.isArray(u.content)&&d.role==="user"){let h=u.content.some(f=>f.type==="tool_use"),m=Array.isArray(d.content)&&d.content.some(f=>f.type==="tool_result");if(h&&!m){let f=u.content.filter(g=>g.type==="text");o[o.length-1]={role:"assistant",content:f.length>0?f:"(tool execution failed)"}}}if(c===a.length-1&&d.role==="assistant"&&Array.isArray(d.content)&&d.content.some(m=>m.type==="tool_use")){let m=d.content.filter(f=>f.type==="text");o.push({role:"assistant",content:m.length>0?m:"(tool execution incomplete)"});continue}o.push(d)}return o}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var ac=w(()=>{"use strict";is();Yo();Xs();Vo();Jo();Zo();Qo();ec();sc();ju();Bu();rc()});var pn,oc=w(()=>{"use strict";pn=class{static{p(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let i=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:i,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 hn,Xu=w(()=>{"use strict";oc();hn=class{static{p(this,"RuleEngine")}rules=[];rateLimiter=new pn;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 Hu,Wu,qu,_t,zu=w(()=>{"use strict";Hu=["allow","deny"],Wu=["global","user","conversation","platform"],qu=["read","write","destructive","admin"],_t=class{static{p(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!Hu.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${Hu.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"||!Wu.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${Wu.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(!qu.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${qu.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 i=n.timeWindow;if(typeof i!="object"||i===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(i.startHour!==void 0&&(typeof i.startHour!="number"||i.startHour<0||i.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(i.endHour!==void 0&&(typeof i.endHour!="number"||i.endHour<0||i.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(i.daysOfWeek!==void 0&&(!Array.isArray(i.daysOfWeek)||!i.daysOfWeek.every(a=>typeof a=="number"&&a>=0&&a<=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 Zg from"node:crypto";var mn,Ku=w(()=>{"use strict";mn=class{static{p(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:Zg.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 Qi=w(()=>{"use strict";Xu();oc();zu();Ku()});var N,X=w(()=>{"use strict";N=class{static{p(this,"Skill")}}});function se(l){return l.masterUserId??l.userId}function Q(l){let e=new Set;if(e.add(se(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var He=w(()=>{"use strict";p(se,"effectiveUserId");p(Q,"allUserIds")});var Hs,Gu=w(()=>{"use strict";Hs=class{static{p(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var Ws,Yu=w(()=>{"use strict";Ws=class{static{p(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:i}=e.metadata;return this.logger.info({skill:i,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,i,r,n):this.executeWithHardTimeout(e,t,s,i,r)}async executeWithTracker(e,t,s,r,n,i){return new Promise(a=>{let o=!1,c,d,u,h=p(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),m=p(f=>{o||(o=!0,h(),a(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),m(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),m({success:!1,error:g})}),u=setTimeout(()=>{if(o)return;let f=i.getIdleMs();if(f>=12e4){let y=i.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),m({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=i.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(o){h();return}let y=i.getIdleMs(),k=i.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:k.state,iteration:k.iteration,totalMs:k.totalElapsedMs},"Agent went inactive \u2014 aborting"),m({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(o)return;let f=i.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),m({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 i,a=await Promise.race([e.execute(t,s),new Promise((o,c)=>{i=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{i&&clearTimeout(i)});return this.logger.info({skill:r,success:a.success,...a.success?{}:{error:a.error}},"Skill execution completed"),a}catch(i){let a=i instanceof Error?i.message:String(i);return this.logger.error({skill:r,error:a},"Skill execution failed"),{success:!1,error:a}}}}});var os,cc=w(()=>{"use strict";os=class{static{p(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import Qg from"node:fs";import lc from"node:path";var ea,Vu=w(()=>{"use strict";X();ea=class{static{p(this,"PluginLoader")}async loadFromDirectory(e){let t=lc.resolve(e),s;try{s=await Qg.promises.readdir(t)}catch(i){let a=i instanceof Error?i.message:String(i);return console.warn(`PluginLoader: failed to read directory "${t}": ${a}`),[]}let r=s.filter(i=>i.endsWith(".js")),n=[];for(let i of r){let a=lc.join(t,i);try{let o=await this.loadFromFile(a);n.push(o)}catch(o){let c=o instanceof Error?o.message:String(o);console.warn(`PluginLoader: skipping "${a}": ${c}`)}}return n}async loadFromFile(e){let t=lc.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 i=new n;if(!(i instanceof N))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(i,t),i}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 ey(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 Ju)e.push({type:"const",value:Ju[s]});else if(s in Zu)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 ty(l){let e=ey(l);if(e.length===0)throw new Error("Empty expression");return new dc(e).parse()}var Zu,Ju,dc,qs,Qu=w(()=>{"use strict";X();Zu={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},Ju={PI:Math.PI,E:Math.E};p(ey,"tokenize");dc=class{static{p(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return Zu[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};p(ty,"safeEval");qs=class extends N{static{p(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=ty(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 i=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${i}`}}}}});var zs,ep=w(()=>{"use strict";X();zs=class extends N{static{p(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=p(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var Ks,tp=w(()=>{"use strict";X();Ks=class extends N{static{p(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let i;switch(this.config.provider){case"brave":i=await this.searchBrave(s,r);break;case"searxng":i=await this.searchSearXNG(s,r);break;case"tavily":i=await this.searchTavily(s,r);break;case"duckduckgo":i=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(i.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let a=i.map((o,c)=>`${c+1}. **${o.title}**
1447
1447
  ${o.url}
1448
1448
  ${o.snippet}`).join(`
1449
1449
 
1450
1450
  `);return{success:!0,data:{query:s,results:i},display:`Search results for "${s}":
1451
1451
 
1452
- ${a}`}}catch(i){return{success:!1,error:`Search failed: ${i instanceof Error?i.message:String(i)}`}}}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(i=>({title:i.title,url:i.url,snippet:i.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(a=>({title:a.title,url:a.url,snippet:a.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,i=[],a;for(;(a=r.exec(e))!==null;){let c=a[1],d=this.stripHtml(a[2]).trim(),u=this.extractDdgUrl(c);d&&u&&i.push({url:u,title:d})}let o=[];for(;(a=n.exec(e))!==null;)o.push(this.stripHtml(a[1]).trim());for(let c=0;c<Math.min(i.length,t);c++)s.push({title:i[c].title,url:i[c].url,snippet:o[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ")}}});var Gs,sp=w(()=>{"use strict";X();We();Gs=class extends N{static{p(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}async getAllReminders(e){let t=new Set,s=[];for(let r of ee(e))for(let n of await 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`}}}async 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 i;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.`};i=u}else if(n!==void 0&&typeof n=="number"&&n>0)i=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 a=await this.reminderRepo.create(se(t),t.platform,t.chatId,s,i),o=i.getTime()-Date.now(),c=Math.round(o/6e4),d=i.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...t.timezone?{timeZone:t.timezone}:{}});return{success:!0,data:{reminderId:a.id,message:s,triggerAt:a.triggerAt},display:`Reminder set (${a.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 i=parseInt(r[1],10),a=parseInt(r[2],10);return i>23||a>59?void 0:this.buildDateInTimezone(i,a,void 0,t)}let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(n){let i=parseInt(n[1],10),a=parseInt(n[2],10)-1,o=parseInt(n[3],10),c=parseInt(n[4],10),d=parseInt(n[5],10);return c>23||d>59||a>11||o>31?void 0:this.buildDateInTimezone(c,d,{year:i,month:a,day:o},t)}}buildDateInTimezone(e,t,s,r){if(!r){let m=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||m.setHours(e,t,0,0),m}let n=new Date,i=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)),a=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 m=a.formatToParts(n),f=parseInt(m.find(D=>D.type==="year").value,10),g=parseInt(m.find(D=>D.type==="month").value,10)-1,y=parseInt(m.find(D=>D.type==="day").value,10),k=new Date(Date.UTC(f,g,y,e,t,0)),b=a.formatToParts(k),S=parseInt(b.find(D=>D.type==="hour").value,10),I=parseInt(b.find(D=>D.type==="minute").value,10),L=(e-S)*60+(t-I);return k=new Date(k.getTime()+L*6e4),k}let o=i,c=a.formatToParts(o),d=parseInt(c.find(m=>m.type==="hour").value,10),u=parseInt(c.find(m=>m.type==="minute").value,10),h=(e-d)*60+(t-u);return o=new Date(o.getTime()+h*6e4),o}async listReminders(e){let s=(await 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:
1452
+ ${a}`}}catch(i){return{success:!1,error:`Search failed: ${i instanceof Error?i.message:String(i)}`}}}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(i=>({title:i.title,url:i.url,snippet:i.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(a=>({title:a.title,url:a.url,snippet:a.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,i=[],a;for(;(a=r.exec(e))!==null;){let c=a[1],d=this.stripHtml(a[2]).trim(),u=this.extractDdgUrl(c);d&&u&&i.push({url:u,title:d})}let o=[];for(;(a=n.exec(e))!==null;)o.push(this.stripHtml(a[1]).trim());for(let c=0;c<Math.min(i.length,t);c++)s.push({title:i[c].title,url:i[c].url,snippet:o[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ")}}});var Gs,sp=w(()=>{"use strict";X();He();Gs=class extends N{static{p(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}async getAllReminders(e){let t=new Set,s=[];for(let r of Q(e))for(let n of await 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`}}}async 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 i;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.`};i=u}else if(n!==void 0&&typeof n=="number"&&n>0)i=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 a=await this.reminderRepo.create(se(t),t.platform,t.chatId,s,i),o=i.getTime()-Date.now(),c=Math.round(o/6e4),d=i.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...t.timezone?{timeZone:t.timezone}:{}});return{success:!0,data:{reminderId:a.id,message:s,triggerAt:a.triggerAt},display:`Reminder set (${a.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 i=parseInt(r[1],10),a=parseInt(r[2],10);return i>23||a>59?void 0:this.buildDateInTimezone(i,a,void 0,t)}let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(n){let i=parseInt(n[1],10),a=parseInt(n[2],10)-1,o=parseInt(n[3],10),c=parseInt(n[4],10),d=parseInt(n[5],10);return c>23||d>59||a>11||o>31?void 0:this.buildDateInTimezone(c,d,{year:i,month:a,day:o},t)}}buildDateInTimezone(e,t,s,r){if(!r){let m=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||m.setHours(e,t,0,0),m}let n=new Date,i=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)),a=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 m=a.formatToParts(n),f=parseInt(m.find(D=>D.type==="year").value,10),g=parseInt(m.find(D=>D.type==="month").value,10)-1,y=parseInt(m.find(D=>D.type==="day").value,10),k=new Date(Date.UTC(f,g,y,e,t,0)),b=a.formatToParts(k),S=parseInt(b.find(D=>D.type==="hour").value,10),I=parseInt(b.find(D=>D.type==="minute").value,10),L=(e-S)*60+(t-I);return k=new Date(k.getTime()+L*6e4),k}let o=i,c=a.formatToParts(o),d=parseInt(c.find(m=>m.type==="hour").value,10),u=parseInt(c.find(m=>m.type==="minute").value,10),h=(e-d)*60+(t-u);return o=new Date(o.getTime()+h*6e4),o}async listReminders(e){let s=(await 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:
1453
1453
  ${s.map(r=>`- ${r.reminderId}: "${r.message}" (triggers at ${r.triggerAt})`).join(`
1454
- `)}`}}async cancelReminder(e,t){let s=e.reminderId;return!s||typeof s!="string"?{success:!1,error:'Missing required field "reminderId" for cancel action'}:(await this.getAllReminders(t)).some(a=>a.id===s)?await 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 Ys,rp=w(()=>{"use strict";X();We();Ys=class extends N{static{p(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"]}};sharedResourceRepo;constructor(e){super(),this.noteRepo=e}async getSharedNoteIds(e){if(!this.sharedResourceRepo||!e.alfredUserId)return[];try{return(await this.sharedResourceRepo.getSharedWith(e.alfredUserId)).filter(s=>s.resourceType==="note").map(s=>s.resourceId)}catch{return[]}}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`}}}async 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=await this.noteRepo.save(se(t),s,r);return{success:!0,data:{noteId:n.id,title:n.title},display:`Note saved: "${s}"`}}async listNotes(e){let t=new Set,s=[];for(let a of ee(e))for(let o of await this.noteRepo.list(a))t.has(o.id)||(t.add(o.id),s.push(o));let r=await this.getSharedNoteIds(e),n=new Set;for(let a of r)if(!t.has(a)){let o=await this.noteRepo.getById(a);o&&(t.add(o.id),n.add(o.id),s.push(o))}if(s.length===0)return{success:!0,data:[],display:"No notes found."};let i=s.map(a=>{let o=n.has(a.id)?" (shared)":"";return`- **${a.title}**${o} (${a.id.slice(0,8)}\u2026)
1454
+ `)}`}}async cancelReminder(e,t){let s=e.reminderId;return!s||typeof s!="string"?{success:!1,error:'Missing required field "reminderId" for cancel action'}:(await this.getAllReminders(t)).some(a=>a.id===s)?await 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 Ys,rp=w(()=>{"use strict";X();He();Ys=class extends N{static{p(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"]}};sharedResourceRepo;constructor(e){super(),this.noteRepo=e}async getSharedNoteIds(e){if(!this.sharedResourceRepo||!e.alfredUserId)return[];try{return(await this.sharedResourceRepo.getSharedWith(e.alfredUserId)).filter(s=>s.resourceType==="note").map(s=>s.resourceId)}catch{return[]}}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`}}}async 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=await this.noteRepo.save(se(t),s,r);return{success:!0,data:{noteId:n.id,title:n.title},display:`Note saved: "${s}"`}}async listNotes(e){let t=new Set,s=[];for(let a of Q(e))for(let o of await this.noteRepo.list(a))t.has(o.id)||(t.add(o.id),s.push(o));let r=await this.getSharedNoteIds(e),n=new Set;for(let a of r)if(!t.has(a)){let o=await this.noteRepo.getById(a);o&&(t.add(o.id),n.add(o.id),s.push(o))}if(s.length===0)return{success:!0,data:[],display:"No notes found."};let i=s.map(a=>{let o=n.has(a.id)?" (shared)":"";return`- **${a.title}**${o} (${a.id.slice(0,8)}\u2026)
1455
1455
  ${a.content.slice(0,100)}${a.content.length>100?"\u2026":""}`}).join(`
1456
1456
  `);return{success:!0,data:s,display:`${s.length} note(s):
1457
- ${i}`}}async 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 d of ee(t))for(let u of await this.noteRepo.search(d,s))r.has(u.id)||(r.add(u.id),n.push(u));let i=await this.getSharedNoteIds(t),a=new Set,o=s.toLowerCase();for(let d of i)if(!r.has(d)){let u=await this.noteRepo.getById(d);u&&(u.title.toLowerCase().includes(o)||u.content.toLowerCase().includes(o))&&(r.add(u.id),a.add(u.id),n.push(u))}if(n.length===0)return{success:!0,data:[],display:`No notes matching "${s}".`};let c=n.map(d=>{let u=a.has(d.id)?" (shared)":"";return`- **${d.title}**${u} (${d.id.slice(0,8)}\u2026)
1457
+ ${i}`}}async 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 d of Q(t))for(let u of await this.noteRepo.search(d,s))r.has(u.id)||(r.add(u.id),n.push(u));let i=await this.getSharedNoteIds(t),a=new Set,o=s.toLowerCase();for(let d of i)if(!r.has(d)){let u=await this.noteRepo.getById(d);u&&(u.title.toLowerCase().includes(o)||u.content.toLowerCase().includes(o))&&(r.add(u.id),a.add(u.id),n.push(u))}if(n.length===0)return{success:!0,data:[],display:`No notes matching "${s}".`};let c=n.map(d=>{let u=a.has(d.id)?" (shared)":"";return`- **${d.title}**${u} (${d.id.slice(0,8)}\u2026)
1458
1458
  ${d.content.slice(0,100)}${d.content.length>100?"\u2026":""}`}).join(`
1459
1459
  `);return{success:!0,data:n,display:`Found ${n.length} note(s):
1460
- ${c}`}}async 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=await this.noteRepo.getById(s);return r?ee(t).includes(r.userId)?await 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 sy,Vs,np=w(()=>{"use strict";X();sy={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"},Vs=class extends N{static{p(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),i=sy[n.weathercode]??`Code ${n.weathercode}`,a=r.admin1?`${r.name}, ${r.admin1}, ${r.country}`:`${r.name}, ${r.country}`,o={location:a,temperature:n.temperature,unit:"\xB0C",condition:i,windSpeed:n.windspeed,windDirection:n.winddirection,isDay:n.is_day===1},c=`${a}: ${n.temperature}\xB0C, ${i}
1460
+ ${c}`}}async 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=await this.noteRepo.getById(s);return r?Q(t).includes(r.userId)?await 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 sy,Vs,np=w(()=>{"use strict";X();sy={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"},Vs=class extends N{static{p(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),i=sy[n.weathercode]??`Code ${n.weathercode}`,a=r.admin1?`${r.name}, ${r.admin1}, ${r.country}`:`${r.name}, ${r.country}`,o={location:a,temperature:n.temperature,unit:"\xB0C",condition:i,windSpeed:n.windspeed,windDirection:n.winddirection,isDay:n.is_day===1},c=`${a}: ${n.temperature}\xB0C, ${i}
1461
1461
  Wind: ${n.windspeed} km/h`;return{success:!0,data:o,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}&current_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 ry}from"node:child_process";function ap(l){return l.length>ip?l.slice(0,ip)+`
1462
1462
  [output truncated]`:l}var ny,ip,Js,op=w(()=>{"use strict";X();ny=3e4,ip=1e4;p(ap,"truncate");Js=class extends N{static{p(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 a of r)if(a.test(s))return{success:!1,error:"Command blocked: potentially destructive system operation"};let n=typeof e.timeout=="number"&&e.timeout>0?e.timeout:ny,i=typeof e.cwd=="string"&&e.cwd.length>0?e.cwd:void 0;try{let{stdout:a,stderr:o,exitCode:c}=await this.run(s,n,i),d=[];return a&&d.push(`stdout:
1463
1463
  ${ap(a)}`),o&&d.push(`stderr:
1464
1464
  ${ap(o)}`),d.length===0&&d.push("(no output)"),d.push(`exit code: ${c}`),{success:c===0,data:{stdout:a,stderr:o,exitCode:c},display:d.join(`
1465
1465
 
1466
- `),...c!==0&&{error:`Command exited with code ${c}`}}}catch(a){return{success:!1,error:`Shell execution failed: ${a instanceof Error?a.message:String(a)}`}}}run(e,t,s){return new Promise(r=>{ry(e,{timeout:t,cwd:s},(n,i,a)=>{let o=n&&"code"in n&&typeof n.code=="number"?n.code:n?1:0;r({stdout:typeof i=="string"?i:"",stderr:typeof a=="string"?a:"",exitCode:o})})})}}});var Zs,cp=w(()=>{"use strict";X();We();Zs=class extends N{static{p(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`}}}async 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 i=await this.memoryRepo.save(se(t),s,r,n??"general");return this.embeddingService&&this.embeddingService.embedAndStore(se(t),`${s}: ${r}`,"memory",s).catch(()=>{}),{success:!0,data:i,display:`Remembered "${s}" = "${r}" (category: ${i.category})`}}async 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 ee(t))if(r=await 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}".`}}async 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 i of ee(t))for(let a of await this.memoryRepo.search(i,s))r.has(a.id)||(r.add(a.id),n.push(a));return{success:!0,data:n,display:n.length===0?`No memories matching "${s}".`:`Found ${n.length} memory(ies):
1466
+ `),...c!==0&&{error:`Command exited with code ${c}`}}}catch(a){return{success:!1,error:`Shell execution failed: ${a instanceof Error?a.message:String(a)}`}}}run(e,t,s){return new Promise(r=>{ry(e,{timeout:t,cwd:s},(n,i,a)=>{let o=n&&"code"in n&&typeof n.code=="number"?n.code:n?1:0;r({stdout:typeof i=="string"?i:"",stderr:typeof a=="string"?a:"",exitCode:o})})})}}});var Zs,cp=w(()=>{"use strict";X();He();Zs=class extends N{static{p(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`}}}async 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 i=await this.memoryRepo.save(se(t),s,r,n??"general");return this.embeddingService&&this.embeddingService.embedAndStore(se(t),`${s}: ${r}`,"memory",s).catch(()=>{}),{success:!0,data:i,display:`Remembered "${s}" = "${r}" (category: ${i.category})`}}async 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 Q(t))if(r=await 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}".`}}async 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 i of Q(t))for(let a of await this.memoryRepo.search(i,s))r.has(a.id)||(r.add(a.id),n.push(a));return{success:!0,data:n,display:n.length===0?`No memories matching "${s}".`:`Found ${n.length} memory(ies):
1467
1467
  ${n.map(i=>`- ${i.key}: "${i.value}"`).join(`
1468
- `)}`}}async listMemories(e,t){let s=e.category,r=new Set,n=[];for(let a of ee(t)){let o=s&&typeof s=="string"?await this.memoryRepo.listByCategory(a,s):await this.memoryRepo.listAll(a);for(let c of o)r.has(c.id)||(r.add(c.id),n.push(c))}let i=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) ${i}:
1468
+ `)}`}}async listMemories(e,t){let s=e.category,r=new Set,n=[];for(let a of Q(t)){let o=s&&typeof s=="string"?await this.memoryRepo.listByCategory(a,s):await this.memoryRepo.listAll(a);for(let c of o)r.has(c.id)||(r.add(c.id),n.push(c))}let i=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) ${i}:
1469
1469
  ${n.map(a=>`- [${a.category}] ${a.key}: "${a.value}"`).join(`
1470
- `)}`}}async 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 ee(t))if(await 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 i of ee(t))for(let a of await this.embeddingService.semanticSearch(i,s,10))r.has(a.key)||(r.add(a.key),n.push(a));return n.length===0?this.searchMemories(e,t):{success:!0,data:n,display:`Found ${n.length} semantically related memory(ies):
1470
+ `)}`}}async 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 Q(t))if(await 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 i of Q(t))for(let a of await this.embeddingService.semanticSearch(i,s,10))r.has(a.key)||(r.add(a.key),n.push(a));return n.length===0?this.searchMemories(e,t):{success:!0,data:n,display:`Found ${n.length} semantically related memory(ies):
1471
1471
  ${n.map(i=>`- ${i.key}: "${i.value}" (score: ${i.score.toFixed(2)})`).join(`
1472
1472
  `)}`}}}});var iy,ay,oy,Qs,lp=w(()=>{"use strict";X();cc();iy=15,ay=25,oy=12e4,Qs=class extends N{static{p(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:oy,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 os(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,i=n?Math.max(1,Math.min(ay,Math.round(n))):iy,a=t.onProgress??this.onProgress,o=t.tracker?t.tracker:new os(a);o.ping("starting",{maxIterations:i});let c=this.buildSubAgentTools(),d=new Map,u=0;if(t.resumeState?.dataStore)for(let[y,k]of Object.entries(t.resumeState.dataStore)){d.set(y,k);let b=y.match(/^result_(\d+)$/);b&&(u=Math.max(u,Number(b[1])))}let h=`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.
1473
1473
 
1474
1474
  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.
1475
1475
  Available JS libraries in code_sandbox (no install needed): exceljs, pdfkit, pdf-parse.`,m=s;r&&typeof r=="string"&&(m=`${s}
1476
1476
 
1477
- Additional context: ${r}`);let f,g;t.resumeState?.conversationHistory?.length?(f=t.resumeState.conversationHistory,g=t.resumeState.currentIteration):(f=[{role:"user",content:m}],g=0);try{let y=g,k=0,b=0;for(;;){if(t.abortSignal?.aborted)return t.onIteration?.({iteration:y,maxIterations:i,messages:[...f],dataStore:Object.fromEntries(d)}),o.ping("done",{iteration:y,maxIterations:i}),{success:!0,data:{response:"Task paused \u2014 can be resumed later.",iterations:y,paused:!0,usage:{inputTokens:k,outputTokens:b}},display:"Task paused \u2014 can be resumed later."};o.ping("llm_call",{iteration:y,maxIterations:i});let S=await this.llm.complete({messages:f,system:h,tools:c.length>0?c:void 0,maxTokens:8192,tier:"strong"});if(k+=S.usage.inputTokens,b+=S.usage.outputTokens,o.ping("processing",{iteration:y,maxIterations:i}),!S.toolCalls||S.toolCalls.length===0||y>=i)return o.ping("done",{iteration:y,maxIterations:i}),{success:!0,data:{response:S.content,iterations:y,usage:{inputTokens:k,outputTokens:b}},display:S.content};y++;let I=[];S.content&&I.push({type:"text",text:S.content});for(let D of S.toolCalls)I.push({type:"tool_use",id:D.id,name:D.name,input:D.input});f.push({role:"assistant",content:I});let L=[];for(let D of S.toolCalls){o.ping("tool_call",{iteration:y,maxIterations:i,tool:D.name});let W=D.input;if(D.name==="code_sandbox"&&D.input.data){let ce=String(D.input.data);d.has(ce)&&(W={...D.input,data:d.get(ce)},W.action==="run"&&(W.action="run_with_data"))}let q=await this.executeSubAgentTool({...D,input:W},t),j=q.content;if(!q.isError&&j.length>500){let ce=`result_${++u}`,me=q.rawData!=null?JSON.stringify(q.rawData):j;d.set(ce,me),j+=`
1477
+ Additional context: ${r}`);let f,g;t.resumeState?.conversationHistory?.length?(f=t.resumeState.conversationHistory,g=t.resumeState.currentIteration):(f=[{role:"user",content:m}],g=0);try{let y=g,k=0,b=0;for(;;){if(t.abortSignal?.aborted)return t.onIteration?.({iteration:y,maxIterations:i,messages:[...f],dataStore:Object.fromEntries(d)}),o.ping("done",{iteration:y,maxIterations:i}),{success:!0,data:{response:"Task paused \u2014 can be resumed later.",iterations:y,paused:!0,usage:{inputTokens:k,outputTokens:b}},display:"Task paused \u2014 can be resumed later."};o.ping("llm_call",{iteration:y,maxIterations:i});let S=await this.llm.complete({messages:f,system:h,tools:c.length>0?c:void 0,maxTokens:8192,tier:"strong"});if(k+=S.usage.inputTokens,b+=S.usage.outputTokens,o.ping("processing",{iteration:y,maxIterations:i}),!S.toolCalls||S.toolCalls.length===0||y>=i)return o.ping("done",{iteration:y,maxIterations:i}),{success:!0,data:{response:S.content,iterations:y,usage:{inputTokens:k,outputTokens:b}},display:S.content};y++;let I=[];S.content&&I.push({type:"text",text:S.content});for(let D of S.toolCalls)I.push({type:"tool_use",id:D.id,name:D.name,input:D.input});f.push({role:"assistant",content:I});let L=[];for(let D of S.toolCalls){o.ping("tool_call",{iteration:y,maxIterations:i,tool:D.name});let W=D.input;if(D.name==="code_sandbox"&&D.input.data){let oe=String(D.input.data);d.has(oe)&&(W={...D.input,data:d.get(oe)},W.action==="run"&&(W.action="run_with_data"))}let q=await this.executeSubAgentTool({...D,input:W},t),j=q.content;if(!q.isError&&j.length>500){let oe=`result_${++u}`,me=q.rawData!=null?JSON.stringify(q.rawData):j;d.set(oe,me),j+=`
1478
1478
 
1479
- [Data stored as "${ce}" \u2014 use code_sandbox action "run_with_data" with data="${ce}" to process this data. Do NOT copy data into code.]`}L.push({type:"tool_result",tool_use_id:D.id,content:j,is_error:q.isError})}f.push({role:"user",content:L}),t.onIteration?.({iteration:y,maxIterations:i,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 kt,ta=w(()=>{"use strict";kt=class{static{p(this,"EmailProvider")}async extractFromSearch(e,t,s,r,n){throw new Error("Extract is not supported by this email provider.")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var dp={};ie(dp,{MicrosoftGraphEmailProvider:()=>sa});var sa,uc=w(()=>{"use strict";ta();sa=class extends kt{static{p(this,"MicrosoftGraphEmailProvider")}config;accessToken="";userPath;constructor(e){super(),this.config=e,this.userPath=e.sharedMailbox?`/users/${e.sharedMailbox}`:"/me"}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:this.config.sharedMailbox?"https://graph.microsoft.com/Mail.ReadWrite.Shared https://graph.microsoft.com/Mail.Send.Shared offline_access":"https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${n.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let n=await s(this.accessToken);if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return this.parseJsonOrUndefined(n)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${n}`}}),"doFetch"),s=await t(this.accessToken);if(s.status===401&&(await this.refreshAccessToken(),s=await t(this.accessToken)),!s.ok)throw new Error(`Graph API error: ${s.status}`);let r=await s.arrayBuffer();return Buffer.from(r)}async fetchInbox(e){let t=new URLSearchParams({$top:String(Math.min(Math.max(1,e),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`${this.userPath}/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(`${this.userPath}/messages/${e}?${t}`),r=[];return s.hasAttachments&&(r=((await this.graphRequest(`${this.userPath}/messages/${e}/attachments?$select=id,name,contentType,size`)).value??[]).map(i=>({id:i.id,name:i.name,contentType:i.contentType,size:i.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(`${this.userPath}/messages?${r}`),i=(n.value??[]).map(a=>this.mapMessage(a));if(t>50){let a=n["@odata.nextLink"];for(;a&&i.length<t;){let o=await this.graphRequest(a.replace("https://graph.microsoft.com/v1.0","")),c=(o.value??[]).map(d=>this.mapMessage(d));i.push(...c),a=o["@odata.nextLink"]}}return i.slice(0,t)}async extractFromSearch(e,t,s,r,n){let i=await this.searchWithDateFilter(e,t,r,n),a=s.includes("amount"),o=[];if(a)for(let d=0;d<i.length;d+=5){let u=i.slice(d,d+5),h=await Promise.allSettled(u.map(async m=>{let f={id:m.id,from:m.from,subject:m.subject,date:m.date.toISOString().split("T")[0],preview:(m.preview??"").slice(0,200)};try{let g=await this.readMessage(m.id),y=this.extractAmount(g.body);y&&(f.amount=y.amount,f.currency=y.currency)}catch{}return f}));for(let m of h)m.status==="fulfilled"&&o.push(m.value)}else for(let c of i)o.push({id:c.id,from:c.from,subject:c.subject,date:c.date.toISOString().split("T")[0],preview:(c.preview??"").slice(0,200)});return o}async searchWithDateFilter(e,t,s,r){let n=Math.min(Math.max(1,t),50),i=[];if(s||r){let h=s?this.toKqlDate(s):"01/01/2000",m=r?this.toKqlDate(r):"12/31/2099";i.push(`received:${h}..${m}`)}e&&i.push(e.includes(" ")?`(${e})`:e);let a=i.join(" AND "),o=new URLSearchParams({$top:String(n),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});a?o.set("$search",`"${a}"`):o.set("$orderby","receivedDateTime desc");let c=await this.graphRequest(`${this.userPath}/messages?${o}`),d=(c.value??[]).map(h=>this.mapMessage(h)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let h=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),m=(h.value??[]).map(f=>this.mapMessage(f));d.push(...m),u=h["@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(`${this.userPath}/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(`${this.userPath}/sendMail`,{method:"POST",body:JSON.stringify({message:t})}),{messageId:`sent-${Date.now()}`}}async createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`${this.userPath}/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(`${this.userPath}/messages`,{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest(`${this.userPath}/mailFolders?$select=displayName&$top=100`)).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest(`${this.userPath}/mailFolders?$select=id,displayName&$top=100`)).value??[]).find(a=>a.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(`${this.userPath}/mailFolders/${r.id}/messages?${n}`)).value??[]).map(a=>this.mapMessage(a))}async downloadAttachment(e,t){return this.graphRequestRaw(`${this.userPath}/messages/${e}/attachments/${t}/$value`)}async forwardMessage(e,t,s){return await this.graphRequest(`${this.userPath}/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,`
1479
+ [Data stored as "${oe}" \u2014 use code_sandbox action "run_with_data" with data="${oe}" to process this data. Do NOT copy data into code.]`}L.push({type:"tool_result",tool_use_id:D.id,content:j,is_error:q.isError})}f.push({role:"user",content:L}),t.onIteration?.({iteration:y,maxIterations:i,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 kt,ta=w(()=>{"use strict";kt=class{static{p(this,"EmailProvider")}async extractFromSearch(e,t,s,r,n){throw new Error("Extract is not supported by this email provider.")}async createDraft(e){throw new Error("Draft creation is not supported by this email provider.")}async forwardMessage(e,t,s){throw new Error("Email forwarding is not supported by this email provider.")}}});var dp={};ie(dp,{MicrosoftGraphEmailProvider:()=>sa});var sa,uc=w(()=>{"use strict";ta();sa=class extends kt{static{p(this,"MicrosoftGraphEmailProvider")}config;accessToken="";userPath;constructor(e){super(),this.config=e,this.userPath=e.sharedMailbox?`/users/${e.sharedMailbox}`:"/me"}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:this.config.sharedMailbox?"https://graph.microsoft.com/Mail.ReadWrite.Shared https://graph.microsoft.com/Mail.Send.Shared offline_access":"https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok){let n=await s.text().catch(()=>"");throw new Error(`Microsoft token refresh failed: ${s.status} \u2014 ${n.slice(0,300)}`)}let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s(this.accessToken);if(r.status===401){await this.refreshAccessToken();let n=await s(this.accessToken);if(!n.ok)throw new Error(`Graph API error: ${n.status}`);return this.parseJsonOrUndefined(n)}if(!r.ok)throw new Error(`Graph API error: ${r.status}`);return this.parseJsonOrUndefined(r)}async parseJsonOrUndefined(e){if(e.status===204||e.status===202)return;let t=await e.text();if(!(!t||t.length===0))return JSON.parse(t)}async graphRequestRaw(e){let t=p(n=>fetch(`https://graph.microsoft.com/v1.0${e}`,{headers:{Authorization:`Bearer ${n}`}}),"doFetch"),s=await t(this.accessToken);if(s.status===401&&(await this.refreshAccessToken(),s=await t(this.accessToken)),!s.ok)throw new Error(`Graph API error: ${s.status}`);let r=await s.arrayBuffer();return Buffer.from(r)}async fetchInbox(e){let t=new URLSearchParams({$top:String(Math.min(Math.max(1,e),50)),$orderby:"receivedDateTime desc",$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});return((await this.graphRequest(`${this.userPath}/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(`${this.userPath}/messages/${e}?${t}`),r=[];return s.hasAttachments&&(r=((await this.graphRequest(`${this.userPath}/messages/${e}/attachments?$select=id,name,contentType,size`)).value??[]).map(i=>({id:i.id,name:i.name,contentType:i.contentType,size:i.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(`${this.userPath}/messages?${r}`),i=(n.value??[]).map(a=>this.mapMessage(a));if(t>50){let a=n["@odata.nextLink"];for(;a&&i.length<t;){let o=await this.graphRequest(a.replace("https://graph.microsoft.com/v1.0","")),c=(o.value??[]).map(d=>this.mapMessage(d));i.push(...c),a=o["@odata.nextLink"]}}return i.slice(0,t)}async extractFromSearch(e,t,s,r,n){let i=await this.searchWithDateFilter(e,t,r,n),a=s.includes("amount"),o=[];if(a)for(let d=0;d<i.length;d+=5){let u=i.slice(d,d+5),h=await Promise.allSettled(u.map(async m=>{let f={id:m.id,from:m.from,subject:m.subject,date:m.date.toISOString().split("T")[0],preview:(m.preview??"").slice(0,200)};try{let g=await this.readMessage(m.id),y=this.extractAmount(g.body);y&&(f.amount=y.amount,f.currency=y.currency)}catch{}return f}));for(let m of h)m.status==="fulfilled"&&o.push(m.value)}else for(let c of i)o.push({id:c.id,from:c.from,subject:c.subject,date:c.date.toISOString().split("T")[0],preview:(c.preview??"").slice(0,200)});return o}async searchWithDateFilter(e,t,s,r){let n=Math.min(Math.max(1,t),50),i=[];if(s||r){let h=s?this.toKqlDate(s):"01/01/2000",m=r?this.toKqlDate(r):"12/31/2099";i.push(`received:${h}..${m}`)}e&&i.push(e.includes(" ")?`(${e})`:e);let a=i.join(" AND "),o=new URLSearchParams({$top:String(n),$select:"id,from,toRecipients,subject,receivedDateTime,isRead,bodyPreview,hasAttachments"});a?o.set("$search",`"${a}"`):o.set("$orderby","receivedDateTime desc");let c=await this.graphRequest(`${this.userPath}/messages?${o}`),d=(c.value??[]).map(h=>this.mapMessage(h)),u=c["@odata.nextLink"];for(;u&&d.length<t;){let h=await this.graphRequest(u.replace("https://graph.microsoft.com/v1.0","")),m=(h.value??[]).map(f=>this.mapMessage(f));d.push(...m),u=h["@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(`${this.userPath}/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(`${this.userPath}/sendMail`,{method:"POST",body:JSON.stringify({message:t})}),{messageId:`sent-${Date.now()}`}}async createDraft(e){if(e.replyTo)return{messageId:(await this.graphRequest(`${this.userPath}/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(`${this.userPath}/messages`,{method:"POST",body:JSON.stringify(t)}))?.id??`draft-${Date.now()}`}}async listFolders(){return((await this.graphRequest(`${this.userPath}/mailFolders?$select=displayName&$top=100`)).value??[]).map(t=>t.displayName)}async fetchFolder(e,t){let r=((await this.graphRequest(`${this.userPath}/mailFolders?$select=id,displayName&$top=100`)).value??[]).find(a=>a.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(`${this.userPath}/mailFolders/${r.id}/messages?${n}`)).value??[]).map(a=>this.mapMessage(a))}async downloadAttachment(e,t){return this.graphRequestRaw(`${this.userPath}/messages/${e}/attachments/${t}/$value`)}async forwardMessage(e,t,s){return await this.graphRequest(`${this.userPath}/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,`
1480
1480
  `).replace(/<\/p>/gi,`
1481
1481
 
1482
1482
  `).replace(/<[^>]+>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/\n{3,}/g,`
@@ -1549,12 +1549,12 @@ ${o}`}],system:"You are an email classifier. Return only a JSON object mapping e
1549
1549
 
1550
1550
  ${f.slice(0,5e3)}`}:{success:!0,data:g,display:`HTTP ${c.status} ${c.statusText}
1551
1551
 
1552
- ${f.slice(0,2e3)}`}}catch(o){return{success:!1,error:`HTTP request failed: ${o instanceof Error?o.message:String(o)}`}}}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,i]=r.map(Number);if(n===10||n===172&&i>=16&&i<=31||n===192&&i===168||n===127||n===169&&i===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 cy(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(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ").trim()}}});import ue from"node:fs";import Mt from"node:path";var mc,gp,ly,sr,yp=w(()=>{"use strict";X();mc=5e5,gp=5e7,ly={".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"},sr=class extends N{static{p(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,i=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 a=this.resolvePath(r),o=this.checkBlocked(a);if(o)return o;try{if(ue.existsSync(a)&&ue.lstatSync(a).isSymbolicLink()){let c=ue.realpathSync(a);if(this.checkBlocked(c))return{success:!1,error:"Access denied: symlink target is a blocked path"}}}catch{}switch(s){case"read":return this.readFile(a);case"write":return this.writeFile(a,n);case"write_binary":return this.writeBinaryFile(a,n);case"append":return this.appendFile(a,n);case"list":return this.listDir(a);case"info":return this.fileInfo(a);case"exists":return this.fileExists(a);case"move":return this.moveFile(a,i);case"copy":return this.copyFile(a,i);case"delete":return this.deleteFile(a);case"send":return this.sendFile(a);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"],i=[".env"];if(r.some(o=>t.startsWith(o)||t===o.replace(/\/$/,"")))return{success:!1,error:"Access to system directories/files is blocked for security"};if(s&&n.some(o=>t.startsWith(s+o)))return{success:!1,error:"Access to sensitive user directories is blocked for security"};let a=Mt.basename(e);return i.includes(a.toLowerCase())?{success:!1,error:"Access to sensitive files is blocked for security"}:null}readFile(e){try{let t=ue.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file. Use action "list" instead.`};if(t.size>mc){let r=ue.readFileSync(e,"utf-8").slice(0,mc);return{success:!0,data:{path:e,size:t.size,truncated:!0},display:`${e} (${t.size} bytes, truncated to ${mc}):
1552
+ ${f.slice(0,2e3)}`}}catch(o){return{success:!1,error:`HTTP request failed: ${o instanceof Error?o.message:String(o)}`}}}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,i]=r.map(Number);if(n===10||n===172&&i>=16&&i<=31||n===192&&i===168||n===127||n===169&&i===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 cy(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(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#x27;/g,"'").replace(/&nbsp;/g," ").replace(/\s+/g," ").trim()}}});import de from"node:fs";import Mt from"node:path";var mc,gp,ly,sr,yp=w(()=>{"use strict";X();mc=5e5,gp=5e7,ly={".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"},sr=class extends N{static{p(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,i=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 a=this.resolvePath(r),o=this.checkBlocked(a);if(o)return o;try{if(de.existsSync(a)&&de.lstatSync(a).isSymbolicLink()){let c=de.realpathSync(a);if(this.checkBlocked(c))return{success:!1,error:"Access denied: symlink target is a blocked path"}}}catch{}switch(s){case"read":return this.readFile(a);case"write":return this.writeFile(a,n);case"write_binary":return this.writeBinaryFile(a,n);case"append":return this.appendFile(a,n);case"list":return this.listDir(a);case"info":return this.fileInfo(a);case"exists":return this.fileExists(a);case"move":return this.moveFile(a,i);case"copy":return this.copyFile(a,i);case"delete":return this.deleteFile(a);case"send":return this.sendFile(a);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"],i=[".env"];if(r.some(o=>t.startsWith(o)||t===o.replace(/\/$/,"")))return{success:!1,error:"Access to system directories/files is blocked for security"};if(s&&n.some(o=>t.startsWith(s+o)))return{success:!1,error:"Access to sensitive user directories is blocked for security"};let a=Mt.basename(e);return i.includes(a.toLowerCase())?{success:!1,error:"Access to sensitive files is blocked for security"}:null}readFile(e){try{let t=de.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file. Use action "list" instead.`};if(t.size>mc){let r=de.readFileSync(e,"utf-8").slice(0,mc);return{success:!0,data:{path:e,size:t.size,truncated:!0},display:`${e} (${t.size} bytes, truncated to ${mc}):
1553
1553
 
1554
- ${r}`}}let s=ue.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 ue.mkdirSync(s,{recursive:!0}),ue.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 ue.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=ue.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(`
1555
- `);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=ue.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}
1554
+ ${r}`}}let s=de.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 de.mkdirSync(s,{recursive:!0}),de.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 de.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=de.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(`
1555
+ `);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=de.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}
1556
1556
  Size: ${t.size} bytes
1557
- Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=ue.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);ue.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return ue.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 ue.mkdirSync(n,{recursive:!0}),ue.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return ue.copyFileSync(e,s),ue.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(i){return{success:!1,error:`Cannot move "${e}" to "${s}": ${i.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 ue.mkdirSync(n,{recursive:!0}),ue.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(!ue.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=ue.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>gp)return{success:!1,error:`File too large to send (${t.size} bytes, max ${gp})`};let s=ue.readFileSync(e),r=Mt.basename(e),n=Mt.extname(e).toLowerCase(),i=ly[n]||"application/octet-stream",a={fileName:r,data:s,mimeType:i};return{success:!0,data:{path:e,size:t.size,fileName:r,mimeType:i},display:`Sending ${r} (${t.size} bytes)`,attachments:[a]}}catch(t){return{success:!1,error:`Cannot send "${e}": ${t.message}`}}}deleteFile(e){try{return ue.existsSync(e)?ue.statSync(e).isDirectory()?{success:!1,error:`"${e}" is a directory. Use shell for directory deletion.`}:(ue.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 rr}from"node:child_process";var nr,Tp=w(()=>{"use strict";X();nr=class extends N{static{p(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=rr("pbpaste",{encoding:"utf-8",timeout:5e3});break;case"win32":e=rr("powershell -NoProfile -Command Get-Clipboard",{encoding:"utf-8",timeout:5e3}).replace(/\r\n$/,"");break;default:e=rr("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)+`
1557
+ Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=de.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);de.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return de.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 de.mkdirSync(n,{recursive:!0}),de.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return de.copyFileSync(e,s),de.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(i){return{success:!1,error:`Cannot move "${e}" to "${s}": ${i.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 de.mkdirSync(n,{recursive:!0}),de.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(!de.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=de.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>gp)return{success:!1,error:`File too large to send (${t.size} bytes, max ${gp})`};let s=de.readFileSync(e),r=Mt.basename(e),n=Mt.extname(e).toLowerCase(),i=ly[n]||"application/octet-stream",a={fileName:r,data:s,mimeType:i};return{success:!0,data:{path:e,size:t.size,fileName:r,mimeType:i},display:`Sending ${r} (${t.size} bytes)`,attachments:[a]}}catch(t){return{success:!1,error:`Cannot send "${e}": ${t.message}`}}}deleteFile(e){try{return de.existsSync(e)?de.statSync(e).isDirectory()?{success:!1,error:`"${e}" is a directory. Use shell for directory deletion.`}:(de.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 rr}from"node:child_process";var nr,Tp=w(()=>{"use strict";X();nr=class extends N{static{p(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=rr("pbpaste",{encoding:"utf-8",timeout:5e3});break;case"win32":e=rr("powershell -NoProfile -Command Get-Clipboard",{encoding:"utf-8",timeout:5e3}).replace(/\r\n$/,"");break;default:e=rr("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)+`
1558
1558
 
1559
1559
  [... 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":rr("pbcopy",{input:e,timeout:5e3});break;case"win32":rr('powershell -NoProfile -Command "$input | Set-Clipboard"',{input:e,timeout:5e3});break;default:rr("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 fn}from"node:child_process";import wp from"node:path";import dy from"node:os";var ir,Ep=w(()=>{"use strict";X();ir=class extends N{static{p(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=wp.join(dy.homedir(),"Desktop"),n=e.path||wp.join(r,`screenshot-${s}.png`);try{switch(process.platform){case"darwin":fn(`screencapture -x "${n}"`,{timeout:1e4});break;case"win32":fn(`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{fn(`scrot "${n}"`,{timeout:1e4})}catch{try{fn(`import -window root "${n}"`,{timeout:1e4})}catch{fn(`gnome-screenshot -f "${n}"`,{timeout:1e4})}}break}return{success:!0,data:{path:n},display:`Screenshot saved to ${n}`}}catch(i){return{success:!1,error:`Screenshot failed: ${i.message}`}}}}});import uy from"node:path";import py from"node:os";import{lookup as hy}from"node:dns/promises";var _p,ar,kp=w(()=>{"use strict";X();_p=5e4,ar=class extends N{static{p(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
1560
1560
  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 i=await n.title(),a=await n.evaluate(`
@@ -1568,7 +1568,7 @@ Or add it to Alfred: npm install puppeteer`};switch(s){case"open":return this.op
1568
1568
 
1569
1569
  `).trim();return{success:!0,data:{url:n.url(),title:i,length:a.length},display:`**${i}** (${n.url()})
1570
1570
 
1571
- ${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 i=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),a=t.path||uy.join(py.homedir(),"Desktop",`browser-${i}.png`);return await s.screenshot({path:a,fullPage:!1}),{success:!0,data:{path:a,url:n},display:`Screenshot saved to ${a}`}}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,i]=r.map(Number);if(n===10||n===172&&i>=16&&i<=31||n===192&&i===168||n===127||n===169&&i===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 hy(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 or,Sp=w(()=>{"use strict";X();We();or=class extends N{static{p(this,"ProfileSkill")}userRepo;metadata={name:"profile",category:"core",description:"Manage user profile settings including timezone, language, and bio. Use this to personalize Alfred for each user.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get","set_timezone","set_language","set_bio","set_preference"],description:"The profile action to perform"},value:{type:"string",description:"The value to set (for set_* actions)"},preference_key:{type:"string",description:"The preference key (for set_preference)"},preference_value:{type:"string",description:"The preference value (for set_preference)"}},required:["action"]}};constructor(e){super(),this.userRepo=e}async execute(e,t){let s=e.action,r=se(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)}"`}}}async getProfile(e){let t=await 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:
1571
+ ${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 i=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),a=t.path||uy.join(py.homedir(),"Desktop",`browser-${i}.png`);return await s.screenshot({path:a,fullPage:!1}),{success:!0,data:{path:a,url:n},display:`Screenshot saved to ${a}`}}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,i]=r.map(Number);if(n===10||n===172&&i>=16&&i<=31||n===192&&i===168||n===127||n===169&&i===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 hy(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 or,Sp=w(()=>{"use strict";X();He();or=class extends N{static{p(this,"ProfileSkill")}userRepo;metadata={name:"profile",category:"core",description:"Manage user profile settings including timezone, language, and bio. Use this to personalize Alfred for each user.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get","set_timezone","set_language","set_bio","set_preference"],description:"The profile action to perform"},value:{type:"string",description:"The value to set (for set_* actions)"},preference_key:{type:"string",description:"The preference key (for set_preference)"},preference_value:{type:"string",description:"The preference value (for set_preference)"}},required:["action"]}};constructor(e){super(),this.userRepo=e}async execute(e,t){let s=e.action,r=se(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)}"`}}}async getProfile(e){let t=await 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:
1572
1572
  ${s.map(r=>`- ${r}`).join(`
1573
1573
  `)}`:"Profile is empty."}}async setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(await this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}async setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let n=(await this.userRepo.getProfile(e))?.preferences??{};return n[t]=s,await this.userRepo.updateProfile(e,{preferences:n}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var st,gn=w(()=>{"use strict";st=class{static{p(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var bp={};ie(bp,{CalDAVProvider:()=>na});var na,fc=w(()=>{"use strict";gn();na=class extends st{static{p(this,"CalDAVProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"caldav"})}catch(e){throw new Error(`CalDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){let s=await this.client.fetchCalendars();if(!s||s.length===0)return[];let r=[];for(let n of s){let i=await this.client.fetchCalendarObjects({calendar:n,timeRange:{start:e.toISOString(),end:t.toISOString()}});for(let a of i){let o=this.parseICalEvent(a.data,a.url);o&&r.push(o)}}return r.sort((n,i)=>n.start.getTime()-i.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 i of n)if(i.url?.includes(e)||i.data?.includes(e)){let a=this.parseICalEvent(i.data,i.url);if(!a)continue;let o={title:t.title??a.title,start:t.start??a.start,end:t.end??a.end,location:t.location??a.location,description:t.description??a.description,allDay:t.allDay??a.allDay},c=this.buildICalEvent(e,o);return await this.client.updateCalendarObject({calendarObject:{...i,data:c}}),{id:e,...o}}}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(`
1574
1574
  `).map(h=>h.trim()),r=p(h=>s.find(m=>m.startsWith(h+":"))?.slice(h.length+1),"get"),n=r("SUMMARY"),i=r("DTSTART")??r("DTSTART;VALUE=DATE"),a=r("DTEND")??r("DTEND;VALUE=DATE"),o=r("LOCATION"),c=r("DESCRIPTION"),d=r("UID")??t;if(!n||!i)return;let u=i.length===8;return{id:d,title:n,start:this.parseICalDate(i),end:a?this.parseICalDate(a):this.parseICalDate(i),location:o||void 0,description:c||void 0,allDay:u}}catch(s){console.error("[caldav] Failed to parse iCal event",s);return}}parseICalDate(e){if(e.length===8)return new Date(`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`);let t=e.replace(/[^0-9TZ]/g,"");return t.length>=15?new Date(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T${t.slice(9,11)}:${t.slice(11,13)}:${t.slice(13,15)}Z`):new Date(e)}buildICalEvent(e,t){let s=p((n,i)=>i?n.toISOString().slice(0,10).replace(/-/g,""):n.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),"formatDate"),r=`BEGIN:VCALENDAR\r
@@ -1602,11 +1602,11 @@ Enter this code on your other platform within 10 minutes using:
1602
1602
  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 i=this.adapters.get(s);if(!i)return{success:!1,error:`Platform "${s}" is not connected. Available: ${[...this.adapters.keys()].join(", ")}`};if(!r||!/^[!0-9]/.test(r)){let a=await this.resolveInternalId(t),o=await this.users.getMasterUserId(a),d=(await this.users.getLinkedUsers(o)).find(u=>u.platform===s);if(d&&this.findConversation){let u=await 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 i.sendMessage(r,n),platform:s,chatId:r},display:`Message sent to ${s}.`}}catch(a){return{success:!1,error:`Failed to send message: ${a instanceof Error?a.message:String(a)}`}}}async listIdentities(e){let t=await this.resolveInternalId(e),s=await this.users.getMasterUserId(t),r=await this.users.getLinkedUsers(s);if(r.length<=1)return{success:!0,data:{identities:r},display:`No linked accounts found. To link another platform, use:
1603
1603
  "Start linking my account" on the platform you want to link from, then enter the code on the other platform.`};let n=r.map(i=>{let a=i.id===t?" (current)":"",o=i.displayName??i.username??i.platformUserId;return`- **${i.platform}**: ${o}${a}`});return{success:!0,data:{identities:r.map(i=>({platform:i.platform,username:i.username,displayName:i.displayName}))},display:`Linked accounts:
1604
1604
  ${n.join(`
1605
- `)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=await this.resolveInternalId(t),n=await this.users.getMasterUserId(r),a=(await this.users.getLinkedUsers(n)).find(o=>o.platform===s&&o.id!==r);return a?(await this.users.setMasterUser(a.id,a.id),{success:!0,data:{unlinkedPlatform:s,unlinkedUserId:a.id},display:`Unlinked ${s} account (${a.displayName??a.username??a.platformUserId}).`}):{success:!1,error:`No linked account found on platform "${s}".`}}}});var dr,Lp=w(()=>{"use strict";X();We();dr=class extends N{static{p(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}async getAllTasks(e){let t=new Set,s=[];for(let r of ee(e))for(let n of await 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`}}}async scheduleTask(e,t){let s=e.description,r=e.skill_name,n=e.skill_input,i=e.persistent,a=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 o=await this.taskRepo.create(se(t),t.platform,t.chatId,s,r,JSON.stringify(n??{}));i&&a?(await this.taskRepo.updatePersistentConfig(o.id,a),o.maxDurationHours=a):i&&(await this.taskRepo.updatePersistentConfig(o.id,24),o.maxDurationHours=24);let c=i?" (persistent)":"";return{success:!0,data:{taskId:o.id,description:s,skillName:r,status:o.status,persistent:!!i},display:`Background task scheduled${c} (${o.id}): "${s}" using skill "${r}". You'll be notified when it completes.`}}async listTasks(e){let t=await 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:
1605
+ `)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=await this.resolveInternalId(t),n=await this.users.getMasterUserId(r),a=(await this.users.getLinkedUsers(n)).find(o=>o.platform===s&&o.id!==r);return a?(await this.users.setMasterUser(a.id,a.id),{success:!0,data:{unlinkedPlatform:s,unlinkedUserId:a.id},display:`Unlinked ${s} account (${a.displayName??a.username??a.platformUserId}).`}):{success:!1,error:`No linked account found on platform "${s}".`}}}});var dr,Lp=w(()=>{"use strict";X();He();dr=class extends N{static{p(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}async getAllTasks(e){let t=new Set,s=[];for(let r of Q(e))for(let n of await 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`}}}async scheduleTask(e,t){let s=e.description,r=e.skill_name,n=e.skill_input,i=e.persistent,a=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 o=await this.taskRepo.create(se(t),t.platform,t.chatId,s,r,JSON.stringify(n??{}));i&&a?(await this.taskRepo.updatePersistentConfig(o.id,a),o.maxDurationHours=a):i&&(await this.taskRepo.updatePersistentConfig(o.id,24),o.maxDurationHours=24);let c=i?" (persistent)":"";return{success:!0,data:{taskId:o.id,description:s,skillName:r,status:o.status,persistent:!!i},display:`Background task scheduled${c} (${o.id}): "${s}" using skill "${r}". You'll be notified when it completes.`}}async listTasks(e){let t=await 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:
1606
1606
  ${r.join(`
1607
- `)}`}}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=(await this.getAllTasks(t)).find(i=>i.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):await this.taskRepo.cancel(s)||await 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=(await this.getAllTasks(t)).find(i=>i.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=(await this.getAllTasks(t)).find(i=>i.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 ur,xp=w(()=>{"use strict";X();We();ur=class extends N{static{p(this,"ScheduledTaskSkill")}actionRepo;metadata={name:"scheduled_task",category:"automation",description:'Create, list, enable, disable, or delete scheduled actions that run automatically on a recurring basis. Supports cron expressions (e.g. "0 9 * * *" for daily at 9 AM), intervals (in minutes), and one-time schedules. Each scheduled action executes a skill or sends a prompt to the LLM at the configured time. Use this for time-based tasks (reports, periodic checks, reminders). For condition-based alerts ("notify me WHEN X happens"), use the watch tool instead.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The scheduled task action to perform"},name:{type:"string",description:"Name for the scheduled action (for create)"},description:{type:"string",description:"What the scheduled action does (for create)"},schedule_type:{type:"string",enum:["cron","interval","once"],description:"Type of schedule: cron expression, interval in minutes, or one-time ISO date (for create)"},schedule_value:{type:"string",description:"Schedule value: cron expression, minutes as string, or ISO date (for create)"},skill_name:{type:"string",description:"The skill to execute on schedule (for create)"},skill_input:{type:"object",description:"Input to pass to the skill (for create)"},prompt_template:{type:"string",description:"Optional LLM prompt to run instead of a skill (for create)"},action_id:{type:"string",description:"Scheduled action ID (for enable, disable, delete)"}},required:["action"]}};constructor(e){super(),this.actionRepo=e}async getAllActions(e){let t=new Set,s=[];for(let r of ee(e))for(let n of await 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`}}}async createAction(e,t){let s=e.name,r=e.description,n=e.schedule_type,i=e.schedule_value,a=e.skill_name,o=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(!i||typeof i!="string")return{success:!1,error:'Missing required field "schedule_value" for create action'};if((!a||typeof a!="string")&&!c)return{success:!1,error:'Missing required field "skill_name" (or "prompt_template") for create action'};if(n==="interval"){let h=parseInt(i,10);if(isNaN(h)||h<=0)return{success:!1,error:"For interval schedule, value must be a positive number of minutes"}}if(n==="cron"&&i.trim().split(/\s+/).length!==5)return{success:!1,error:"Cron expression must have 5 fields: minute hour dayOfMonth month dayOfWeek"};if(n==="once"){let h=new Date(i);if(isNaN(h.getTime()))return{success:!1,error:"For once schedule, value must be a valid ISO date string"};if(h.getTime()<=Date.now())return{success:!1,error:"The scheduled time is in the past. Please specify a future time."}}let d=await this.actionRepo.create({userId:se(t),platform:t.platform,chatId:t.chatId,name:s,description:r,scheduleType:n,scheduleValue:i,skillName:a??"llm_prompt",skillInput:JSON.stringify(o??{}),promptTemplate:c}),u=n==="cron"?`cron: ${i}`:n==="interval"?`every ${i} minutes`:`once at ${i}`;return{success:!0,data:{actionId:d.id,name:s,scheduleType:n,scheduleValue:i,skillName:a},display:`Scheduled action created (${d.id}): "${s}" \u2014 ${u}, running "${a}"${d.nextRunAt?`. Next run: ${d.nextRunAt}`:""}`}}async listActions(e){let t=await 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",i=r.scheduleType==="cron"?`cron: ${r.scheduleValue}`:r.scheduleType==="interval"?`every ${r.scheduleValue} min`:`once: ${r.scheduleValue}`,a=r.nextRunAt?` | next: ${r.nextRunAt}`:"";return`- ${n} ${r.id}: "${r.name}" [${i}] \u2192 ${r.skillName}${a}`});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:
1607
+ `)}`}}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=(await this.getAllTasks(t)).find(i=>i.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):await this.taskRepo.cancel(s)||await 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=(await this.getAllTasks(t)).find(i=>i.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=(await this.getAllTasks(t)).find(i=>i.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 ur,xp=w(()=>{"use strict";X();He();ur=class extends N{static{p(this,"ScheduledTaskSkill")}actionRepo;metadata={name:"scheduled_task",category:"automation",description:'Create, list, enable, disable, or delete scheduled actions that run automatically on a recurring basis. Supports cron expressions (e.g. "0 9 * * *" for daily at 9 AM), intervals (in minutes), and one-time schedules. Each scheduled action executes a skill or sends a prompt to the LLM at the configured time. Use this for time-based tasks (reports, periodic checks, reminders). For condition-based alerts ("notify me WHEN X happens"), use the watch tool instead.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The scheduled task action to perform"},name:{type:"string",description:"Name for the scheduled action (for create)"},description:{type:"string",description:"What the scheduled action does (for create)"},schedule_type:{type:"string",enum:["cron","interval","once"],description:"Type of schedule: cron expression, interval in minutes, or one-time ISO date (for create)"},schedule_value:{type:"string",description:"Schedule value: cron expression, minutes as string, or ISO date (for create)"},skill_name:{type:"string",description:"The skill to execute on schedule (for create)"},skill_input:{type:"object",description:"Input to pass to the skill (for create)"},prompt_template:{type:"string",description:"Optional LLM prompt to run instead of a skill (for create)"},action_id:{type:"string",description:"Scheduled action ID (for enable, disable, delete)"}},required:["action"]}};constructor(e){super(),this.actionRepo=e}async getAllActions(e){let t=new Set,s=[];for(let r of Q(e))for(let n of await 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`}}}async createAction(e,t){let s=e.name,r=e.description,n=e.schedule_type,i=e.schedule_value,a=e.skill_name,o=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(!i||typeof i!="string")return{success:!1,error:'Missing required field "schedule_value" for create action'};if((!a||typeof a!="string")&&!c)return{success:!1,error:'Missing required field "skill_name" (or "prompt_template") for create action'};if(n==="interval"){let h=parseInt(i,10);if(isNaN(h)||h<=0)return{success:!1,error:"For interval schedule, value must be a positive number of minutes"}}if(n==="cron"&&i.trim().split(/\s+/).length!==5)return{success:!1,error:"Cron expression must have 5 fields: minute hour dayOfMonth month dayOfWeek"};if(n==="once"){let h=new Date(i);if(isNaN(h.getTime()))return{success:!1,error:"For once schedule, value must be a valid ISO date string"};if(h.getTime()<=Date.now())return{success:!1,error:"The scheduled time is in the past. Please specify a future time."}}let d=await this.actionRepo.create({userId:se(t),platform:t.platform,chatId:t.chatId,name:s,description:r,scheduleType:n,scheduleValue:i,skillName:a??"llm_prompt",skillInput:JSON.stringify(o??{}),promptTemplate:c}),u=n==="cron"?`cron: ${i}`:n==="interval"?`every ${i} minutes`:`once at ${i}`;return{success:!0,data:{actionId:d.id,name:s,scheduleType:n,scheduleValue:i,skillName:a},display:`Scheduled action created (${d.id}): "${s}" \u2014 ${u}, running "${a}"${d.nextRunAt?`. Next run: ${d.nextRunAt}`:""}`}}async listActions(e){let t=await 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",i=r.scheduleType==="cron"?`cron: ${r.scheduleValue}`:r.scheduleType==="interval"?`every ${r.scheduleValue} min`:`once: ${r.scheduleValue}`,a=r.nextRunAt?` | next: ${r.nextRunAt}`:"";return`- ${n} ${r.id}: "${r.name}" [${i}] \u2192 ${r.skillName}${a}`});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:
1608
1608
  ${s.join(`
1609
- `)}`}}async 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=await this.actionRepo.findById(r),i=ee(s);return!n||!i.includes(n.userId)?{success:!1,error:`Scheduled action "${r}" not found`}:await 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`}}async 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=await this.actionRepo.findById(s),n=ee(t);return!r||!n.includes(r.userId)?{success:!1,error:`Scheduled action "${s}" not found`}:await this.actionRepo.delete(s)?{success:!0,data:{actionId:s},display:`Scheduled action "${s}" deleted.`}:{success:!1,error:`Scheduled action "${s}" not found`}}}});var ls,wc=w(()=>{"use strict";ls=class{static{p(this,"MCPClient")}serverName;config;logger;client;transport;connected=!1;constructor(e,t,s){this.serverName=e,this.config=t,this.logger=s}async connect(){try{let{Client:e}=await import("@modelcontextprotocol/sdk/client/index.js");if(this.client=new e({name:`alfred-${this.serverName}`,version:"1.0.0"},{capabilities:{}}),this.config.command){let{StdioClientTransport:t}=await import("@modelcontextprotocol/sdk/client/stdio.js"),s={PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:process.env.NODE_ENV??"",SYSTEMROOT:process.env.SYSTEMROOT??""};if(this.config.env)for(let[r,n]of Object.entries(this.config.env))s[r]=n.replace(/\$\{(\w+)\}/g,(i,a)=>process.env[a]??"");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(`
1609
+ `)}`}}async 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=await this.actionRepo.findById(r),i=Q(s);return!n||!i.includes(n.userId)?{success:!1,error:`Scheduled action "${r}" not found`}:await 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`}}async 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=await this.actionRepo.findById(s),n=Q(t);return!r||!n.includes(r.userId)?{success:!1,error:`Scheduled action "${s}" not found`}:await this.actionRepo.delete(s)?{success:!0,data:{actionId:s},display:`Scheduled action "${s}" deleted.`}:{success:!1,error:`Scheduled action "${s}" not found`}}}});var ls,wc=w(()=>{"use strict";ls=class{static{p(this,"MCPClient")}serverName;config;logger;client;transport;connected=!1;constructor(e,t,s){this.serverName=e,this.config=t,this.logger=s}async connect(){try{let{Client:e}=await import("@modelcontextprotocol/sdk/client/index.js");if(this.client=new e({name:`alfred-${this.serverName}`,version:"1.0.0"},{capabilities:{}}),this.config.command){let{StdioClientTransport:t}=await import("@modelcontextprotocol/sdk/client/stdio.js"),s={PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:process.env.NODE_ENV??"",SYSTEMROOT:process.env.SYSTEMROOT??""};if(this.config.env)for(let[r,n]of Object.entries(this.config.env))s[r]=n.replace(/\$\{(\w+)\}/g,(i,a)=>process.env[a]??"");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(`
1610
1610
  `),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 my,ds,Ec=w(()=>{"use strict";X();my=["read","write","destructive","admin"],ds=class extends N{static{p(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,n,i){super(),this.client=e,this.serverName=t,this.toolName=s;let a=i&&my.includes(i)?i:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:a,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 yn,Cp=w(()=>{"use strict";wc();Ec();yn=class{static{p(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new ls(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 i=new ds(s,t.name,n.name,n.description??"",n.inputSchema);this.skills.push(i)}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 Op=w(()=>{"use strict";wc();Ec();Cp()});import{spawn as fy}from"node:child_process";import rt from"node:fs";import nt from"node:path";import gy from"node:os";import yy from"node:crypto";var us,_c=w(()=>{"use strict";us=class{static{p(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=vd.resolve(`${s}/package.json`);e.add(nt.dirname(nt.dirname(r)))}catch{}try{let s=rt.realpathSync(process.argv[1]??""),r=nt.dirname(s),n=nt.join(r,"node_modules");rt.existsSync(n)&&e.add(n);let i=nt.join(r,"..","node_modules");rt.existsSync(i)&&e.add(rt.realpathSync(i))}catch{}let t=nt.join(process.cwd(),"node_modules");if(rt.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(nt.delimiter))s&&e.add(s);return[...e].join(nt.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=nt.join(gy.tmpdir(),`alfred-sandbox-${yy.randomUUID()}`);rt.mkdirSync(n,{recursive:!0});try{let i=t==="javascript"?"js":"py",a=nt.join(n,`script.${i}`);rt.writeFileSync(a,e);let o=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[a],d=Date.now();return await new Promise(u=>{let h=fy(o,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"]}),m="",f="";h.stdout.on("data",g=>{m+=g.toString()}),h.stderr.on("data",g=>{f+=g.toString()}),h.on("close",g=>{let y=Date.now()-d,k=[];try{let b=rt.readdirSync(n).filter(S=>!S.startsWith("script."));for(let S of b){let I=nt.join(n,S),L=rt.statSync(I);if(L.isFile()&&L.size<1e7){let D=rt.readFileSync(I),W=S.endsWith(".png")?"image/png":S.endsWith(".jpg")||S.endsWith(".jpeg")?"image/jpeg":S.endsWith(".svg")?"image/svg+xml":S.endsWith(".csv")?"text/csv":S.endsWith(".json")?"application/json":S.endsWith(".html")||S.endsWith(".htm")?"text/html":S.endsWith(".txt")?"text/plain":S.endsWith(".md")?"text/markdown":S.endsWith(".xml")?"application/xml":S.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":S.endsWith(".xls")?"application/vnd.ms-excel":S.endsWith(".pdf")?"application/pdf":"application/octet-stream";k.push({name:S,data:D,mimeType:W})}}}catch{}u({stdout:m.slice(0,5e4),stderr:f.slice(0,1e4),exitCode:g??1,files:k.length>0?k:void 0,durationMs:y})}),h.on("error",g=>{u({stdout:"",stderr:g.message,exitCode:1,durationMs:Date.now()-d})}),h.stdin.end()})}finally{try{rt.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var Tn,Dp=w(()=>{"use strict";X();_c();Tn=class extends N{static{p(this,"CodeExecutionSkill")}metadata={name:"code_sandbox",category:"automation",description:"Execute code in a sandboxed environment. Supports JavaScript (Node.js) and Python. Use for calculations, data processing, generating files (PDF, HTML, CSV, images, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. Any files written to the working directory are automatically collected and sent to the user as attachments \u2014 do NOT use the file skill to send them afterwards. For PDF generation use pdfkit (Node.js) or reportlab/fpdf (Python). IMPORTANT: When generating large files, write compact data-driven code \u2014 define data as arrays/objects, then build the output programmatically. Never embed large HTML/text as string literals.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","run_with_data"],description:"Action to perform"},code:{type:"string",description:"Code to execute"},language:{type:"string",enum:["javascript","python"],description:"Programming language"},data:{type:"string",description:"Input data (available as variable INPUT_DATA, already parsed if JSON). Do NOT use os.environ or process.env \u2014 use INPUT_DATA directly."},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new us;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,i=e.data,a=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 o=r;if(s==="run_with_data"&&i){let h=!1;try{JSON.parse(i),h=!0}catch{}n==="javascript"?o=h?`const INPUT_DATA = ${i};
1611
1611
  ${r}`:`const INPUT_DATA = ${JSON.stringify(i)};
1612
1612
  ${r}`:o=h?`import json as _json
@@ -1616,7 +1616,7 @@ ${r}`}let c=await this.executor.execute(o,n,{timeout:a}),d=c.files?.map(h=>({fil
1616
1616
  ${c.stdout}`:"",c.stderr?`Errors:
1617
1617
  ${c.stderr}`:"",`Exit code: ${c.exitCode}`,`Duration: ${c.durationMs}ms`,d&&d.length>0?`Files generated: ${d.map(h=>h.fileName).join(", ")}`:""].filter(Boolean).join(`
1618
1618
 
1619
- `);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 Mp=w(()=>{"use strict";_c();Dp()});var pr,Up=w(()=>{"use strict";X();We();pr=class extends N{static{p(this,"DocumentSkill")}docRepo;processor;embeddingService;sharedResourceRepo;metadata={name:"document",category:"files",description:"Ingest, search, summarize, list, delete, share, or unshare documents. Supports PDF, DOCX, TXT, CSV, and Markdown files. Documents are chunked and embedded for semantic search. Documents can be private (default), shared with specific users, or public (visible to all users).",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["ingest","search","summarize","list","delete","share","unshare"],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, share, unshare)"},limit:{type:"number",description:"Max results (for search, list)"},visibility:{type:"string",enum:["private","shared","public"],description:'Document visibility (for share). "public" = all users, "shared" = specific users, "private" = only owner'}},required:["action"]}};constructor(e,t,s,r){super(),this.docRepo=e,this.processor=t,this.embeddingService=s,this.sharedResourceRepo=r}async getSharedDocIds(e){if(!this.sharedResourceRepo||!e.alfredUserId)return[];try{return(await this.sharedResourceRepo.getSharedWith(e.alfredUserId)).filter(s=>s.resourceType==="document").map(s=>s.resourceId)}catch{return[]}}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,t);case"list":return this.list(e,t);case"delete":return this.deleteDoc(e,t);case"share":return this.shareDoc(e,t);case"unshare":return this.unshareDoc(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: ingest, search, summarize, list, delete, share, unshare`}}}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 i=await import("node:path"),a=i.resolve(s);if(a!==i.normalize(s)&&s.includes(".."))return{success:!1,error:"Invalid file path: path traversal not allowed"};let o=a.toLowerCase();if(o.startsWith("/etc/")||o.startsWith("/proc/")||o.startsWith("/sys/")||o.startsWith("c:\\windows\\")||o.startsWith("/root/"))return{success:!1,error:"Access to system directories is not allowed"};try{let c=await this.processor.ingest(se(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=ee(t),i=new Set,a=[];for(let u of n)for(let h of await this.embeddingService.semanticSearch(u,s,r))i.has(h.key)||(i.add(h.key),a.push(h));let o=se(t),c=[];for(let u of a){if(u.category!=="document")continue;let h=u.key.match(/^doc:([^:]+)/);h?await this.docRepo.canAccess(h[1],o)&&c.push(u):c.push(u)}if(c.length===0)return{success:!0,data:[],display:`No document matches found for "${s}".`};let d=c.map((u,h)=>`${h+1}. (score: ${u.score.toFixed(3)}) ${u.value.slice(0,200)}${u.value.length>200?"...":""}`).join(`
1619
+ `);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 Mp=w(()=>{"use strict";_c();Dp()});var pr,Up=w(()=>{"use strict";X();He();pr=class extends N{static{p(this,"DocumentSkill")}docRepo;processor;embeddingService;sharedResourceRepo;metadata={name:"document",category:"files",description:"Ingest, search, summarize, list, delete, share, or unshare documents. Supports PDF, DOCX, TXT, CSV, and Markdown files. Documents are chunked and embedded for semantic search. Documents can be private (default), shared with specific users, or public (visible to all users).",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["ingest","search","summarize","list","delete","share","unshare"],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, share, unshare)"},limit:{type:"number",description:"Max results (for search, list)"},visibility:{type:"string",enum:["private","shared","public"],description:'Document visibility (for share). "public" = all users, "shared" = specific users, "private" = only owner'}},required:["action"]}};constructor(e,t,s,r){super(),this.docRepo=e,this.processor=t,this.embeddingService=s,this.sharedResourceRepo=r}async getSharedDocIds(e){if(!this.sharedResourceRepo||!e.alfredUserId)return[];try{return(await this.sharedResourceRepo.getSharedWith(e.alfredUserId)).filter(s=>s.resourceType==="document").map(s=>s.resourceId)}catch{return[]}}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,t);case"list":return this.list(e,t);case"delete":return this.deleteDoc(e,t);case"share":return this.shareDoc(e,t);case"unshare":return this.unshareDoc(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: ingest, search, summarize, list, delete, share, unshare`}}}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 i=await import("node:path"),a=i.resolve(s);if(a!==i.normalize(s)&&s.includes(".."))return{success:!1,error:"Invalid file path: path traversal not allowed"};let o=a.toLowerCase();if(o.startsWith("/etc/")||o.startsWith("/proc/")||o.startsWith("/sys/")||o.startsWith("c:\\windows\\")||o.startsWith("/root/"))return{success:!1,error:"Access to system directories is not allowed"};try{let c=await this.processor.ingest(se(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=Q(t),i=new Set,a=[];for(let u of n)for(let h of await this.embeddingService.semanticSearch(u,s,r))i.has(h.key)||(i.add(h.key),a.push(h));let o=se(t),c=[];for(let u of a){if(u.category!=="document")continue;let h=u.key.match(/^doc:([^:]+)/);h?await this.docRepo.canAccess(h[1],o)&&c.push(u):c.push(u)}if(c.length===0)return{success:!0,data:[],display:`No document matches found for "${s}".`};let d=c.map((u,h)=>`${h+1}. (score: ${u.score.toFixed(3)}) ${u.value.slice(0,200)}${u.value.length>200?"...":""}`).join(`
1620
1620
 
1621
1621
  `);return{success:!0,data:c,display:`Found ${c.length} relevant chunk(s):
1622
1622
 
@@ -1707,11 +1707,11 @@ ${r}`}}catch(s){return{success:!1,error:`Failed to list contacts: ${s instanceof
1707
1707
  |------|-------|-------|`,s=e.map(r=>{let n=r.emails[0]?.address??"-",i=r.phones[0]?.number??"-";return`| ${r.displayName} | ${n} | ${i} |`});return`${t}
1708
1708
  ${s.join(`
1709
1709
  `)}`}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(`
1710
- `)}}});var Gp=w(()=>{"use strict";En();Sc();bc();vc();Ic();Kp()});var fr,Yp=w(()=>{"use strict";X();We();fr=class extends N{static{p(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"]}};sharedResourceRepo;constructor(e){super(),this.todoRepo=e}async getSharedTodoLists(e){if(!this.sharedResourceRepo||!e.alfredUserId)return[];try{return(await this.sharedResourceRepo.getSharedWith(e.alfredUserId)).filter(s=>s.resourceType==="todo_list").map(s=>s.resourceId)}catch{return[]}}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`}}}async 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,i=e.priority,a=e.dueDate,o=await this.todoRepo.add(se(t),s,{list:r,description:n,priority:i,dueDate:a});return{success:!0,data:{todoId:o.id,title:o.title,list:o.list},display:`Todo added: "${s}"`}}async listTodos(e,t){let s=e.list,r=e.includeCompleted??!1,n=new Set,i=[];for(let u of ee(t))for(let h of await this.todoRepo.list(u,s,r))n.has(h.id)||(n.add(h.id),i.push(h));let a=await this.getSharedTodoLists(t),o=new Set;for(let u of a)if(!(s&&u!==s))for(let h of await this.todoRepo.listByListName(u,r))n.has(h.id)||(n.add(h.id),o.add(h.id),i.push(h));if(i.length===0)return{success:!0,data:[],display:"No todos found."};let c=`| | Priority | Title | Due | ID |
1710
+ `)}}});var Gp=w(()=>{"use strict";En();Sc();bc();vc();Ic();Kp()});var fr,Yp=w(()=>{"use strict";X();He();fr=class extends N{static{p(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"]}};sharedResourceRepo;constructor(e){super(),this.todoRepo=e}async getSharedTodoLists(e){if(!this.sharedResourceRepo||!e.alfredUserId)return[];try{return(await this.sharedResourceRepo.getSharedWith(e.alfredUserId)).filter(s=>s.resourceType==="todo_list").map(s=>s.resourceId)}catch{return[]}}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`}}}async 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,i=e.priority,a=e.dueDate,o=await this.todoRepo.add(se(t),s,{list:r,description:n,priority:i,dueDate:a});return{success:!0,data:{todoId:o.id,title:o.title,list:o.list},display:`Todo added: "${s}"`}}async listTodos(e,t){let s=e.list,r=e.includeCompleted??!1,n=new Set,i=[];for(let u of Q(t))for(let h of await this.todoRepo.list(u,s,r))n.has(h.id)||(n.add(h.id),i.push(h));let a=await this.getSharedTodoLists(t),o=new Set;for(let u of a)if(!(s&&u!==s))for(let h of await this.todoRepo.listByListName(u,r))n.has(h.id)||(n.add(h.id),o.add(h.id),i.push(h));if(i.length===0)return{success:!0,data:[],display:"No todos found."};let c=`| | Priority | Title | Due | ID |
1711
1711
  |---|---|---|---|---|`,d=i.map(u=>{let h=u.completed?"\u2611":"\u2610",m=u.dueDate??"",f=o.has(u.id)?" (shared)":"";return`| ${h} | ${u.priority} | ${u.title}${f} | ${m} | ${u.id} |`}).join(`
1712
1712
  `);return{success:!0,data:i,display:`${i.length} todo(s):
1713
1713
  ${c}
1714
- ${d}`}}async 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=await this.todoRepo.getById(s);if(!r)return{success:!1,error:`Todo "${s}" not found`};let n=ee(t),i=await this.getSharedTodoLists(t);return!n.includes(r.userId)&&!i.includes(r.list)?{success:!1,error:`Todo "${s}" not found`}:await this.todoRepo.complete(s)?{success:!0,data:{todoId:s},display:"Todo completed."}:{success:!1,error:`Todo "${s}" is already completed`}}async 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=await this.todoRepo.getById(s);if(!r)return{success:!1,error:`Todo "${s}" not found`};let n=ee(t),i=await this.getSharedTodoLists(t);return!n.includes(r.userId)&&!i.includes(r.list)?{success:!1,error:`Todo "${s}" not found`}:await this.todoRepo.uncomplete(s)?{success:!0,data:{todoId:s},display:"Todo reopened."}:{success:!1,error:`Todo "${s}" is not completed`}}async 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=await this.todoRepo.getById(s);return r?ee(t).includes(r.userId)?await 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`}}async showLists(e){let t=new Map;for(let a of ee(e))for(let o of await this.todoRepo.getLists(a)){let c=t.get(o.list);c?(c.open+=o.open,c.completed+=o.completed,c.total+=o.total):t.set(o.list,{open:o.open,completed:o.completed,total:o.total})}let s=await this.getSharedTodoLists(e);for(let a of s)if(!t.has(a)){let o=await this.todoRepo.listByListName(a,!0),c=o.filter(u=>!u.completed).length,d=o.filter(u=>u.completed).length;t.set(a,{open:c,completed:d,total:o.length,shared:!0})}if(t.size===0)return{success:!0,data:[],display:"No todo lists found."};let r=[...t.entries()].map(([a,o])=>({list:a,...o})),n=`| List | Open | Completed | Total |
1714
+ ${d}`}}async 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=await this.todoRepo.getById(s);if(!r)return{success:!1,error:`Todo "${s}" not found`};let n=Q(t),i=await this.getSharedTodoLists(t);return!n.includes(r.userId)&&!i.includes(r.list)?{success:!1,error:`Todo "${s}" not found`}:await this.todoRepo.complete(s)?{success:!0,data:{todoId:s},display:"Todo completed."}:{success:!1,error:`Todo "${s}" is already completed`}}async 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=await this.todoRepo.getById(s);if(!r)return{success:!1,error:`Todo "${s}" not found`};let n=Q(t),i=await this.getSharedTodoLists(t);return!n.includes(r.userId)&&!i.includes(r.list)?{success:!1,error:`Todo "${s}" not found`}:await this.todoRepo.uncomplete(s)?{success:!0,data:{todoId:s},display:"Todo reopened."}:{success:!1,error:`Todo "${s}" is not completed`}}async 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=await this.todoRepo.getById(s);return r?Q(t).includes(r.userId)?await 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`}}async showLists(e){let t=new Map;for(let a of Q(e))for(let o of await this.todoRepo.getLists(a)){let c=t.get(o.list);c?(c.open+=o.open,c.completed+=o.completed,c.total+=o.total):t.set(o.list,{open:o.open,completed:o.completed,total:o.total})}let s=await this.getSharedTodoLists(e);for(let a of s)if(!t.has(a)){let o=await this.todoRepo.listByListName(a,!0),c=o.filter(u=>!u.completed).length,d=o.filter(u=>u.completed).length;t.set(a,{open:c,completed:d,total:o.length,shared:!0})}if(t.size===0)return{success:!0,data:[],display:"No todo lists found."};let r=[...t.entries()].map(([a,o])=>({list:a,...o})),n=`| List | Open | Completed | Total |
1715
1715
  |---|---|---|---|`,i=r.map(a=>{let o=a.shared?" (shared)":"";return`| ${a.list}${o} | ${a.open} | ${a.completed} | ${a.total} |`}).join(`
1716
1716
  `);return{success:!0,data:r,display:`${r.length} list(s):
1717
1717
  ${n}
@@ -1737,8 +1737,8 @@ ${i}`}}async clearCompleted(e,t){let s=e.list,r=await this.todoRepo.clearComplet
1737
1737
  `)}}async fetchVin(e){let t=await fetch(`${ya}/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(i=>i.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(`${ya}/customers/containers`,{headers:this.apiHeaders(e),signal:AbortSignal.timeout(15e3)});if(t.ok){let n=await t.json(),a=(Array.isArray(n)?n:Array.isArray(n.containers)?n.containers:[]).find(o=>o.name===ih);if(a)return a.containerId}let s=await fetch(`${ya}/customers/containers`,{method:"POST",headers:{...this.apiHeaders(e),"Content-Type":"application/json"},body:JSON.stringify({name:ih,purpose:"Alfred AI Assistant",technicalDescriptors:Ny}),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":vy,Accept:"application/json"}}async apiGet(e){let t=e,s=this.cache.get(t);if(s&&Date.now()-s.ts<Ay)return s.data;let r=await this.ensureToken(),n=`${ya}${e}`,i=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)});if(i.status===401){let o=await this.loadTokens();o&&(r=await this.refreshAccessToken(o),i=await fetch(n,{headers:this.apiHeaders(r),signal:AbortSignal.timeout(15e3)}))}if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`HTTP ${i.status} \u2014 ${o.slice(0,300)}`)}let a=await i.json();return this.cache.set(t,{data:a,ts:Date.now()}),a}async loadTokens(){if(this.tokens)return this.tokens;if(this.activeContext?.userServiceResolver&&this.activeContext.alfredUserId)try{let e=await this.activeContext.userServiceResolver.getServiceConfig(this.activeContext.alfredUserId,"bmw_tokens","tokens");if(e)return this.tokens=e,this.tokens}catch{}return await this.loadTokensFromDisk()}async loadTokensFromDisk(){try{let e=await th(kn(this.activeUserId),"utf-8"),t=JSON.parse(e);return this.tokens=t,t}catch{return null}}async saveTokens(e){if(this.activeContext?.userServiceResolver&&this.activeContext.alfredUserId)try{await this.activeContext.userServiceResolver.saveServiceConfig(this.activeContext.alfredUserId,"bmw_tokens","tokens",e);return}catch{}await rh(Nc(Rc(),".alfred"),{recursive:!0}),await sh(kn(this.activeUserId),JSON.stringify(e,null,2),"utf-8");try{await Sy(kn(this.activeUserId),384)}catch{}}async savePartialTokens(e){await rh(Nc(Rc(),".alfred"),{recursive:!0});let t={};try{let s=await th(kn(this.activeUserId),"utf-8");t=JSON.parse(s)}catch{}await sh(kn(this.activeUserId),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(nh,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:this.cfg.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`)]),i=r.telematicData??{},a=be(i,"vehicle.drivetrain.batteryManagement.header"),o=be(i,"vehicle.drivetrain.electricEngine.remainingElectricRange"),c=be(i,"vehicle.drivetrain.batteryManagement.maxEnergy"),d=be(i,"vehicle.powertrain.electric.battery.stateOfHealth.displayed"),h=["## BMW Fahrzeugstatus","",`**Modell:** ${n.modelName??n.model??"?"}`,`**VIN:** ${t}`,`**Ladestand (SoC):** ${a} %`,`**Elektrische Reichweite:** ${o} km`,`**Batteriekapazit\xE4t:** ${c} kWh`,`**Batterie-Gesundheit (SoH):** ${d} %`];return{success:!0,data:{telematic:i,basic:n},display:h.join(`
1738
1738
  `)}}async getCharging(e){let t=await this.resolveVin(e),s=await this.resolveContainerId(),n=(await this.apiGet(`/customers/vehicles/${t}/telematicData?containerId=${s}`)).telematicData??{},i=be(n,"vehicle.drivetrain.electricEngine.charging.status"),a=be(n,"vehicle.drivetrain.batteryManagement.header"),o=be(n,"vehicle.drivetrain.electricEngine.charging.level"),c=be(n,"vehicle.drivetrain.electricEngine.charging.timeRemaining"),d=be(n,"vehicle.powertrain.electric.battery.charging.power"),u=be(n,"vehicle.drivetrain.electricEngine.charging.hvStatus"),h=be(n,"vehicle.powertrain.electric.battery.stateOfCharge.target"),m=be(n,"vehicle.drivetrain.electricEngine.charging.acVoltage"),f=be(n,"vehicle.drivetrain.electricEngine.charging.acAmpere"),g=be(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.isPlugged"),y=be(n,"vehicle.powertrain.tractionBattery.charging.port.anyPosition.flap.isOpen"),k=be(n,"vehicle.body.chargingPort.lockedStatus"),b=["## BMW Ladestatus","",`**Status:** ${i}`,`**Ladestand:** ${a} %`,`**Ladelevel:** ${o}`,`**Ladeleistung:** ${d} kW`,`**Restzeit:** ${c} min`,`**Ziel-SoC:** ${h} %`,`**HV-Batterie:** ${u}`,`**AC Spannung:** ${m} V`,`**AC Strom:** ${f} A`,`**Stecker eingesteckt:** ${g}`,`**Ladeklappe offen:** ${y}`,`**Ladeport-Schloss:** ${k}`];return{success:!0,data:n,display:b.join(`
1739
1739
  `)}}async getChargingSessions(e,t,s){let r=await this.resolveVin(e),n=new Date,i=s??n.toISOString(),a=t??new Date(n.getTime()-720*60*6e4).toISOString(),o=await this.apiGet(`/customers/vehicles/${r}/chargingHistory?from=${encodeURIComponent(a)}&to=${encodeURIComponent(i)}`),c=o.data??o.chargingSessions??[],d=[`## BMW Lade-Sessions (${a.slice(0,10)} \u2013 ${i.slice(0,10)})`,"","| Start | Ende | Dauer | Energie | Start-SoC | End-SoC | km-Stand | Ort |","|-------|------|-------|---------|-----------|---------|----------|-----|"];for(let u of c.slice(0,20)){let h=u.startTime,m=u.endTime,f=p(j=>new Date(j*1e3).toLocaleString("de-AT",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"}),"fmtDateTime"),g=h?f(h):"-",y=m?f(m):"-",k=u.totalChargingDurationSec,b=k!=null?Math.round(k/60):"-",S=u.energyConsumedFromPowerGridKwh??"-",I=u.displayedStartSoc??"-",L=u.displayedSoc??"-",D=u.mileage!=null?`${u.mileage}`:"-",W=u.chargingLocation,q=W?.formattedAddress??W?.streetAddress??"-";d.push(`| ${g} | ${y} | ${b} min | ${S} kWh | ${I}% | ${L}% | ${D} | ${q} |`)}return c.length===0&&d.push("| - | - | Keine Sessions gefunden | - | - | - | - | - |"),{success:!0,data:o,display:d.join(`
1740
- `)}}async getConsumption(e,t){let s=await this.resolveVin(e),r=await this.resolveContainerId(),n=new Date,a={last:7,week:7,month:30,year:365,all:730}[t??"month"]??30,o=new Date(n.getTime()-a*864e5).toISOString(),c=n.toISOString(),[d,u]=await Promise.all([this.apiGet(`/customers/vehicles/${s}/chargingHistory?from=${encodeURIComponent(o)}&to=${encodeURIComponent(c)}`),this.apiGet(`/customers/vehicles/${s}/telematicData?containerId=${r}`)]),h=d.data??d.chargingSessions??[],m=parseFloat(be(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(h.length<2)return{success:!0,data:{sessions:h.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let f=h.filter(j=>typeof j.mileage=="number"&&typeof j.displayedStartSoc=="number"&&typeof j.displayedSoc=="number").sort((j,ce)=>j.mileage-ce.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 j=1;j<f.length;j++){let ce=f[j-1],me=f[j],O=ce.mileage,pe=me.mileage,he=pe-O;if(he<=0)continue;let ye=ce.displayedSoc,$e=me.displayedStartSoc,ae=ye-$e;if(ae<=0)continue;let z=ae/100*m,le=z/he*100,Ye=me.startTime,we=Ye?new Date(Ye*1e3).toLocaleDateString("de-AT"):"-";g.push({fromKm:O,toKm:pe,distance:he,socUsed:ae,kWhUsed:z,consumption:le,date:we})}if(g.length===0)return{success:!0,data:{},display:"Keine auswertbaren Fahrtabschnitte gefunden."};if(t==="last"){let j=g[g.length-1];return{success:!0,data:j,display:["## Letzte Fahrt (gesch\xE4tzt)","",`**Datum:** ${j.date}`,`**Strecke:** ${j.distance} km`,`**Verbrauch:** ${j.consumption.toFixed(1)} kWh/100km`,`**Energie:** ${j.kWhUsed.toFixed(1)} kWh (${j.socUsed}% SoC)`,`**km-Stand:** ${j.fromKm} \u2192 ${j.toKm}`].join(`
1741
- `)}}let y=g.reduce((j,ce)=>j+ce.distance,0),k=g.reduce((j,ce)=>j+ce.kWhUsed,0),b=k/y*100,S=g.map(j=>j.consumption).sort((j,ce)=>j-ce),I=S[0],L=S[S.length-1],D=S[Math.floor(S.length/2)],q=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${m} kWh`,`**Ausgewertete Fahrten:** ${g.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${k.toFixed(1)} kWh`,"",`**Durchschnitt:** ${b.toFixed(1)} kWh/100km`,`**Min:** ${I.toFixed(1)} kWh/100km`,`**Max:** ${L.toFixed(1)} kWh/100km`,`**Median:** ${D.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let j of g)q.push(`| ${j.date} | ${j.distance} km | ${j.consumption.toFixed(1)} kWh/100km | ${j.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:b,totalDistance:y,totalKwh:k,segments:g},display:q.join(`
1740
+ `)}}async getConsumption(e,t){let s=await this.resolveVin(e),r=await this.resolveContainerId(),n=new Date,a={last:7,week:7,month:30,year:365,all:730}[t??"month"]??30,o=new Date(n.getTime()-a*864e5).toISOString(),c=n.toISOString(),[d,u]=await Promise.all([this.apiGet(`/customers/vehicles/${s}/chargingHistory?from=${encodeURIComponent(o)}&to=${encodeURIComponent(c)}`),this.apiGet(`/customers/vehicles/${s}/telematicData?containerId=${r}`)]),h=d.data??d.chargingSessions??[],m=parseFloat(be(u.telematicData??{},"vehicle.drivetrain.batteryManagement.maxEnergy"))||63;if(h.length<2)return{success:!0,data:{sessions:h.length},display:"Nicht gen\xFCgend Lade-Sessions f\xFCr Verbrauchsberechnung (min. 2 n\xF6tig)."};let f=h.filter(j=>typeof j.mileage=="number"&&typeof j.displayedStartSoc=="number"&&typeof j.displayedSoc=="number").sort((j,oe)=>j.mileage-oe.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 j=1;j<f.length;j++){let oe=f[j-1],me=f[j],O=oe.mileage,ue=me.mileage,he=ue-O;if(he<=0)continue;let ye=oe.displayedSoc,$e=me.displayedStartSoc,pe=ye-$e;if(pe<=0)continue;let z=pe/100*m,ce=z/he*100,Ge=me.startTime,Te=Ge?new Date(Ge*1e3).toLocaleDateString("de-AT"):"-";g.push({fromKm:O,toKm:ue,distance:he,socUsed:pe,kWhUsed:z,consumption:ce,date:Te})}if(g.length===0)return{success:!0,data:{},display:"Keine auswertbaren Fahrtabschnitte gefunden."};if(t==="last"){let j=g[g.length-1];return{success:!0,data:j,display:["## Letzte Fahrt (gesch\xE4tzt)","",`**Datum:** ${j.date}`,`**Strecke:** ${j.distance} km`,`**Verbrauch:** ${j.consumption.toFixed(1)} kWh/100km`,`**Energie:** ${j.kWhUsed.toFixed(1)} kWh (${j.socUsed}% SoC)`,`**km-Stand:** ${j.fromKm} \u2192 ${j.toKm}`].join(`
1741
+ `)}}let y=g.reduce((j,oe)=>j+oe.distance,0),k=g.reduce((j,oe)=>j+oe.kWhUsed,0),b=k/y*100,S=g.map(j=>j.consumption).sort((j,oe)=>j-oe),I=S[0],L=S[S.length-1],D=S[Math.floor(S.length/2)],q=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${m} kWh`,`**Ausgewertete Fahrten:** ${g.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${k.toFixed(1)} kWh`,"",`**Durchschnitt:** ${b.toFixed(1)} kWh/100km`,`**Min:** ${I.toFixed(1)} kWh/100km`,`**Max:** ${L.toFixed(1)} kWh/100km`,`**Median:** ${D.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let j of g)q.push(`| ${j.date} | ${j.distance} km | ${j.consumption.toFixed(1)} kWh/100km | ${j.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:b,totalDistance:y,totalKwh:k,segments:g},display:q.join(`
1742
1742
  `)}}}});var Ly,wa,ch=w(()=>{"use strict";X();Ly="https://routes.googleapis.com/directions/v2:computeRoutes",wa=class extends N{static{p(this,"RoutingSkill")}metadata={name:"routing",category:"information",description:'Routenberechnung mit Live-Traffic via Google Routes API. "route" berechnet Route mit Distanz, Dauer und Dauer im aktuellen Verkehr. "departure_time" empfiehlt wann man losfahren soll, um zu einer bestimmten Zeit anzukommen. WICHTIG: Aliase wie "zuhause", "daheim", "home", "bei mir", "im B\xFCro", "work" VOR dem Tool-Call in konkrete Adressen aufl\xF6sen \u2014 daf\xFCr bekannte Adressen aus Memory/Kontext verwenden. Nie rohe Alias-Werte wie "home" oder "work" als origin/destination senden. Wenn keine Adresse im Kontext vorhanden ist, den User nach der Adresse fragen.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["route","departure_time"],description:"Routing action"},origin:{type:"string",description:'Start-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},departure_time:{type:"string",description:"ISO-Zeitpunkt f\xFCr Abfahrt (optional, f\xFCr Traffic-Berechnung)"},arrival_time:{type:"string",description:"ISO-Zeitpunkt gew\xFCnschte Ankunft (f\xFCr departure_time-Action)"},travel_mode:{type:"string",enum:["DRIVE","BICYCLE","WALK","TRANSIT"],description:"Fortbewegungsart (Standard: DRIVE)"}},required:["action","origin","destination"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};let r=e.origin,n=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!n)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,n,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,n,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(i){return{success:!1,error:`Google Routes API error: ${i instanceof Error?i.message:String(i)}`}}}async computeRoute(e,t,s,r){let n=this.buildRequestBody(e,t,r,s),a=(await this.callRoutesApi(n)).routes?.[0];if(!a)return{success:!1,error:"Keine Route gefunden."};let o=(a.distanceMeters/1e3).toFixed(1),c=this.parseDuration(a.duration),d=this.parseDuration(a.staticDuration),u=c-d,h=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${o} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(c)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(u>1&&h.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(u)}`),s){let m=new Date(new Date(s).getTime()+c*6e4);h.push(`**Gesch\xE4tzte Ankunft:** ${m.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(o),durationMinutes:c,staticDurationMinutes:d},display:h.join(`
1743
1743
  `)}}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),a=(await this.callRoutesApi(n)).routes?.[0];if(!a)return{success:!1,error:"Keine Route gefunden."};let o=this.parseDuration(a.duration),c=Math.max(5,Math.round(o*.15)),d=new Date(s),u=new Date(d.getTime()-(o+c)*6e4),h=["## Abfahrtszeit-Empfehlung","",`**Route:** ${e} \u2192 ${t}`,`**Gew\xFCnschte Ankunft:** ${d.toLocaleString("de-AT")}`,`**Gesch\xE4tzte Fahrzeit:** ${this.formatMinutes(o)} (inkl. Verkehr)`,`**Puffer:** ${c} min`,"",`**Empfohlene Abfahrt:** ${u.toLocaleString("de-AT")}`];return{success:!0,data:{departureTime:u.toISOString(),durationMinutes:o,bufferMinutes:c},display:h.join(`
1744
1744
  `)}}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),i=String(Math.floor(n/60)).padStart(2,"0"),a=String(n%60).padStart(2,"0"),o=p(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${o(t.getMonth()+1)}-${o(t.getDate())}T${o(t.getHours())}:${o(t.getMinutes())}:${o(t.getSeconds())}${r}${i}:${a}`}buildRequestBody(e,t,s,r,n){let i={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let a=this.normalizeTimestamp(r);new Date(a).getTime()>Date.now()+6e4&&(i.departureTime=a)}if(n){let a=this.normalizeTimestamp(n);new Date(a).getTime()>Date.now()+6e4&&(i.arrivalTime=a)}return i}async callRoutesApi(e){let t=await fetch(Ly,{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 lh,dh,xy,Cy,Oy,gr,uh,ph,hh,Lc,xc,mh,Ea,fh=w(()=>{"use strict";X();lh=1.5,dh=4.79,xy=5.75,Cy=1.03,Oy=new Date("2026-04-01T00:00:00+02:00"),gr=1.2,uh=.1,ph=.58,hh=.04,Lc=.32,xc=1.62,mh="https://api.awattar.at/v1/marketdata",Ea=class extends N{static{p(this,"EnergyPriceSkill")}metadata={name:"energy_price",category:"information",description:'Strompreise (aWATTar HOURLY Tarif, EPEX Spot AT). "current" zeigt den aktuellen Strompreis mit Aufschl\xFCsselung (Marktpreis, Netzentgelte, Abgaben, Brutto). "today" zeigt alle Stundenpreise f\xFCr heute. "tomorrow" zeigt Stundenpreise f\xFCr morgen (verf\xFCgbar ab ~14:00). "cheapest" findet die g\xFCnstigsten Stunden (Standard: 3 Stunden in den n\xE4chsten 24h). "average" zeigt den Durchschnittspreis f\xFCr heute oder ein bestimmtes Datum.',riskLevel:"read",version:"1.0.0",timeoutMs:15e3,inputSchema:{type:"object",properties:{action:{type:"string",enum:["current","today","tomorrow","cheapest","average","briefing"],description:"Aktion (briefing = kompakte Tages\xFCbersicht f\xFCr Morgenbriefing)"},hours:{type:"number",description:"F\xFCr cheapest: Anzahl g\xFCnstigster Stunden (Standard: 3)"},date:{type:"string",description:"ISO-Datum f\xFCr average (Standard: heute)"}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"current":return await this.current();case"today":return await this.dayPrices("today");case"tomorrow":return await this.dayPrices("tomorrow");case"cheapest":return await this.cheapest(e.hours);case"average":return await this.average(e.date);case"briefing":return await this.briefingSummary();default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`aWATTar API error: ${r instanceof Error?r.message:String(r)}`}}}async current(){let e=Date.now(),s=(await this.fetchMarketData()).find(a=>a.start_timestamp<=e&&a.end_timestamp>e);if(!s)return{success:!1,error:"Kein Marktpreis f\xFCr die aktuelle Stunde verf\xFCgbar."};let r=this.calculatePrice(s.marketprice),i=[`## Aktueller Strompreis (${this.formatHourRange(s.start_timestamp,s.end_timestamp)})`,""];return i.push(this.formatBreakdown(r)),{success:!0,data:r,display:i.join(`
@@ -1771,12 +1771,12 @@ ${d}=${h}
1771
1771
  `)}}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 i=n.name??`VMID ${n.vmid}`,a=n.status,o=n.maxdisk,c=n.disk;if(o&&o>0&&c!=null){let d=c/o*100;d>90&&t.push({source:"proxmox",message:`${i} disk usage ${d.toFixed(1)}%`})}if(a==="running"){let d=n.maxmem,u=n.mem;if(d&&d>0&&u!=null){let h=u/d*100;h>95&&t.push({source:"proxmox",message:`${i} RAM usage ${h.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=[],i;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),h;if(u.status===200)h="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(m=>m.split(";")[0]),i=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let m=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!m.ok)throw new Error(`UniFi login failed: HTTP ${m.status}`);h="classic",n=(m.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("; ")),i&&(r["X-CSRF-Token"]=i)}let a=p(c=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${c}`,"apiUrl"),o=p(async c=>{let d=await this.apiFetch(a(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 o("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 o("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 o("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 i of s){let a=i.entity_id;if(a.startsWith("update."))continue;if(i.state==="unavailable"&&(r++,n.length<5)){let d=i.attributes?.friendly_name??a;n.push(d)}let o=i.attributes?.device_class??"",c=i.attributes?.unit_of_measurement??"";if(a.startsWith("sensor.")&&o==="battery"&&c==="%"){let d=parseFloat(i.state);if(!isNaN(d)&&d>=0&&d<20){let u=i.attributes?.friendly_name??a;t.push({source:"homeassistant",message:`Low battery: ${u} at ${d}%`})}}}if(r>0){let i=n.join(", "),a=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${i}${a}`})}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}`},i=await this.apiFetch(r,{method:"GET",headers:n,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!i.ok)return t.push({source:"proxmox_backup",message:`PBS unreachable: HTTP ${i.status}`}),t;let c=((await i.json()).data??[]).filter(m=>m.worker_type==="backup"),d=Date.now()/1e3,u=c.filter(m=>m.status==="OK").sort((m,f)=>(f.endtime??f.starttime)-(m.endtime??m.starttime));if(u.length===0)t.push({source:"proxmox_backup",message:"No successful backups found"});else{let m=u[0].endtime??u[0].starttime,f=(d-m)/3600;f>s&&t.push({source:"proxmox_backup",message:`Last successful backup is ${f.toFixed(1)}h old (threshold: ${s}h)`})}let h=c.filter(m=>m.status!=="OK"&&d-(m.endtime??m.starttime)<s*3600);return h.length>0&&t.push({source:"proxmox_backup",message:`${h.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 ka,_h=w(()=>{"use strict";X();ka=class extends N{static{p(this,"MicrosoftTodoSkill")}config;accessToken="";get userPath(){let e=this.cfg;return e.sharedUser?`/users/${e.sharedUser}`:"/me"}activeConfig;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}get cfg(){return this.activeConfig??this.config}async execute(e,t){let s=await this.resolveUserConfig(t);this.activeConfig=s??void 0;try{let r=e.action;try{switch(r){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: ${r}`}}}catch(n){return{success:!1,error:n instanceof Error?n.message:String(n)}}}finally{this.activeConfig=void 0}}async resolveUserConfig(e){if(!e.userServiceResolver||!e.alfredUserId)return null;let t=await e.userServiceResolver.getServiceConfig(e.alfredUserId,"todo");return!t||!t.clientId?null:t}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.cfg.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.cfg.clientId,client_secret:this.cfg.clientSecret,refresh_token:this.cfg.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Tasks.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=p(()=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s();if(r.status===401){if(await this.refreshAccessToken(),r=await s(),!r.ok)throw new Error(`Graph API error: ${r.status}`)}else if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async resolveListId(e){if(e.listId)return e.listId;let s=(await this.graphRequest(`${this.userPath}/todo/lists`)).value??[];if(e.list){let n=e.list.toLowerCase(),i=s.find(a=>a.displayName.toLowerCase()===n);if(!i){let a=s.map(o=>o.displayName).join(", ");throw new Error(`List "${e.list}" not found. Available lists: ${a}`)}return i.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(`${this.userPath}/todo/lists`)).value??[],s=t.map(r=>`\u2022 **${r.displayName}**${r.wellknownListName==="defaultList"?" (Standard)":""} [listId=${r.id}]`).join(`
1772
1772
  `);return{success:!0,data:t,display:s||"Keine Listen gefunden."}}async listTasks(e){let t=await this.resolveListId(e),s=e.includeCompleted===!0,r=`${this.userPath}/todo/lists/${t}/tasks`;s||(r+="?$filter=status ne 'completed'");let i=(await this.graphRequest(r)).value??[],a=i.map(o=>{let c=o.status==="completed"?"\u2611":"\u2610",d=o.importance==="high"?" \u2757":"",u=o.dueDateTime?` (f\xE4llig: ${o.dueDateTime.dateTime.slice(0,10)})`:"";return`${c} ${o.title}${d}${u} [taskId=${o.id}]`});return{success:!0,data:i,display:a.length>0?`listId=${t}
1773
1773
  ${a.join(`
1774
- `)}`:"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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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 Sa,Er,kh=w(()=>{"use strict";X();Sa=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Er=class extends N{static{p(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,t,!0);case"disable":return this.toggleWatch(e,t,!1);case"delete":return this.deleteWatch(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}async createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},i=e.condition_field,a=e.condition_operator,o=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,h=e.action_skill_name,m=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,k=e.conditions,b=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(k)&&k.length>0,I=!!i&&!!a;if(!S&&!I)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let L;if(S){for(let O of k){if(!O.field||!O.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!Sa.includes(O.operator))return{success:!1,error:`Invalid operator "${O.operator}" in conditions. Must be one of: ${Sa.join(", ")}`}}L={logic:b,conditions:k.map(O=>({field:O.field,operator:O.operator,value:O.value}))}}if(I&&!Sa.includes(a))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${Sa.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&&!await this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let O=this.skillRegistry.get(r);if(!O)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let pe=O.metadata.inputSchema;if(pe&&Array.isArray(pe.required)){let he=pe.required.filter(ye=>!(ye in n));if(he.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${he.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(pe.required)}`}}}let D=i??(L?L.conditions[0].field:""),W=a??(L?L.conditions[0].operator:"changed"),q=o??(L?L.conditions[0].value:void 0),j=await this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:D,operator:W,value:q},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:L,actionSkillName:h,actionSkillParams:m,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),ce=L?`${L.logic.toUpperCase()}(${L.conditions.map(O=>`${O.field} ${O.operator}${O.value!=null?" "+O.value:""}`).join(", ")})`:`${D} ${W}${q!=null?" "+q:""}`,me=y?` \u2192 Chain \u2192 Watch ${y}`:h?` \u2192 Aktion: ${h} (${f})`:"";return{success:!0,data:{watchId:j.id,name:s,skillName:r,conditionField:D,conditionOperator:W,conditionValue:q,intervalMinutes:c,compositeCondition:L,triggerWatchId:y},display:`Watch erstellt (${j.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${ce}${me}`}}async listWatches(e){let t=await 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",i=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,a=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",o=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${i}${o}${a}`});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:
1774
+ `)}`:"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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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(`${this.userPath}/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 Sa,Er,kh=w(()=>{"use strict";X();Sa=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Er=class extends N{static{p(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,t,!0);case"disable":return this.toggleWatch(e,t,!1);case"delete":return this.deleteWatch(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}async createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},i=e.condition_field,a=e.condition_operator,o=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,h=e.action_skill_name,m=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,k=e.conditions,b=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(k)&&k.length>0,I=!!i&&!!a;if(!S&&!I)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let L;if(S){for(let O of k){if(!O.field||!O.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!Sa.includes(O.operator))return{success:!1,error:`Invalid operator "${O.operator}" in conditions. Must be one of: ${Sa.join(", ")}`}}L={logic:b,conditions:k.map(O=>({field:O.field,operator:O.operator,value:O.value}))}}if(I&&!Sa.includes(a))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${Sa.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&&!await this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let O=this.skillRegistry.get(r);if(!O)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let ue=O.metadata.inputSchema;if(ue&&Array.isArray(ue.required)){let he=ue.required.filter(ye=>!(ye in n));if(he.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${he.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(ue.required)}`}}}let D=i??(L?L.conditions[0].field:""),W=a??(L?L.conditions[0].operator:"changed"),q=o??(L?L.conditions[0].value:void 0),j=await this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:D,operator:W,value:q},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:L,actionSkillName:h,actionSkillParams:m,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),oe=L?`${L.logic.toUpperCase()}(${L.conditions.map(O=>`${O.field} ${O.operator}${O.value!=null?" "+O.value:""}`).join(", ")})`:`${D} ${W}${q!=null?" "+q:""}`,me=y?` \u2192 Chain \u2192 Watch ${y}`:h?` \u2192 Aktion: ${h} (${f})`:"";return{success:!0,data:{watchId:j.id,name:s,skillName:r,conditionField:D,conditionOperator:W,conditionValue:q,intervalMinutes:c,compositeCondition:L,triggerWatchId:y},display:`Watch erstellt (${j.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${oe}${me}`}}async listWatches(e){let t=await 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",i=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,a=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",o=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${i}${o}${a}`});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:
1775
1775
  ${s.join(`
1776
- `)}`}}async verifyOwnership(e,t){let s=await this.watchRepo.getById(e);return s&&(s.chatId===t.chatId&&s.platform===t.platform||s.chatId.includes(t.userId)||t.userRole==="admin")?s:null}async toggleWatch(e,t,s){let r=e.watch_id;return r?await this.verifyOwnership(r,t)?(await this.watchRepo.toggle(r,s),{success:!0,data:{watchId:r,enabled:s},display:`Watch "${r}" ${s?"aktiviert":"deaktiviert"}.`}):{success:!1,error:`Watch "${r}" nicht gefunden oder keine Berechtigung.`}:{success:!1,error:`Missing "watch_id" for ${s?"enable":"disable"}`}}async deleteWatch(e,t){let s=e.watch_id;return s?await this.verifyOwnership(s,t)?(await this.watchRepo.delete(s),{success:!0,data:{watchId:s},display:`Watch "${s}" gel\xF6scht.`}):{success:!1,error:`Watch "${s}" nicht gefunden oder keine Berechtigung.`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var _r,Sh=w(()=>{"use strict";X();We();_r=class extends N{static{p(this,"WorkflowSkill")}workflowRepo;metadata={name:"workflow",category:"automation",description:'Create and manage multi-step workflows (skill chains). Use "create" to define a workflow with sequential steps. Each step runs a skill and can pass data to the next via {{prev.field}} or {{steps.0.field}} templates. Use "run" to execute a workflow, "list" to see all workflows, "delete" to remove, "history" to see recent executions.',riskLevel:"write",version:"1.0.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","run","delete","history"],description:"Workflow action"},name:{type:"string",description:"Workflow name (for create)"},steps:{type:"array",description:'Workflow steps (for create). Action step: { skillName, inputMapping: { paramName: "{{prev.field}}" }, onError: "stop"|"skip"|"retry", jumpTo?: stepIndex|"end" }. Condition step: { type: "condition", condition: { field: "prev.rain", operator: "eq", value: "true" }, then: stepIndex|"end"|null, else: stepIndex|"end"|null, label?: "Regen?" }. Jump targets are 0-based step indices, "end" finishes the workflow, null proceeds to next step.',items:{type:"object"}},workflow_id:{type:"string",description:"Workflow ID (for run/delete/history)"}},required:["action"]}};runner;constructor(e){super(),this.workflowRepo=e}setRunner(e){this.runner=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWorkflow(e,t);case"list":return this.listWorkflows(t);case"run":return this.runWorkflow(e,t);case"delete":return this.deleteWorkflow(e,t);case"history":return this.getHistory(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async 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 a=0;a<r.length;a++){let o=r[a];if(o.type==="condition"){if(!o.condition||typeof o.condition!="object")return{success:!1,error:`Step ${a}: condition step missing "condition" object`};if(!o.condition.field||typeof o.condition.field!="string")return{success:!1,error:`Step ${a}: condition.field must be a non-empty string`};if(!n.includes(o.condition.operator))return{success:!1,error:`Step ${a}: condition.operator must be one of: ${n.join(", ")}`};for(let c of["then","else"]){let d=o[c];if(d!==null&&d!=="end"&&(typeof d!="number"||d<0||d>=r.length))return{success:!1,error:`Step ${a}: "${c}" must be null, "end", or a step index (0-${r.length-1})`}}}else{if(!o.skillName)return{success:!1,error:`Step ${a}: missing skillName`};if(!o.inputMapping||typeof o.inputMapping!="object")return{success:!1,error:`Step ${a}: missing inputMapping`};if(!["stop","skip","retry"].includes(o.onError))return{success:!1,error:`Step ${a}: onError must be stop|skip|retry`};if(o.jumpTo!==void 0&&o.jumpTo!=="end"&&(typeof o.jumpTo!="number"||o.jumpTo<0||o.jumpTo>=r.length))return{success:!1,error:`Step ${a}: jumpTo must be "end" or a step index (0-${r.length-1})`}}}let i=await this.workflowRepo.create({name:s,userId:se(t),chatId:t.chatId,platform:t.platform,steps:r,triggerType:"manual",enabled:!0});return{success:!0,data:{workflowId:i.id,name:s,stepCount:r.length},display:`Workflow "${s}" erstellt (${i.id}) mit ${r.length} Schritten.`}}async listWorkflows(e){let t=[],s=new Set;for(let n of ee(e))for(let i of await this.workflowRepo.findByUser(n))s.has(i.id)||(s.add(i.id),t.push(i));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:
1776
+ `)}`}}async verifyOwnership(e,t){let s=await this.watchRepo.getById(e);return s&&(s.chatId===t.chatId&&s.platform===t.platform||s.chatId.includes(t.userId)||t.userRole==="admin")?s:null}async toggleWatch(e,t,s){let r=e.watch_id;return r?await this.verifyOwnership(r,t)?(await this.watchRepo.toggle(r,s),{success:!0,data:{watchId:r,enabled:s},display:`Watch "${r}" ${s?"aktiviert":"deaktiviert"}.`}):{success:!1,error:`Watch "${r}" nicht gefunden oder keine Berechtigung.`}:{success:!1,error:`Missing "watch_id" for ${s?"enable":"disable"}`}}async deleteWatch(e,t){let s=e.watch_id;return s?await this.verifyOwnership(s,t)?(await this.watchRepo.delete(s),{success:!0,data:{watchId:s},display:`Watch "${s}" gel\xF6scht.`}):{success:!1,error:`Watch "${s}" nicht gefunden oder keine Berechtigung.`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var _r,Sh=w(()=>{"use strict";X();He();_r=class extends N{static{p(this,"WorkflowSkill")}workflowRepo;metadata={name:"workflow",category:"automation",description:'Create and manage multi-step workflows (skill chains). Use "create" to define a workflow with sequential steps. Each step runs a skill and can pass data to the next via {{prev.field}} or {{steps.0.field}} templates. Use "run" to execute a workflow, "list" to see all workflows, "delete" to remove, "history" to see recent executions.',riskLevel:"write",version:"1.0.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","run","delete","history"],description:"Workflow action"},name:{type:"string",description:"Workflow name (for create)"},steps:{type:"array",description:'Workflow steps (for create). Action step: { skillName, inputMapping: { paramName: "{{prev.field}}" }, onError: "stop"|"skip"|"retry", jumpTo?: stepIndex|"end" }. Condition step: { type: "condition", condition: { field: "prev.rain", operator: "eq", value: "true" }, then: stepIndex|"end"|null, else: stepIndex|"end"|null, label?: "Regen?" }. Jump targets are 0-based step indices, "end" finishes the workflow, null proceeds to next step.',items:{type:"object"}},workflow_id:{type:"string",description:"Workflow ID (for run/delete/history)"}},required:["action"]}};runner;constructor(e){super(),this.workflowRepo=e}setRunner(e){this.runner=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWorkflow(e,t);case"list":return this.listWorkflows(t);case"run":return this.runWorkflow(e,t);case"delete":return this.deleteWorkflow(e,t);case"history":return this.getHistory(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}async 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 a=0;a<r.length;a++){let o=r[a];if(o.type==="condition"){if(!o.condition||typeof o.condition!="object")return{success:!1,error:`Step ${a}: condition step missing "condition" object`};if(!o.condition.field||typeof o.condition.field!="string")return{success:!1,error:`Step ${a}: condition.field must be a non-empty string`};if(!n.includes(o.condition.operator))return{success:!1,error:`Step ${a}: condition.operator must be one of: ${n.join(", ")}`};for(let c of["then","else"]){let d=o[c];if(d!==null&&d!=="end"&&(typeof d!="number"||d<0||d>=r.length))return{success:!1,error:`Step ${a}: "${c}" must be null, "end", or a step index (0-${r.length-1})`}}}else{if(!o.skillName)return{success:!1,error:`Step ${a}: missing skillName`};if(!o.inputMapping||typeof o.inputMapping!="object")return{success:!1,error:`Step ${a}: missing inputMapping`};if(!["stop","skip","retry"].includes(o.onError))return{success:!1,error:`Step ${a}: onError must be stop|skip|retry`};if(o.jumpTo!==void 0&&o.jumpTo!=="end"&&(typeof o.jumpTo!="number"||o.jumpTo<0||o.jumpTo>=r.length))return{success:!1,error:`Step ${a}: jumpTo must be "end" or a step index (0-${r.length-1})`}}}let i=await this.workflowRepo.create({name:s,userId:se(t),chatId:t.chatId,platform:t.platform,steps:r,triggerType:"manual",enabled:!0});return{success:!0,data:{workflowId:i.id,name:s,stepCount:r.length},display:`Workflow "${s}" erstellt (${i.id}) mit ${r.length} Schritten.`}}async listWorkflows(e){let t=[],s=new Set;for(let n of Q(e))for(let i of await this.workflowRepo.findByUser(n))s.has(i.id)||(s.add(i.id),t.push(i));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:
1777
1777
  ${r.join(`
1778
1778
  `)}`}}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=await 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),a=[`${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} Workflow "${r.name}": ${n.status}`];a.push(`Schritte: ${n.stepsCompleted}/${n.totalSteps}`),n.error&&a.push(`Fehler: ${n.error}`);for(let o=0;o<n.stepResults.length;o++){let c=n.stepResults[o];a.push(` ${o+1}. ${c.skillName}: ${c.success?"\u2705":"\u274C "+(c.error??"")}`)}return{success:n.status==="completed",data:n,display:a.join(`
1779
- `)}}async deleteWorkflow(e,t){let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=await this.workflowRepo.getById(s);return r?ee(t).includes(r.userId)?(await 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`}}async getHistory(e){let t=e.workflow_id;if(!t)return{success:!1,error:'Missing "workflow_id"'};let s=await 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:
1779
+ `)}}async deleteWorkflow(e,t){let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=await this.workflowRepo.getById(s);return r?Q(t).includes(r.userId)?(await 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`}}async getHistory(e){let t=e.workflow_id;if(!t)return{success:!1,error:'Missing "workflow_id"'};let s=await 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:
1780
1780
  ${r.join(`
1781
1781
  `)}`}}}});var hs,ba=w(()=>{"use strict";hs=class{static{p(this,"MarketplaceProvider")}async getDetail(e){throw new Error("Detail not supported")}}});var bh,Sn,Oc=w(()=>{"use strict";ba();bh="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",Sn=class extends hs{static{p(this,"WillhabenProvider")}platform="willhaben";async search(e){let t=Math.min(e.rows??100,100),s=new URL("https://www.willhaben.at/iad/kaufen-und-verkaufen/marktplatz");if(s.searchParams.set("keyword",e.query),s.searchParams.set("rows",String(t)),e.priceMin!=null&&s.searchParams.set("PRICE_FROM",String(e.priceMin)),e.priceMax!=null&&s.searchParams.set("PRICE_TO",String(e.priceMax)),e.sort){let d={date_desc:"1",price_asc:"2",price_desc:"3"};s.searchParams.set("sfId",d[e.sort])}e.postcode&&s.searchParams.set("postcode",e.postcode);let r=await fetch(s.toString(),{headers:{"User-Agent":bh,Accept:"text/html"}});if(!r.ok)throw new Error(`willhaben HTTP ${r.status}`);let n=await r.text(),a=this.parseNextData(n).map(d=>this.mapAdvert(d)),o=e.query.toLowerCase().split(/\s+/).filter(d=>d.length>=2);return{listings:o.length>0?a.filter(d=>o.every(u=>d.title.toLowerCase().includes(u))):a,totalCount:this.extractTotalCount(n)??a.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":bh,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 i;try{i=JSON.parse(n[1])}catch{throw new Error("willhaben detail: __NEXT_DATA__ contains invalid JSON")}let a=i?.props?.pageProps?.advertDetails;if(!a)throw new Error("willhaben detail: advertDetails not found in page data");let o=a.attributes?.attribute??[],c=p(I=>o.find(D=>D.name===I)?.values?.[0]??void 0,"attr"),d={};for(let I of o)I.name&&I.values?.[0]&&(d[I.name]=I.values[0]);let u=a.attributeInformation??[];for(let I of u){let L=I.treeAttributeElement?.label,D=I.values?.[0]?.label;L&&D&&(d[L]=D)}let h=(a.advertImageList?.advertImage??[]).map(I=>I.mainImageUrl??I.referenceImageUrl).filter(Boolean),m=a.advertAddressDetails,f=m?[m.postalName,m.postCode,m.district,m.province].filter(Boolean).join(", "):[c("LOCATION/ADDRESS_2"),c("LOCATION/ADDRESS_3")].filter(Boolean).join(", "),g=a.sellerProfileUserData,k=(c("DESCRIPTION")??a.description??"").replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim(),b=c("PRICE"),S=u.find(I=>I.treeAttributeElement?.code==="Zustand")?.values?.[0]?.label;return{id:e,title:a.description??"Kein Titel",price:b?parseFloat(b):null,currency:"EUR",condition:S,location:f,url:s.url||t,imageUrls:h,seller:g?.name??void 0,sellerSince:g?.registerDate??void 0,publishedAt:a.publishedDate??void 0,description:k,attributes:d,platform:"willhaben"}}parseNextData(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)throw new Error("willhaben: __NEXT_DATA__ not found \u2014 page structure may have changed");let s;try{s=JSON.parse(t[1])}catch{throw new Error("willhaben: __NEXT_DATA__ contains invalid JSON")}return s?.props?.pageProps?.searchResult?.advertSummaryList?.advertSummary??[]}extractTotalCount(e){let t=e.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);if(!t)return;let s;try{s=JSON.parse(t[1])}catch{return}return s?.props?.pageProps?.searchResult?.rowsFound}mapAdvert(e){let t=e.attributes?.attribute??[],s=p(i=>t.find(o=>o.name===i)?.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 bn,Dc=w(()=>{"use strict";ba();bn=class extends hs{static{p(this,"EbayProvider")}appId;certId;platform="ebay";tokenCache=null;constructor(e,t){super(),this.appId=e,this.certId=t}async getToken(){if(this.tokenCache&&Date.now()<this.tokenCache.expiresAt)return this.tokenCache.token;let e=Buffer.from(`${this.appId}:${this.certId}`).toString("base64"),t=await fetch("https://api.ebay.com/identity/v1/oauth2/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:`Basic ${e}`},body:"grant_type=client_credentials&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope"});if(!t.ok)throw new Error(`eBay OAuth failed: HTTP ${t.status}`);let s=await t.json();return this.tokenCache={token:s.access_token,expiresAt:Date.now()+(s.expires_in-300)*1e3},this.tokenCache.token}async search(e){let t=await this.getToken(),s=Math.min(e.rows??50,200),r=new URL("https://api.ebay.com/buy/browse/v1/item_summary/search");if(r.searchParams.set("q",e.query),r.searchParams.set("limit",String(s)),e.sort){let d={price_asc:"price",price_desc:"-price",date_desc:"newlyListed"};r.searchParams.set("sort",d[e.sort])}let n=[];if(e.priceMin!=null||e.priceMax!=null){let d=e.priceMin!=null?String(e.priceMin):"",u=e.priceMax!=null?String(e.priceMax):"";n.push(`price:[${d}..${u}]`)}e.condition==="new"&&n.push("conditionIds:{1000}"),e.condition==="used"&&n.push("conditionIds:{3000}"),n.length>0&&r.searchParams.set("filter",n.join(","));let i=await fetch(r.toString(),{headers:{Authorization:`Bearer ${t}`,"X-EBAY-C-MARKETPLACE-ID":"EBAY_AT"}});if(!i.ok)throw new Error(`eBay API error: HTTP ${i.status}`);let a=await i.json(),c=(a.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:a.total??c.length,query:e.query,platform:"ebay"}}}});function va(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 Mc(l,e){return l==null?"k.A.":`${l.toFixed(2)} ${e}`}var vn,vh=w(()=>{"use strict";X();Oc();Dc();p(va,"median");p(Mc,"formatPrice");vn=class extends N{static{p(this,"MarketplaceSkill")}metadata={name:"marketplace",category:"information",description:'Marktplatz-Suche auf willhaben.at und eBay. "search" liefert Inseratliste mit Preisstatistik. "compare" liefert Preisvergleich + g\xFCnstigste 5. "detail" zeigt Einzelinserat mit Beschreibung, Fotos, Verk\xE4ufer-Info \u2014 bewerte bei detail immer Seriosit\xE4t (Preis vs. Markt, Account-Alter, Foto-Anzahl, Beschreibungsqualit\xE4t, Zahlungsmethode). Filter: priceMin/priceMax, sort, condition (new/used), postcode. Watch-kompatibel: search\u2192"count"/"minPrice", compare\u2192"minPrice"/"avgPrice".',riskLevel:"read",version:"2.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["search","compare","detail"],description:"Aktion: search = Inserate auflisten, compare = Preisstatistik, detail = Einzelinserat"},query:{type:"string",description:"Suchbegriff (f\xFCr search/compare)"},platform:{type:"string",enum:["willhaben","ebay","all"],description:"Plattform (default: willhaben)"},priceMin:{type:"number",description:"Mindestpreis EUR"},priceMax:{type:"number",description:"H\xF6chstpreis EUR"},rows:{type:"number",description:"Max Ergebnisse (default 50, max 200)"},sort:{type:"string",enum:["price_asc","price_desc","date_desc"],description:"Sortierung"},condition:{type:"string",enum:["new","used"],description:"Zustand"},postcode:{type:"string",description:'PLZ-Filter (z.B. "1010")'},listing_id:{type:"string",description:"Inserat-ID f\xFCr detail-Aktion"}},required:["action"]}};providers=[];constructor(e){super(),this.providers.push(new Sn),e?.ebay?.appId&&e?.ebay?.certId&&this.providers.push(new bn(e.ebay.appId,e.ebay.certId))}async execute(e,t){let s=e.action,r=e.platform??"willhaben",n=e.query,i=e.priceMin,a=e.priceMax,o=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 h=this.getProviders(r);if(h.length===0)return{success:!1,error:"Keine Marketplace-Provider verf\xFCgbar f\xFCr diese Plattform"};let m={query:n,priceMin:i,priceMax:a,rows:o,sort:c,condition:d,postcode:u};switch(s){case"search":return this.handleSearch(h,m);case"compare":return this.handleCompare(h,{...m,rows:Math.min(o,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(a=>a.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(a=>a.price).filter(a=>a!=null),i=[];i.push(`**${r.length} Inserate** f\xFCr "${t.query}"${s.length>1?` (${s.map(a=>`${a.platform}: ${a.listings.length}`).join(", ")})`:""}
1782
1782
  `),i.push("| # | Titel | Preis | Standort | Plattform | Link |"),i.push("|---|-------|-------|----------|-----------|------|");for(let a=0;a<r.length;a++){let o=r[a],c=o.title.length>60?o.title.slice(0,57)+"...":o.title;i.push(`| ${a+1} | ${c} | ${Mc(o.price,o.currency)} | ${o.location??"\u2014"} | ${o.platform} | [Link](${o.url}) |`)}return n.length>0&&(i.push(""),i.push(`**Min:** ${Math.min(...n).toFixed(2)} EUR | **Max:** ${Math.max(...n).toFixed(2)} EUR | **Median:** ${va(n).toFixed(2)} EUR`)),{success:!0,data:{query:t.query,count:r.length,totalCount:s.reduce((a,o)=>a+o.totalCount,0),minPrice:n.length?Math.min(...n):null,maxPrice:n.length?Math.max(...n):null,medianPrice:n.length?va(n):null,listings:r.map(a=>({id:a.id,title:a.title,price:a.price,location:a.location,url:a.url,platform:a.platform}))},display:i.join(`
@@ -1786,7 +1786,7 @@ ${r.join(`
1786
1786
  `)}}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),i=[];i.push(`**${n.title}** \u2014 ${Mc(n.price,n.currency)}`),i.push(`\u{1F4CD} ${n.location??"k.A."}`),n.condition&&i.push(`Zustand: ${n.condition}`),i.push(`Verk\xE4ufer: ${n.seller??"k.A."}${n.sellerSince?` (registriert seit ${n.sellerSince.split("T")[0]})`:""}`),i.push(`Fotos: ${n.imageUrls.length}`),n.publishedAt&&i.push(`Ver\xF6ffentlicht: ${n.publishedAt.split("T")[0]}`);let a=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"]),o=Object.entries(n.attributes).filter(([c])=>!a.has(c));return o.length>0&&i.push(`Attribute: ${o.map(([c,d])=>`${c}=${d}`).join(", ")}`),i.push(`
1787
1787
  ${n.description.slice(0,500)}`),i.push(`
1788
1788
  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:i.join(`
1789
- `)}}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 Ih=w(()=>{"use strict";vh();ba();Oc();Dc()});function My(){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 Uy(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 Py(){let l=new Date().getDay();return l>=1&&l<=5}var Uc,Ia,Ah=w(()=>{"use strict";X();We();p(My,"todayRange");Uc=[{name:"calendar",skill:"calendar",input:{action:"list_events"},label:"Kalender"},{name:"weather",skill:"weather",input:{},label:"Wetter"},{name:"todo",skill:"todo",input:{action:"list"},label:"Lokale Todos"},{name:"mstodo",skill:"microsoft_todo",input:{action:"list_tasks"},label:"Microsoft To Do"},{name:"email",skill:"email",input:{action:"inbox"},label:"E-Mail"},{name:"energy",skill:"energy_price",input:{action:"briefing"},label:"Strompreise"},{name:"bmw",skill:"bmw",input:{action:"status"},label:"BMW Status"},{name:"home",skill:"homeassistant",input:{action:"briefing_summary"},label:"Smart Home"},{name:"infra",skill:"monitor",input:{},label:"Infrastruktur"}];p(Uy,"extractCity");p(Py,"isWeekday");Ia=class extends N{static{p(this,"BriefingSkill")}skillRegistry;alfredConfig;memoryRepo;metadata={name:"briefing",category:"productivity",description:'T\xE4gliches Morgenbriefing \u2014 sammelt Daten aus mehreren Skills parallel und liefert ein strukturiertes Ergebnis: Kalender, Wetter, Todos, E-Mails, Strompreise, Auto-Status, Smart Home, Infrastruktur. Mo\u2013Fr automatisch: Pendelzeit Heim\u2192B\xFCro + BMW-Akkucheck (wenn kein ausw\xE4rtiger Termin). "run" f\xFChrt das Briefing aus (optional mit location f\xFCr Wetter). "modules" zeigt verf\xFCgbare und aktive Module.',riskLevel:"read",version:"1.1.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","modules"],description:"run = Briefing ausf\xFChren, modules = verf\xFCgbare Module anzeigen"},location:{type:"string",description:'Ort f\xFCr Wetterabfrage (default: aus Config oder "Vienna")'},modules:{type:"array",items:{type:"string"},description:"Optionale Liste aktiver Module (default: alle verf\xFCgbaren)"}},required:["action"]}};constructor(e,t,s){super(),this.skillRegistry=e,this.alfredConfig=t,this.memoryRepo=s}async execute(e,t){let s=e.action??"run";switch(s){case"run":return this.runBriefing(e,t);case"modules":return this.showModules();default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getAvailableModules(){return Uc.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=Uc.map(n=>`${e.some(a=>a.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:Uc.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
1789
+ `)}}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 Ih=w(()=>{"use strict";vh();ba();Oc();Dc()});function My(){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 Uy(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 Py(){let l=new Date().getDay();return l>=1&&l<=5}var Uc,Ia,Ah=w(()=>{"use strict";X();He();p(My,"todayRange");Uc=[{name:"calendar",skill:"calendar",input:{action:"list_events"},label:"Kalender"},{name:"weather",skill:"weather",input:{},label:"Wetter"},{name:"todo",skill:"todo",input:{action:"list"},label:"Lokale Todos"},{name:"mstodo",skill:"microsoft_todo",input:{action:"list_tasks"},label:"Microsoft To Do"},{name:"email",skill:"email",input:{action:"inbox"},label:"E-Mail"},{name:"energy",skill:"energy_price",input:{action:"briefing"},label:"Strompreise"},{name:"bmw",skill:"bmw",input:{action:"status"},label:"BMW Status"},{name:"home",skill:"homeassistant",input:{action:"briefing_summary"},label:"Smart Home"},{name:"infra",skill:"monitor",input:{},label:"Infrastruktur"}];p(Uy,"extractCity");p(Py,"isWeekday");Ia=class extends N{static{p(this,"BriefingSkill")}skillRegistry;alfredConfig;memoryRepo;metadata={name:"briefing",category:"productivity",description:'T\xE4gliches Morgenbriefing \u2014 sammelt Daten aus mehreren Skills parallel und liefert ein strukturiertes Ergebnis: Kalender, Wetter, Todos, E-Mails, Strompreise, Auto-Status, Smart Home, Infrastruktur. Mo\u2013Fr automatisch: Pendelzeit Heim\u2192B\xFCro + BMW-Akkucheck (wenn kein ausw\xE4rtiger Termin). "run" f\xFChrt das Briefing aus (optional mit location f\xFCr Wetter). "modules" zeigt verf\xFCgbare und aktive Module.',riskLevel:"read",version:"1.1.0",timeoutMs:6e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","modules"],description:"run = Briefing ausf\xFChren, modules = verf\xFCgbare Module anzeigen"},location:{type:"string",description:'Ort f\xFCr Wetterabfrage (default: aus Config oder "Vienna")'},modules:{type:"array",items:{type:"string"},description:"Optionale Liste aktiver Module (default: alle verf\xFCgbaren)"}},required:["action"]}};constructor(e,t,s){super(),this.skillRegistry=e,this.alfredConfig=t,this.memoryRepo=s}async execute(e,t){let s=e.action??"run";switch(s){case"run":return this.runBriefing(e,t);case"modules":return this.showModules();default:return{success:!1,error:`Unbekannte Aktion: ${s}`}}}getAvailableModules(){return Uc.filter(e=>this.skillRegistry.has(e.skill))}showModules(){let e=this.getAvailableModules(),t=Uc.map(n=>`${e.some(a=>a.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:Uc.map(n=>n.name),commuteAvailable:s,commuteConfigured:r},display:`Briefing-Module:
1790
1790
  ${t.join(`
1791
1791
  `)}
1792
1792
 
@@ -1801,10 +1801,10 @@ ${typeof g.data=="string"?g.data:JSON.stringify(g.data,null,2)}`):!g.success&&g.
1801
1801
  ${o.display}`):o.error&&d.push(`**Route:** \u26A0\uFE0F ${o.error}`),c?.success&&c.data){let u=this.extractBatteryLevel(c.data);u!=null&&u<30?d.push(`
1802
1802
  \u26A0\uFE0F **BMW Akku niedrig (${u}%)** \u2014 Laden vor der Fahrt empfohlen!`):u!=null&&d.push(`
1803
1803
  \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:o.data,bmwBattery:this.extractBatteryLevel(c?.data)},display:d.join(`
1804
- `)}}async 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 i of ee(e)){let a=await this.memoryRepo.search(i,"adresse");for(let o of a){let c=o.key.toLowerCase(),d=o.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}}async 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 ee(e)){let n=await this.memoryRepo.search(r,"briefing");for(let i of n){let a=i.key.toLowerCase();if(/ha_entit|home.?assistant.*entit|briefing.*entit/.test(a)){let o=i.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(o.length)return{entities:o}}if(/ha_domain|home.?assistant.*domain|briefing.*domain/.test(a)){let o=i.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(o.length)return{domains:o}}}}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(i=>i.trim()).filter(Boolean);if(n.length>=3){let i=n[0],a=n[1]&&n[1]!==""?` [${n[1]}]`:"",o=n[2];return`${i}${a} ${o}`}return r}),s=s.replace(/^\d+\s+todo\(s\):\n?/i,""),s=s.replace(/\n{2,}/g,`
1804
+ `)}}async 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 i of Q(e)){let a=await this.memoryRepo.search(i,"adresse");for(let o of a){let c=o.key.toLowerCase(),d=o.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}}async 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 Q(e)){let n=await this.memoryRepo.search(r,"briefing");for(let i of n){let a=i.key.toLowerCase();if(/ha_entit|home.?assistant.*entit|briefing.*entit/.test(a)){let o=i.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(o.length)return{entities:o}}if(/ha_domain|home.?assistant.*domain|briefing.*domain/.test(a)){let o=i.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(o.length)return{domains:o}}}}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(i=>i.trim()).filter(Boolean);if(n.length>=3){let i=n[0],a=n[1]&&n[1]!==""?` [${n[1]}]`:"",o=n[2];return`${i}${a} ${o}`}return r}),s=s.replace(/^\d+\s+todo\(s\):\n?/i,""),s=s.replace(/\n{2,}/g,`
1805
1805
  `)),e==="mstodo"&&(s=s.replace(/\s*\[(?:taskId|listId)=[^\]]+\]/g,"")),s=s.replace(/^\[[\w-]+\]\s*/gm,""),s=s.replace(/\n{3,}/g,`
1806
1806
 
1807
- `),s.trim()}buildHighlights(e){let t=[],s=e.find(a=>a.module==="bmw")?.data;if(s){let a=this.extractBatteryLevel(s);a!=null&&a<30&&t.push(`\u{1F697} BMW Akku bei ${a}% \u2014 laden empfohlen`)}let r=e.find(a=>a.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(a=>a.module==="energy")?.data;if(n){let a=n.currentCt,o=n.avgCt;a!=null&&o!=null&&a<o&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${a} ct/kWh)`)}let i=e.find(a=>a.module==="calendar")?.data;return Array.isArray(i)&&i.length>0&&t.push(`\u{1F4C5} ${i.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 kr,$h=w(()=>{"use strict";X();We();kr=class extends N{static{p(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=se(t);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 await 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?await 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=(await 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:
1807
+ `),s.trim()}buildHighlights(e){let t=[],s=e.find(a=>a.module==="bmw")?.data;if(s){let a=this.extractBatteryLevel(s);a!=null&&a<30&&t.push(`\u{1F697} BMW Akku bei ${a}% \u2014 laden empfohlen`)}let r=e.find(a=>a.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(a=>a.module==="energy")?.data;if(n){let a=n.currentCt,o=n.avgCt;a!=null&&o!=null&&a<o&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${a} ct/kWh)`)}let i=e.find(a=>a.module==="calendar")?.data;return Array.isArray(i)&&i.length>0&&t.push(`\u{1F4C5} ${i.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 kr,$h=w(()=>{"use strict";X();He();kr=class extends N{static{p(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=se(t);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 await 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?await 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=(await 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:
1808
1808
  ${r.join(`
1809
1809
  `)}`}}async check(e,t){if(!t){let a=await this.memoryRepo.listByCategory(e,"feed");if(a.length===0)return{success:!0,data:{newCount:0},display:"No feed subscriptions to check."};let o=0,c=[];for(let u of a)try{let h=JSON.parse(u.value),m=await this.checkSingleFeed(e,h);m.newCount>0&&(o+=m.newCount,c.push(m))}catch{}let d=c.map(u=>`${u.label}: ${u.newCount} new
1810
1810
  ${u.items.map(h=>` \u2022 ${h.title}${h.link?` \u2014 ${h.link}`:""}${h.snippet?`
@@ -2043,7 +2043,7 @@ Antworte als JSON:
2043
2043
  "phases": ["Phase 1: ...", "Phase 2: ...", ...],
2044
2044
  "buildStrategy": "npm install && npm run build && npm test",
2045
2045
  "estimatedIterations": 4
2046
- }`;p(Fn,"createProjectPlan")});var Kh=w(()=>{"use strict";Hh();xa();nl();Qc();sl();Wh();qh();zh()});var re={};ie(re,{ActivityTracker:()=>os,BMWSkill:()=>Ta,BackgroundTaskSkill:()=>dr,BriefingSkill:()=>Ia,BrowserSkill:()=>ar,CalculatorSkill:()=>qs,CalendarProvider:()=>st,CalendarSkill:()=>cs,ClipboardSkill:()=>nr,CodeAgentSkill:()=>Ln,CodeExecutionSkill:()=>Tn,CodeExecutor:()=>us,ConfigureSkill:()=>wr,ContactsProvider:()=>it,ContactsSkill:()=>_n,CrossPlatformSkill:()=>lr,DatabaseSkill:()=>An,DelegateSkill:()=>Qs,DockerSkill:()=>ga,DocumentSkill:()=>pr,EmailProvider:()=>kt,EmailSkill:()=>Dt,EnergyPriceSkill:()=>Ea,FeedReaderSkill:()=>kr,FileSkill:()=>sr,ForgeClient:()=>ms,HelpSkill:()=>Sr,HomeAssistantSkill:()=>da,HttpSkill:()=>tr,ImageGenerateSkill:()=>mr,MCPClient:()=>ls,MCPManager:()=>yn,MCPSkillAdapter:()=>ds,MarketplaceSkill:()=>vn,MemorySkill:()=>Zs,MicrosoftTodoSkill:()=>ka,MonitorSkill:()=>_a,NoteSkill:()=>Ys,PluginLoader:()=>ea,ProfileSkill:()=>or,ProjectAgentSkill:()=>Cn,ProxmoxSkill:()=>ca,ROLE_SKILL_ACCESS:()=>Oh,ReminderSkill:()=>Gs,RoutingSkill:()=>wa,ScheduledTaskSkill:()=>ur,ScreenshotSkill:()=>ir,SharingSkill:()=>Na,ShellSkill:()=>Js,Skill:()=>N,SkillRegistry:()=>Hs,SkillSandbox:()=>Ws,SystemInfoSkill:()=>zs,TTSSkill:()=>hr,TodoSkill:()=>fr,TransitSkill:()=>yr,UniFiSkill:()=>la,UserManagementSkill:()=>Ra,WatchSkill:()=>Er,WeatherSkill:()=>Vs,WebSearchSkill:()=>Ks,WorkflowSkill:()=>_r,YouTubeSkill:()=>$a,allUserIds:()=>ee,createCalendarProvider:()=>cr,createContactsProvider:()=>fa,createEmailProvider:()=>er,createForgeClient:()=>Ir,createProjectPlan:()=>Fn,drainInterjections:()=>On,effectiveUserId:()=>se,executeAgent:()=>ut,gitAddRemote:()=>Rn,gitGetRemoteUrl:()=>br,gitInitRepo:()=>$n,orchestrate:()=>fs,orchestrateWithGit:()=>Nn,parseRemoteUrl:()=>vr,pushInterjection:()=>xn,registerAbortController:()=>Dn,removeAbortController:()=>Mn,validateBuild:()=>Pn});var te=w(()=>{"use strict";X();We();Gu();Yu();cc();Vu();Qu();ep();tp();sp();rp();np();op();cp();lp();hp();fp();yp();Tp();Ep();kp();Sp();Rp();Np();Lp();xp();Op();Mp();Up();Pp();Fp();jp();Bp();Xp();Gp();Yp();eh();oh();ch();fh();gh();wh();Eh();_h();kh();Sh();Ih();Ah();$h();Nh();Lh();Ch();Dh();Mh();Kh()});var jn,al=w(()=>{"use strict";jn=class{static{p(this,"ConversationManager")}conversations;constructor(e){this.conversations=e}async getOrCreateConversation(e,t,s){let r=await this.conversations.findByPlatformChat(e,t);return r?(await this.conversations.updateTimestamp(r.id),r):this.conversations.create(e,t,s)}async addMessage(e,t,s,r){return this.conversations.addMessage(e,t,s,r)}async getHistory(e,t=20){return this.conversations.getMessages(e,t)}async pruneMessages(e,t){return this.conversations.pruneMessages(e,t)}}});async function De(l,e){let t;if(e.platformUserId)t=await l.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=await l.findById(e.userId)??await l.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in l?await l.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in l&&(r=(await l.getLinkedUsers(s)).map(o=>o.platformUserId));let n;try{"getProfile"in l?n=(await 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 Ut=w(()=>{"use strict";p(De,"buildSkillContext")});function Gh(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(dT))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 Yh(l,e){return l.filter(t=>e.has(t.category??"core"))}var dT,Vh=w(()=>{"use strict";dT={productivity:/\b(todo|note|notiz|remind|erinner|calendar|kalender|termin|event|email|e-mail|mail|contact|kontakt|briefing|morgenbriefing|tagesbriefing)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info|transit|bahn|zug|bus|tram|u.?bahn|s.?bahn|abfahrt|verbindung|haltestelle|öffi|fahrplan|strom|energy|preis|price|kwh|awattar|marktpreis|spot|günstig|cheapest|netzentgelt|rss|feed|atom|news|nachricht|schlagzeil|headline|youtube|video|transkript|transcript|channel|kanal|zusammenfass)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows|bild|image|generier|photo|foto)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|script|skript|befehl|kommando|tägliche?r?s?|stündliche?r?s?|wöchentliche?r?s?|monatliche?r?s?|jeden\s+(tag|morgen|abend|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag)|um\s+\d{1,2}\s*(uhr|:|h)|alle\s+\d+\s*(min|stund|sekund)|in\s+\d+\s*(minuten?|stunden?|sekunden?|hours?|minutes?|seconds?|min)|daily|hourly|weekly|every\s+(day|hour|morning|evening|night|\d+\s*min)|führ.{0,5}aus|execut|ausführ)\b/i,files:/\b(file|datei|document|dokument|pdf|http|download|upload|herunterlad|hochlad|anhang|attachment)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|netzwerk|network|homeassistant|home.?assistant|smarthome|smart.?home|licht|light|schalter|switch|solar|photovoltaik|pv|wechselrichter|inverter|batterie.?speicher|wallbox|energieverbrauch|stromverbrauch|verbrauch.{0,5}kwh|einspeis|netzeinspeis|autarkie|eigenverbrauch|bmw|auto|fahrzeug|ladestand|reichweite|laden(?!e)|charging|vehicle|soc|ladehistorie|ladesession|ladevorgang|ladezyklus|ladekurve|km|kilometer|kilometerstand|mileage|tachostand|database|datenbank|sql|query|tabelle|table|schema|postgres|mysql|mariadb|mongodb|mongo|influx|redis|mssql|select|insert|verbindung.{0,5}db)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};p(Gh,"selectCategories");p(Yh,"filterSkills")});import ol from"node:fs";import cl from"node:path";function gT(l,e){if(l.length<=e)return l;let t=l.split(`
2046
+ }`;p(Fn,"createProjectPlan")});var Kh=w(()=>{"use strict";Hh();xa();nl();Qc();sl();Wh();qh();zh()});var re={};ie(re,{ActivityTracker:()=>os,BMWSkill:()=>Ta,BackgroundTaskSkill:()=>dr,BriefingSkill:()=>Ia,BrowserSkill:()=>ar,CalculatorSkill:()=>qs,CalendarProvider:()=>st,CalendarSkill:()=>cs,ClipboardSkill:()=>nr,CodeAgentSkill:()=>Ln,CodeExecutionSkill:()=>Tn,CodeExecutor:()=>us,ConfigureSkill:()=>wr,ContactsProvider:()=>it,ContactsSkill:()=>_n,CrossPlatformSkill:()=>lr,DatabaseSkill:()=>An,DelegateSkill:()=>Qs,DockerSkill:()=>ga,DocumentSkill:()=>pr,EmailProvider:()=>kt,EmailSkill:()=>Dt,EnergyPriceSkill:()=>Ea,FeedReaderSkill:()=>kr,FileSkill:()=>sr,ForgeClient:()=>ms,HelpSkill:()=>Sr,HomeAssistantSkill:()=>da,HttpSkill:()=>tr,ImageGenerateSkill:()=>mr,MCPClient:()=>ls,MCPManager:()=>yn,MCPSkillAdapter:()=>ds,MarketplaceSkill:()=>vn,MemorySkill:()=>Zs,MicrosoftTodoSkill:()=>ka,MonitorSkill:()=>_a,NoteSkill:()=>Ys,PluginLoader:()=>ea,ProfileSkill:()=>or,ProjectAgentSkill:()=>Cn,ProxmoxSkill:()=>ca,ROLE_SKILL_ACCESS:()=>Oh,ReminderSkill:()=>Gs,RoutingSkill:()=>wa,ScheduledTaskSkill:()=>ur,ScreenshotSkill:()=>ir,SharingSkill:()=>Na,ShellSkill:()=>Js,Skill:()=>N,SkillRegistry:()=>Hs,SkillSandbox:()=>Ws,SystemInfoSkill:()=>zs,TTSSkill:()=>hr,TodoSkill:()=>fr,TransitSkill:()=>yr,UniFiSkill:()=>la,UserManagementSkill:()=>Ra,WatchSkill:()=>Er,WeatherSkill:()=>Vs,WebSearchSkill:()=>Ks,WorkflowSkill:()=>_r,YouTubeSkill:()=>$a,allUserIds:()=>Q,createCalendarProvider:()=>cr,createContactsProvider:()=>fa,createEmailProvider:()=>er,createForgeClient:()=>Ir,createProjectPlan:()=>Fn,drainInterjections:()=>On,effectiveUserId:()=>se,executeAgent:()=>ut,gitAddRemote:()=>Rn,gitGetRemoteUrl:()=>br,gitInitRepo:()=>$n,orchestrate:()=>fs,orchestrateWithGit:()=>Nn,parseRemoteUrl:()=>vr,pushInterjection:()=>xn,registerAbortController:()=>Dn,removeAbortController:()=>Mn,validateBuild:()=>Pn});var ee=w(()=>{"use strict";X();He();Gu();Yu();cc();Vu();Qu();ep();tp();sp();rp();np();op();cp();lp();hp();fp();yp();Tp();Ep();kp();Sp();Rp();Np();Lp();xp();Op();Mp();Up();Pp();Fp();jp();Bp();Xp();Gp();Yp();eh();oh();ch();fh();gh();wh();Eh();_h();kh();Sh();Ih();Ah();$h();Nh();Lh();Ch();Dh();Mh();Kh()});var jn,al=w(()=>{"use strict";jn=class{static{p(this,"ConversationManager")}conversations;constructor(e){this.conversations=e}async getOrCreateConversation(e,t,s){let r=await this.conversations.findByPlatformChat(e,t);return r?(await this.conversations.updateTimestamp(r.id),r):this.conversations.create(e,t,s)}async addMessage(e,t,s,r){return this.conversations.addMessage(e,t,s,r)}async getHistory(e,t=20){return this.conversations.getMessages(e,t)}async pruneMessages(e,t){return this.conversations.pruneMessages(e,t)}}});async function Oe(l,e){let t;if(e.platformUserId)t=await l.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=await l.findById(e.userId)??await l.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in l?await l.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in l&&(r=(await l.getLinkedUsers(s)).map(o=>o.platformUserId));let n;try{"getProfile"in l?n=(await 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 Ut=w(()=>{"use strict";p(Oe,"buildSkillContext")});function Gh(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(dT))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 Yh(l,e){return l.filter(t=>e.has(t.category??"core"))}var dT,Vh=w(()=>{"use strict";dT={productivity:/\b(todo|note|notiz|remind|erinner|calendar|kalender|termin|event|email|e-mail|mail|contact|kontakt|briefing|morgenbriefing|tagesbriefing)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info|transit|bahn|zug|bus|tram|u.?bahn|s.?bahn|abfahrt|verbindung|haltestelle|öffi|fahrplan|strom|energy|preis|price|kwh|awattar|marktpreis|spot|günstig|cheapest|netzentgelt|rss|feed|atom|news|nachricht|schlagzeil|headline|youtube|video|transkript|transcript|channel|kanal|zusammenfass)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows|bild|image|generier|photo|foto)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|script|skript|befehl|kommando|tägliche?r?s?|stündliche?r?s?|wöchentliche?r?s?|monatliche?r?s?|jeden\s+(tag|morgen|abend|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag)|um\s+\d{1,2}\s*(uhr|:|h)|alle\s+\d+\s*(min|stund|sekund)|in\s+\d+\s*(minuten?|stunden?|sekunden?|hours?|minutes?|seconds?|min)|daily|hourly|weekly|every\s+(day|hour|morning|evening|night|\d+\s*min)|führ.{0,5}aus|execut|ausführ)\b/i,files:/\b(file|datei|document|dokument|pdf|http|download|upload|herunterlad|hochlad|anhang|attachment)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|netzwerk|network|homeassistant|home.?assistant|smarthome|smart.?home|licht|light|schalter|switch|solar|photovoltaik|pv|wechselrichter|inverter|batterie.?speicher|wallbox|energieverbrauch|stromverbrauch|verbrauch.{0,5}kwh|einspeis|netzeinspeis|autarkie|eigenverbrauch|bmw|auto|fahrzeug|ladestand|reichweite|laden(?!e)|charging|vehicle|soc|ladehistorie|ladesession|ladevorgang|ladezyklus|ladekurve|km|kilometer|kilometerstand|mileage|tachostand|database|datenbank|sql|query|tabelle|table|schema|postgres|mysql|mariadb|mongodb|mongo|influx|redis|mssql|select|insert|verbindung.{0,5}db)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};p(Gh,"selectCategories");p(Yh,"filterSkills")});import ol from"node:fs";import cl from"node:path";function gT(l,e){if(l.length<=e)return l;let t=l.split(`
2047
2047
  `);if(t.length<=10)return l.slice(0,e)+`
2048
2048
 
2049
2049
  [... 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,i=t.slice(0,s),a=t.slice(t.length-r),o=`
@@ -2054,11 +2054,11 @@ Antworte als JSON:
2054
2054
 
2055
2055
  [... truncated, total `+l.length+` chars]
2056
2056
 
2057
- `+l.slice(l.length-Math.floor(e*.2))}return c}var uT,pT,Jh,hT,mT,fT,Zh,yT,TT,wT,Qh,ET,Bn,ll=w(()=>{"use strict";ac();Ut();Vh();uT=new Set(["shell","file","system_info","screenshot","clipboard","docker","code_sandbox","code_agent","project_agent","browser"]),pT=900*1e3,Jh=50,hT=2,mT=12e3,fT=3,Zh=.85;p(gT,"truncateToolResult");yT=1e5,TT=2e3,wT=.1,Qh=3,ET=10,Bn=class{static{p(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;fileStore;processedMessageRepo;nodeId;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;confirmationQueue;activityLogger;skillHealthTracker;alfredUserRepo;roleSkillAccess;usageRepo;userServiceResolver;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}setAlfredUserRepo(e,t,s,r){this.alfredUserRepo=e,this.roleSkillAccess=t,this.usageRepo=s,this.userServiceResolver=r}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.fileStore=e.fileStore,this.processedMessageRepo=e.processedMessageRepo,this.nodeId=e.nodeId??"single",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 un}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}=await De(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{if(this.processedMessageRepo){let K=e.id??`${e.chatId}:${e.userId}:${Date.now()}`,V=`${e.platform}:${K}`;if(!await this.processedMessageRepo.markProcessed(V,this.nodeId))return this.logger.debug({messageKey:V},"Message already processed by another node, skipping"),{text:""}}let r=e.metadata?.originalChatId??e.chatId,{user:n,masterUserId:i,linkedPlatformUserIds:a,context:o}=await De(this.users,{platformUserId:e.userId,platform:e.platform,chatId:r,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),c;try{c=await this.alfredUserRepo?.getUserByPlatform(e.platform,e.userId)}catch(K){this.logger.debug({err:K},"Alfred user lookup failed (table may not exist yet)")}if(c){if(!c.active)return{text:"Dein Account ist deaktiviert. Bitte kontaktiere den Admin."};o.userRole=c.role,o.alfredUserId=c.id,this.userServiceResolver&&(o.userServiceResolver=this.userServiceResolver)}this.nodeId!=="single"&&(o.nodeId=this.nodeId,o.clusterEnabled=!0);let d=e.chatType==="group"?`${e.chatId}:${e.userId}`:e.chatId,u=await this.conversationManager.getOrCreateConversation(e.platform,d,n.id),h=!e.metadata?.skipHistory&&this.conversationSummarizer?await this.conversationSummarizer.getSummary(u.id):void 0,m=h?ET:this.maxHistoryMessages,f=e.metadata?.skipHistory?[]:await this.conversationManager.getHistory(u.id,m);await this.conversationManager.addMessage(u.id,"user",e.text);let g,y=this.isSyntheticLabel(e.text),k=e.attachments?.some(K=>K.type==="audio")??!1,b=y&&!k;if(this.memoryRetriever&&e.text&&!b)try{g=await this.memoryRetriever.retrieve(i,e.text,15,a)}catch(K){this.logger.debug({err:K},"Hybrid memory retrieval failed")}if(!g&&this.memoryRepo&&!b)try{let K=[i,...(a??[]).filter(V=>V!==i)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let V=new Set;g=[];for(let de of K)for(let A of await this.embeddingService.semanticSearch(de,e.text,10))V.has(A.key)||(V.add(A.key),g.push(A));for(let de of K)for(let A of await this.memoryRepo.getRecentForPrompt(de,5))V.has(A.key)||(V.add(A.key),g.push(A))}else{let V=new Set;g=[];for(let de of K)for(let A of await this.memoryRepo.getRecentForPrompt(de,20))V.has(A.key)||(V.add(A.key),g.push(A))}}catch(K){this.logger.debug({err:K},"Memory loading failed")}g&&g.length>0&&(g=this.applyMemoryBudget(g));let S;try{"getProfile"in this.users&&(S=await this.users.getProfile(i),S&&!S.displayName&&(S.displayName=n.displayName??n.username))}catch(K){this.logger.debug({err:K},"Profile loading failed")}let I=o.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,L=this.skillRegistry?this.skillRegistry.getAll().map(K=>K.metadata):void 0,D=L;if(L&&e.text){let K=new Set(L.map(H=>H.category??"core")),V=f.filter(H=>H.role==="user").slice(-3).map(H=>H.content).join(" "),de=V?`${e.text} ${V}`:e.text,A=Gh(de,K);D=Yh(L,A)}if(D&&this.roleSkillAccess){let K=c?.role??(this.alfredUserRepo?"guest":void 0);if(K){let V=this.roleSkillAccess[K];if(V&&V!=="*"){let de=new Set(V);D=D.filter(A=>de.has(A.name))}}}let W=D?this.promptBuilder.buildTools(D):void 0,q=this.promptBuilder.buildSystemPrompt({memories:g,skills:D,userProfile:S,conversationSummary:h?.summary}),j=this.buildActiveAgentStatus();j&&(q+=`
2057
+ `+l.slice(l.length-Math.floor(e*.2))}return c}var uT,pT,Jh,hT,mT,fT,Zh,yT,TT,wT,Qh,ET,Bn,ll=w(()=>{"use strict";ac();Ut();Vh();uT=new Set(["shell","file","system_info","screenshot","clipboard","docker","code_sandbox","code_agent","project_agent","browser"]),pT=900*1e3,Jh=50,hT=2,mT=12e3,fT=3,Zh=.85;p(gT,"truncateToolResult");yT=1e5,TT=2e3,wT=.1,Qh=3,ET=10,Bn=class{static{p(this,"MessagePipeline")}promptBuilder;llm;conversationManager;users;logger;skillRegistry;skillSandbox;securityManager;memoryRepo;speechTranscriber;inboxPath;fileStore;processedMessageRepo;nodeId;embeddingService;activeLearning;memoryRetriever;maxHistoryMessages;documentProcessor;conversationSummarizer;confirmationQueue;activityLogger;skillHealthTracker;alfredUserRepo;roleSkillAccess;usageRepo;userServiceResolver;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}setAlfredUserRepo(e,t,s,r){this.alfredUserRepo=e,this.roleSkillAccess=t,this.usageRepo=s,this.userServiceResolver=r}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.fileStore=e.fileStore,this.processedMessageRepo=e.processedMessageRepo,this.nodeId=e.nodeId??"single",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 un}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}=await Oe(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{if(this.processedMessageRepo){let K=e.id??`${e.chatId}:${e.userId}:${Date.now()}`,Y=`${e.platform}:${K}`;if(!await this.processedMessageRepo.markProcessed(Y,this.nodeId))return this.logger.debug({messageKey:Y},"Message already processed by another node, skipping"),{text:""}}let r=e.metadata?.originalChatId??e.chatId,{user:n,masterUserId:i,linkedPlatformUserIds:a,context:o}=await Oe(this.users,{platformUserId:e.userId,platform:e.platform,chatId:r,chatType:e.chatType,userName:e.userName,displayName:e.displayName}),c;try{c=await this.alfredUserRepo?.getUserByPlatform(e.platform,e.userId)}catch(K){this.logger.debug({err:K},"Alfred user lookup failed (table may not exist yet)")}if(c){if(!c.active)return{text:"Dein Account ist deaktiviert. Bitte kontaktiere den Admin."};o.userRole=c.role,o.alfredUserId=c.id,this.userServiceResolver&&(o.userServiceResolver=this.userServiceResolver)}this.nodeId!=="single"&&(o.nodeId=this.nodeId,o.clusterEnabled=!0);let d=e.chatType==="group"?`${e.chatId}:${e.userId}`:e.chatId,u=await this.conversationManager.getOrCreateConversation(e.platform,d,n.id),h=!e.metadata?.skipHistory&&this.conversationSummarizer?await this.conversationSummarizer.getSummary(u.id):void 0,m=h?ET:this.maxHistoryMessages,f=e.metadata?.skipHistory?[]:await this.conversationManager.getHistory(u.id,m);await this.conversationManager.addMessage(u.id,"user",e.text);let g,y=this.isSyntheticLabel(e.text),k=e.attachments?.some(K=>K.type==="audio")??!1,b=y&&!k;if(this.memoryRetriever&&e.text&&!b)try{g=await this.memoryRetriever.retrieve(i,e.text,15,a)}catch(K){this.logger.debug({err:K},"Hybrid memory retrieval failed")}if(!g&&this.memoryRepo&&!b)try{let K=[i,...(a??[]).filter(Y=>Y!==i)];if(this.embeddingService&&e.text&&this.llm.supportsEmbeddings()){let Y=new Set;g=[];for(let le of K)for(let A of await this.embeddingService.semanticSearch(le,e.text,10))Y.has(A.key)||(Y.add(A.key),g.push(A));for(let le of K)for(let A of await this.memoryRepo.getRecentForPrompt(le,5))Y.has(A.key)||(Y.add(A.key),g.push(A))}else{let Y=new Set;g=[];for(let le of K)for(let A of await this.memoryRepo.getRecentForPrompt(le,20))Y.has(A.key)||(Y.add(A.key),g.push(A))}}catch(K){this.logger.debug({err:K},"Memory loading failed")}g&&g.length>0&&(g=this.applyMemoryBudget(g));let S;try{"getProfile"in this.users&&(S=await this.users.getProfile(i),S&&!S.displayName&&(S.displayName=n.displayName??n.username))}catch(K){this.logger.debug({err:K},"Profile loading failed")}let I=o.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,L=this.skillRegistry?this.skillRegistry.getAll().map(K=>K.metadata):void 0,D=L;if(L&&e.text){let K=new Set(L.map(H=>H.category??"core")),Y=f.filter(H=>H.role==="user").slice(-3).map(H=>H.content).join(" "),le=Y?`${e.text} ${Y}`:e.text,A=Gh(le,K);D=Yh(L,A)}if(D&&this.roleSkillAccess){let K=c?.role??(this.alfredUserRepo?"guest":void 0);if(K){let Y=this.roleSkillAccess[K];if(Y&&Y!=="*"){let le=new Set(Y);D=D.filter(A=>le.has(A.name))}}}let W=D?this.promptBuilder.buildTools(D):void 0,q=this.promptBuilder.buildSystemPrompt({memories:g,skills:D,userProfile:S,conversationSummary:h?.summary}),j=this.buildActiveAgentStatus();j&&(q+=`
2058
2058
 
2059
- `+j);let ce=this.promptBuilder.buildMessages(f),me=this.collapseRepeatedToolErrors(ce),O=ic(me),pe=me.reduce((K,V)=>K+as(V),0)-O.reduce((K,V)=>K+as(V),0);pe>100&&this.logger.debug(`Tool result trimming saved ~${pe} tokens`);let he=await this.buildUserContent(e,t);O.push({role:"user",content:he});let ye=W?tt(JSON.stringify(W)):0,$e=1,ae=this.trimToContextWindow(q,O,ye,$e),z,le=0,Ye=Date.now(),we="",Re=0,Ue=0,Pe=0,pt,It=[],ht=new Set,Xt=[],mt=[];for(t?.("Thinking...");;){le>0&&this.compressToolLoop(ae,q,ye),this.logger.info({messageCount:ae.length,messageRoles:ae.map((U,G)=>{let Q=Array.isArray(U.content)&&U.content.some(Ne=>Ne.type==="tool_use"),Te=Array.isArray(U.content)&&U.content.some(Ne=>Ne.type==="tool_result");return`[${G}]${U.role}${Q?"[tool_use]":""}${Te?"[tool_result]":""}`})},"LLM request message structure");try{z=await this.llm.complete({messages:ae,system:q,tools:W&&W.length>0?W:void 0,tier:e.metadata?.tier}),Ue+=z.usage?.inputTokens??0,Pe+=z.usage?.outputTokens??0}catch(U){if((U instanceof Error?U.message:String(U)).includes("prompt is too long")&&$e>.3){$e*=.5,this.logger.warn({budgetMultiplier:$e},"Prompt too long, retrimming with reduced budget"),ae=this.trimToContextWindow(q,O,ye,$e);continue}throw U}if(z.stopReason==="max_tokens"&&z.toolCalls?.length&&(this.logger.warn({toolCallCount:z.toolCalls.length},"Discarding truncated tool calls due to max_tokens"),z={...z,toolCalls:[]}),!z.toolCalls||z.toolCalls.length===0){if(z.stopReason==="max_tokens"){let U=0,G=z.content??"";for(;z.stopReason==="max_tokens"&&U<fT;){U++,this.logger.info({continuationRounds:U,textLength:G.length},"Output truncated, requesting continuation"),G?(ae.push({role:"assistant",content:G}),ae.push({role:"user",content:"Fahre exakt dort fort wo du aufgeh\xF6rt hast. Keine Wiederholung, nur der Rest."})):ae.push({role:"user",content:"Deine Antwort war zu lang und wurde abgeschnitten. Bitte antworte k\xFCrzer und kompakter. Fasse zusammen statt alles aufzulisten."});try{z=await this.llm.complete({messages:ae,system:q,tools:W&&W.length>0?W:void 0,tier:e.metadata?.tier}),Ue+=z.usage?.inputTokens??0,Pe+=z.usage?.outputTokens??0,z.content&&(G+=z.content)}catch{break}}z={...z,content:G,stopReason:"end_turn"}}break}let K=Date.now()-Ye;if(K>=pT){let U=Math.round(K/6e4);this.logger.warn({iteration:le,elapsedMin:U,pendingToolCalls:z.toolCalls.length},"Tool loop timeout reached"),z=await this.abortToolLoop(ae,z,u.id,q,`Das Zeitlimit von ${U} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(le>=Jh){this.logger.warn({iteration:le,pendingToolCalls:z.toolCalls.length},"Tool loop iteration cap reached"),z=await this.abortToolLoop(ae,z,u.id,q,`Das Iterationslimit von ${Jh} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}le++,this.logger.info({iteration:le,toolCalls:z.toolCalls.length},"Processing tool calls");let V=[];z.content&&V.push({type:"text",text:z.content});for(let U of z.toolCalls)V.push({type:"tool_use",id:U.id,name:U.name,input:U.input});ae.push({role:"assistant",content:V});let de=await this.executeToolCallsParallel(z.toolCalls,{...o,conversationId:u.id,timezone:I},t),A=de.blocks;de.attachments.length>0&&It.push(...de.attachments);for(let U of z.toolCalls)ht.add(U.name);Xt.push(...z.toolCalls),mt.push(...A);let H=this.buildErrorSignature(A);if(H){if(H===we?Re++:(Re=1,we=H),Re>=hT){this.logger.warn({iteration:le,consecutiveErrors:Re,errorSignature:H},"Tool loop aborted: same error repeated consecutively"),z=await this.abortToolLoop(ae,z,u.id,q,`Der gleiche Tool-Fehler ist ${Re}x hintereinander aufgetreten: "${we.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else Re=0,we="";ae.push({role:"user",content:A}),t?.("Thinking...")}let Ee=z.content;if(!Ee)for(let K=ae.length-1;K>=0;K--){let V=ae[K];if(V.role==="assistant"&&Array.isArray(V.content)){let de=V.content.find(A=>A.type==="text");if(de&&"text"in de&&de.text){Ee=de.text;break}}}if(Ee||(Ee="(no response)"),Xt.length>0&&(await this.conversationManager.addMessage(u.id,"assistant","",JSON.stringify(Xt)),await this.conversationManager.addMessage(u.id,"user","",JSON.stringify(mt))),await this.conversationManager.addMessage(u.id,"assistant",Ee),this.activeLearning&&this.activeLearning.onMessageProcessed(i,e.text,Ee),this.conversationSummarizer&&!e.metadata?.skipHistory){let K=f.slice(-8).map(V=>({role:V.role,content:V.content}));this.conversationSummarizer.onMessageProcessed(u.id,f.length+2,e.text,Ee,K)}let Oe=Date.now()-s,At=z.model??pt??"unknown";pt=At;let ot=Ji(At,{inputTokens:Ue,outputTokens:Pe});if(this.logger.info({duration:Oe,model:At,tokens:z.usage,totalTokens:{inputTokens:Ue,outputTokens:Pe},costUsd:Math.round(ot*1e6)/1e6,stopReason:z.stopReason,toolIterations:le},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:Ue,output:Pe,costUsd:ot}),c&&this.usageRepo&&ot>0)try{await this.usageRepo.record(pt??"unknown",Ue,Pe,0,0,ot,c.id)}catch{}return{text:Ee,attachments:It.length>0?It:void 0,usedSkills:ht.size>0?[...ht]:void 0}}catch(r){this.recordMetric(!1,Date.now()-s),this.logger.error({err:r},"Failed to process message");try{let n=e.chatType==="group"?`${e.chatId}:${e.userId}`:e.chatId,i=await this.conversationManager.getOrCreateConversation(e.platform,n,e.userId);await this.conversationManager.addMessage(i.id,"assistant","Sorry, I encountered an error processing your message. Please try again.")}catch{}throw r}}async abortToolLoop(e,t,s,r,n,i=!1,a){if(!i){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 o=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:o}),i||await this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),await this.conversationManager.addMessage(s,"user","",JSON.stringify(o));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:a})}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(i=>i.type==="tool_result"&&i.is_error)){let i=this.toolPairSignature(r,n),a=1,o=s+2;for(;o+1<e.length;){let c=e[o],d=e[o+1];if(c.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(c,d)===i)a++,o+=2;else break}if(a>1){t.push(r),t.push(n),t.push({role:"user",content:`[System: The above tool error repeated ${a} times with identical input. The loop was aborted.]`}),s=o;continue}}}t.push(r),s++}return t}toolPairSignature(e,t){let s=Array.isArray(e.content)?e.content.filter(n=>n.type==="tool_use").map(n=>`${n.name}:${JSON.stringify(n.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(n=>n.type==="tool_result").map(n=>n.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],n=p((u,h)=>{let m=h.content;if(h.attachments&&h.attachments.length>0){r.push(...h.attachments);let f=h.attachments.map(g=>g.fileName).join(", ");m+=`
2059
+ `+j);let oe=this.promptBuilder.buildMessages(f),me=this.collapseRepeatedToolErrors(oe),O=ic(me),ue=me.reduce((K,Y)=>K+as(Y),0)-O.reduce((K,Y)=>K+as(Y),0);ue>100&&this.logger.debug(`Tool result trimming saved ~${ue} tokens`);let he=await this.buildUserContent(e,t);O.push({role:"user",content:he});let ye=W?tt(JSON.stringify(W)):0,$e=1,pe=this.trimToContextWindow(q,O,ye,$e),z,ce=0,Ge=Date.now(),Te="",Re=0,Me=0,Ue=0,pt,It=[],ht=new Set,Xt=[],mt=[];for(t?.("Thinking...");;){ce>0&&this.compressToolLoop(pe,q,ye);try{z=await this.llm.complete({messages:pe,system:q,tools:W&&W.length>0?W:void 0,tier:e.metadata?.tier}),Me+=z.usage?.inputTokens??0,Ue+=z.usage?.outputTokens??0}catch(F){if((F instanceof Error?F.message:String(F)).includes("prompt is too long")&&$e>.3){$e*=.5,this.logger.warn({budgetMultiplier:$e},"Prompt too long, retrimming with reduced budget"),pe=this.trimToContextWindow(q,O,ye,$e);continue}throw F}if(z.stopReason==="max_tokens"&&z.toolCalls?.length&&(this.logger.warn({toolCallCount:z.toolCalls.length},"Discarding truncated tool calls due to max_tokens"),z={...z,toolCalls:[]}),!z.toolCalls||z.toolCalls.length===0){if(z.stopReason==="max_tokens"){let F=0,V=z.content??"";for(;z.stopReason==="max_tokens"&&F<fT;){F++,this.logger.info({continuationRounds:F,textLength:V.length},"Output truncated, requesting continuation"),V?(pe.push({role:"assistant",content:V}),pe.push({role:"user",content:"Fahre exakt dort fort wo du aufgeh\xF6rt hast. Keine Wiederholung, nur der Rest."})):pe.push({role:"user",content:"Deine Antwort war zu lang und wurde abgeschnitten. Bitte antworte k\xFCrzer und kompakter. Fasse zusammen statt alles aufzulisten."});try{z=await this.llm.complete({messages:pe,system:q,tools:W&&W.length>0?W:void 0,tier:e.metadata?.tier}),Me+=z.usage?.inputTokens??0,Ue+=z.usage?.outputTokens??0,z.content&&(V+=z.content)}catch{break}}z={...z,content:V,stopReason:"end_turn"}}break}let K=Date.now()-Ge;if(K>=pT){let F=Math.round(K/6e4);this.logger.warn({iteration:ce,elapsedMin:F,pendingToolCalls:z.toolCalls.length},"Tool loop timeout reached"),z=await this.abortToolLoop(pe,z,u.id,q,`Das Zeitlimit von ${F} Minuten f\xFCr Tool-Aufrufe wurde erreicht.`,!1,e.metadata?.tier);break}if(ce>=Jh){this.logger.warn({iteration:ce,pendingToolCalls:z.toolCalls.length},"Tool loop iteration cap reached"),z=await this.abortToolLoop(pe,z,u.id,q,`Das Iterationslimit von ${Jh} Tool-Aufrufen wurde erreicht.`,!1,e.metadata?.tier);break}ce++,this.logger.info({iteration:ce,toolCalls:z.toolCalls.length},"Processing tool calls");let Y=[];z.content&&Y.push({type:"text",text:z.content});for(let F of z.toolCalls)Y.push({type:"tool_use",id:F.id,name:F.name,input:F.input});pe.push({role:"assistant",content:Y});let le=await this.executeToolCallsParallel(z.toolCalls,{...o,conversationId:u.id,timezone:I},t),A=le.blocks;le.attachments.length>0&&It.push(...le.attachments);for(let F of z.toolCalls)ht.add(F.name);Xt.push(...z.toolCalls),mt.push(...A);let H=this.buildErrorSignature(A);if(H){if(H===Te?Re++:(Re=1,Te=H),Re>=hT){this.logger.warn({iteration:ce,consecutiveErrors:Re,errorSignature:H},"Tool loop aborted: same error repeated consecutively"),z=await this.abortToolLoop(pe,z,u.id,q,`Der gleiche Tool-Fehler ist ${Re}x hintereinander aufgetreten: "${Te.slice(0,200)}". Erkl\xE4re dem User kurz was nicht funktioniert hat und schlage eine Alternative vor.`,!0,e.metadata?.tier);break}}else Re=0,Te="";pe.push({role:"user",content:A}),t?.("Thinking...")}let we=z.content;if(!we)for(let K=pe.length-1;K>=0;K--){let Y=pe[K];if(Y.role==="assistant"&&Array.isArray(Y.content)){let le=Y.content.find(A=>A.type==="text");if(le&&"text"in le&&le.text){we=le.text;break}}}if(we||(we="(no response)"),Xt.length>0&&(await this.conversationManager.addMessage(u.id,"assistant","",JSON.stringify(Xt)),await this.conversationManager.addMessage(u.id,"user","",JSON.stringify(mt))),await this.conversationManager.addMessage(u.id,"assistant",we),this.activeLearning&&this.activeLearning.onMessageProcessed(i,e.text,we),this.conversationSummarizer&&!e.metadata?.skipHistory){let K=f.slice(-8).map(Y=>({role:Y.role,content:Y.content}));this.conversationSummarizer.onMessageProcessed(u.id,f.length+2,e.text,we,K)}let Ce=Date.now()-s,At=z.model??pt??"unknown";pt=At;let ot=Ji(At,{inputTokens:Me,outputTokens:Ue});if(this.logger.info({duration:Ce,model:At,tokens:z.usage,totalTokens:{inputTokens:Me,outputTokens:Ue},costUsd:Math.round(ot*1e6)/1e6,stopReason:z.stopReason,toolIterations:ce},"Message processed"),this.recordMetric(!0,Date.now()-s,{input:Me,output:Ue,costUsd:ot}),c&&this.usageRepo&&ot>0)try{await this.usageRepo.record(pt??"unknown",Me,Ue,0,0,ot,c.id)}catch{}return{text:we,attachments:It.length>0?It:void 0,usedSkills:ht.size>0?[...ht]:void 0}}catch(r){this.recordMetric(!1,Date.now()-s),this.logger.error({err:r},"Failed to process message");try{let n=e.chatType==="group"?`${e.chatId}:${e.userId}`:e.chatId,i=await this.conversationManager.getOrCreateConversation(e.platform,n,e.userId);await this.conversationManager.addMessage(i.id,"assistant","Sorry, I encountered an error processing your message. Please try again.")}catch{}throw r}}async abortToolLoop(e,t,s,r,n,i=!1,a){if(!i){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 o=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:o}),i||await this.conversationManager.addMessage(s,"assistant",t.content??"",JSON.stringify(t.toolCalls)),await this.conversationManager.addMessage(s,"user","",JSON.stringify(o));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:a})}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(i=>i.type==="tool_result"&&i.is_error)){let i=this.toolPairSignature(r,n),a=1,o=s+2;for(;o+1<e.length;){let c=e[o],d=e[o+1];if(c.role==="assistant"&&d?.role==="user"&&this.toolPairSignature(c,d)===i)a++,o+=2;else break}if(a>1){t.push(r),t.push(n),t.push({role:"user",content:`[System: The above tool error repeated ${a} times with identical input. The loop was aborted.]`}),s=o;continue}}}t.push(r),s++}return t}toolPairSignature(e,t){let s=Array.isArray(e.content)?e.content.filter(n=>n.type==="tool_use").map(n=>`${n.name}:${JSON.stringify(n.input)}`).join(","):"",r=Array.isArray(t.content)?t.content.filter(n=>n.type==="tool_result").map(n=>n.content).join(","):"";return`${s}|${r}`}async executeToolCallsParallel(e,t,s){let r=[],n=p((u,h)=>{let m=h.content;if(h.attachments&&h.attachments.length>0){r.push(...h.attachments);let f=h.attachments.map(g=>g.fileName).join(", ");m+=`
2060
2060
 
2061
- [${h.attachments.length} Datei(en) werden dem User gesendet: ${f}]`}return m=gT(m,mT),{type:"tool_result",tool_use_id:u.id,content:m,is_error:h.isError}},"buildBlock");if(e.length===1){let u=e[0],h=this.getToolLabel(u.name,u.input);s?.(h);let m=await this.executeToolCall(u,t,s);return{blocks:[n(u,m)],attachments:r}}let i=3;s?.(`Running ${e.length} tools...`);let a=new Map;for(let u=0;u<e.length;u++){let h=e[u].name,m=a.get(h);m||(m=[],a.set(h,m)),m.push(u)}let o=[...a.values()].some(u=>u.length>i),c;if(o){c=new Map;let u=[...a.entries()].map(async([h,m])=>{for(let f=0;f<m.length;f+=i){let g=m.slice(f,f+i),y=await Promise.allSettled(g.map(k=>this.executeToolCall(e[k],t,s)));for(let k=0;k<g.length;k++)c.set(g[k],y[k])}});await Promise.all(u)}else{let u=await Promise.allSettled(e.map(h=>this.executeToolCall(h,t,s)));c=new Map(u.map((h,m)=>[m,h]))}return{blocks:e.map((u,h)=>{let m=c.get(h);return m.status==="fulfilled"?n(u,m.value):{type:"tool_result",tool_use_id:u.id,content:`Tool execution failed: ${m.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=await this.skillHealthTracker.isDisabled(e.name);if(n){let i=n.disabledUntil?new Date(n.disabledUntil).toISOString():"unknown";return this.logger.warn({tool:e.name,disabledUntil:i,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 ${i}.`,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,i;if(e.name==="delegate"){let{ActivityTracker:c}=await Promise.resolve().then(()=>(te(),re));n=new c(s),i=`agent-${++this.agentIdCounter}`,this.activeAgents.set(i,{chatId:t.chatId,task:String(e.input.task??"").slice(0,200),tracker:n,startedAt:Date.now()})}let a=e.name==="delegate"?{...t,tracker:n,onProgress:s}:s?{...t,onProgress:s}:t,o=Date.now();try{let c=await this.skillSandbox.execute(r,e.input,a,void 0,n);this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:c.success?"success":"error",durationMs:Date.now()-o,error:c.error}),this.skillHealthTracker&&(c.success?await this.skillHealthTracker.recordSuccess(e.name):await this.skillHealthTracker.recordFailure(e.name,c.error??"Unknown error"));let d=c.display??(c.success?JSON.stringify(c.data):c.error??"Unknown error");return this.nodeId!=="single"&&uT.has(e.name)&&c.success&&(d=`[${this.nodeId}] ${d}`),{content:d,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()-o,error:d}),this.skillHealthTracker?.recordFailure(e.name,d),c}finally{i&&this.activeAgents.delete(i)}}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 i=n instanceof Error?n.message:String(n);return this.skillHealthTracker?.recordFailure(e.name,i),{content:`Skill execution failed: ${i}`,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(`
2061
+ [${h.attachments.length} Datei(en) werden dem User gesendet: ${f}]`}return m=gT(m,mT),{type:"tool_result",tool_use_id:u.id,content:m,is_error:h.isError}},"buildBlock");if(e.length===1){let u=e[0],h=this.getToolLabel(u.name,u.input);s?.(h);let m=await this.executeToolCall(u,t,s);return{blocks:[n(u,m)],attachments:r}}let i=3;s?.(`Running ${e.length} tools...`);let a=new Map;for(let u=0;u<e.length;u++){let h=e[u].name,m=a.get(h);m||(m=[],a.set(h,m)),m.push(u)}let o=[...a.values()].some(u=>u.length>i),c;if(o){c=new Map;let u=[...a.entries()].map(async([h,m])=>{for(let f=0;f<m.length;f+=i){let g=m.slice(f,f+i),y=await Promise.allSettled(g.map(k=>this.executeToolCall(e[k],t,s)));for(let k=0;k<g.length;k++)c.set(g[k],y[k])}});await Promise.all(u)}else{let u=await Promise.allSettled(e.map(h=>this.executeToolCall(h,t,s)));c=new Map(u.map((h,m)=>[m,h]))}return{blocks:e.map((u,h)=>{let m=c.get(h);return m.status==="fulfilled"?n(u,m.value):{type:"tool_result",tool_use_id:u.id,content:`Tool execution failed: ${m.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=await this.skillHealthTracker.isDisabled(e.name);if(n){let i=n.disabledUntil?new Date(n.disabledUntil).toISOString():"unknown";return this.logger.warn({tool:e.name,disabledUntil:i,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 ${i}.`,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,i;if(e.name==="delegate"){let{ActivityTracker:c}=await Promise.resolve().then(()=>(ee(),re));n=new c(s),i=`agent-${++this.agentIdCounter}`,this.activeAgents.set(i,{chatId:t.chatId,task:String(e.input.task??"").slice(0,200),tracker:n,startedAt:Date.now()})}let a=e.name==="delegate"?{...t,tracker:n,onProgress:s}:s?{...t,onProgress:s}:t,o=Date.now();try{let c=await this.skillSandbox.execute(r,e.input,a,void 0,n);this.activityLogger?.logSkillExec({userId:t.userId,platform:t.platform,chatId:t.chatId,skillName:e.name,outcome:c.success?"success":"error",durationMs:Date.now()-o,error:c.error}),this.skillHealthTracker&&(c.success?await this.skillHealthTracker.recordSuccess(e.name):await this.skillHealthTracker.recordFailure(e.name,c.error??"Unknown error"));let d=c.display??(c.success?JSON.stringify(c.data):c.error??"Unknown error");return this.nodeId!=="single"&&uT.has(e.name)&&c.success&&(d=`[${this.nodeId}] ${d}`),{content:d,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()-o,error:d}),this.skillHealthTracker?.recordFailure(e.name,d),c}finally{i&&this.activeAgents.delete(i)}}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 i=n instanceof Error?n.message:String(n);return this.skillHealthTracker?.recordFailure(e.name,i),{content:`Skill execution failed: ${i}`,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(`
2062
2062
  `)}applyMemoryBudget(e){let t=e.some(i=>i.score!=null&&i.score>0),s=e;t&&(s=e.filter(i=>(i.score??1)>=wT));let r=0,n=[];for(let i of s){let a=tt(`[${i.category}] ${i.key}: ${i.value}`);if(r+a>TT)break;r+=a,n.push(i)}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*Zh);if(tt(t)+s+e.reduce((g,y)=>g+as(y),0)<=n)return;let o=[];for(let g=0;g<e.length-1;g++){let y=e[g],k=e[g+1];y.role==="assistant"&&Array.isArray(y.content)&&y.content.some(b=>b.type==="tool_use")&&k.role==="user"&&Array.isArray(k.content)&&k.content.some(b=>b.type==="tool_result")&&o.push({start:g,end:g+1})}if(o.length<=Qh)return;let c=o.length-Qh,d=o.slice(0,c),u=[];for(let g of d){let y=e[g.start],k=[];if(Array.isArray(y.content))for(let I of y.content)I.type==="tool_use"&&k.push(I.name);let b=e[g.end],S="ok";Array.isArray(b.content)&&b.content.some(L=>L.type==="tool_result"&&L.is_error)&&(S="error"),u.push(`- ${k.join(", ")}: ${S}`)}let h=d[0].start,f=d[d.length-1].end-h+1;e.splice(h,f,{role:"assistant",content:`[Earlier tool interactions compressed (${d.length} pairs):
2063
2063
  ${u.join(`
2064
2064
  `)}
@@ -2078,20 +2078,20 @@ ${u}`}if(this.documentProcessor&&this.isIngestable(a.mimeType))try{let u=await t
2078
2078
 
2079
2079
  `),t}flattenNestedTag(e,t){let s=`<${t}>`,r=`</${t}>`,n=0,i="",a=0;for(;a<e.length;){if(e.slice(a,a+s.length).toLowerCase()===s){n++,n===1&&(i+=s),a+=s.length;continue}if(e.slice(a,a+r.length).toLowerCase()===r){n--,n<=0&&(i+=r,n=0),a+=r.length;continue}i+=e[a],a++}return i}toMarkdown(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<code>([^<]*)<\/code>/gi,"`$1`"),t=t.replace(/<pre>([^<]*)<\/pre>/gi,"```\n$1\n```"),t=t.replace(/<a\s+href="([^"]*)"[^>]*>([^<]*)<\/a>/gi,"[$2]($1)"),t=t.replace(/<[^>]+>/g,""),t}toWhatsApp(e){let t=e;return t=t.replace(/<\/?(?:b|strong)>/gi,"**"),t=t.replace(/<\/?(?:i|em)>/gi,"*"),t=t.replace(/<\/?(?:s|del|strike)>/gi,"~~"),t=t.replace(/<[^>]+>/g,""),t=t.replace(/^#{1,6}\s+(.+)$/gm,"*$1*"),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"*$1*"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"_$1_"),t=t.replace(/~~(.+?)~~/g,"~$1~"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}stripFormatting(e){let t=e;return t=t.replace(/<[^>]+>/g,""),t=t.replace(/```\w*\n?/g,""),t=t.replace(/`([^`]+)`/g,"$1"),t=t.replace(/^#{1,6}\s+/gm,""),t=t.replace(/^[-*_]{3,}\s*$/gm,""),t=t.replace(/\*\*(.+?)\*\*/g,"$1"),t=t.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"$1"),t=t.replace(/~~(.+?)~~/g,"$1"),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 ($2)"),t}escapeHTML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}}});var Gn,gl=w(()=>{"use strict";Gn=class{static{p(this,"EmbeddingService")}llm;embeddingRepo;logger;constructor(e,t,s){this.llm=e,this.embeddingRepo=t,this.logger=s}async embedAndStore(e,t,s,r){if(this.llm.supportsEmbeddings())try{let n=await this.llm.embed(t);if(!n)return;let i=await 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"),i.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=await this.embeddingRepo.findByUser(e);if(n.length===0)return[];let i=n.map(o=>{let c=this.cosineSimilarity(r.embedding,o.embedding);return{...o,score:c}});return i.sort((o,c)=>c.score-o.score),i.slice(0,s).map(o=>({key:o.sourceId,value:o.content,category:o.sourceType,score:o.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 a=0;a<e.length;a++)s+=e[a]*t[a],r+=e[a]*e[a],n+=t[a]*t[a];let i=Math.sqrt(r)*Math.sqrt(n);return i===0?0:s/i}}});import{createHash as _T}from"node:crypto";var Yn,yl=w(()=>{"use strict";Yn=class{static{p(this,"DocumentProcessor")}docRepo;embeddingService;logger;constructor(e,t,s){this.docRepo=e,this.embeddingService=t,this.logger=s}async ingest(e,t,s,r,n){let i=await import("node:fs"),a=n??i.readFileSync(t),o=_T("sha256").update(a).digest("hex"),c=await this.docRepo.findByContentHash(e,o);if(c&&c.chunkCount>0)return this.logger.info({documentId:c.id,filename:s,contentHash:o.slice(0,12)},"Document already ingested (duplicate)"),{documentId:c.id,chunkCount:c.chunkCount,existing:!0};c&&c.chunkCount===0&&(this.logger.info({documentId:c.id,filename:s},"Removing failed previous ingest attempt"),await this.docRepo.deleteDocument(c.id));let d=await this.extractText(t,r,a),u=await this.docRepo.createDocument(e,s,r,a.length,o),h=this.chunkText(d,500,50);for(let m=0;m<h.length;m++){let f;try{f=await this.embeddingService.embedAndStore(e,h[m],"document",`${u.id}:${m}`)}catch(g){this.logger.warn({documentId:u.id,chunkIndex:m,err:g},"Embedding failed for chunk, continuing")}await this.docRepo.addChunk(u.id,m,h[m],f)}return await this.docRepo.updateChunkCount(u.id,h.length),this.logger.info({documentId:u.id,filename:s,chunkCount:h.length},"Document ingested"),{documentId:u.id,chunkCount:h.length}}async extractText(e,t,s){let r=await import("node:fs"),n=s??r.readFileSync(e);if(t==="application/pdf")try{let i=(await import("pdf-parse")).default;return(await i(n)).text}catch(i){throw this.logger.error({err:i},"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({buffer:n})).value}catch(i){throw this.logger.error({err:i},"DOCX parsing failed"),new Error("Failed to parse DOCX")}return n.toString("utf-8")}chunkText(e,t,s){let n=Math.round(t*3.5),i=Math.round(s*3.5),a=[],o=0;for(;o<e.length;){let c=o+n;if(c>=e.length){a.push(e.slice(o).trim());break}let d=Math.max(c-200,o),u=e.slice(d,c+200),h=u.lastIndexOf(`
2080
2080
 
2081
- `);if(h>0)c=d+h;else{let f=u.lastIndexOf(". ");f>0&&(c=d+f+1)}let m=e.slice(o,c).trim();m&&a.push(m),o=c-i}return a.filter(c=>c.length>0)}}});var Vn,Tl=w(()=>{"use strict";Ut();Vn=class{static{p(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;skillHealthTracker;pollTimer;running=0;polling=!1;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;persistentRunner;constructor(e,t,s,r,n,i,a,o){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=i,this.activityLogger=a,this.skillHealthTracker=o}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=await 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){await this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}if(this.skillHealthTracker?.isDisabled(e.skillName)){await 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"),await this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:n}=await De(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),i,a=new Promise((u,h)=>{i=setTimeout(()=>h(new Error("Background task timed out")),this.taskTimeoutMs)}),o=await Promise.race([this.skillSandbox.execute(s,r,n),a]).finally(()=>{i&&clearTimeout(i)}),c=JSON.stringify(o.data??o.display??o.error);await this.taskRepo.updateStatus(e.id,o.success?"completed":"failed",c,o.error),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:o.success?"success":"error",durationMs:Date.now()-t,error:o.error}),this.skillHealthTracker&&(o.success?this.skillHealthTracker.recordSuccess(e.skillName):this.skillHealthTracker.recordFailure(e.skillName,o.error??"Unknown error"));let d=this.adapters.get(e.platform);if(d){let u=o.success?`\u2705 Background task completed: ${e.description}
2081
+ `);if(h>0)c=d+h;else{let f=u.lastIndexOf(". ");f>0&&(c=d+f+1)}let m=e.slice(o,c).trim();m&&a.push(m),o=c-i}return a.filter(c=>c.length>0)}}});var Vn,Tl=w(()=>{"use strict";Ut();Vn=class{static{p(this,"BackgroundTaskRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;skillHealthTracker;pollTimer;running=0;polling=!1;maxConcurrent=3;pollIntervalMs=5e3;taskTimeoutMs=5*6e4;persistentRunner;constructor(e,t,s,r,n,i,a,o){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=i,this.activityLogger=a,this.skillHealthTracker=o}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=await 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){await this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}if(this.skillHealthTracker?.isDisabled(e.skillName)){await 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"),await this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:n}=await Oe(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),i,a=new Promise((u,h)=>{i=setTimeout(()=>h(new Error("Background task timed out")),this.taskTimeoutMs)}),o=await Promise.race([this.skillSandbox.execute(s,r,n),a]).finally(()=>{i&&clearTimeout(i)}),c=JSON.stringify(o.data??o.display??o.error);await this.taskRepo.updateStatus(e.id,o.success?"completed":"failed",c,o.error),this.activityLogger?.logBackgroundTask({taskId:e.id,skillName:e.skillName,platform:e.platform,chatId:e.chatId,userId:e.userId,outcome:o.success?"success":"error",durationMs:Date.now()-t,error:o.error}),this.skillHealthTracker&&(o.success?this.skillHealthTracker.recordSuccess(e.skillName):this.skillHealthTracker.recordFailure(e.skillName,o.error??"Unknown error"));let d=this.adapters.get(e.platform);if(d){let u=o.success?`\u2705 Background task completed: ${e.description}
2082
2082
 
2083
2083
  Result: ${o.display??JSON.stringify(o.data)}`:`\u274C Background task failed: ${e.description}
2084
2084
 
2085
2085
  Error: ${o.error}`;await d.sendMessage(e.chatId,u)}}catch(s){let r=s instanceof Error?s.message:String(s);await 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}
2086
2086
 
2087
- Error: ${r}`)}}}});var kT,Jn,wl=w(()=>{"use strict";Ut();kT=5,Jn=class{static{p(this,"PersistentAgentRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;activeAbortControllers=new Map;constructor(e,t,s,r,n,i,a){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=i,this.activityLogger=a}async recoverInterrupted(){try{let e=await 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")})):(await 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(!await 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){await this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}let n;try{n=JSON.parse(e.skillInput)}catch{await this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:i}=await De(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),a=Date.now()-new Date(e.createdAt).getTime();if(a>t){await 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 o;if(e.agentState)try{let y=JSON.parse(e.agentState);y.conversationHistory?.length>0&&(o={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=o?.currentIteration??0,d={...i,resumeState:o,abortSignal:s.signal,onIteration:p(async y=>{if(y.iteration-c>=kT||s.signal.aborted){c=y.iteration;let k={conversationHistory:y.messages,partialResults:[],currentIteration:y.iteration,totalIterations:y.maxIterations,startedAt:e.startedAt??e.createdAt,lastActivityAt:new Date().toISOString(),dataStore:y.dataStore};try{await this.taskRepo.checkpoint(e.id,JSON.stringify(k)),this.logLifecycle(e,"checkpoint"),this.logger.debug({taskId:e.id,iteration:y.iteration},"Persistent task checkpointed")}catch(b){this.logger.warn({err:b,taskId:e.id},"Failed to write checkpoint, retrying once");try{await this.taskRepo.checkpoint(e.id,JSON.stringify(k)),this.logger.info({taskId:e.id},"Checkpoint retry succeeded")}catch(S){this.logger.error({err:S,taskId:e.id},"Checkpoint retry failed, aborting task"),await this.taskRepo.updateStatus(e.id,"failed",void 0,"Checkpoint write failed after retry"),s.abort()}}}},"onIteration")},u=t-a,h,m=new Promise((y,k)=>{h=setTimeout(()=>k(new Error(`Max duration of ${e.maxDurationHours}h exceeded`)),u)}),f=await Promise.race([this.skillSandbox.execute(r,n,d),m]).finally(()=>{h&&clearTimeout(h)});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);await this.taskRepo.updateStatus(e.id,f.success?"completed":"failed",g,f.error),this.notifyUser(e,f.success?`\u2705 Persistenter Task abgeschlossen: ${e.description}
2087
+ Error: ${r}`)}}}});var kT,Jn,wl=w(()=>{"use strict";Ut();kT=5,Jn=class{static{p(this,"PersistentAgentRunner")}skillRegistry;skillSandbox;taskRepo;adapters;users;logger;activityLogger;activeAbortControllers=new Map;constructor(e,t,s,r,n,i,a){this.skillRegistry=e,this.skillSandbox=t,this.taskRepo=s,this.adapters=r,this.users=n,this.logger=i,this.activityLogger=a}async recoverInterrupted(){try{let e=await 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")})):(await 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(!await 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){await this.taskRepo.updateStatus(e.id,"failed",void 0,`Unknown skill: ${e.skillName}`);return}let n;try{n=JSON.parse(e.skillInput)}catch{await this.taskRepo.updateStatus(e.id,"failed",void 0,"Malformed skill input JSON");return}let{context:i}=await Oe(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),a=Date.now()-new Date(e.createdAt).getTime();if(a>t){await 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 o;if(e.agentState)try{let y=JSON.parse(e.agentState);y.conversationHistory?.length>0&&(o={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=o?.currentIteration??0,d={...i,resumeState:o,abortSignal:s.signal,onIteration:p(async y=>{if(y.iteration-c>=kT||s.signal.aborted){c=y.iteration;let k={conversationHistory:y.messages,partialResults:[],currentIteration:y.iteration,totalIterations:y.maxIterations,startedAt:e.startedAt??e.createdAt,lastActivityAt:new Date().toISOString(),dataStore:y.dataStore};try{await this.taskRepo.checkpoint(e.id,JSON.stringify(k)),this.logLifecycle(e,"checkpoint"),this.logger.debug({taskId:e.id,iteration:y.iteration},"Persistent task checkpointed")}catch(b){this.logger.warn({err:b,taskId:e.id},"Failed to write checkpoint, retrying once");try{await this.taskRepo.checkpoint(e.id,JSON.stringify(k)),this.logger.info({taskId:e.id},"Checkpoint retry succeeded")}catch(S){this.logger.error({err:S,taskId:e.id},"Checkpoint retry failed, aborting task"),await this.taskRepo.updateStatus(e.id,"failed",void 0,"Checkpoint write failed after retry"),s.abort()}}}},"onIteration")},u=t-a,h,m=new Promise((y,k)=>{h=setTimeout(()=>k(new Error(`Max duration of ${e.maxDurationHours}h exceeded`)),u)}),f=await Promise.race([this.skillSandbox.execute(r,n,d),m]).finally(()=>{h&&clearTimeout(h)});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);await this.taskRepo.updateStatus(e.id,f.success?"completed":"failed",g,f.error),this.notifyUser(e,f.success?`\u2705 Persistenter Task abgeschlossen: ${e.description}
2088
2088
 
2089
2089
  Ergebnis: ${f.display??JSON.stringify(f.data)}`:`\u274C Persistenter Task fehlgeschlagen: ${e.description}
2090
2090
 
2091
2091
  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}await 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}
2092
2092
 
2093
- Fehler: ${n}`)}}async resume(e){await this.taskRepo.markResuming(e.id),this.logLifecycle(e,"resume");let t=await 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){await 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)),await 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 ST from"node:crypto";var Zn,El=w(()=>{"use strict";Ko();Ut();Zn=class{static{p(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;activityLogger;nodeId;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,n,i,a,o,c,d,u,h="single"){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=n,this.users=i,this.logger=a,this.pipeline=o,this.formatter=c,this.conversationManager=d,this.activityLogger=u,this.nodeId=h}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=await this.actionRepo.claimDue(this.nodeId);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 m=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}=await De(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),y=await this.skillSandbox.execute(m,f,g);if(y.success){let k=y.display??JSON.stringify(y.data);if(this.formatter){let b=this.formatter.format(k,e.platform);r=b.text,n=b.parseMode}else r=k}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 m=`scheduled-${e.id}`,f=await this.users.findById(e.userId),g=f?.platformUserId??e.userId,y={id:`scheduled-${ST.randomUUID()}`,platform:e.platform,chatId:m,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}},k=await this.pipeline.process(y),b=this.formatter?this.formatter.format(k.text,e.platform):{text:k.text,parseMode:"text"};r=b.text,n=b.parseMode;let S=this.adapters.get(e.platform);if(S&&k.attachments)for(let I of k.attachments)try{let L=I.mimeType.startsWith("image/"),D=I.mimeType==="audio/ogg"||I.mimeType==="audio/opus";L?await S.sendPhoto(e.chatId,I.data,I.fileName):D?await S.sendVoice(e.chatId,I.data):await S.sendFile(e.chatId,I.data,I.fileName)}catch(L){this.logger.warn({err:L,fileName:I.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(m){let f=m instanceof Error?m.message:String(m);this.logger.error({actionId:e.id,err:m},"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(m){let f=m instanceof Error?m.message:String(m);this.logger.error({actionId:e.id,err:m},"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 i=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:i?"error":"success",durationMs:Date.now()-s,error:i?r:void 0});let a=r.trim(),o=(e.promptTemplate??"").toLowerCase(),c=/nichts|silent|no\s*output|don't\s*respond|do\s*not\s*respond/i.test(o),d=/offline|down|fehler|error|warn|critical|alert|fail|nicht\s+(erreichbar|verf[uü]gbar|gefunden|online)|ausgefallen|stopped|unreachable|unavailable|⚠|❌|🚨|🔴/i.test(a)&&!/keine\s+(probleme|fehler|auff[aä]lligkeiten)/i.test(a);if(!a||a.length<3||c&&!d)this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let m=this.adapters.get(e.platform);if(m)try{if(await m.sendMessage(e.chatId,r,{parseMode:n!=="text"?n:void 0}),e.promptTemplate&&this.conversationManager){let f=await this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),g=`[Automated Scheduled Alert: ${e.name}]
2094
- ${r}`;await 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 m=`scheduled-${e.id}`,f=await this.conversationManager.getOrCreateConversation(e.platform,m,e.userId);await this.conversationManager.pruneMessages(f.id,20)}catch{}let h=this.calculateNextRun(e);h?await this.actionRepo.updateLastRun(e.id,t,h):(await this.actionRepo.updateLastRun(e.id,t,null),await 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 Wi(e.scheduleValue,t)?.toISOString()??null;default:return null}}}});function Pt(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 Da(l,e,t,s){let r=bT(l);if(s===null)return{triggered:!1,displayValue:r};switch(e){case"lt":case"gt":case"lte":case"gte":{let n=qe(l),i=qe(t);if(n===null||i===null)return{triggered:!1,displayValue:r};if(!(e==="lt"?n<i:e==="gt"?n>i:e==="lte"?n<=i:n>=i))return{triggered:!1,displayValue:r};let o=qe(s);return o!==null&&(e==="lt"?o<i:e==="gt"?o>i:e==="lte"?o<=i:o>=i)?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"eq":{let n=qe(l),i=qe(t);if(n!==null&&i!==null){if(n!==i)return{triggered:!1,displayValue:r};let c=qe(s);return c!==null&&c===i?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let a=String(l),o=String(t);return a!==o?{triggered:!1,displayValue:r}:String(s)===o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"neq":{let n=qe(l),i=qe(t);if(n!==null&&i!==null){if(n===i)return{triggered:!1,displayValue:r};let c=qe(s);return c!==null&&c!==i?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let a=String(l),o=String(t);return a===o?{triggered:!1,displayValue:r}:String(s)!==o?{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=qe(l),i=qe(s);return n===null||i===null?{triggered:!1,displayValue:r}:{triggered:n>i,displayValue:r}}case"decreased":{let n=qe(l),i=qe(s);return n===null||i===null?{triggered:!1,displayValue:r}:{triggered:n<i,displayValue:r}}default:return{triggered:!1,displayValue:r}}}function _l(l,e,t){let s={},r={},n=[];for(let a of e.conditions){let o=Pt(l,a.field),c=t?.[a.field]??null,{triggered:d,displayValue:u}=Da(o,a.operator,a.value,c);n.push(d),s[a.field]=u,r[a.field]=o}return{triggered:e.logic==="and"?n.every(Boolean):n.some(Boolean),displayValues:s,newLastValues:r}}function qe(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}function bT(l){return l==null?"null":typeof l=="object"?JSON.stringify(l):String(l)}var Qn=w(()=>{"use strict";p(Pt,"extractField");p(Da,"evaluateCondition");p(_l,"evaluateCompositeCondition");p(qe,"toNumber");p(bT,"formatValue")});function ei(l,e){return l.replace(/\{\{([^}]+)\}\}/g,(t,s)=>{let r=Pt(e,s.trim());return r==null?"":typeof r=="object"?JSON.stringify(r):String(r)})}function gs(l,e){let t={};for(let[s,r]of Object.entries(l))typeof r=="string"?t[s]=ei(r,e):r!==null&&typeof r=="object"&&!Array.isArray(r)?t[s]=gs(r,e):Array.isArray(r)?t[s]=r.map(n=>typeof n=="string"?ei(n,e):n!==null&&typeof n=="object"&&!Array.isArray(n)?gs(n,e):n):t[s]=r;return t}var Ma=w(()=>{"use strict";Qn();p(ei,"resolveTemplates");p(gs,"resolveTemplatesInObject")});var vT,IT,Ua,em=w(()=>{"use strict";Qn();Ma();Ut();vT=5,IT={lt:"<",gt:">",lte:"<=",gte:">=",eq:"=",neq:"!=",contains:"contains",not_contains:"not contains",changed:"changed",increased:"increased",decreased:"decreased"},Ua=class{static{p(this,"WatchEngine")}watchRepo;skillRegistry;skillSandbox;adapters;users;logger;confirmationQueue;activityLogger;skillHealthTracker;llmProvider;nodeId;timer=null;tickIntervalMs=6e4;constructor(e,t,s,r,n,i,a,o,c,d,u="single"){this.watchRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.users=n,this.logger=i,this.confirmationQueue=a,this.activityLogger=o,this.skillHealthTracker=c,this.llmProvider=d,this.nodeId=u}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=await this.watchRepo.getById(e);if(!t)throw new Error(`Watch ${e} not found`);if(!t.enabled)throw new Error(`Watch ${e} is disabled`);if(!await this.watchRepo.claimSingle(e,this.nodeId)){this.logger.debug({watchId:e},"Watch claim held by another node, skipping webhook trigger");return}this.logger.info({watchId:e,name:t.name},"Watch triggered via webhook"),await this.checkWatch(t)}async tick(){try{let e=await this.watchRepo.claimDue(this.nodeId);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"),await 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"),await this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}let{context:n}=await De(this.users,{platformUserId:e.chatId,platform:e.platform,chatId:e.chatId}),i=await this.skillSandbox.execute(r,e.skillParams,n);if(!i.success){this.logger.warn({watchId:e.id,error:i.error},"Watch skill execution failed"),this.skillHealthTracker?.recordFailure(e.skillName,i.error??"Watch poll failed"),await this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}this.skillHealthTracker?.recordSuccess(e.skillName);let a,o,c;if(e.compositeCondition){let d=null;if(e.lastValue!==null)try{let h=JSON.parse(e.lastValue);d=h!==null&&typeof h=="object"&&!Array.isArray(h)?h:null}catch{}let u=_l(i.data,e.compositeCondition,d);a=u.triggered,c=JSON.stringify(u.newLastValues),o=Object.entries(u.displayValues).map(([h,m])=>`${h}=${m}`).join(", ")}else{let d=Pt(i.data,e.condition.field),u=null;if(e.lastValue!==null)try{u=JSON.parse(e.lastValue)}catch{}let h=Da(d,e.condition.operator,e.condition.value,u);a=h.triggered,o=h.displayValue,c=JSON.stringify(d)}if(a&&this.isCooldownExpired(e)){let d=e.actionOnTrigger??"alert",u={result:i.data,currentValue:o,watchName:e.name},h=e.actionSkillParams?gs(e.actionSkillParams,u):{},m=e.messageTemplate?ei(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:h}),d==="alert_and_action"){let g=await this.buildAlertText(e,o,i.data,m);g+=`
2093
+ Fehler: ${n}`)}}async resume(e){await this.taskRepo.markResuming(e.id),this.logLifecycle(e,"resume");let t=await 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){await 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)),await 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 ST from"node:crypto";var Zn,El=w(()=>{"use strict";Ko();Ut();Zn=class{static{p(this,"ProactiveScheduler")}actionRepo;skillRegistry;skillSandbox;llm;adapters;users;logger;pipeline;formatter;conversationManager;activityLogger;nodeId;tickTimer;tickIntervalMs=6e4;constructor(e,t,s,r,n,i,a,o,c,d,u,h="single"){this.actionRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.llm=r,this.adapters=n,this.users=i,this.logger=a,this.pipeline=o,this.formatter=c,this.conversationManager=d,this.activityLogger=u,this.nodeId=h}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=await this.actionRepo.claimDue(this.nodeId);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 m=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}=await Oe(this.users,{userId:e.userId,platform:e.platform,chatId:e.chatId,chatType:"dm"}),y=await this.skillSandbox.execute(m,f,g);if(y.success){let k=y.display??JSON.stringify(y.data);if(this.formatter){let b=this.formatter.format(k,e.platform);r=b.text,n=b.parseMode}else r=k}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 m=`scheduled-${e.id}`,f=await this.users.findById(e.userId),g=f?.platformUserId??e.userId,y={id:`scheduled-${ST.randomUUID()}`,platform:e.platform,chatId:m,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}},k=await this.pipeline.process(y),b=this.formatter?this.formatter.format(k.text,e.platform):{text:k.text,parseMode:"text"};r=b.text,n=b.parseMode;let S=this.adapters.get(e.platform);if(S&&k.attachments)for(let I of k.attachments)try{let L=I.mimeType.startsWith("image/"),D=I.mimeType==="audio/ogg"||I.mimeType==="audio/opus";L?await S.sendPhoto(e.chatId,I.data,I.fileName):D?await S.sendVoice(e.chatId,I.data):await S.sendFile(e.chatId,I.data,I.fileName)}catch(L){this.logger.warn({err:L,fileName:I.fileName,actionId:e.id},"Failed to send scheduled action attachment")}}catch(m){let f=m instanceof Error?m.message:String(m);this.logger.error({actionId:e.id,err:m},"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(m){let f=m instanceof Error?m.message:String(m);this.logger.error({actionId:e.id,err:m},"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 i=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:i?"error":"success",durationMs:Date.now()-s,error:i?r:void 0});let a=r.trim(),o=(e.promptTemplate??"").toLowerCase(),c=/nichts|silent|no\s*output|don't\s*respond|do\s*not\s*respond/i.test(o),d=/offline|down|fehler|error|warn|critical|alert|fail|nicht\s+(erreichbar|verf[uü]gbar|gefunden|online)|ausgefallen|stopped|unreachable|unavailable|⚠|❌|🚨|🔴/i.test(a)&&!/keine\s+(probleme|fehler|auff[aä]lligkeiten)/i.test(a);if(!a||a.length<3||c&&!d)this.logger.info({actionId:e.id,name:e.name},"Scheduled action produced no actionable output \u2014 skipping notification");else{let m=this.adapters.get(e.platform);if(m)try{if(await m.sendMessage(e.chatId,r,{parseMode:n!=="text"?n:void 0}),e.promptTemplate&&this.conversationManager){let f=await this.conversationManager.getOrCreateConversation(e.platform,e.chatId,e.userId),g=`[Automated Scheduled Alert: ${e.name}]
2094
+ ${r}`;await 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 m=`scheduled-${e.id}`,f=await this.conversationManager.getOrCreateConversation(e.platform,m,e.userId);await this.conversationManager.pruneMessages(f.id,20)}catch{}let h=this.calculateNextRun(e);h?await this.actionRepo.updateLastRun(e.id,t,h):(await this.actionRepo.updateLastRun(e.id,t,null),await 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 Wi(e.scheduleValue,t)?.toISOString()??null;default:return null}}}});function Pt(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 Da(l,e,t,s){let r=bT(l);if(s===null)return{triggered:!1,displayValue:r};switch(e){case"lt":case"gt":case"lte":case"gte":{let n=We(l),i=We(t);if(n===null||i===null)return{triggered:!1,displayValue:r};if(!(e==="lt"?n<i:e==="gt"?n>i:e==="lte"?n<=i:n>=i))return{triggered:!1,displayValue:r};let o=We(s);return o!==null&&(e==="lt"?o<i:e==="gt"?o>i:e==="lte"?o<=i:o>=i)?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"eq":{let n=We(l),i=We(t);if(n!==null&&i!==null){if(n!==i)return{triggered:!1,displayValue:r};let c=We(s);return c!==null&&c===i?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let a=String(l),o=String(t);return a!==o?{triggered:!1,displayValue:r}:String(s)===o?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}case"neq":{let n=We(l),i=We(t);if(n!==null&&i!==null){if(n===i)return{triggered:!1,displayValue:r};let c=We(s);return c!==null&&c!==i?{triggered:!1,displayValue:r}:{triggered:!0,displayValue:r}}let a=String(l),o=String(t);return a===o?{triggered:!1,displayValue:r}:String(s)!==o?{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=We(l),i=We(s);return n===null||i===null?{triggered:!1,displayValue:r}:{triggered:n>i,displayValue:r}}case"decreased":{let n=We(l),i=We(s);return n===null||i===null?{triggered:!1,displayValue:r}:{triggered:n<i,displayValue:r}}default:return{triggered:!1,displayValue:r}}}function _l(l,e,t){let s={},r={},n=[];for(let a of e.conditions){let o=Pt(l,a.field),c=t?.[a.field]??null,{triggered:d,displayValue:u}=Da(o,a.operator,a.value,c);n.push(d),s[a.field]=u,r[a.field]=o}return{triggered:e.logic==="and"?n.every(Boolean):n.some(Boolean),displayValues:s,newLastValues:r}}function We(l){if(typeof l=="number")return isFinite(l)?l:null;let e=parseFloat(String(l));return isNaN(e)||!isFinite(e)?null:e}function bT(l){return l==null?"null":typeof l=="object"?JSON.stringify(l):String(l)}var Qn=w(()=>{"use strict";p(Pt,"extractField");p(Da,"evaluateCondition");p(_l,"evaluateCompositeCondition");p(We,"toNumber");p(bT,"formatValue")});function ei(l,e){return l.replace(/\{\{([^}]+)\}\}/g,(t,s)=>{let r=Pt(e,s.trim());return r==null?"":typeof r=="object"?JSON.stringify(r):String(r)})}function gs(l,e){let t={};for(let[s,r]of Object.entries(l))typeof r=="string"?t[s]=ei(r,e):r!==null&&typeof r=="object"&&!Array.isArray(r)?t[s]=gs(r,e):Array.isArray(r)?t[s]=r.map(n=>typeof n=="string"?ei(n,e):n!==null&&typeof n=="object"&&!Array.isArray(n)?gs(n,e):n):t[s]=r;return t}var Ma=w(()=>{"use strict";Qn();p(ei,"resolveTemplates");p(gs,"resolveTemplatesInObject")});var vT,IT,Ua,em=w(()=>{"use strict";Qn();Ma();Ut();vT=5,IT={lt:"<",gt:">",lte:"<=",gte:">=",eq:"=",neq:"!=",contains:"contains",not_contains:"not contains",changed:"changed",increased:"increased",decreased:"decreased"},Ua=class{static{p(this,"WatchEngine")}watchRepo;skillRegistry;skillSandbox;adapters;users;logger;confirmationQueue;activityLogger;skillHealthTracker;llmProvider;nodeId;timer=null;tickIntervalMs=6e4;constructor(e,t,s,r,n,i,a,o,c,d,u="single"){this.watchRepo=e,this.skillRegistry=t,this.skillSandbox=s,this.adapters=r,this.users=n,this.logger=i,this.confirmationQueue=a,this.activityLogger=o,this.skillHealthTracker=c,this.llmProvider=d,this.nodeId=u}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=await this.watchRepo.getById(e);if(!t)throw new Error(`Watch ${e} not found`);if(!t.enabled)throw new Error(`Watch ${e} is disabled`);if(!await this.watchRepo.claimSingle(e,this.nodeId)){this.logger.debug({watchId:e},"Watch claim held by another node, skipping webhook trigger");return}this.logger.info({watchId:e,name:t.name},"Watch triggered via webhook"),await this.checkWatch(t)}async tick(){try{let e=await this.watchRepo.claimDue(this.nodeId);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"),await 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"),await this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}let{context:n}=await Oe(this.users,{platformUserId:e.chatId,platform:e.platform,chatId:e.chatId}),i=await this.skillSandbox.execute(r,e.skillParams,n);if(!i.success){this.logger.warn({watchId:e.id,error:i.error},"Watch skill execution failed"),this.skillHealthTracker?.recordFailure(e.skillName,i.error??"Watch poll failed"),await this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:e.lastValue});return}this.skillHealthTracker?.recordSuccess(e.skillName);let a,o,c;if(e.compositeCondition){let d=null;if(e.lastValue!==null)try{let h=JSON.parse(e.lastValue);d=h!==null&&typeof h=="object"&&!Array.isArray(h)?h:null}catch{}let u=_l(i.data,e.compositeCondition,d);a=u.triggered,c=JSON.stringify(u.newLastValues),o=Object.entries(u.displayValues).map(([h,m])=>`${h}=${m}`).join(", ")}else{let d=Pt(i.data,e.condition.field),u=null;if(e.lastValue!==null)try{u=JSON.parse(e.lastValue)}catch{}let h=Da(d,e.condition.operator,e.condition.value,u);a=h.triggered,o=h.displayValue,c=JSON.stringify(d)}if(a&&this.isCooldownExpired(e)){let d=e.actionOnTrigger??"alert",u={result:i.data,currentValue:o,watchName:e.name},h=e.actionSkillParams?gs(e.actionSkillParams,u):{},m=e.messageTemplate?ei(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:h}),d==="alert_and_action"){let g=await this.buildAlertText(e,o,i.data,m);g+=`
2095
2095
 
2096
2096
  (Aktion wartet auf Best\xE4tigung)`;let y=this.adapters.get(e.platform);if(y)try{await y.sendMessage(e.chatId,g)}catch(k){this.logger.error({err:k,watchId:e.id,chatId:e.chatId},"Failed to send watch alert message")}}await this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}if(d==="trigger_watch"&&e.triggerWatchId){if(t>=vT){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}),await this.watchRepo.updateAfterCheck(e.id,{lastCheckedAt:s,lastValue:c,lastTriggeredAt:s});return}let g=await this.watchRepo.getById(e.triggerWatchId);if(!g){this.logger.warn({watchId:e.id,targetId:e.triggerWatchId},"Chained watch not found"),await this.watchRepo.updateActionError(e.id,`Chained watch "${e.triggerWatchId}" not found`),await 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"),await 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),await this.watchRepo.updateActionError(e.id,null)}catch(y){let k=y instanceof Error?y.message:String(y);await this.watchRepo.updateActionError(e.id,k),this.logger.warn({watchId:e.id,targetId:g.id,err:y},"Watch chain execution failed")}await 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`,await 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,h,n),await 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),await 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`,await 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,o,i.data,m);f&&(g+=`
2097
2097
 
@@ -2175,7 +2175,7 @@ ${c.slice(0,200)}`)}let o=this.adapters.get(this.defaultPlatform);if(o)try{await
2175
2175
  ${o.join(`
2176
2176
 
2177
2177
  `)}`,d=this.adapters.get(this.defaultPlatform);if(d){await d.sendMessage(this.defaultChatId,c);for(let u of o)await this.markSent(u);this.logger.info({durationMs:i,insights:o.length},"Reasoning pass: insights sent")}}a.actions.length>0&&await this.processActions(a.actions),this.activityLogger?.logScheduledExec({actionId:"reasoning-engine",actionName:"Reasoning Engine",platform:this.defaultPlatform,chatId:this.defaultChatId,userId:this.defaultChatId,outcome:"success",durationMs:i})}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"})]),i=await this.fetchTodos(),a=await this.fetchWatches(),o=await this.fetchMemories(),c=await this.fetchActivity(),d=await this.fetchSkillHealth(),u=await this.fetchFeedback();return{dateTime:t,events:s,todos:i,watches:a,memories:o,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 i=n.start instanceof Date?n.start.toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}):String(n.start),a=n.location?` (${n.location})`:"";return`- ${i}: ${n.title??"Termin"}${a}`}).join(`
2178
- `)}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}=await De(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)`}}async fetchTodos(){try{let e=await this.todoRepo.getOverdue(),t=new Date(Date.now()+1440*60*1e3).toISOString(),s=await this.todoRepo.getDueInWindow(t),r=await this.todoRepo.list(this.defaultChatId),n=[];if(e.length>0){n.push(`\xDCberf\xE4llig (${e.length}):`);for(let i of e.slice(0,10))n.push(` - [${i.priority}] ${i.title} (f\xE4llig: ${i.dueDate})`)}if(s.length>0){n.push(`Bald f\xE4llig (${s.length}):`);for(let i of s.slice(0,10))n.push(` - [${i.priority}] ${i.title} (f\xE4llig: ${i.dueDate})`)}return r.length>0&&n.push(`Gesamt offene Todos: ${r.length}`),n.length>0?n.join(`
2178
+ `)}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}=await Oe(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)`}}async fetchTodos(){try{let e=await this.todoRepo.getOverdue(),t=new Date(Date.now()+1440*60*1e3).toISOString(),s=await this.todoRepo.getDueInWindow(t),r=await this.todoRepo.list(this.defaultChatId),n=[];if(e.length>0){n.push(`\xDCberf\xE4llig (${e.length}):`);for(let i of e.slice(0,10))n.push(` - [${i.priority}] ${i.title} (f\xE4llig: ${i.dueDate})`)}if(s.length>0){n.push(`Bald f\xE4llig (${s.length}):`);for(let i of s.slice(0,10))n.push(` - [${i.priority}] ${i.title} (f\xE4llig: ${i.dueDate})`)}return r.length>0&&n.push(`Gesamt offene Todos: ${r.length}`),n.length>0?n.join(`
2179
2179
  `):"Keine offenen Todos."}catch(e){return this.logger.warn({err:e},"Reasoning: todo fetch failed"),"(Todo-Abfrage fehlgeschlagen)"}}async fetchWatches(){try{let e=await 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}
2180
2180
  Letzter Wert: ${s}`}).join(`
2181
2181
  `)}catch(e){return this.logger.warn({err:e},"Reasoning: watch fetch failed"),"(Watch-Abfrage fehlgeschlagen)"}}async fetchMemories(){try{let e=await this.memoryRepo.getRecentForPrompt(this.defaultChatId,30);return e.length===0?"Keine gespeicherten Erinnerungen.":e.map(t=>`- [${t.type}] ${t.key}: ${t.value}`).join(`
@@ -2240,7 +2240,7 @@ Aktionstypen: "execute_skill" (Skill ausf\xFChren) oder "create_reminder" (Erinn
2240
2240
  Format: nach deinen Text-Insights, trenne mit "${ui}", dann ein JSON-Array:
2241
2241
  ${ui}
2242
2242
  [{"type":"execute_skill","description":"Wallbox ein (Strom <5ct, BMW 45%)","skillName":"homeassistant","skillParams":{"action":"turn_on","entity_id":"switch.wallbox"}}]
2243
- Wenn keine Aktionen sinnvoll: lass den ${ui} 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 sm.createHash("sha256").update(t).digest("hex").slice(0,16)}async wasRecentlySent(e){let s=`reasoning:${this.insightHash(e)}`;return await this.notifRepo.wasNotified(s,this.defaultChatId)}async markSent(e){let s=`reasoning:${this.insightHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();await this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}parseReasoningResponse(e){let t=e.indexOf(ui);if(t===-1)return{insights:this.parseInsights(e),actions:[]};let s=e.slice(0,t).trim(),r=e.slice(t+ui.length).trim(),n=s?this.parseInsights(s):[],i=[];try{let a=JSON.parse(r);Array.isArray(a)&&(i=a.filter(o=>o&&typeof o=="object"&&typeof o.type=="string"&&typeof o.description=="string"&&typeof o.skillName=="string"&&typeof o.skillParams=="object"&&o.skillParams!==null))}catch{this.logger.warn("Reasoning: failed to parse actions JSON, ignoring")}return{insights:n,actions:i}}actionHash(e){let t=`${e.type}:${e.skillName}:${JSON.stringify(e.skillParams)}`.slice(0,150).toLowerCase().replace(/\s+/g," ");return sm.createHash("sha256").update(t).digest("hex").slice(0,16)}async actionWasRecentlyProposed(e){let t=this.actionHash(e);return await this.notifRepo.wasNotified(`reasoning-action:${t}`,this.defaultChatId)}async markActionProposed(e){let s=`reasoning-action:${this.actionHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();await 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(await 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}),await this.markActionProposed(s),this.logger.info({action:s.description},"Reasoning: action enqueued for confirmation")}catch(r){this.logger.error({err:r,action:s.description},"Reasoning: failed to enqueue action")}}}}});var nm={};ie(nm,{ProjectAgentRunner:()=>Fa});import{execFile as FT}from"node:child_process";import{promisify as jT}from"node:util";var rm,Fa,Fl=w(()=>{"use strict";te();rm=jT(FT),Fa=class{static{p(this,"ProjectAgentRunner")}agents;llm;sessionRepo;adapters;logger;lastProgressAt=0;throttleMs=3e4;constructor(e,t,s,r,n){this.agents=e,this.llm=t,this.sessionRepo=s,this.adapters=r,this.logger=n}async run(e,t,s,r){let n={goal:t.goal,cwd:t.cwd,agentName:t.agentName,buildCommands:t.buildCommands,testCommands:t.testCommands,maxDurationHours:t.maxDurationHours??8,maxFixAttempts:t.maxFixAttempts??3,buildTimeoutMs:t.buildTimeoutMs??3e5},i=this.agents.get(n.agentName);if(!i){this.logger.error({sessionId:e,agent:n.agentName},"Project agent not found"),await this.sendProgress(s,r,`\u{1F4A5} Agent "${n.agentName}" nicht gefunden.`);return}let a=new AbortController;Dn(e,a);let o={projectPhase:"planning",projectIteration:0,projectGoal:n.goal,buildCommands:n.buildCommands,testCommands:n.testCommands,projectCwd:n.cwd,lastBuildOutput:"",injectedMessages:[],totalFilesChanged:0,milestonesReached:[],consecutiveFixFailures:0,agentName:n.agentName},c=!1;try{await this.sendProgress(s,r,`\u{1F680} Project Agent gestartet: ${n.goal}`),o.projectPhase="planning",await this.updateSession(e,o,c),await this.sendProgress(s,r,"\u{1F4CB} Erstelle Projekt-Plan...");let d=await Fn(n.goal,this.llm);await this.sendProgress(s,r,`\u{1F4CB} Plan erstellt: ${d.phases.length} Phasen
2243
+ Wenn keine Aktionen sinnvoll: lass den ${ui} 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 sm.createHash("sha256").update(t).digest("hex").slice(0,16)}async wasRecentlySent(e){let s=`reasoning:${this.insightHash(e)}`;return await this.notifRepo.wasNotified(s,this.defaultChatId)}async markSent(e){let s=`reasoning:${this.insightHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();await this.notifRepo.markNotified(s,this.defaultChatId,this.defaultPlatform,r)}parseReasoningResponse(e){let t=e.indexOf(ui);if(t===-1)return{insights:this.parseInsights(e),actions:[]};let s=e.slice(0,t).trim(),r=e.slice(t+ui.length).trim(),n=s?this.parseInsights(s):[],i=[];try{let a=JSON.parse(r);Array.isArray(a)&&(i=a.filter(o=>o&&typeof o=="object"&&typeof o.type=="string"&&typeof o.description=="string"&&typeof o.skillName=="string"&&typeof o.skillParams=="object"&&o.skillParams!==null))}catch{this.logger.warn("Reasoning: failed to parse actions JSON, ignoring")}return{insights:n,actions:i}}actionHash(e){let t=`${e.type}:${e.skillName}:${JSON.stringify(e.skillParams)}`.slice(0,150).toLowerCase().replace(/\s+/g," ");return sm.createHash("sha256").update(t).digest("hex").slice(0,16)}async actionWasRecentlyProposed(e){let t=this.actionHash(e);return await this.notifRepo.wasNotified(`reasoning-action:${t}`,this.defaultChatId)}async markActionProposed(e){let s=`reasoning-action:${this.actionHash(e)}`,r=new Date(Date.now()+this.deduplicationHours*60*60*1e3).toISOString();await 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(await 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}),await this.markActionProposed(s),this.logger.info({action:s.description},"Reasoning: action enqueued for confirmation")}catch(r){this.logger.error({err:r,action:s.description},"Reasoning: failed to enqueue action")}}}}});var nm={};ie(nm,{ProjectAgentRunner:()=>Fa});import{execFile as FT}from"node:child_process";import{promisify as jT}from"node:util";var rm,Fa,Fl=w(()=>{"use strict";ee();rm=jT(FT),Fa=class{static{p(this,"ProjectAgentRunner")}agents;llm;sessionRepo;adapters;logger;lastProgressAt=0;throttleMs=3e4;constructor(e,t,s,r,n){this.agents=e,this.llm=t,this.sessionRepo=s,this.adapters=r,this.logger=n}async run(e,t,s,r){let n={goal:t.goal,cwd:t.cwd,agentName:t.agentName,buildCommands:t.buildCommands,testCommands:t.testCommands,maxDurationHours:t.maxDurationHours??8,maxFixAttempts:t.maxFixAttempts??3,buildTimeoutMs:t.buildTimeoutMs??3e5},i=this.agents.get(n.agentName);if(!i){this.logger.error({sessionId:e,agent:n.agentName},"Project agent not found"),await this.sendProgress(s,r,`\u{1F4A5} Agent "${n.agentName}" nicht gefunden.`);return}let a=new AbortController;Dn(e,a);let o={projectPhase:"planning",projectIteration:0,projectGoal:n.goal,buildCommands:n.buildCommands,testCommands:n.testCommands,projectCwd:n.cwd,lastBuildOutput:"",injectedMessages:[],totalFilesChanged:0,milestonesReached:[],consecutiveFixFailures:0,agentName:n.agentName},c=!1;try{await this.sendProgress(s,r,`\u{1F680} Project Agent gestartet: ${n.goal}`),o.projectPhase="planning",await this.updateSession(e,o,c),await this.sendProgress(s,r,"\u{1F4CB} Erstelle Projekt-Plan...");let d=await Fn(n.goal,this.llm);await this.sendProgress(s,r,`\u{1F4CB} Plan erstellt: ${d.phases.length} Phasen
2244
2244
  ${d.phases.map((m,f)=>` ${f+1}. ${m}`).join(`
2245
2245
  `)}`),o.milestonesReached.push("Plan erstellt"),await this.sessionRepo.addMilestone(e,"Plan erstellt");let u=Date.now(),h=n.maxDurationHours*60*60*1e3;for(let m=0;m<d.phases.length;m++){if(a.signal.aborted){await this.sendProgress(s,r,"\u23F9 Project Agent abgebrochen.");return}if(Date.now()-u>h){await this.sendProgress(s,r,`\u23F0 Max-Dauer (${n.maxDurationHours}h) \xFCberschritten. Agent gestoppt.`);return}let f=On(e);if(f.includes("__STOP__")){await this.sendProgress(s,r,`\u23F9 Project Agent gestoppt nach Phase ${m}/${d.phases.length}.`);return}o.projectIteration=m+1,o.projectPhase="coding",o.consecutiveFixFailures=0,c=!1,await this.updateSession(e,o,c);let g=d.phases[m],y=f.filter(I=>I!=="__STOP__"),k=this.assemblePrompt(n.goal,g,o,y);await this.sendProgress(s,r,`\u{1F528} Phase ${m+1}/${d.phases.length}: ${g}`),this.logger.info({sessionId:e,phase:m+1,description:g},"Project agent: coding phase");let b=await ut(i,k,{cwd:n.cwd,onProgress:p(I=>{this.sendProgressThrottled(s,r,` [${n.agentName}] ${I}`)},"onProgress")});o.totalFilesChanged+=b.modifiedFiles.length;let S=!1;for(let I=0;I<=n.maxFixAttempts&&!a.signal.aborted;I++){if(o.projectPhase="validating",await this.updateSession(e,o,c),n.buildCommands.length===0&&n.testCommands.length===0){S=!0;break}let L=await Pn(n.cwd,n.buildCommands,n.testCommands,n.buildTimeoutMs);if(o.lastBuildOutput=L.combinedOutput,L.passed){S=!0,c=!0,await this.sendProgress(s,r,`\u2705 Build passed (Phase ${m+1}). ${b.modifiedFiles.length} Dateien ge\xE4ndert.`);break}if(o.consecutiveFixFailures++,I>=n.maxFixAttempts){await this.sendProgress(s,r,`\u274C Build failed nach ${n.maxFixAttempts} Fix-Versuchen.
2246
2246
  Letzter Fehler:
@@ -2262,7 +2262,7 @@ ${r.map(i=>`- ${i}`).join(`
2262
2262
  last_seen_at = excluded.last_seen_at,
2263
2263
  uptime_s = excluded.uptime_s`,[this.config.nodeId,"",e,e,Math.floor(process.uptime())])}catch(e){this.logger.debug({err:e},"PG heartbeat write failed")}}async getNodesFromPg(){if(!this.pgAdapter)return[];try{let e=new Date(Date.now()-this.failoverMs).toISOString();return(await this.pgAdapter.query("SELECT * FROM node_heartbeats WHERE last_seen_at > ?",[e])).map(s=>({id:s.node_id,host:s.host??"",port:0,adapters:[],lastHeartbeat:s.last_seen_at,healthy:!0}))}catch{return[]}}async getNodesAny(){let e=await this.getNodes();return e.length>0?e:this.getNodesFromPg()}stopPgHeartbeat(){this.pgHeartbeatTimer&&clearInterval(this.pgHeartbeatTimer)}}});var am={};ie(am,{UserServiceResolver:()=>ja});var ja,Bl=w(()=>{"use strict";ja=class{static{p(this,"UserServiceResolver")}userRepo;constructor(e){this.userRepo=e}async getServiceConfig(e,t,s){if(!e)return null;try{return(await this.userRepo.getService(e,t,s))?.config??null}catch{return null}}async getUserServices(e,t){if(!e)return[];try{let s=await this.userRepo.getServices(e);return t?s.filter(r=>r.serviceType===t):s}catch{return[]}}async saveServiceConfig(e,t,s,r){await this.userRepo.addService(e,t,s,r)}async removeServiceConfig(e,t,s){return await this.userRepo.removeService(e,t,s)}}});var lm={};ie(lm,{ClusterDiscovery:()=>Xa});import om from"node:dgram";var Ba,cm,Xa,Xl=w(()=>{"use strict";Ba=3421,cm="ALFRED_CLUSTER_V1",Xa=class{static{p(this,"ClusterDiscovery")}logger;socket=null;broadcastTimer;constructor(e){this.logger=e}startBroadcasting(e){this.socket=om.createSocket({type:"udp4",reuseAddr:!0}),this.socket.bind(()=>{this.socket.setBroadcast(!0);let t=Buffer.from(JSON.stringify({magic:cm,...e,timestamp:Date.now()}));this.broadcastTimer=setInterval(()=>{try{this.socket.send(t,0,t.length,Ba,"255.255.255.255")}catch(s){this.logger.debug({err:s},"Discovery broadcast failed")}},5e3),this.logger.info({port:Ba},"Cluster discovery broadcasting started")})}async discoverPrimary(e=15e3){return new Promise(t=>{let s=om.createSocket({type:"udp4",reuseAddr:!0}),r=!1,n=setTimeout(()=>{r||(s.close(),t(null))},e);s.on("message",(i,a)=>{try{let o=JSON.parse(i.toString());o.magic===cm&&o.role==="primary"&&(r=!0,clearTimeout(n),s.close(),this.logger.info({nodeId:o.nodeId,host:a.address,port:o.port},"Discovered primary node"),t({nodeId:o.nodeId,host:a.address,port:o.port,role:o.role}))}catch{}}),s.bind(Ba,()=>{this.logger.info({port:Ba},"Listening for cluster discovery broadcasts...")}),s.on("error",i=>{this.logger.warn({err:i},"Discovery listen error"),clearTimeout(n),t(null)})})}stop(){this.broadcastTimer&&clearInterval(this.broadcastTimer),this.socket?.close(),this.socket=null}}});import{EventEmitter as BT}from"node:events";var ke,St=w(()=>{"use strict";ke=class extends BT{static{p(this,"MessagingAdapter")}status="disconnected";async sendPhoto(e,t,s){}async sendFile(e,t,s,r){}async sendVoice(e,t,s){}endStream(e){}async sendDirectMessage(e,t,s){try{return await this.sendMessage(e,t,s)}catch{return}}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,a=r.slice(0,t).lastIndexOf(`
2264
2264
 
2265
- `);if(a>0&&(n=a),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 dm,InputFile as Hl}from"grammy";function um(l){if(l==="markdown")return"MarkdownV2";if(l==="html")return"HTML"}var Ha,pm=w(()=>{"use strict";St();p(um,"mapParseMode");Ha=class extends ke{static{p(this,"TelegramAdapter")}platform="telegram";bot;token;constructor(e){super(),this.token=e,this.bot=new dm(e)}async connect(){this.bot=new dm(this.token),this.status="connecting";try{let e=await this.bot.api.getUpdates({offset:-1,limit:1,timeout:0});e.length>0&&await this.bot.api.getUpdates({offset:e[0].update_id+1,limit:0,timeout:0})}catch{}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],i=await this.downloadAttachment(n.file_id,"image","image/jpeg"),a=this.normalizeMessage(t,r);a.attachments=i?[i]:void 0,this.emit("message",a)}),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"),i=this.normalizeMessage(t,r);i.attachments=n?[n]:void 0,this.emit("message",i)}),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"),i=this.normalizeMessage(t,r);i.attachments=n?[n]:void 0,this.emit("message",i)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,n=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,i=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),a=this.normalizeMessage(t,n);a.attachments=i?[i]:void 0,this.emit("message",a)}),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:p(()=>{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 i=0;i<r.length;i++){let o=i===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[i],{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:um(s?.parseMode),message_thread_id:s?.threadId?Number(s.threadId):void 0,reply_markup:o});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:um(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 Hl(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 Hl(t,s),{caption:r});return String(n.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new Hl(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 i=(await this.bot.api.getFile(e)).file_path;if(!i)return;let a=`https://api.telegram.org/file/bot${this.bot.token}/${i}`,o=await fetch(a);if(!o.ok)return;let c=Buffer.from(await o.arrayBuffer());return{type:t,mimeType:s,fileName:r??i.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 XT,GatewayIntentBits as Wa,Events as Wl}from"discord.js";var qa,hm=w(()=>{"use strict";St();qa=class extends ke{static{p(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new XT({intents:[Wa.Guilds,Wa.GuildMessages,Wa.MessageContent,Wa.DirectMessages]}),this.client.on(Wl.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(Wl.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(Wl.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),i="";for(let a=0;a<n.length;a++)a===0&&s?.replyToMessageId?i=(await(await r.messages.fetch(s.replyToMessageId)).reply(n[a])).id:i=(await r.send(n[a])).id;return i}async sendDirectMessage(e,t,s){if(this.client)try{let n=await(await this.client.users.fetch(e)).createDM();return await this.sendMessage(n.id,t,s)}catch{return}}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 i=await fetch(n.url);if(!i.ok)continue;let a=await i.arrayBuffer(),o=Buffer.from(a),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??o.length,data:o})}catch(i){console.error("[discord] Failed to download attachment",n.url,i)}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 HT}from"node:os";import{join as WT}from"node:path";var za,mm=w(()=>{"use strict";St();za=class extends ke{static{p(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??WT(HT(),".alfred","matrix-storage")}async connect(){this.status="connecting";let e,t,s;try{({MatrixClient:e,SimpleFsStorageProvider:t,AutojoinRoomsMixin:s}=Function('return require("matrix-bot-sdk")')())}catch{({MatrixClient:e,SimpleFsStorageProvider:t,AutojoinRoomsMixin:s}=await import("matrix-bot-sdk"))}let 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,i)=>{if(i.sender===this.botUserId)return;let a=i.content?.msgtype;if(a)try{let o=await this.normalizeEvent(n,i,a);o&&this.emit("message",o)}catch(o){this.emit("error",o instanceof Error?o:new Error(String(o)))}}),await this.client.start(),this.status="connected",this.emit("connected")}async disconnect(){this.client.stop(),this.status="disconnected",this.emit("disconnected")}async sendDirectMessage(e,t,s){if(this.client)try{let r=this.client.getRooms?.()??[],n;for(let i of r){let a=i.getJoinedMembers?.()??[];if(a.length===2&&a.some(o=>o.userId===e)){n=i.roomId;break}}if(!n){let{room_id:i}=await this.client.createRoom({invite:[e],is_direct:!0,preset:"trusted_private_chat"});n=i}return await this.sendMessage(n,t,s)}catch{return}}async sendMessage(e,t,s){let r=this.splitText(t,32e3),n="";for(let i of r)s?.parseMode==="html"?n=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:i.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:i}):n=await this.client.sendText(e,i);return n}async editMessage(e,t,s,r){let n=r?.parseMode==="html",i={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",i)}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),i=await this.client.uploadContent(t,n,s),a={msgtype:"m.file",body:r??s,filename:s,url:i,info:{mimetype:n,size:t.length}};return await this.client.sendEvent(e,"m.room.message",a)}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 i=await this.downloadAttachment(t.content,"image");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Photo]",attachments:i?[i]:void 0}}case"m.audio":{let i=await this.downloadAttachment(t.content,"audio");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Voice message]",attachments:i?[i]:void 0}}case"m.video":{let i=await this.downloadAttachment(t.content,"video");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Video]",attachments:i?[i]:void 0}}case"m.file":{let i=await this.downloadAttachment(t.content,"document");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Document]",attachments:i?[i]: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,i=r.size,a=e.filename??e.body??"file",o=s.slice(6),c=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${o}`,`${this.homeserverUrl}/_matrix/media/v3/download/${o}`];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 h=await u.arrayBuffer(),m=Buffer.from(h);return{type:t,mimeType:n,fileName:a,size:i??m.length,data:m}}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 Ka,fm=w(()=>{"use strict";St();Ka=class extends ke{static{p(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:i}=await t(this.dataPath);this.socket=e({auth:n,printQRInTerminal:!0}),this.socket.ev.on("creds.update",i),this.socket.ev.on("connection.update",a=>{if(a.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),a.connection==="close"){let c=a.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:a,type:o})=>{if(o==="notify")for(let c of a)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 i=0;i<r.length;i++)n=(await this.socket.sendMessage(e,{text:r[i]},i===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 a=await this.downloadMediaSafe(e);if(a){let o=t.imageMessage.mimetype??"image/jpeg";r.push({type:"image",mimeType:o,fileName:t.imageMessage.fileName??`image.${o.split("/")[1]??"jpeg"}`,size:t.imageMessage.fileLength??a.length,data:a})}n||(n="[Photo]")}else if(t.audioMessage){let a=await this.downloadMediaSafe(e);if(a){let o=t.audioMessage.mimetype??"audio/ogg";r.push({type:"audio",mimeType:o,fileName:t.audioMessage.fileName??`audio.${o.split("/")[1]??"ogg"}`,size:t.audioMessage.fileLength??a.length,data:a})}n||(n="[Voice message]")}else if(t.videoMessage){let a=await this.downloadMediaSafe(e);a&&r.push({type:"video",mimeType:t.videoMessage.mimetype??"video/mp4",size:t.videoMessage.fileLength??a.length,data:a}),n||(n="[Video]")}else if(t.documentMessage){let a=await this.downloadMediaSafe(e);a&&r.push({type:"document",mimeType:t.documentMessage.mimetype??"application/octet-stream",fileName:t.documentMessage.fileName??"document",size:t.documentMessage.fileLength??a.length,data:a}),n||(n="[Document]")}else if(t.stickerMessage&&!s)return;if(!n&&r.length===0)return;let i={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",i)}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 Ga,gm=w(()=>{"use strict";St();Ga=class extends ke{static{p(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(i=>setTimeout(i,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 i of r){let a=e.startsWith("group."),o={message:i,number:this.phoneNumber};a?o.recipients=[e.replace("group.","")]:o.recipients=[e];let c=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});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,i=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:n.sourceNumber??n.source??"",a=[];if(r.attachments)for(let d of r.attachments){let u=await this.downloadAttachment(d);u&&a.push(u)}let o=r.message||this.inferTextFromAttachments(a)||"";if(!o&&a.length===0)continue;let c={id:String(r.timestamp??Date.now()),platform:"signal",chatId:i,chatType:r.groupInfo?"group":"dm",userId:n.sourceNumber??n.source??"",userName:n.sourceName??n.sourceNumber??n.source??"",displayName:n.sourceName,text:o,timestamp:new Date(r.timestamp??Date.now()),attachments:a.length>0?a: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 ql from"node:readline";var Ya,ym=w(()=>{"use strict";St();Ya=class extends ke{static{p(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=ql.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
2265
+ `);if(a>0&&(n=a),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 dm,InputFile as Hl}from"grammy";function um(l){if(l==="markdown")return"MarkdownV2";if(l==="html")return"HTML"}var Ha,pm=w(()=>{"use strict";St();p(um,"mapParseMode");Ha=class extends ke{static{p(this,"TelegramAdapter")}platform="telegram";bot;token;constructor(e){super(),this.token=e,this.bot=new dm(e)}async connect(){this.bot=new dm(this.token),this.status="connecting";try{let e=await this.bot.api.getUpdates({offset:-1,limit:1,timeout:0});e.length>0&&await this.bot.api.getUpdates({offset:e[0].update_id+1,limit:0,timeout:0})}catch{}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],i=await this.downloadAttachment(n.file_id,"image","image/jpeg"),a=this.normalizeMessage(t,r);a.attachments=i?[i]:void 0,this.emit("message",a)}),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"),i=this.normalizeMessage(t,r);i.attachments=n?[n]:void 0,this.emit("message",i)}),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"),i=this.normalizeMessage(t,r);i.attachments=n?[n]:void 0,this.emit("message",i)}),this.bot.on("message:document",async e=>{let t=e.message,s=t.document,n=(t.caption??"")||`[Document: ${s.file_name??"file"}]`,i=await this.downloadAttachment(s.file_id,"document",s.mime_type??"application/octet-stream",s.file_name),a=this.normalizeMessage(t,n);a.attachments=i?[i]:void 0,this.emit("message",a)}),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:p(()=>{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 i=0;i<r.length;i++){let o=i===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[i],{reply_to_message_id:s?.replyToMessageId?Number(s.replyToMessageId):void 0,parse_mode:um(s?.parseMode),message_thread_id:s?.threadId?Number(s.threadId):void 0,reply_markup:o});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:um(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 Hl(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 Hl(t,s),{caption:r});return String(n.message_id)}async sendVoice(e,t,s){let r=await this.bot.api.sendVoice(Number(e),new Hl(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 i=(await this.bot.api.getFile(e)).file_path;if(!i)return;let a=`https://api.telegram.org/file/bot${this.bot.token}/${i}`,o=await fetch(a);if(!o.ok)return;let c=Buffer.from(await o.arrayBuffer());return{type:t,mimeType:s,fileName:r??i.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 XT,GatewayIntentBits as Wa,Events as Wl}from"discord.js";var qa,hm=w(()=>{"use strict";St();qa=class extends ke{static{p(this,"DiscordAdapter")}platform="discord";client=null;token;constructor(e){super(),this.token=e}async connect(){this.status="connecting",this.client=new XT({intents:[Wa.Guilds,Wa.GuildMessages,Wa.MessageContent,Wa.DirectMessages]}),this.client.on(Wl.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(Wl.ClientReady,()=>{this.status="connected",this.emit("connected")}),this.client.on(Wl.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),i="";for(let a=0;a<n.length;a++)a===0&&s?.replyToMessageId?i=(await(await r.messages.fetch(s.replyToMessageId)).reply(n[a])).id:i=(await r.send(n[a])).id;return i}async sendDirectMessage(e,t,s){if(this.client)try{let n=await(await this.client.users.fetch(e)).createDM();return await this.sendMessage(n.id,t,s)}catch{return}}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 i=await fetch(n.url);if(!i.ok)continue;let a=await i.arrayBuffer(),o=Buffer.from(a),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??o.length,data:o})}catch(i){console.error("[discord] Failed to download attachment",n.url,i)}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 HT}from"node:os";import{join as WT}from"node:path";var za,mm=w(()=>{"use strict";St();za=class extends ke{static{p(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??WT(HT(),".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,i)=>{if(i.sender===this.botUserId)return;let a=i.content?.msgtype;if(a)try{let o=await this.normalizeEvent(n,i,a);o&&this.emit("message",o)}catch(o){this.emit("error",o instanceof Error?o:new Error(String(o)))}}),await this.client.start(),this.status="connected",this.emit("connected")}async disconnect(){this.client.stop(),this.status="disconnected",this.emit("disconnected")}async sendDirectMessage(e,t,s){if(this.client)try{let r=this.client.getRooms?.()??[],n;for(let i of r){let a=i.getJoinedMembers?.()??[];if(a.length===2&&a.some(o=>o.userId===e)){n=i.roomId;break}}if(!n){let{room_id:i}=await this.client.createRoom({invite:[e],is_direct:!0,preset:"trusted_private_chat"});n=i}return await this.sendMessage(n,t,s)}catch{return}}async sendMessage(e,t,s){let r=this.splitText(t,32e3),n="";for(let i of r)s?.parseMode==="html"?n=await this.client.sendEvent(e,"m.room.message",{msgtype:"m.text",body:i.replace(/<[^>]*>/g,""),format:"org.matrix.custom.html",formatted_body:i}):n=await this.client.sendText(e,i);return n}async editMessage(e,t,s,r){let n=r?.parseMode==="html",i={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",i)}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),i=await this.client.uploadContent(t,n,s),a={msgtype:"m.file",body:r??s,filename:s,url:i,info:{mimetype:n,size:t.length}};return await this.client.sendEvent(e,"m.room.message",a)}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 i=await this.downloadAttachment(t.content,"image");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Photo]",attachments:i?[i]:void 0}}case"m.audio":{let i=await this.downloadAttachment(t.content,"audio");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Voice message]",attachments:i?[i]:void 0}}case"m.video":{let i=await this.downloadAttachment(t.content,"video");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Video]",attachments:i?[i]:void 0}}case"m.file":{let i=await this.downloadAttachment(t.content,"document");return i&&t.content.body&&(i.fileName=t.content.body),{...n,text:"[Document]",attachments:i?[i]: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,i=r.size,a=e.filename??e.body??"file",o=s.slice(6),c=[`${this.homeserverUrl}/_matrix/client/v1/media/download/${o}`,`${this.homeserverUrl}/_matrix/media/v3/download/${o}`];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 h=await u.arrayBuffer(),m=Buffer.from(h);return{type:t,mimeType:n,fileName:a,size:i??m.length,data:m}}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 Ka,fm=w(()=>{"use strict";St();Ka=class extends ke{static{p(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:i}=await t(this.dataPath);this.socket=e({auth:n,printQRInTerminal:!0}),this.socket.ev.on("creds.update",i),this.socket.ev.on("connection.update",a=>{if(a.connection==="open"&&(this.status="connected",this.reconnectAttempts=0,this.emit("connected")),a.connection==="close"){let c=a.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:a,type:o})=>{if(o==="notify")for(let c of a)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 i=0;i<r.length;i++)n=(await this.socket.sendMessage(e,{text:r[i]},i===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 a=await this.downloadMediaSafe(e);if(a){let o=t.imageMessage.mimetype??"image/jpeg";r.push({type:"image",mimeType:o,fileName:t.imageMessage.fileName??`image.${o.split("/")[1]??"jpeg"}`,size:t.imageMessage.fileLength??a.length,data:a})}n||(n="[Photo]")}else if(t.audioMessage){let a=await this.downloadMediaSafe(e);if(a){let o=t.audioMessage.mimetype??"audio/ogg";r.push({type:"audio",mimeType:o,fileName:t.audioMessage.fileName??`audio.${o.split("/")[1]??"ogg"}`,size:t.audioMessage.fileLength??a.length,data:a})}n||(n="[Voice message]")}else if(t.videoMessage){let a=await this.downloadMediaSafe(e);a&&r.push({type:"video",mimeType:t.videoMessage.mimetype??"video/mp4",size:t.videoMessage.fileLength??a.length,data:a}),n||(n="[Video]")}else if(t.documentMessage){let a=await this.downloadMediaSafe(e);a&&r.push({type:"document",mimeType:t.documentMessage.mimetype??"application/octet-stream",fileName:t.documentMessage.fileName??"document",size:t.documentMessage.fileLength??a.length,data:a}),n||(n="[Document]")}else if(t.stickerMessage&&!s)return;if(!n&&r.length===0)return;let i={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",i)}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 Ga,gm=w(()=>{"use strict";St();Ga=class extends ke{static{p(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(i=>setTimeout(i,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 i of r){let a=e.startsWith("group."),o={message:i,number:this.phoneNumber};a?o.recipients=[e.replace("group.","")]:o.recipients=[e];let c=await fetch(`${this.apiUrl}/v2/send`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});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,i=r.groupInfo?.groupId?`group.${r.groupInfo.groupId}`:n.sourceNumber??n.source??"",a=[];if(r.attachments)for(let d of r.attachments){let u=await this.downloadAttachment(d);u&&a.push(u)}let o=r.message||this.inferTextFromAttachments(a)||"";if(!o&&a.length===0)continue;let c={id:String(r.timestamp??Date.now()),platform:"signal",chatId:i,chatType:r.groupInfo?"group":"dm",userId:n.sourceNumber??n.source??"",userName:n.sourceName??n.sourceNumber??n.source??"",displayName:n.sourceName,text:o,timestamp:new Date(r.timestamp??Date.now()),attachments:a.length>0?a: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 ql from"node:readline";var Ya,ym=w(()=>{"use strict";St();Ya=class extends ke{static{p(this,"CLIAdapter")}platform="cli";rl;messageCounter=0;async connect(){this.status="connecting",this.rl=ql.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "}),console.log(`
2266
2266
  Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leave.
2267
2267
  `),this.rl.on("line",e=>{let t=e.trim();if(!t){this.prompt();return}if(t==="/quit"||t==="/exit"){console.log(`
2268
2268
  Goodbye!
@@ -2275,8 +2275,8 @@ data: ${JSON.stringify(s)}
2275
2275
  VALUES (?, ?, ?, ?)
2276
2276
  ON CONFLICT (platform) DO UPDATE
2277
2277
  SET node_id = excluded.node_id, claimed_at = excluded.claimed_at, expires_at = excluded.expires_at
2278
- WHERE adapter_claims.expires_at < ?`,[e,this.nodeId,t,s,t])).changes>0?(this.claimedPlatforms.add(e),!0):await this.adapter.queryOne("SELECT node_id FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])?(this.claimedPlatforms.add(e),!0):!1}start(){this.renewTimer=setInterval(()=>this.renewClaims(),this.claimTtlMs/2),this.checkTimer=setInterval(()=>this.checkExpiredClaims(),15e3)}stop(){this.renewTimer&&clearInterval(this.renewTimer),this.checkTimer&&clearInterval(this.checkTimer),this.releaseClaims().catch(()=>{})}async renewClaims(){if(this.claimedPlatforms.size===0||this.adapter.type==="sqlite")return;let e=new Date(Date.now()+this.claimTtlMs).toISOString();for(let t of this.claimedPlatforms)try{await this.adapter.execute("UPDATE adapter_claims SET expires_at = ? WHERE platform = ? AND node_id = ?",[e,t,this.nodeId])}catch(s){this.logger.warn({err:s,platform:t},"Failed to renew adapter claim")}}knownPlatforms=new Set;registerPlatform(e){this.knownPlatforms.add(e)}async checkExpiredClaims(){if(this.adapter.type!=="sqlite")try{let e=new Date().toISOString();for(let t of this.knownPlatforms){if(this.claimedPlatforms.has(t))continue;let s=await this.adapter.queryOne("SELECT node_id, expires_at FROM adapter_claims WHERE platform = ?",[t]);(!s||s.expires_at<e)&&await this.tryClaim(t)&&(this.logger.info({platform:t,nodeId:this.nodeId},"Acquired adapter claim from dead node"),this.onClaimAcquired?.(t))}}catch(e){this.logger.debug({err:e},"Adapter claim check failed")}}async releaseClaims(){if(this.adapter.type!=="sqlite"){for(let e of this.claimedPlatforms)try{await this.adapter.execute("DELETE FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])}catch{}this.claimedPlatforms.clear()}}owns(e){return this.claimedPlatforms.has(e)}}});import $r from"node:fs";import Ge from"node:path";import GT from"js-yaml";var ys,km=w(()=>{"use strict";Bo();Xe();ct();ac();Qi();te();al();ll();dl();ul();pl();hl();ml();fl();gl();yl();Tl();wl();El();em();kl();Al();$l();Rl();Nl();Ll();xl();Cl();Ol();Ul();Pl();ys=class{static{p(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new Kn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;clusterManager;adapterClaimManager;webAuthCallback;reminderRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=Zr("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=await lt.create({backend:this.config.storage.backend??"sqlite",path:this.config.storage.path,connectionString:this.config.storage.connectionString});let e=this.database.getAdapter(),t=new Ss(e),s=new bs(e);this.userRepo=s;let r=new xt(e);this.auditRepo=r;let n=new vs(e);this.memoryRepo=n;let i=new Is(e);this.reminderRepo=i;let a=new As(e),o=new $s(e),c=new Rs(e),d=new Ns(e),u=new xs(e);this.scheduledActionRepo=u;let h=new Ot(e);this.activityRepo=h;let m=new ci(h,this.logger.child({component:"activity"})),f=new Fs(e);this.skillHealthRepo=f;let g=new li(f,this.logger.child({component:"skill-health"}),m);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new hn,k=this.loadSecurityRules();y.loadRules(k);let b=new mn(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:k.length},"Security engine initialized");let S=nc(this.config.llm,this.logger.child({component:"llm"}));await S.initialize(),this.llmProvider=S;let I=new Ps(e);this.usageRepo=I,S.setPersist((A,H,U,G,Q,Te)=>{I.record(A,H,U,G,Q,Te).catch(()=>{})});let L=new Gn(S,o,this.logger.child({component:"embeddings"})),D=this.config.activeLearning?.enabled!==!1,W,q;D&&(W=new ri({llm:S,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:L,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),q=new ni(n,this.logger.child({component:"memory-retriever"}),L),this.logger.info("Active learning & memory retriever initialized"));let j=new Us(e);this.summaryRepo=j;let ce=new ii(S,j,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let me=new Ws(this.logger.child({component:"sandbox"})),O=this.skillRegistry=new Hs;O.register(new qs),O.register(new zs),O.register(new Ks(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),O.register(new Gs(i));let pe=new Ys(a);O.register(pe);let he=new Os(e),ye=new fr(he);if(O.register(ye),O.register(new Vs),O.register(new Js),O.register(new Zs(n,L)),O.register(new Qs(S,O,me,b)),this.config.email?.accounts?.length){let A=new Map;for(let U of this.config.email.accounts)try{U.provider==="microsoft"&&!U.microsoft?.clientId&&this.config.calendar?.microsoft&&(U.microsoft={...this.config.calendar.microsoft});let G=await er(U);A.set(U.name,G),this.logger.info({account:U.name,provider:U.provider??"imap-smtp"},"Email account initialized")}catch(G){this.logger.warn({err:G,account:U.name},"Email account initialization failed, skipping")}let H=A.size>0?new Dt(A):new Dt;H.setLLM(S),O.register(H)}else{let A=new Dt;A.setLLM(S),O.register(A)}O.register(new tr),O.register(new sr);let $e=new wr;$e.setReloadCallback(A=>this.reloadService(A)),O.register($e),O.register(new nr),O.register(new ir),O.register(new ar),O.register(new or(s)),O.register(new lr(s,c,this.adapters,(A,H)=>t.findByPlatformAndUser(A,H)));let ae=new dr(d);O.register(ae),O.register(new ur(u));let z=new Cs(e),le=new Yn(z,L,this.logger.child({component:"documents"})),Ye=new pr(z,le,L);O.register(Ye);let we,Re;if(this.config.calendar)try{Re=await cr(this.config.calendar),we=new cs(Re),O.register(we),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(A){this.logger.warn({err:A},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=we,Re&&this.config.calendar?.vorlauf?.enabled){let A=new Ct(e),H=this.config.security?.ownerUserId;H&&(this.calendarWatcher=new ai(Re,A,this.adapters,H,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),m))}{let A=this.config.security?.ownerUserId;if(A){let H=new Ct(e);this.todoWatcher=new oi(he,H,this.adapters,A,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),m,A)}}if(this.config.mcp?.servers?.length){let{MCPManager:A}=await Promise.resolve().then(()=>(te(),re));this.mcpManager=new A(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let H of this.mcpManager.getSkills())O.register(H);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},S)),this.logger.info({agents:this.config.codeAgents.agents.map(H=>H.name)},"Code agent skill enabled")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:A}=await Promise.resolve().then(()=>(te(),re)),{ProjectAgentSessionRepository:H}=await Promise.resolve().then(()=>(Xe(),dt)),U=new H(e),G=new A({...this.config.projectAgents,agents:this.config.codeAgents.agents},S,U),{ProjectAgentRunner:Q}=await Promise.resolve().then(()=>(Fl(),nm)),Te=new Q(new Map(this.config.codeAgents.agents.map(Ne=>[Ne.name,Ne])),S,U,this.adapters,this.logger.child({component:"project-agent"}));G.setRunner(Te),O.register(G),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:A,createContactsProvider:H}=await Promise.resolve().then(()=>(te(),re)),U=await H(this.config.contacts);O.register(new A(U)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(A){this.logger.warn({err:A},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(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:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A({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:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(O,this.config,n)),this.logger.info("Briefing skill registered")}O.register(new kr(n)),this.logger.info("Feed reader skill registered");let Ue=new Sr(O);O.register(Ue);{let{AlfredUserRepository:A}=await Promise.resolve().then(()=>(Xe(),dt)),{UserManagementSkill:H}=await Promise.resolve().then(()=>(te(),re)),U=new A(e);if(this.config.security?.ownerUserId){let Fe=this.config.security.ownerUserId,Ve=(await U.getAll()).filter(Nr=>Nr.role==="admin")[0];Ve||(Ve=await U.create({username:"admin",role:"admin",displayName:"Admin"}),await U.clearInviteCode(Ve.id),this.logger.info({userId:Fe},"Auto-created admin user from ownerUserId"));let Ht=["telegram","discord","matrix","signal","api"];for(let Nr of Ht)if(!await U.getUserByPlatform(Nr,Fe))try{await U.linkPlatform(Ve.id,Nr,Fe)}catch{}}O.register(new H(U)),this.logger.info("User management skill registered");let{SharingSkill:G}=await Promise.resolve().then(()=>(te(),re)),{SharedResourceRepository:Q}=await Promise.resolve().then(()=>(Xe(),dt)),Te=new Q(e);O.register(new G(Te,U)),Ye.sharedResourceRepo=Te,pe.sharedResourceRepo=Te,ye.sharedResourceRepo=Te,this.logger.info("Sharing skill registered");let Ne=c;this.webAuthCallback={loginWithCode:p(async Fe=>{let $t=`web-pending-${Date.now()}`,Le=await U.consumeInviteCode(Fe,"api",$t);if(!Le)return{success:!1,error:"Ung\xFCltiger oder abgelaufener Code"};let Ve=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,Ht=new Date(Date.now()+720*60*6e4).toISOString();return await Ne.createSession(Ve,Le.id,"web-session",Ht),{success:!0,userId:Le.id,username:Le.username,role:Le.role,token:Ve}},"loginWithCode"),getUserByToken:p(async Fe=>{let $t=await Ne.findByToken(Fe);if(!$t||new Date($t.expiresAt)<new Date)return null;let Le=await U.getById($t.userId);return Le?{userId:Le.id,username:Le.username,role:Le.role}:null},"getUserByToken")}}if(this.config.database?.enabled){let{DatabaseSkill:A}=await Promise.resolve().then(()=>(te(),re)),{DatabaseConnectionRepository:H}=await Promise.resolve().then(()=>(Xe(),dt)),U=new H(e),G=new A(this.config.database,U);if(this.config.database.connections)for(let Q of this.config.database.connections)await U.getByName(Q.name)||await U.create({name:Q.name,type:Q.type,host:Q.host,port:Q.port,databaseName:Q.database,username:Q.username,authConfig:Q.password?{password:Q.password}:void 0,options:{readOnly:Q.options?.readOnly??!0,rowLimit:Q.options?.rowLimit,timeoutMs:Q.options?.timeoutMs}});O.register(G),this.logger.info("Database skill registered")}if(this.config.youtube?.apiKey){let{YouTubeSkill:A}=await Promise.resolve().then(()=>(te(),re));O.register(new A(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:O.getAll().map(A=>A.metadata.name)},"Skills registered");let Pe;if(this.config.speech?.apiKey&&(Pe=new Hn(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 A=new Wn(this.config.speech,this.logger.child({component:"tts"}));O.register(new hr(A)),this.logger.info("Text-to-speech skill registered")}let pt=this.detectImageGenProvider();if(pt){let A=new qn(pt,this.logger.child({component:"image-gen"}));O.register(new mr(A)),this.logger.info({provider:pt.provider},"Image generation skill registered")}try{let A=new zn(this.logger.child({component:"transit"}));O.register(new yr(A)),this.logger.info("Public transit skill registered")}catch(A){this.logger.warn({err:A},"Failed to register transit skill")}let It;if(this.config.fileStore){let{createFileStore:A}=await Promise.resolve().then(()=>(Xe(),dt));It=A(this.config.fileStore),this.logger.info({backend:this.config.fileStore.backend},"File store initialized")}let ht=new jn(t),Xt=Ge.resolve(Ge.dirname(this.config.storage.path),"inbox");if(this.pipeline=new Bn({llm:S,conversationManager:ht,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:O,skillSandbox:me,securityManager:b,memoryRepo:n,speechTranscriber:Pe,inboxPath:Xt,fileStore:It,processedMessageRepo:this.config.cluster?.enabled?new(await Promise.resolve().then(()=>(Xe(),dt))).ProcessedMessageRepository(e):void 0,nodeId:this.config.cluster?.nodeId??"single",embeddingService:L,activeLearning:W,memoryRetriever:q,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:le,conversationSummarizer:ce}),this.config.cluster?.enabled){if(e.type!=="postgres")throw new Error('HA Cluster erfordert storage.backend: "postgres". SQLite ist nicht f\xFCr Multi-Node geeignet.');if(!this.config.cluster.nodeId)throw new Error("HA Cluster erfordert cluster.nodeId. Jeder Node braucht eine eindeutige ID.");(!this.config.fileStore||this.config.fileStore.backend==="local")&&this.logger.warn('HA Cluster ohne S3/NFS FileStore \u2014 Datei-Uploads sind nur auf dem empfangenden Node sichtbar. Empfohlen: fileStore.backend: "s3" oder "nfs"');let{ClusterManager:A}=await Promise.resolve().then(()=>(jl(),im));this.clusterManager=new A(this.config.cluster,this.logger.child({component:"cluster"})),await this.clusterManager.connect(),this.clusterManager.isConnected||this.logger.warn("Redis nicht erreichbar \u2014 Cross-Node Pub/Sub und Echtzeit-Heartbeat deaktiviert. PG-Heartbeat als Fallback aktiv.");let{PgMigrator:H,PG_MIGRATIONS:U}=await Promise.resolve().then(()=>(Xe(),dt));await new H(e).migrate(U),this.clusterManager.startPgHeartbeat(e),this.logger.info({nodeId:this.config.cluster.nodeId},"Cluster manager initialized (Active-Active)")}this.reminderScheduler=new Xn(i,async(A,H,U)=>{let G=this.adapters.get(A);G?await G.sendMessage(H,U):this.logger.warn({platform:A,chatId:H},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:p(A=>s.getMasterUserId(A),"getMasterUserId"),getLinkedUsers:p(A=>s.getLinkedUsers(A),"getLinkedUsers"),findConversation:p((A,H)=>t.findByPlatformAndUser(A,H),"findConversation")},this.config.cluster?.nodeId??"single"),this.backgroundTaskRunner=new Vn(O,me,d,this.adapters,s,this.logger.child({component:"background-tasks"}),m,g);let mt=new Jn(O,me,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),m);this.backgroundTaskRunner.setPersistentRunner(mt),ae.setPersistentRunner(mt),this.proactiveScheduler=new Zn(u,O,me,S,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,ht,m,this.config.cluster?.nodeId??"single");let Ee=new Ds(e);this.watchRepo=Ee,O.register(new Er(Ee,O));let Oe=new Ms(e);this.confirmationQueue=new ti(Oe,O,me,this.adapters,this.logger.child({component:"confirmation-queue"}),m);let At=new Bs(e),ot=new Ar(At,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(ot),W&&W.setFeedbackService(ot),this.watchEngine=new Ua(Ee,O,me,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,m,g,S,this.config.cluster?.nodeId??"single");let K=new js(e),V=new _r(K);O.register(V);let de=new di(K,O,me,this.logger.child({component:"workflow-runner"}),m,g);V.setRunner(de);{let A=this.config.security?.ownerUserId;if(A&&this.config.reasoning?.enabled!==!1){let H=new Ct(e);this.reasoningEngine=new pi(Re,he,Ee,n,h,f,H,O,me,S,this.adapters,s,A,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),m,this.config.briefing?.location,At,this.confirmationQueue,this.config.cluster?.nodeId??"single",e)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(m),this.pipeline.setSkillHealthTracker(g);{let{AlfredUserRepository:A,UsageRepository:H}=await Promise.resolve().then(()=>(Xe(),dt)),{ROLE_SKILL_ACCESS:U}=await Promise.resolve().then(()=>(te(),re)),G=new A(e),{UserServiceResolver:Q}=await Promise.resolve().then(()=>(Bl(),am)),Te=new Q(G);this.pipeline.setAlfredUserRepo(G,U,this.usageRepo,Te),Ue.roleAccess=U}if(this.clusterManager&&(await this.clusterManager.subscribe("messages",A=>{let{targetPlatform:H,chatId:U,text:G}=A,Q=this.adapters.get(H);Q&&Q.sendMessage(U,G).catch(Te=>{this.logger.warn({err:Te,targetPlatform:H,chatId:U},"Cross-node message delivery failed")})}),this.config.cluster)){let{ClusterDiscovery:A}=await Promise.resolve().then(()=>(Xl(),lm));new A(this.logger.child({component:"cluster-discovery"})).startBroadcasting({nodeId:this.config.cluster.nodeId,host:"0.0.0.0",port:this.config.api?.port??3420,role:this.config.cluster?.role??"node"})}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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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,tls:e.api?.tls,authCallback:this.webAuthCallback,healthCheck:p(async()=>{let n;try{let i=this.config.storage.path,a=$r.statSync(i);n={path:i,sizeBytes:a.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([i,a])=>[i,a.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:await this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:await this.watchRepo?.countEnabled()??0,schedulersActive:await this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:p(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:p(async()=>{let n=new Date().toISOString().slice(0,10),i=new Date(Date.now()-10080*6e4).toISOString().slice(0,10);return{watches:await this.watchRepo?.getEnabled()??[],scheduled:await this.scheduledActionRepo?.getAll()??[],skillHealth:await this.skillHealthRepo?.getAll()??[],reminders:await this.reminderRepo?.getAllPending()??[],usage:{today:await this.usageRepo?.getDaily(n)??null,week:await this.usageRepo?.getRange(i,n)??[],total:await this.usageRepo?.getTotal()??[]},uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters.entries()].map(([a,o])=>[a,o.getStatus()])),llmProviders:this.llmProvider.getProviderStatuses(),userUsage:await this.usageRepo?.getByUser(i,n)??[],userSkillUsage:await this.activityRepo?.skillUsageByUser(i)??[]}},"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(){if(this.logger.info("Starting Alfred..."),this.config.cluster?.enabled&&this.database.getAdapter().type==="postgres"){let{AdapterClaimManager:e}=await Promise.resolve().then(()=>(_m(),Em));this.adapterClaimManager=new e(this.database.getAdapter(),this.config.cluster.nodeId,this.logger.child({component:"adapter-claims"}));for(let[t,s]of this.adapters){if(t==="api"){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected (always-on)")}catch(n){this.logger.error({platform:t,err:n},"Adapter connection failed")}continue}if(this.adapterClaimManager.registerPlatform(t),await this.adapterClaimManager.tryClaim(t)){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected (claimed)")}catch(n){this.logger.error({platform:t,err:n},"Adapter connection failed")}}else this.logger.info({platform:t},"Adapter claimed by another node, skipping")}this.adapterClaimManager.onAcquired(async t=>{let s=this.adapters.get(t);if(s&&s.getStatus()==="disconnected"){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected (failover)")}catch(r){this.logger.error({platform:t,err:r},"Failover adapter connection failed")}}}),this.adapterClaimManager.start()}else for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:p(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let i=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,i)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:await this.auditRepo?.cleanup(90)??0,summaries:await this.summaryRepo?.cleanup(180)??0,activity:await this.activityRepo?.cleanup(90)??0,usage:await this.usageRepo?.cleanup(365)??0,expiredMemories:await this.memoryRepo?.cleanupExpired()??0,processedMessages:this.config.cluster?.enabled?await new(await Promise.resolve().then(()=>(Xe(),dt))).ProcessedMessageRepository(this.database.getAdapter()).cleanup():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.clusterManager&&setInterval(async()=>{try{let e=await this.clusterManager.getNodesAny();e.length>0&&this.logger.debug({liveNodes:e.map(t=>t.id)},"Cluster node status")}catch{}},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(()=>(jt(),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.adapterClaimManager?.stop(),this.clusterManager?.stopPgHeartbeat(),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{Fo();let t=new ge().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(te(),re));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(te(),re));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(te(),re));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(te(),re)),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(()=>(te(),re));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(te(),re));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(te(),re));this.skillRegistry.register(new s(t.routing)),this.config.routing=t.routing,this.logger.info("Routing skill hot-reloaded")}if(e==="todo"&&t.todo){let{MicrosoftTodoSkill:s}=await Promise.resolve().then(()=>(te(),re));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}resolveWebUiPath(){let e;try{e=Ge.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Ge.join(process.cwd(),"web-ui"),Ge.join(e,"..","web-ui"),Ge.join(e,"web-ui"),Ge.join(e,"..","..","web-ui"),Ge.join(e,"..","..","apps","web","out")];for(let s of t)try{let r=Ge.resolve(s);if($r.existsSync(Ge.join(r,"index.html")))return this.logger.info({path:r},"Web UI found"),r}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}async 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,i]of Object.entries(r.byModel)){let a=`model="${n}"`;e.push(`alfred_llm_calls_total{${a}} ${i.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,i]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${i.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,i]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${i.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,i]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${i.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 ${await 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 ${await this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),i=await 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 ${i.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 ${i.totalCalls}`)}return e.push(""),e.join(`
2279
- `)}async autoLinkApiUser(e){if(e.platform==="api")try{let t=await this.userRepo.findOrCreate("api",e.userId,e.userName);if(await this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=await this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=await this.userRepo.getMasterUserId(r.id);await 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="",i=p(async u=>{if(u!==n){n=u;try{e==="api"?await t.editMessage(s.chatId,r??"",u):r?await t.editMessage(s.chatId,r,u):r=await t.sendMessage(s.chatId,u)}catch(h){this.logger.debug({err:h,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),a=await this.pipeline.process(s,i),o=new Set(["email","calendar","contacts","bmw","todo","microsoft_todo","database","memory","note","reminder","file","shell"]);if(s.chatType==="group"&&a.usedSkills?.some(u=>o.has(u))&&a.text){try{let u=this.formatter.format(a.text,s.platform),h=u.parseMode!=="text"?{parseMode:u.parseMode}:void 0;if(await t.sendDirectMessage(s.userId,u.text,h)){if(await t.sendMessage(s.chatId,`@${s.userName??s.userId}, Antwort per DM gesendet (pers\xF6nliche Daten).`),a.attachments)for(let f of a.attachments)try{await t.sendDirectMessage(s.userId,f.fileName??"file")}catch{}}else await t.sendMessage(s.chatId,u.text,h)}catch(u){this.logger.warn({err:u,chatId:s.chatId},"Group privacy DM redirect failed, sending in group");let h=this.formatter.format(a.text,s.platform);await t.sendMessage(s.chatId,h.text)}"endStream"in t&&t.endStream(s.chatId);return}if(a.text){let u=this.formatter.format(a.text,s.platform),h=u.parseMode!=="text"?{parseMode:u.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,u.text,h)}catch(m){this.logger.debug({err:m,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,u.text,h)}else await t.sendMessage(s.chatId,u.text,h)}catch(m){this.logger.warn({err:m,chatId:s.chatId},"Formatted send failed, retrying as plain text");let f=this.formatter.format(a.text,"signal");await t.sendMessage(s.chatId,f.text)}}if(a.attachments)for(let u of a.attachments)try{let h=u.mimeType?.startsWith("image/")??!1,m=u.mimeType==="audio/ogg"||u.mimeType==="audio/opus";h?await t.sendPhoto(s.chatId,u.data,u.fileName):m?await t.sendVoice(s.chatId,u.data):await t.sendFile(s.chatId,u.data,u.fileName)}catch(h){this.logger.warn({err:h,fileName:u.fileName,chatId:s.chatId},"Failed to send attachment")}"endStream"in t&&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")}"endStream"in t&&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=Ge.resolve(this.config.security.rulesPath),t=[];if(!$r.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!$r.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=$r.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let i=Ge.join(e,n),a=$r.readFileSync(i,"utf-8"),o=GT.load(a);if(o?.rules&&Array.isArray(o.rules)){let d=new _t().loadFromObject({rules:o.rules});t.push(...d),this.logger.info({file:n,count:d.length},"Loaded security rules")}}catch(i){this.logger.error({err:i,file:n},"Failed to load security rules file")}return t}}});var Sm=w(()=>{"use strict"});var Kl=w(()=>{"use strict";$l();Il()});var bm=w(()=>{"use strict";jl();Xl()});var Gl=w(()=>{"use strict";km();ll();al();dl();ul();pl();fl();gl();Tl();wl();El();Ut();yl();hl();ml();Al();Rl();vl();Sm();bl();Nl();Qn();Ml();kl();Kl();Fl();bm();Bl();Kl();Ll();xl();Cl();Ma();Ol();Ul();Pl()});import Za from"node:fs";import vm from"node:path";import YT from"node:os";function Im(){try{let l=Za.readFileSync(Yl,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Am(l){try{let e=vm.dirname(Yl);Za.existsSync(e)||Za.mkdirSync(e,{recursive:!0}),Za.writeFileSync(Yl,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Ts(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),JT);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function $m(l,e,t){switch(l){case"anthropic":{let s=await Ts("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 Ts(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(i=>({id:i.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await Ts(s);return r.ok?((await r.json()).models??[]).map(i=>({id:i.name.replace(/^models\//,""),name:i.displayName})):[]}case"mistral":{let s=await Ts("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 Ts("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 Ts(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(i=>({id:i.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await Ts(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(i=>({id:i.id})):[]}default:return[]}}async function Vl(l,e,t){let s=Im(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<VT)return r.models;try{let n=await $m(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Am(s),n}catch{}return r?r.models:[]}function Qa(l,e,t){$m(l,e,t).then(s=>{if(s.length>0){let r=Im();r.providers[l]={fetchedAt:Date.now(),models:s},Am(r)}}).catch(()=>{})}function Jl(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(i=>i.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 VT,JT,Yl,Zl=w(()=>{"use strict";VT=1440*60*1e3,JT=5e3,Yl=vm.join(YT.homedir(),".alfred","model-cache.json");p(Im,"readCache");p(Am,"writeCache");p(Ts,"fetchWithTimeout");p($m,"fetchModelsFromAPI");p(Vl,"getModels");p(Qa,"refreshCacheInBackground");p(Jl,"mergeModels")});var Rm={};ie(Rm,{startCommand:()=>ZT});async function ZT(){let l=new ge,e;try{e=l.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let t=Zr("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new ys(e),r=!1,n=p(async i=>{if(!r){r=!0,t.info({signal:i},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(a){t.error({error:a},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",i=>{t.fatal({error:i},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",i=>{t.fatal({reason:i},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let i=e.llm;i?.default?.provider?Qa(i.default.provider,i.default.apiKey,i.default.baseUrl):i?.provider&&Qa(i.provider,void 0,i.baseUrl);for(let a of["strong","fast"]){let o=i?.[a];o?.provider&&Qa(o.provider,o.apiKey,o.baseUrl)}}catch(i){let a=i instanceof Error?i:new Error(String(i));t.fatal({err:a},"Failed to start Alfred"),process.exit(1)}}var Nm=w(()=>{"use strict";ct();Bo();Gl();Zl();p(ZT,"startCommand")});var xm={};ie(xm,{chatCommand:()=>tw});import Lm from"node:http";import mi from"node:readline";function QT(l,e){return new Promise(t=>{let s=Lm.get(`http://${l}:${e}/api/health`,{timeout:2e3},r=>{let n="";r.on("data",i=>{n+=i.toString()}),r.on("end",()=>{try{let i=JSON.parse(n);t(i.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function ew(l,e){let t=mi.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
2278
+ WHERE adapter_claims.expires_at < ? OR adapter_claims.node_id = ?`,[e,this.nodeId,t,s,t,this.nodeId])).changes>0?(this.claimedPlatforms.add(e),!0):await this.adapter.queryOne("SELECT node_id FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])?(this.claimedPlatforms.add(e),!0):!1}start(){this.renewTimer=setInterval(()=>this.renewClaims(),this.claimTtlMs/2),this.checkTimer=setInterval(()=>this.checkExpiredClaims(),15e3)}stop(){this.renewTimer&&clearInterval(this.renewTimer),this.checkTimer&&clearInterval(this.checkTimer),this.releaseClaims().catch(()=>{})}async renewClaims(){if(this.claimedPlatforms.size===0||this.adapter.type==="sqlite")return;let e=new Date(Date.now()+this.claimTtlMs).toISOString();for(let t of this.claimedPlatforms)try{await this.adapter.execute("UPDATE adapter_claims SET expires_at = ? WHERE platform = ? AND node_id = ?",[e,t,this.nodeId])}catch(s){this.logger.warn({err:s,platform:t},"Failed to renew adapter claim")}}knownPlatforms=new Set;registerPlatform(e){this.knownPlatforms.add(e)}async checkExpiredClaims(){if(this.adapter.type!=="sqlite")try{let e=new Date().toISOString();for(let t of this.knownPlatforms){if(this.claimedPlatforms.has(t))continue;let s=await this.adapter.queryOne("SELECT node_id, expires_at FROM adapter_claims WHERE platform = ?",[t]);(!s||s.expires_at<e)&&await this.tryClaim(t)&&(this.logger.info({platform:t,nodeId:this.nodeId},"Acquired adapter claim from dead node"),this.onClaimAcquired?.(t))}}catch(e){this.logger.debug({err:e},"Adapter claim check failed")}}async releaseClaims(){if(this.adapter.type!=="sqlite"){for(let e of this.claimedPlatforms)try{await this.adapter.execute("DELETE FROM adapter_claims WHERE platform = ? AND node_id = ?",[e,this.nodeId])}catch{}this.claimedPlatforms.clear()}}owns(e){return this.claimedPlatforms.has(e)}}});import $r from"node:fs";import Ke from"node:path";import GT from"js-yaml";var ys,km=w(()=>{"use strict";Bo();Be();ct();ac();Qi();ee();al();ll();dl();ul();pl();hl();ml();fl();gl();yl();Tl();wl();El();em();kl();Al();$l();Rl();Nl();Ll();xl();Cl();Ol();Ul();Pl();ys=class{static{p(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new Kn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;clusterManager;adapterClaimManager;webAuthCallback;reminderRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=Zr("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=await lt.create({backend:this.config.storage.backend??"sqlite",path:this.config.storage.path,connectionString:this.config.storage.connectionString});let e=this.database.getAdapter(),t=new Ss(e),s=new bs(e);this.userRepo=s;let r=new xt(e);this.auditRepo=r;let n=new vs(e);this.memoryRepo=n;let i=new Is(e);this.reminderRepo=i;let a=new As(e),o=new $s(e),c=new Rs(e),d=new Ns(e),u=new xs(e);this.scheduledActionRepo=u;let h=new Ot(e);this.activityRepo=h;let m=new ci(h,this.logger.child({component:"activity"})),f=new Fs(e);this.skillHealthRepo=f;let g=new li(f,this.logger.child({component:"skill-health"}),m);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new hn,k=this.loadSecurityRules();y.loadRules(k);let b=new mn(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:k.length},"Security engine initialized");let S=nc(this.config.llm,this.logger.child({component:"llm"}));await S.initialize(),this.llmProvider=S;let I=new Ps(e);this.usageRepo=I,S.setPersist((A,H,F,V,te,Ee)=>{I.record(A,H,F,V,te,Ee).catch(()=>{})});let L=new Gn(S,o,this.logger.child({component:"embeddings"})),D=this.config.activeLearning?.enabled!==!1,W,q;D&&(W=new ri({llm:S,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:L,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),q=new ni(n,this.logger.child({component:"memory-retriever"}),L),this.logger.info("Active learning & memory retriever initialized"));let j=new Us(e);this.summaryRepo=j;let oe=new ii(S,j,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let me=new Ws(this.logger.child({component:"sandbox"})),O=this.skillRegistry=new Hs;O.register(new qs),O.register(new zs),O.register(new Ks(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),O.register(new Gs(i));let ue=new Ys(a);O.register(ue);let he=new Os(e),ye=new fr(he);if(O.register(ye),O.register(new Vs),O.register(new Js),O.register(new Zs(n,L)),O.register(new Qs(S,O,me,b)),this.config.email?.accounts?.length){let A=new Map;for(let F of this.config.email.accounts)try{F.provider==="microsoft"&&!F.microsoft?.clientId&&this.config.calendar?.microsoft&&(F.microsoft={...this.config.calendar.microsoft});let V=await er(F);A.set(F.name,V),this.logger.info({account:F.name,provider:F.provider??"imap-smtp"},"Email account initialized")}catch(V){this.logger.warn({err:V,account:F.name},"Email account initialization failed, skipping")}let H=A.size>0?new Dt(A):new Dt;H.setLLM(S),O.register(H)}else{let A=new Dt;A.setLLM(S),O.register(A)}O.register(new tr),O.register(new sr);let $e=new wr;$e.setReloadCallback(A=>this.reloadService(A)),O.register($e),O.register(new nr),O.register(new ir),O.register(new ar),O.register(new or(s)),O.register(new lr(s,c,this.adapters,(A,H)=>t.findByPlatformAndUser(A,H)));let pe=new dr(d);O.register(pe),O.register(new ur(u));let z=new Cs(e),ce=new Yn(z,L,this.logger.child({component:"documents"})),Ge=new pr(z,ce,L);O.register(Ge);let Te,Re;if(this.config.calendar)try{Re=await cr(this.config.calendar),Te=new cs(Re),O.register(Te),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(A){this.logger.warn({err:A},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Te,Re&&this.config.calendar?.vorlauf?.enabled){let A=new Ct(e),H=this.config.security?.ownerUserId;H&&(this.calendarWatcher=new ai(Re,A,this.adapters,H,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),m))}{let A=this.config.security?.ownerUserId;if(A){let H=new Ct(e);this.todoWatcher=new oi(he,H,this.adapters,A,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),m,A)}}if(this.config.mcp?.servers?.length){let{MCPManager:A}=await Promise.resolve().then(()=>(ee(),re));this.mcpManager=new A(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let H of this.mcpManager.getSkills())O.register(H);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},S)),this.logger.info({agents:this.config.codeAgents.agents.map(H=>H.name)},"Code agent skill enabled")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:A}=await Promise.resolve().then(()=>(ee(),re)),{ProjectAgentSessionRepository:H}=await Promise.resolve().then(()=>(Be(),dt)),F=new H(e),V=new A({...this.config.projectAgents,agents:this.config.codeAgents.agents},S,F),{ProjectAgentRunner:te}=await Promise.resolve().then(()=>(Fl(),nm)),Ee=new te(new Map(this.config.codeAgents.agents.map(Ye=>[Ye.name,Ye])),S,F,this.adapters,this.logger.child({component:"project-agent"}));V.setRunner(Ee),O.register(V),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:A,createContactsProvider:H}=await Promise.resolve().then(()=>(ee(),re)),F=await H(this.config.contacts);O.register(new A(F)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(A){this.logger.warn({err:A},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(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:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A({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:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(O,this.config,n)),this.logger.info("Briefing skill registered")}O.register(new kr(n)),this.logger.info("Feed reader skill registered");let Me=new Sr(O);O.register(Me);{let{AlfredUserRepository:A}=await Promise.resolve().then(()=>(Be(),dt)),{UserManagementSkill:H}=await Promise.resolve().then(()=>(ee(),re)),F=new A(e);if(this.config.security?.ownerUserId){let Pe=this.config.security.ownerUserId,Ve=(await F.getAll()).filter(Nr=>Nr.role==="admin")[0];Ve||(Ve=await F.create({username:"admin",role:"admin",displayName:"Admin"}),await F.clearInviteCode(Ve.id),this.logger.info({userId:Pe},"Auto-created admin user from ownerUserId"));let Ht=["telegram","discord","matrix","signal","api"];for(let Nr of Ht)if(!await F.getUserByPlatform(Nr,Pe))try{await F.linkPlatform(Ve.id,Nr,Pe)}catch{}}O.register(new H(F)),this.logger.info("User management skill registered");let{SharingSkill:V}=await Promise.resolve().then(()=>(ee(),re)),{SharedResourceRepository:te}=await Promise.resolve().then(()=>(Be(),dt)),Ee=new te(e);O.register(new V(Ee,F)),Ge.sharedResourceRepo=Ee,ue.sharedResourceRepo=Ee,ye.sharedResourceRepo=Ee,this.logger.info("Sharing skill registered");let Ye=c;this.webAuthCallback={loginWithCode:p(async Pe=>{let $t=`web-pending-${Date.now()}`,Ne=await F.consumeInviteCode(Pe,"api",$t);if(!Ne)return{success:!1,error:"Ung\xFCltiger oder abgelaufener Code"};let Ve=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,Ht=new Date(Date.now()+720*60*6e4).toISOString();return await Ye.createSession(Ve,Ne.id,"web-session",Ht),{success:!0,userId:Ne.id,username:Ne.username,role:Ne.role,token:Ve}},"loginWithCode"),getUserByToken:p(async Pe=>{let $t=await Ye.findByToken(Pe);if(!$t||new Date($t.expiresAt)<new Date)return null;let Ne=await F.getById($t.userId);return Ne?{userId:Ne.id,username:Ne.username,role:Ne.role}:null},"getUserByToken")}}if(this.config.database?.enabled){let{DatabaseSkill:A}=await Promise.resolve().then(()=>(ee(),re)),{DatabaseConnectionRepository:H}=await Promise.resolve().then(()=>(Be(),dt)),F=new H(e),V=new A(this.config.database,F);if(this.config.database.connections)for(let te of this.config.database.connections)await F.getByName(te.name)||await F.create({name:te.name,type:te.type,host:te.host,port:te.port,databaseName:te.database,username:te.username,authConfig:te.password?{password:te.password}:void 0,options:{readOnly:te.options?.readOnly??!0,rowLimit:te.options?.rowLimit,timeoutMs:te.options?.timeoutMs}});O.register(V),this.logger.info("Database skill registered")}if(this.config.youtube?.apiKey){let{YouTubeSkill:A}=await Promise.resolve().then(()=>(ee(),re));O.register(new A(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:O.getAll().map(A=>A.metadata.name)},"Skills registered");let Ue;if(this.config.speech?.apiKey&&(Ue=new Hn(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 A=new Wn(this.config.speech,this.logger.child({component:"tts"}));O.register(new hr(A)),this.logger.info("Text-to-speech skill registered")}let pt=this.detectImageGenProvider();if(pt){let A=new qn(pt,this.logger.child({component:"image-gen"}));O.register(new mr(A)),this.logger.info({provider:pt.provider},"Image generation skill registered")}try{let A=new zn(this.logger.child({component:"transit"}));O.register(new yr(A)),this.logger.info("Public transit skill registered")}catch(A){this.logger.warn({err:A},"Failed to register transit skill")}let It;if(this.config.fileStore){let{createFileStore:A}=await Promise.resolve().then(()=>(Be(),dt));It=A(this.config.fileStore),this.logger.info({backend:this.config.fileStore.backend},"File store initialized")}let ht=new jn(t),Xt=Ke.resolve(Ke.dirname(this.config.storage.path),"inbox");if(this.pipeline=new Bn({llm:S,conversationManager:ht,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:O,skillSandbox:me,securityManager:b,memoryRepo:n,speechTranscriber:Ue,inboxPath:Xt,fileStore:It,processedMessageRepo:this.config.cluster?.enabled?new(await Promise.resolve().then(()=>(Be(),dt))).ProcessedMessageRepository(e):void 0,nodeId:this.config.cluster?.nodeId??"single",embeddingService:L,activeLearning:W,memoryRetriever:q,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:ce,conversationSummarizer:oe}),this.config.cluster?.enabled){if(e.type!=="postgres")throw new Error('HA Cluster erfordert storage.backend: "postgres". SQLite ist nicht f\xFCr Multi-Node geeignet.');if(!this.config.cluster.nodeId)throw new Error("HA Cluster erfordert cluster.nodeId. Jeder Node braucht eine eindeutige ID.");(!this.config.fileStore||this.config.fileStore.backend==="local")&&this.logger.warn('HA Cluster ohne S3/NFS FileStore \u2014 Datei-Uploads sind nur auf dem empfangenden Node sichtbar. Empfohlen: fileStore.backend: "s3" oder "nfs"');let{ClusterManager:A}=await Promise.resolve().then(()=>(jl(),im));this.clusterManager=new A(this.config.cluster,this.logger.child({component:"cluster"})),await this.clusterManager.connect(),this.clusterManager.isConnected||this.logger.warn("Redis nicht erreichbar \u2014 Cross-Node Pub/Sub und Echtzeit-Heartbeat deaktiviert. PG-Heartbeat als Fallback aktiv.");let{PgMigrator:H,PG_MIGRATIONS:F}=await Promise.resolve().then(()=>(Be(),dt));await new H(e).migrate(F),this.clusterManager.startPgHeartbeat(e),this.logger.info({nodeId:this.config.cluster.nodeId},"Cluster manager initialized (Active-Active)")}this.reminderScheduler=new Xn(i,async(A,H,F)=>{let V=this.adapters.get(A);V?await V.sendMessage(H,F):this.logger.warn({platform:A,chatId:H},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:p(A=>s.getMasterUserId(A),"getMasterUserId"),getLinkedUsers:p(A=>s.getLinkedUsers(A),"getLinkedUsers"),findConversation:p((A,H)=>t.findByPlatformAndUser(A,H),"findConversation")},this.config.cluster?.nodeId??"single"),this.backgroundTaskRunner=new Vn(O,me,d,this.adapters,s,this.logger.child({component:"background-tasks"}),m,g);let mt=new Jn(O,me,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),m);this.backgroundTaskRunner.setPersistentRunner(mt),pe.setPersistentRunner(mt),this.proactiveScheduler=new Zn(u,O,me,S,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,ht,m,this.config.cluster?.nodeId??"single");let we=new Ds(e);this.watchRepo=we,O.register(new Er(we,O));let Ce=new Ms(e);this.confirmationQueue=new ti(Ce,O,me,this.adapters,this.logger.child({component:"confirmation-queue"}),m);let At=new Bs(e),ot=new Ar(At,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(ot),W&&W.setFeedbackService(ot),this.watchEngine=new Ua(we,O,me,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,m,g,S,this.config.cluster?.nodeId??"single");let K=new js(e),Y=new _r(K);O.register(Y);let le=new di(K,O,me,this.logger.child({component:"workflow-runner"}),m,g);Y.setRunner(le);{let A=this.config.security?.ownerUserId;if(A&&this.config.reasoning?.enabled!==!1){let H=new Ct(e);this.reasoningEngine=new pi(Re,he,we,n,h,f,H,O,me,S,this.adapters,s,A,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),m,this.config.briefing?.location,At,this.confirmationQueue,this.config.cluster?.nodeId??"single",e)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(m),this.pipeline.setSkillHealthTracker(g);{let{AlfredUserRepository:A,UsageRepository:H}=await Promise.resolve().then(()=>(Be(),dt)),{ROLE_SKILL_ACCESS:F}=await Promise.resolve().then(()=>(ee(),re)),V=new A(e),{UserServiceResolver:te}=await Promise.resolve().then(()=>(Bl(),am)),Ee=new te(V);this.pipeline.setAlfredUserRepo(V,F,this.usageRepo,Ee),Me.roleAccess=F}if(this.clusterManager&&(await this.clusterManager.subscribe("messages",A=>{let{targetPlatform:H,chatId:F,text:V}=A,te=this.adapters.get(H);te&&te.sendMessage(F,V).catch(Ee=>{this.logger.warn({err:Ee,targetPlatform:H,chatId:F},"Cross-node message delivery failed")})}),this.config.cluster)){let{ClusterDiscovery:A}=await Promise.resolve().then(()=>(Xl(),lm));new A(this.logger.child({component:"cluster-discovery"})).startBroadcasting({nodeId:this.config.cluster.nodeId,host:"0.0.0.0",port:this.config.api?.port??3420,role:this.config.cluster?.role??"node"})}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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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(()=>(jt(),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,tls:e.api?.tls,authCallback:this.webAuthCallback,healthCheck:p(async()=>{let n;try{let i=this.config.storage.path,a=$r.statSync(i);n={path:i,sizeBytes:a.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([i,a])=>[i,a.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:await this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:await this.watchRepo?.countEnabled()??0,schedulersActive:await this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:p(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:p(async()=>{let n=new Date().toISOString().slice(0,10),i=new Date(Date.now()-10080*6e4).toISOString().slice(0,10);return{watches:await this.watchRepo?.getEnabled()??[],scheduled:await this.scheduledActionRepo?.getAll()??[],skillHealth:await this.skillHealthRepo?.getAll()??[],reminders:await this.reminderRepo?.getAllPending()??[],usage:{today:await this.usageRepo?.getDaily(n)??null,week:await this.usageRepo?.getRange(i,n)??[],total:await this.usageRepo?.getTotal()??[]},uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters.entries()].map(([a,o])=>[a,o.getStatus()])),llmProviders:this.llmProvider.getProviderStatuses(),userUsage:await this.usageRepo?.getByUser(i,n)??[],userSkillUsage:await this.activityRepo?.skillUsageByUser(i)??[]}},"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(){if(this.logger.info("Starting Alfred..."),this.config.cluster?.enabled&&this.database.getAdapter().type==="postgres"){let{AdapterClaimManager:e}=await Promise.resolve().then(()=>(_m(),Em));this.adapterClaimManager=new e(this.database.getAdapter(),this.config.cluster.nodeId,this.logger.child({component:"adapter-claims"}));for(let[t,s]of this.adapters){if(t==="api"){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected (always-on)")}catch(n){this.logger.error({platform:t,err:n},"Adapter connection failed")}continue}if(this.adapterClaimManager.registerPlatform(t),await this.adapterClaimManager.tryClaim(t)){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected (claimed)")}catch(n){this.logger.error({platform:t,err:n},"Adapter connection failed")}}else this.logger.info({platform:t},"Adapter claimed by another node, skipping")}this.adapterClaimManager.onAcquired(async t=>{let s=this.adapters.get(t);if(s&&s.getStatus()==="disconnected"){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected (failover)")}catch(r){this.logger.error({platform:t,err:r},"Failover adapter connection failed")}}}),this.adapterClaimManager.start()}else for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:p(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let i=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,i)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:await this.auditRepo?.cleanup(90)??0,summaries:await this.summaryRepo?.cleanup(180)??0,activity:await this.activityRepo?.cleanup(90)??0,usage:await this.usageRepo?.cleanup(365)??0,expiredMemories:await this.memoryRepo?.cleanupExpired()??0,processedMessages:this.config.cluster?.enabled?await new(await Promise.resolve().then(()=>(Be(),dt))).ProcessedMessageRepository(this.database.getAdapter()).cleanup():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.clusterManager&&setInterval(async()=>{try{let e=await this.clusterManager.getNodesAny();e.length>0&&this.logger.debug({liveNodes:e.map(t=>t.id)},"Cluster node status")}catch{}},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(()=>(jt(),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.adapterClaimManager?.stop(),this.clusterManager?.stopPgHeartbeat(),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{Fo();let t=new ge().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(ee(),re));this.skillRegistry.register(new s(t.proxmox)),this.config.proxmox=t.proxmox,this.logger.info({baseUrl:t.proxmox.baseUrl},"Proxmox skill hot-reloaded")}if(e==="unifi"&&t.unifi){let{UniFiSkill:s}=await Promise.resolve().then(()=>(ee(),re));this.skillRegistry.register(new s(t.unifi)),this.config.unifi=t.unifi,this.logger.info({baseUrl:t.unifi.baseUrl},"UniFi skill hot-reloaded")}if(e==="homeassistant"&&t.homeassistant){let{HomeAssistantSkill:s}=await Promise.resolve().then(()=>(ee(),re));this.skillRegistry.register(new s(t.homeassistant)),this.config.homeassistant=t.homeassistant,this.logger.info({baseUrl:t.homeassistant.baseUrl},"Home Assistant skill hot-reloaded")}if(e==="contacts"&&t.contacts){let{ContactsSkill:s,createContactsProvider:r}=await Promise.resolve().then(()=>(ee(),re)),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(()=>(ee(),re));this.skillRegistry.register(new s(t.docker)),this.config.docker=t.docker,this.logger.info("Docker skill hot-reloaded")}if(e==="bmw"&&t.bmw){let{BMWSkill:s}=await Promise.resolve().then(()=>(ee(),re));this.skillRegistry.register(new s(t.bmw)),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(ee(),re));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(()=>(ee(),re));this.skillRegistry.register(new s(t.todo)),this.config.todo=t.todo,this.logger.info("Microsoft To Do skill hot-reloaded")}return{success:!0}}catch(t){let s=t instanceof Error?t.message:String(t);return this.logger.error({err:t,service:e},"Failed to hot-reload service"),{success:!1,error:s}}}resolveWebUiPath(){let e;try{e=Ke.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Ke.join(process.cwd(),"web-ui"),Ke.join(e,"..","web-ui"),Ke.join(e,"web-ui"),Ke.join(e,"..","..","web-ui"),Ke.join(e,"..","..","apps","web","out")];for(let s of t)try{let r=Ke.resolve(s);if($r.existsSync(Ke.join(r,"index.html")))return this.logger.info({path:r},"Web UI found"),r}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}async 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,i]of Object.entries(r.byModel)){let a=`model="${n}"`;e.push(`alfred_llm_calls_total{${a}} ${i.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,i]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${i.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,i]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${i.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,i]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${i.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 ${await 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 ${await this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),i=await 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 ${i.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 ${i.totalCalls}`)}return e.push(""),e.join(`
2279
+ `)}async autoLinkApiUser(e){if(e.platform==="api")try{let t=await this.userRepo.findOrCreate("api",e.userId,e.userName);if(await this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=await this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=await this.userRepo.getMasterUserId(r.id);await 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="",i=p(async u=>{if(u!==n){n=u;try{e==="api"?await t.editMessage(s.chatId,r??"",u):r?await t.editMessage(s.chatId,r,u):r=await t.sendMessage(s.chatId,u)}catch(h){this.logger.debug({err:h,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),a=await this.pipeline.process(s,i),o=new Set(["email","calendar","contacts","bmw","todo","microsoft_todo","database","memory","note","reminder","file","shell"]);if(s.chatType==="group"&&a.usedSkills?.some(u=>o.has(u))&&a.text){try{let u=this.formatter.format(a.text,s.platform),h=u.parseMode!=="text"?{parseMode:u.parseMode}:void 0;if(await t.sendDirectMessage(s.userId,u.text,h)){if(await t.sendMessage(s.chatId,`@${s.userName??s.userId}, Antwort per DM gesendet (pers\xF6nliche Daten).`),a.attachments)for(let f of a.attachments)try{await t.sendDirectMessage(s.userId,f.fileName??"file")}catch{}}else await t.sendMessage(s.chatId,u.text,h)}catch(u){this.logger.warn({err:u,chatId:s.chatId},"Group privacy DM redirect failed, sending in group");let h=this.formatter.format(a.text,s.platform);await t.sendMessage(s.chatId,h.text)}"endStream"in t&&t.endStream(s.chatId);return}if(a.text){let u=this.formatter.format(a.text,s.platform),h=u.parseMode!=="text"?{parseMode:u.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,u.text,h)}catch(m){this.logger.debug({err:m,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,u.text,h)}else await t.sendMessage(s.chatId,u.text,h)}catch(m){this.logger.warn({err:m,chatId:s.chatId},"Formatted send failed, retrying as plain text");let f=this.formatter.format(a.text,"signal");await t.sendMessage(s.chatId,f.text)}}if(a.attachments)for(let u of a.attachments)try{let h=u.mimeType?.startsWith("image/")??!1,m=u.mimeType==="audio/ogg"||u.mimeType==="audio/opus";h?await t.sendPhoto(s.chatId,u.data,u.fileName):m?await t.sendVoice(s.chatId,u.data):await t.sendFile(s.chatId,u.data,u.fileName)}catch(h){this.logger.warn({err:h,fileName:u.fileName,chatId:s.chatId},"Failed to send attachment")}"endStream"in t&&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")}"endStream"in t&&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=Ke.resolve(this.config.security.rulesPath),t=[];if(!$r.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!$r.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=$r.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let i=Ke.join(e,n),a=$r.readFileSync(i,"utf-8"),o=GT.load(a);if(o?.rules&&Array.isArray(o.rules)){let d=new _t().loadFromObject({rules:o.rules});t.push(...d),this.logger.info({file:n,count:d.length},"Loaded security rules")}}catch(i){this.logger.error({err:i,file:n},"Failed to load security rules file")}return t}}});var Sm=w(()=>{"use strict"});var Kl=w(()=>{"use strict";$l();Il()});var bm=w(()=>{"use strict";jl();Xl()});var Gl=w(()=>{"use strict";km();ll();al();dl();ul();pl();fl();gl();Tl();wl();El();Ut();yl();hl();ml();Al();Rl();vl();Sm();bl();Nl();Qn();Ml();kl();Kl();Fl();bm();Bl();Kl();Ll();xl();Cl();Ma();Ol();Ul();Pl()});import Za from"node:fs";import vm from"node:path";import YT from"node:os";function Im(){try{let l=Za.readFileSync(Yl,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function Am(l){try{let e=vm.dirname(Yl);Za.existsSync(e)||Za.mkdirSync(e,{recursive:!0}),Za.writeFileSync(Yl,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Ts(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),JT);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function $m(l,e,t){switch(l){case"anthropic":{let s=await Ts("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 Ts(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(i=>({id:i.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await Ts(s);return r.ok?((await r.json()).models??[]).map(i=>({id:i.name.replace(/^models\//,""),name:i.displayName})):[]}case"mistral":{let s=await Ts("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 Ts("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 Ts(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(i=>({id:i.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await Ts(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(i=>({id:i.id})):[]}default:return[]}}async function Vl(l,e,t){let s=Im(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<VT)return r.models;try{let n=await $m(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},Am(s),n}catch{}return r?r.models:[]}function Qa(l,e,t){$m(l,e,t).then(s=>{if(s.length>0){let r=Im();r.providers[l]={fetchedAt:Date.now(),models:s},Am(r)}}).catch(()=>{})}function Jl(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(i=>i.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 VT,JT,Yl,Zl=w(()=>{"use strict";VT=1440*60*1e3,JT=5e3,Yl=vm.join(YT.homedir(),".alfred","model-cache.json");p(Im,"readCache");p(Am,"writeCache");p(Ts,"fetchWithTimeout");p($m,"fetchModelsFromAPI");p(Vl,"getModels");p(Qa,"refreshCacheInBackground");p(Jl,"mergeModels")});var Rm={};ie(Rm,{startCommand:()=>ZT});async function ZT(){let l=new ge,e;try{e=l.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let t=Zr("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new ys(e),r=!1,n=p(async i=>{if(!r){r=!0,t.info({signal:i},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(a){t.error({error:a},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",i=>{t.fatal({error:i},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",i=>{t.fatal({reason:i},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let i=e.llm;i?.default?.provider?Qa(i.default.provider,i.default.apiKey,i.default.baseUrl):i?.provider&&Qa(i.provider,void 0,i.baseUrl);for(let a of["strong","fast"]){let o=i?.[a];o?.provider&&Qa(o.provider,o.apiKey,o.baseUrl)}}catch(i){let a=i instanceof Error?i:new Error(String(i));t.fatal({err:a},"Failed to start Alfred"),process.exit(1)}}var Nm=w(()=>{"use strict";ct();Bo();Gl();Zl();p(ZT,"startCommand")});var xm={};ie(xm,{chatCommand:()=>tw});import Lm from"node:http";import mi from"node:readline";function QT(l,e){return new Promise(t=>{let s=Lm.get(`http://${l}:${e}/api/health`,{timeout:2e3},r=>{let n="";r.on("data",i=>{n+=i.toString()}),r.on("end",()=>{try{let i=JSON.parse(n);t(i.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function ew(l,e){let t=mi.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
2280
2280
  Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
2281
2281
  `),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
2282
2282
  Goodbye!
@@ -2291,56 +2291,56 @@ Error: ${m.text??"Unknown error"}
2291
2291
  `),t.prompt();break}}catch{}}}),a.on("end",()=>{if(o.length>0){let c=o.split(`
2292
2292
  `).find(d=>d.startsWith("data: "));if(c)try{let d=JSON.parse(c.slice(6));(d.type==="done"||d.type==="error")&&t.prompt()}catch{}}}),a.on("error",c=>{console.error(`
2293
2293
  Connection error: ${c.message}`),t.prompt()})});i.on("error",a=>{console.error(`
2294
- Failed to send message: ${a.message}`),t.prompt()}),i.write(n),i.end()}),t.on("close",()=>{process.exit(0)})}async function tw(l){let e=new ge,t;try{t=e.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let s=t.api?.host??"127.0.0.1",r=t.api?.port??3420;if(await QT(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),ew(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let a=t.llm[l.tier];a?t.llm.default=a:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let i=new ys(t);try{await i.initialize(),await i.startWithCLI()}catch(a){console.error("Failed to start chat:",a.message),process.exit(1)}}var Cm=w(()=>{"use strict";ct();Gl();p(QT,"checkHealth");p(ew,"startClientMode");p(tw,"chatCommand")});var Um={};ie(Um,{setupCommand:()=>uw});import{createInterface as sw}from"node:readline/promises";import{stdin as rw,stdout as nw}from"node:process";import{execFileSync as iw}from"node:child_process";import Ae from"node:fs";import aw from"node:os";import Me from"node:path";import Ql from"js-yaml";function M(l){return`${eo}${l}${v}`}function Om(l){return`${P}${l}${v}`}function fe(l){return`${to}${l}${v}`}function Mm(l){return`${ow}${l}${v}`}function x(l){return`${Y}${l}${v}`}function E(l){return`${Bt}${l}${v}`}function Ie(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function lw(l){let e=process.platform==="win32",t=e?"where":"which";try{let n=iw(t,[l],{stdio:"pipe"}).toString().trim();if(n)return n.split(/\r?\n/)[0]}catch{}let s=aw.homedir(),r=e?[Me.join(s,".local","bin",`${l}.exe`),Me.join(s,"AppData","Roaming","npm",`${l}.cmd`),Me.join(s,"AppData","Roaming","npm",`${l}`)]:[Me.join(s,".local","bin",l),"/usr/local/bin/"+l,"/opt/homebrew/bin/"+l,Me.join(s,".npm-global","bin",l)];for(let n of r)try{return Ae.accessSync(n,Ae.constants.X_OK),n}catch{}return null}function dw(l){let e={},t={},s=!1,r=!1,n=30,i=Me.join(l,"config","default.yml");if(Ae.existsSync(i))try{let m=Ql.load(Ae.readFileSync(i,"utf-8"));m&&typeof m=="object"&&Object.assign(e,m)}catch{}let a=Me.join(l,".env");if(Ae.existsSync(a))try{let m=Ae.readFileSync(a,"utf-8").split(`
2295
- `);for(let f of m){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 o=Me.join(l,"config","rules","default-rules.yml");if(Ae.existsSync(o))try{let m=Ql.load(Ae.readFileSync(o,"utf-8"));if(m?.rules){s=m.rules.some(y=>y.id==="allow-owner-admin"&&y.effect==="allow"),m.rules.find(y=>y.id==="allow-write-for-dm"||y.id==="allow-write-all")?.id==="allow-write-all"&&(r=!0);let g=m.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,h={};if(u){for(let m of["strong","fast","embeddings","local"])u[m]?.provider&&u[m]?.model&&(h[m]=u[m]);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:h}}async function uw(){let l=sw({input:rw,output:nw}),e=process.cwd(),t=dw(e),s=Object.keys(t.config).length>0;try{pw(),console.log(s?`${to}Existing configuration found \u2014 press Enter to keep current values.${v}
2294
+ Failed to send message: ${a.message}`),t.prompt()}),i.write(n),i.end()}),t.on("close",()=>{process.exit(0)})}async function tw(l){let e=new ge,t;try{t=e.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let s=t.api?.host??"127.0.0.1",r=t.api?.port??3420;if(await QT(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),ew(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let a=t.llm[l.tier];a?t.llm.default=a:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let i=new ys(t);try{await i.initialize(),await i.startWithCLI()}catch(a){console.error("Failed to start chat:",a.message),process.exit(1)}}var Cm=w(()=>{"use strict";ct();Gl();p(QT,"checkHealth");p(ew,"startClientMode");p(tw,"chatCommand")});var Um={};ie(Um,{setupCommand:()=>uw});import{createInterface as sw}from"node:readline/promises";import{stdin as rw,stdout as nw}from"node:process";import{execFileSync as iw}from"node:child_process";import Ae from"node:fs";import aw from"node:os";import De from"node:path";import Ql from"js-yaml";function M(l){return`${eo}${l}${v}`}function Om(l){return`${U}${l}${v}`}function fe(l){return`${to}${l}${v}`}function Mm(l){return`${ow}${l}${v}`}function x(l){return`${G}${l}${v}`}function E(l){return`${Bt}${l}${v}`}function Ie(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function lw(l){let e=process.platform==="win32",t=e?"where":"which";try{let n=iw(t,[l],{stdio:"pipe"}).toString().trim();if(n)return n.split(/\r?\n/)[0]}catch{}let s=aw.homedir(),r=e?[De.join(s,".local","bin",`${l}.exe`),De.join(s,"AppData","Roaming","npm",`${l}.cmd`),De.join(s,"AppData","Roaming","npm",`${l}`)]:[De.join(s,".local","bin",l),"/usr/local/bin/"+l,"/opt/homebrew/bin/"+l,De.join(s,".npm-global","bin",l)];for(let n of r)try{return Ae.accessSync(n,Ae.constants.X_OK),n}catch{}return null}function dw(l){let e={},t={},s=!1,r=!1,n=30,i=De.join(l,"config","default.yml");if(Ae.existsSync(i))try{let m=Ql.load(Ae.readFileSync(i,"utf-8"));m&&typeof m=="object"&&Object.assign(e,m)}catch{}let a=De.join(l,".env");if(Ae.existsSync(a))try{let m=Ae.readFileSync(a,"utf-8").split(`
2295
+ `);for(let f of m){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 o=De.join(l,"config","rules","default-rules.yml");if(Ae.existsSync(o))try{let m=Ql.load(Ae.readFileSync(o,"utf-8"));if(m?.rules){s=m.rules.some(y=>y.id==="allow-owner-admin"&&y.effect==="allow"),m.rules.find(y=>y.id==="allow-write-for-dm"||y.id==="allow-write-all")?.id==="allow-write-all"&&(r=!0);let g=m.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,h={};if(u){for(let m of["strong","fast","embeddings","local"])u[m]?.provider&&u[m]?.model&&(h[m]=u[m]);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:h}}async function uw(){let l=sw({input:rw,output:nw}),e=process.cwd(),t=dw(e),s=Object.keys(t.config).length>0;try{pw(),console.log(s?`${to}Existing configuration found \u2014 press Enter to keep current values.${v}
2296
2296
  ${Bt}Only change what you need to update.${v}
2297
2297
  `:`${to}Welcome to the Alfred setup wizard!${v}
2298
2298
  ${Bt}This will walk you through configuring your AI assistant.${v}
2299
2299
  ${Bt}Press Enter to accept defaults shown in [brackets].${v}
2300
2300
  `);let r=await B(l,"What should your bot be called?",t.config.name??"Alfred"),n=t.config.llm?.provider?vt.findIndex(_=>_.name===t.config.llm?.provider):-1,i=n>=0?n+1:1;console.log(`
2301
- ${x("Which LLM provider would you like to use?")}`);for(let _=0;_<vt.length;_++){let $=_===n?` ${E("(current)")}`:"";console.log(` ${fe(String(_+1)+")")} ${vt[_].label}${$}`)}let a=await fi(l,"> ",1,vt.length,i),o=vt[a-1];console.log(` ${M(">")} Selected: ${x(o.label)}`);let c="",d=t.env[o.envKeyName]??"";o.needsApiKey&&(console.log(""),d?c=await B(l,`${o.name.charAt(0).toUpperCase()+o.name.slice(1)} API key`,d):c=await ze(l,`Enter your ${o.name.charAt(0).toUpperCase()+o.name.slice(1)} API key`),console.log(` ${M(">")} API key set: ${E(Ie(c))}`));let u=o.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(o.name)){let $=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||o.baseUrl||"";if($){let C={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,C[o.name]??"API Base URL",$.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${M(">")} URL: ${E(u)}`)}}let m=t.config.llm?.model??o.defaultModel;console.log("");let f,g=await Vl(o.name,c,u),y=Jl(g,o.models??[]);if(y.length>0){console.log(`${x("Available models:")}`);for(let C=0;C<y.length;C++){let Z=y[C],F=Z.desc??Z.name??"",J=Z.id===m?` ${M("(current)")}`:"";console.log(` ${fe(`${C+1})`)} ${Z.id}${F?` ${E(`\u2014 ${F}`)}`:""}${J}`)}console.log(` ${fe(`${y.length+1})`)} ${E("Other (enter manually)")}`);let _=await B(l,"Choose model","1"),$=parseInt(_,10)-1;$>=0&&$<y.length?f=y[$].id:f=await B(l,"Model ID",m)}else f=await B(l,"Which model?",m);let k=Object.keys(t.multiModelTiers).length>0,b=k?"Y/n":"y/N";console.log(`
2302
- ${x("Configure additional model tiers for specialized tasks?")}`),console.log(`${E("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let S=(await l.question(`${P}> ${v}${E(`[${b}] `)}`)).trim().toLowerCase(),I=S===""?k:S==="y"||S==="yes",L={};if(I){let _=[{key:"strong",label:"Strong",hint:"complex reasoning, coding, long documents",defaultModel:"claude-opus-4-20250514"},{key:"fast",label:"Fast",hint:"quick responses, simple tasks",defaultModel:"claude-haiku-4-5-20251001"},{key:"embeddings",label:"Embeddings",hint:"semantic search & memory",defaultModel:"text-embedding-3-small"},{key:"local",label:"Local",hint:"offline fallback via Ollama",defaultModel:"llama3.2"}];for(let $ of _){let C=t.multiModelTiers[$.key],Z=!!C?.model;console.log(`
2303
- ${x(`${$.label} model`)} ${E(`(${$.hint})`)}`),Z&&console.log(` ${E(`Current: ${C.provider}/${C.model}`)}`);let F=C?.provider??o.name,J=vt.map(Be=>Be.name).join(", ");console.log(` ${E(`Providers: ${J}`)}`);let xe=(await l.question(` ${P}Provider: ${v}${E(`[${F}] `)}`)).trim()||F;if(!xe&&!Z){console.log(` ${E("Skipped.")}`);continue}let ne=xe,Ce,Qe;if(ne!==o.name){let Be=C?.apiKey??t.env[`ALFRED_LLM_${$.key.toUpperCase()}_API_KEY`]??"";if(Be?Ce=await B(l,` API key for ${ne}`,Be):(vt.find(yt=>yt.name===ne)?.needsApiKey??!0)&&(Ce=await ze(l,` API key for ${ne}`)),["ollama","openwebui"].includes(ne)){let yt=(C?.baseUrl??"")||vt.find(Fi=>Fi.name===ne)?.baseUrl||"";yt&&(Qe=await B(l,` ${ne} URL`,yt))}}let ts=Ce??(ne===o.name?c:void 0),Jr=Qe??(ne===o.name?u:void 0),xo=vt.find(Be=>Be.name===ne),Co=await Vl(ne,ts,Jr),Lt=Jl(Co,xo?.models??[]),gt;if(Lt.length>0){console.log(` ${x("Available models:")}`);for(let ks=0;ks<Lt.length;ks++){let yt=Lt[ks],Fi=yt.desc??yt.name??"",xf=yt.id===C?.model?` ${M("(current)")}`:"";console.log(` ${fe(`${ks+1})`)} ${yt.id}${Fi?` ${E(`\u2014 ${Fi}`)}`:""}${xf}`)}console.log(` ${fe(`${Lt.length+1})`)} ${E("Other (enter manually)")}`),console.log(` ${fe("0)")} ${E("Skip this tier")}`);let Be=(await l.question(` ${P}> ${v}${Z?E(`[${C.model}] `):""}`)).trim();if(Be==="0"){console.log(` ${E("Skipped.")}`);continue}let Pi=parseInt(Be,10)-1;Pi>=0&&Pi<Lt.length?gt=Lt[Pi].id:!Be&&Z?gt=C.model:gt=await B(l," Model ID",Z?C.model:$.defaultModel)}else if(console.log(` ${E("Press Enter to skip.")}`),gt=(await l.question(` ${P}Model: ${v}${Z?E(`[${C.model}] `):""}`)).trim()||(Z?C.model:""),!gt){console.log(` ${E("Skipped.")}`);continue}L[$.key]={provider:ne,model:gt,...Ce?{apiKey:Ce}:{},...Qe?{baseUrl:Qe}:{}},console.log(` ${M(">")} ${$.label}: ${x(ne)}/${x(gt)}`)}Object.keys(L).length===0&&console.log(`
2301
+ ${x("Which LLM provider would you like to use?")}`);for(let _=0;_<vt.length;_++){let $=_===n?` ${E("(current)")}`:"";console.log(` ${fe(String(_+1)+")")} ${vt[_].label}${$}`)}let a=await fi(l,"> ",1,vt.length,i),o=vt[a-1];console.log(` ${M(">")} Selected: ${x(o.label)}`);let c="",d=t.env[o.envKeyName]??"";o.needsApiKey&&(console.log(""),d?c=await B(l,`${o.name.charAt(0).toUpperCase()+o.name.slice(1)} API key`,d):c=await qe(l,`Enter your ${o.name.charAt(0).toUpperCase()+o.name.slice(1)} API key`),console.log(` ${M(">")} API key set: ${E(Ie(c))}`));let u=o.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(o.name)){let $=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||o.baseUrl||"";if($){let C={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,C[o.name]??"API Base URL",$.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${M(">")} URL: ${E(u)}`)}}let m=t.config.llm?.model??o.defaultModel;console.log("");let f,g=await Vl(o.name,c,u),y=Jl(g,o.models??[]);if(y.length>0){console.log(`${x("Available models:")}`);for(let C=0;C<y.length;C++){let Z=y[C],P=Z.desc??Z.name??"",J=Z.id===m?` ${M("(current)")}`:"";console.log(` ${fe(`${C+1})`)} ${Z.id}${P?` ${E(`\u2014 ${P}`)}`:""}${J}`)}console.log(` ${fe(`${y.length+1})`)} ${E("Other (enter manually)")}`);let _=await B(l,"Choose model","1"),$=parseInt(_,10)-1;$>=0&&$<y.length?f=y[$].id:f=await B(l,"Model ID",m)}else f=await B(l,"Which model?",m);let k=Object.keys(t.multiModelTiers).length>0,b=k?"Y/n":"y/N";console.log(`
2302
+ ${x("Configure additional model tiers for specialized tasks?")}`),console.log(`${E("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let S=(await l.question(`${U}> ${v}${E(`[${b}] `)}`)).trim().toLowerCase(),I=S===""?k:S==="y"||S==="yes",L={};if(I){let _=[{key:"strong",label:"Strong",hint:"complex reasoning, coding, long documents",defaultModel:"claude-opus-4-20250514"},{key:"fast",label:"Fast",hint:"quick responses, simple tasks",defaultModel:"claude-haiku-4-5-20251001"},{key:"embeddings",label:"Embeddings",hint:"semantic search & memory",defaultModel:"text-embedding-3-small"},{key:"local",label:"Local",hint:"offline fallback via Ollama",defaultModel:"llama3.2"}];for(let $ of _){let C=t.multiModelTiers[$.key],Z=!!C?.model;console.log(`
2303
+ ${x(`${$.label} model`)} ${E(`(${$.hint})`)}`),Z&&console.log(` ${E(`Current: ${C.provider}/${C.model}`)}`);let P=C?.provider??o.name,J=vt.map(je=>je.name).join(", ");console.log(` ${E(`Providers: ${J}`)}`);let Le=(await l.question(` ${U}Provider: ${v}${E(`[${P}] `)}`)).trim()||P;if(!Le&&!Z){console.log(` ${E("Skipped.")}`);continue}let ne=Le,xe,Qe;if(ne!==o.name){let je=C?.apiKey??t.env[`ALFRED_LLM_${$.key.toUpperCase()}_API_KEY`]??"";if(je?xe=await B(l,` API key for ${ne}`,je):(vt.find(yt=>yt.name===ne)?.needsApiKey??!0)&&(xe=await qe(l,` API key for ${ne}`)),["ollama","openwebui"].includes(ne)){let yt=(C?.baseUrl??"")||vt.find(Fi=>Fi.name===ne)?.baseUrl||"";yt&&(Qe=await B(l,` ${ne} URL`,yt))}}let ts=xe??(ne===o.name?c:void 0),Jr=Qe??(ne===o.name?u:void 0),xo=vt.find(je=>je.name===ne),Co=await Vl(ne,ts,Jr),Lt=Jl(Co,xo?.models??[]),gt;if(Lt.length>0){console.log(` ${x("Available models:")}`);for(let ks=0;ks<Lt.length;ks++){let yt=Lt[ks],Fi=yt.desc??yt.name??"",xf=yt.id===C?.model?` ${M("(current)")}`:"";console.log(` ${fe(`${ks+1})`)} ${yt.id}${Fi?` ${E(`\u2014 ${Fi}`)}`:""}${xf}`)}console.log(` ${fe(`${Lt.length+1})`)} ${E("Other (enter manually)")}`),console.log(` ${fe("0)")} ${E("Skip this tier")}`);let je=(await l.question(` ${U}> ${v}${Z?E(`[${C.model}] `):""}`)).trim();if(je==="0"){console.log(` ${E("Skipped.")}`);continue}let Pi=parseInt(je,10)-1;Pi>=0&&Pi<Lt.length?gt=Lt[Pi].id:!je&&Z?gt=C.model:gt=await B(l," Model ID",Z?C.model:$.defaultModel)}else if(console.log(` ${E("Press Enter to skip.")}`),gt=(await l.question(` ${U}Model: ${v}${Z?E(`[${C.model}] `):""}`)).trim()||(Z?C.model:""),!gt){console.log(` ${E("Skipped.")}`);continue}L[$.key]={provider:ne,model:gt,...xe?{apiKey:xe}:{},...Qe?{baseUrl:Qe}:{}},console.log(` ${M(">")} ${$.label}: ${x(ne)}/${x(gt)}`)}Object.keys(L).length===0&&console.log(`
2304
2304
  ${E("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${E("Using single model for all tasks.")}`);let D=["brave","tavily","duckduckgo","searxng"],W=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",q=D.indexOf(W),j=q>=0?q+1:0;console.log(`
2305
- ${x("Web Search provider (for searching the internet):")}`);let ce=["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"],me=p(_=>q===_?` ${E("(current)")}`:"","mark");console.log(` ${fe("0)")} None (disable web search)${q===-1&&W===""?` ${E("(current)")}`:""}`);for(let _=0;_<ce.length;_++)console.log(` ${fe(String(_+1)+")")} ${ce[_]}${me(_)}`);let O=await fi(l,"> ",0,D.length,j),pe,he="",ye="";if(O>=1&&O<=D.length&&(pe=D[O-1]),pe==="brave"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?he=await B(l," Brave Search API key",_):(console.log(` ${E("Get your free API key at: https://brave.com/search/api/")}`),he=await ze(l," Brave Search API key")),console.log(` ${M(">")} Brave Search: ${E(Ie(he))}`)}else if(pe==="tavily"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?he=await B(l," Tavily API key",_):(console.log(` ${E("Get your free API key at: https://tavily.com/")}`),he=await ze(l," Tavily API key")),console.log(` ${M(">")} Tavily: ${E(Ie(he))}`)}else if(pe==="duckduckgo")console.log(` ${M(">")} DuckDuckGo: ${E("no API key needed")}`);else if(pe==="searxng"){let _=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";ye=await B(l," SearXNG URL",_),ye=ye.replace(/\/+$/,""),console.log(` ${M(">")} SearXNG: ${E(ye)}`)}else console.log(` ${E("Web search disabled \u2014 you can configure it later.")}`);let $e=[];for(let _=0;_<Rr.length;_++){let $=Rr[_];t.config[$.configKey]?.enabled&&$e.push(_+1)}let ae=$e.length>0?$e.join(","):"";console.log(`
2306
- ${x("Which messaging platforms do you want to enable?")}`),console.log(`${E("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let _=0;_<Rr.length;_++){let $=$e.includes(_+1)?` ${E("(enabled)")}`:"";console.log(` ${fe(String(_+1)+")")} ${Rr[_].label}${$}`)}console.log(` ${fe("0)")} None (configure later)`);let z=(await l.question(`${P}> ${v}${ae?E(`[${ae}] `):""}`)).trim(),le=[],Ye=z||ae;if(Ye&&Ye!=="0"){let _=Ye.split(",").map($=>parseInt($.trim(),10));for(let $ of _)if($>=1&&$<=Rr.length){let C=Rr[$-1];le.includes(C)||le.push(C)}}le.length>0?console.log(` ${M(">")} Enabling: ${le.map(_=>x(_.label)).join(", ")}`):console.log(` ${E("No platforms selected \u2014 you can configure them later.")}`);let we={},Re={};for(let _ of le){if(_.credentials.length===0){_.name==="whatsapp"&&console.log(`
2305
+ ${x("Web Search provider (for searching the internet):")}`);let oe=["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"],me=p(_=>q===_?` ${E("(current)")}`:"","mark");console.log(` ${fe("0)")} None (disable web search)${q===-1&&W===""?` ${E("(current)")}`:""}`);for(let _=0;_<oe.length;_++)console.log(` ${fe(String(_+1)+")")} ${oe[_]}${me(_)}`);let O=await fi(l,"> ",0,D.length,j),ue,he="",ye="";if(O>=1&&O<=D.length&&(ue=D[O-1]),ue==="brave"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?he=await B(l," Brave Search API key",_):(console.log(` ${E("Get your free API key at: https://brave.com/search/api/")}`),he=await qe(l," Brave Search API key")),console.log(` ${M(">")} Brave Search: ${E(Ie(he))}`)}else if(ue==="tavily"){let _=t.env.ALFRED_SEARCH_API_KEY??"";_?he=await B(l," Tavily API key",_):(console.log(` ${E("Get your free API key at: https://tavily.com/")}`),he=await qe(l," Tavily API key")),console.log(` ${M(">")} Tavily: ${E(Ie(he))}`)}else if(ue==="duckduckgo")console.log(` ${M(">")} DuckDuckGo: ${E("no API key needed")}`);else if(ue==="searxng"){let _=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";ye=await B(l," SearXNG URL",_),ye=ye.replace(/\/+$/,""),console.log(` ${M(">")} SearXNG: ${E(ye)}`)}else console.log(` ${E("Web search disabled \u2014 you can configure it later.")}`);let $e=[];for(let _=0;_<Rr.length;_++){let $=Rr[_];t.config[$.configKey]?.enabled&&$e.push(_+1)}let pe=$e.length>0?$e.join(","):"";console.log(`
2306
+ ${x("Which messaging platforms do you want to enable?")}`),console.log(`${E("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let _=0;_<Rr.length;_++){let $=$e.includes(_+1)?` ${E("(enabled)")}`:"";console.log(` ${fe(String(_+1)+")")} ${Rr[_].label}${$}`)}console.log(` ${fe("0)")} None (configure later)`);let z=(await l.question(`${U}> ${v}${pe?E(`[${pe}] `):""}`)).trim(),ce=[],Ge=z||pe;if(Ge&&Ge!=="0"){let _=Ge.split(",").map($=>parseInt($.trim(),10));for(let $ of _)if($>=1&&$<=Rr.length){let C=Rr[$-1];ce.includes(C)||ce.push(C)}}ce.length>0?console.log(` ${M(">")} Enabling: ${ce.map(_=>x(_.label)).join(", ")}`):console.log(` ${E("No platforms selected \u2014 you can configure them later.")}`);let Te={},Re={};for(let _ of ce){if(_.credentials.length===0){_.name==="whatsapp"&&console.log(`
2307
2307
  ${Om("i")} WhatsApp: a QR code will be displayed on first start.`);continue}console.log(`
2308
- ${x(_.label+" configuration:")}`);let $={};for(let C of _.credentials){let Z=t.env[C.envKey]??"",F;Z?F=await B(l,` ${C.prompt}`,Z):C.defaultValue?F=await B(l,` ${C.prompt}`,C.defaultValue):C.required?F=await ze(l,` ${C.prompt}`):(F=(await l.question(` ${C.prompt}: ${P}`)).trim(),process.stdout.write(v)),$[C.configField]=F,Re[C.envKey]=F,C.configField==="token"||C.configField==="accessToken"?console.log(` ${M(">")} Set: ${E(Ie(F))}`):console.log(` ${M(">")} Set: ${E(F)}`)}we[_.configKey]=$}let Ue=t.config.email?.accounts??[],Pe=Ue[0],pt=Pe?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",It=Pe?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",ht=Ue.length>0||!!pt||It==="microsoft",Xt=ht?"Y/n":"y/N";console.log(`
2309
- ${x("Email access (read & send emails)?")}`),console.log(`${E("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let mt=(await l.question(`${P}> ${v}${E(`[${Xt}] `)}`)).trim().toLowerCase(),Ee=mt===""?ht:mt==="y"||mt==="yes",Oe=[],At={"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"}},ot=p(async(_,$)=>{let C={name:_,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},Z=$?.provider??"",F=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],J=Z==="microsoft"?1:0;console.log("");for(let ne=0;ne<F.length;ne++){let Ce=ne===J?` ${E("(current)")}`:"";console.log(` ${fe(`${ne+1})`)} ${F[ne]}${Ce}`)}let oe=(await l.question(`${P}> ${v}${E(`[${J+1}] `)}`)).trim(),xe=oe===""?J:parseInt(oe,10)-1;if(C.provider=xe===1?"microsoft":"imap-smtp",C.provider==="microsoft"){let ne=t.config.calendar?.microsoft,Ce=$?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Qe=$?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",ts=$?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(ne&&!Ce)console.log(` ${M(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${E("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${E("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${E("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),C.msClientId=await B(l," Client ID",Ce),C.msClientId||(C.msClientId=await ze(l," Client ID"));let Jr=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";C.msClientSecret=await B(l," Client Secret",Jr),C.msClientSecret||(C.msClientSecret=await ze(l," Client Secret")),C.msTenantId=await B(l," Tenant ID",Qe),C.msTenantId||(C.msTenantId=await ze(l," Tenant ID")),console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),C.msRefreshToken=await B(l," Refresh Token",ts),C.msRefreshToken||(C.msRefreshToken=await ze(l," Refresh Token"))}console.log(` ${M(">")} Email [${_}]: Microsoft 365 (Graph API)`)}else{let ne=$?.auth?.user??"";console.log(""),C.user=await B(l," Email address",ne||""),C.user||(C.user=await ze(l," Email address"));let Ce=$?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";Ce?C.pass=await B(l," Password / App password",Ce):(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")}`),C.pass=await ze(l," Password / App password"));let Qe=C.user.split("@")[1]?.toLowerCase()??"",ts=At[Qe],Jr=$?.imap?.host??ts?.imap??`imap.${Qe}`,xo=$?.smtp?.host??ts?.smtp??`smtp.${Qe}`,Co=$?.imap?.port??993,Lt=$?.smtp?.port??587;ts&&console.log(` ${M(">")} Detected ${Qe} \u2014 using preset server settings`),C.imapHost=await B(l," IMAP server",Jr);let gt=await B(l," IMAP port",String(Co));C.imapPort=parseInt(gt,10)||993,C.smtpHost=await B(l," SMTP server",xo);let Be=await B(l," SMTP port",String(Lt));C.smtpPort=parseInt(Be,10)||587,console.log(` ${M(">")} Email [${_}]: ${E(C.user)} via ${E(C.imapHost)}`)}return C},"configureEmailAccount");if(Ee){let _=Pe??(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);Oe.push(await ot("default",_));let $=!0;for(;$;){let C=(await l.question(`
2310
- ${x("Add another email account?")} ${E("[y/N]")} `)).trim().toLowerCase();if(C==="y"||C==="yes"){let F=(await l.question(` ${x("Account name:")} `)).trim()||`account${Oe.length+1}`,J=Ue.find(oe=>oe.name===F);Oe.push(await ot(F,J))}else $=!1}}else console.log(` ${E("Email disabled \u2014 you can configure it later.")}`);let K=["openai","groq"],V=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",de=K.indexOf(V),A=de>=0?de+1:0;console.log(`
2311
- ${x("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${E("Transcribes voice messages from Telegram, Discord, etc.")}`);let H=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${fe("0)")} None (disable voice transcription)${de===-1?` ${E("(current)")}`:""}`);for(let _=0;_<H.length;_++){let $=de===_?` ${E("(current)")}`:"";console.log(` ${fe(String(_+1)+")")} ${H[_]}${$}`)}let U=await fi(l,"> ",0,K.length,A),G,Q="",Te="";if(U>=1&&U<=K.length&&(G=K[U-1]),G==="openai"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?Q=await B(l," OpenAI API key (for Whisper)",_):(console.log(` ${E("Uses your OpenAI API key for Whisper transcription.")}`),Q=await ze(l," OpenAI API key")),console.log(` ${M(">")} OpenAI Whisper: ${E(Ie(Q))}`)}else if(G==="groq"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?Q=await B(l," Groq API key",_):(console.log(` ${E("Get your free API key at: https://console.groq.com/")}`),Q=await ze(l," Groq API key"));let $=t.env.ALFRED_SPEECH_BASE_URL??"";$&&(Te=await B(l," Groq API URL",$)),console.log(` ${M(">")} Groq Whisper: ${E(Ie(Q))}`)}else console.log(` ${E("Voice transcription disabled \u2014 you can configure it later.")}`);let Ne=!1,Fe="alloy";if(G){let _=t.config.speech?.ttsEnabled??!1,$=_?"Y/n":"y/N";console.log(`
2312
- ${x("Voice responses (Text-to-Speech)?")}`),console.log(`${E("Alfred can reply as a voice message when the user asks for it.")}`);let C=(await l.question(`${P}> ${v}${E(`[${$}] `)}`)).trim().toLowerCase();if(Ne=C===""?_:C==="y"||C==="yes",Ne){let Z=["alloy","echo","fable","onyx","nova","shimmer"],F=t.config.speech?.ttsVoice??"alloy",J=Z.indexOf(F),oe=J>=0?J+1:1;console.log(`
2313
- ${x("Which voice?")}`);for(let ne=0;ne<Z.length;ne++){let Ce=J===ne?` ${E("(current)")}`:"";console.log(` ${fe(String(ne+1)+")")} ${Z[ne]}${Ce}`)}let xe=await fi(l," > ",1,Z.length,oe);Fe=Z[xe-1],console.log(` ${M(">")} TTS voice: ${x(Fe)}`)}else console.log(` ${E("Voice responses disabled.")}`)}let $t=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
2314
- ${x("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${E("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let Le=(await l.question(`${P}> ${v}${E(`[${$t}] `)}`)).trim().toLowerCase(),Ve=Le===""?t.codeSandboxEnabled:Le==="y"||Le==="yes";console.log(Ve?` ${M(">")} Code Sandbox ${x("enabled")} (JavaScript + Python)`:` ${E("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
2308
+ ${x(_.label+" configuration:")}`);let $={};for(let C of _.credentials){let Z=t.env[C.envKey]??"",P;Z?P=await B(l,` ${C.prompt}`,Z):C.defaultValue?P=await B(l,` ${C.prompt}`,C.defaultValue):C.required?P=await qe(l,` ${C.prompt}`):(P=(await l.question(` ${C.prompt}: ${U}`)).trim(),process.stdout.write(v)),$[C.configField]=P,Re[C.envKey]=P,C.configField==="token"||C.configField==="accessToken"?console.log(` ${M(">")} Set: ${E(Ie(P))}`):console.log(` ${M(">")} Set: ${E(P)}`)}Te[_.configKey]=$}let Me=t.config.email?.accounts??[],Ue=Me[0],pt=Ue?.auth?.user??t.config.email?.auth?.user??t.env.ALFRED_EMAIL_USER??"",It=Ue?.provider??t.config.email?.provider??t.env.ALFRED_EMAIL_PROVIDER??"",ht=Me.length>0||!!pt||It==="microsoft",Xt=ht?"Y/n":"y/N";console.log(`
2309
+ ${x("Email access (read & send emails)?")}`),console.log(`${E("Works with Gmail, Outlook, Microsoft 365, or any IMAP/SMTP provider. Supports multiple accounts.")}`);let mt=(await l.question(`${U}> ${v}${E(`[${Xt}] `)}`)).trim().toLowerCase(),we=mt===""?ht:mt==="y"||mt==="yes",Ce=[],At={"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"}},ot=p(async(_,$)=>{let C={name:_,provider:"imap-smtp",user:"",pass:"",imapHost:"",imapPort:993,smtpHost:"",smtpPort:587,msClientId:"",msClientSecret:"",msTenantId:"",msRefreshToken:""},Z=$?.provider??"",P=["IMAP/SMTP (classic)","Microsoft 365 (Graph API, OAuth)"],J=Z==="microsoft"?1:0;console.log("");for(let ne=0;ne<P.length;ne++){let xe=ne===J?` ${E("(current)")}`:"";console.log(` ${fe(`${ne+1})`)} ${P[ne]}${xe}`)}let ae=(await l.question(`${U}> ${v}${E(`[${J+1}] `)}`)).trim(),Le=ae===""?J:parseInt(ae,10)-1;if(C.provider=Le===1?"microsoft":"imap-smtp",C.provider==="microsoft"){let ne=t.config.calendar?.microsoft,xe=$?.microsoft?.clientId??t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_ID??"",Qe=$?.microsoft?.tenantId??t.env.ALFRED_MICROSOFT_EMAIL_TENANT_ID??"",ts=$?.microsoft?.refreshToken??t.env.ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN??"";if(ne&&!xe)console.log(` ${M(">")} Microsoft Calendar already configured \u2014 credentials will be shared.`),console.log(` ${E("The same Azure App Registration will be used for Mail + Calendar.")}`),console.log(` ${E("Ensure the app has Mail.ReadWrite and Mail.Send scopes.")}`);else{console.log(` ${E("Azure Portal \u2192 App Registrations \u2192 your app \u2192 Mail.ReadWrite + Mail.Send scopes")}`),C.msClientId=await B(l," Client ID",xe),C.msClientId||(C.msClientId=await qe(l," Client ID"));let Jr=t.env.ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET??"";C.msClientSecret=await B(l," Client Secret",Jr),C.msClientSecret||(C.msClientSecret=await qe(l," Client Secret")),C.msTenantId=await B(l," Tenant ID",Qe),C.msTenantId||(C.msTenantId=await qe(l," Tenant ID")),console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),C.msRefreshToken=await B(l," Refresh Token",ts),C.msRefreshToken||(C.msRefreshToken=await qe(l," Refresh Token"))}console.log(` ${M(">")} Email [${_}]: Microsoft 365 (Graph API)`)}else{let ne=$?.auth?.user??"";console.log(""),C.user=await B(l," Email address",ne||""),C.user||(C.user=await qe(l," Email address"));let xe=$?.auth?.pass??t.env.ALFRED_EMAIL_PASS??"";xe?C.pass=await B(l," Password / App password",xe):(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")}`),C.pass=await qe(l," Password / App password"));let Qe=C.user.split("@")[1]?.toLowerCase()??"",ts=At[Qe],Jr=$?.imap?.host??ts?.imap??`imap.${Qe}`,xo=$?.smtp?.host??ts?.smtp??`smtp.${Qe}`,Co=$?.imap?.port??993,Lt=$?.smtp?.port??587;ts&&console.log(` ${M(">")} Detected ${Qe} \u2014 using preset server settings`),C.imapHost=await B(l," IMAP server",Jr);let gt=await B(l," IMAP port",String(Co));C.imapPort=parseInt(gt,10)||993,C.smtpHost=await B(l," SMTP server",xo);let je=await B(l," SMTP port",String(Lt));C.smtpPort=parseInt(je,10)||587,console.log(` ${M(">")} Email [${_}]: ${E(C.user)} via ${E(C.imapHost)}`)}return C},"configureEmailAccount");if(we){let _=Ue??(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);Ce.push(await ot("default",_));let $=!0;for(;$;){let C=(await l.question(`
2310
+ ${x("Add another email account?")} ${E("[y/N]")} `)).trim().toLowerCase();if(C==="y"||C==="yes"){let P=(await l.question(` ${x("Account name:")} `)).trim()||`account${Ce.length+1}`,J=Me.find(ae=>ae.name===P);Ce.push(await ot(P,J))}else $=!1}}else console.log(` ${E("Email disabled \u2014 you can configure it later.")}`);let K=["openai","groq"],Y=t.config.speech?.provider??t.env.ALFRED_SPEECH_PROVIDER??"",le=K.indexOf(Y),A=le>=0?le+1:0;console.log(`
2311
+ ${x("Voice message transcription (Speech-to-Text via Whisper)?")}`),console.log(`${E("Transcribes voice messages from Telegram, Discord, etc.")}`);let H=["OpenAI Whisper \u2014 best quality","Groq Whisper \u2014 fast & free"];console.log(` ${fe("0)")} None (disable voice transcription)${le===-1?` ${E("(current)")}`:""}`);for(let _=0;_<H.length;_++){let $=le===_?` ${E("(current)")}`:"";console.log(` ${fe(String(_+1)+")")} ${H[_]}${$}`)}let F=await fi(l,"> ",0,K.length,A),V,te="",Ee="";if(F>=1&&F<=K.length&&(V=K[F-1]),V==="openai"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?te=await B(l," OpenAI API key (for Whisper)",_):(console.log(` ${E("Uses your OpenAI API key for Whisper transcription.")}`),te=await qe(l," OpenAI API key")),console.log(` ${M(">")} OpenAI Whisper: ${E(Ie(te))}`)}else if(V==="groq"){let _=t.env.ALFRED_SPEECH_API_KEY??"";_?te=await B(l," Groq API key",_):(console.log(` ${E("Get your free API key at: https://console.groq.com/")}`),te=await qe(l," Groq API key"));let $=t.env.ALFRED_SPEECH_BASE_URL??"";$&&(Ee=await B(l," Groq API URL",$)),console.log(` ${M(">")} Groq Whisper: ${E(Ie(te))}`)}else console.log(` ${E("Voice transcription disabled \u2014 you can configure it later.")}`);let Ye=!1,Pe="alloy";if(V){let _=t.config.speech?.ttsEnabled??!1,$=_?"Y/n":"y/N";console.log(`
2312
+ ${x("Voice responses (Text-to-Speech)?")}`),console.log(`${E("Alfred can reply as a voice message when the user asks for it.")}`);let C=(await l.question(`${U}> ${v}${E(`[${$}] `)}`)).trim().toLowerCase();if(Ye=C===""?_:C==="y"||C==="yes",Ye){let Z=["alloy","echo","fable","onyx","nova","shimmer"],P=t.config.speech?.ttsVoice??"alloy",J=Z.indexOf(P),ae=J>=0?J+1:1;console.log(`
2313
+ ${x("Which voice?")}`);for(let ne=0;ne<Z.length;ne++){let xe=J===ne?` ${E("(current)")}`:"";console.log(` ${fe(String(ne+1)+")")} ${Z[ne]}${xe}`)}let Le=await fi(l," > ",1,Z.length,ae);Pe=Z[Le-1],console.log(` ${M(">")} TTS voice: ${x(Pe)}`)}else console.log(` ${E("Voice responses disabled.")}`)}let $t=t.codeSandboxEnabled?"Y/n":"y/N";console.log(`
2314
+ ${x("Code Sandbox (execute Python/JavaScript in a sandboxed environment)?")}`),console.log(`${E("Enables code execution for calculations, data processing, PDF generation, charts, etc.")}`);let Ne=(await l.question(`${U}> ${v}${E(`[${$t}] `)}`)).trim().toLowerCase(),Ve=Ne===""?t.codeSandboxEnabled:Ne==="y"||Ne==="yes";console.log(Ve?` ${M(">")} Code Sandbox ${x("enabled")} (JavaScript + Python)`:` ${E("Code Sandbox disabled \u2014 you can enable it later in config/default.yml.")}`),console.log(`
2315
2315
  ${x("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log(`${E("Scanning for known coding agents on this system...")}`);let Ht=[];for(let _ of Dm){let $=lw(_.whichCmd);$?(Ht.push({..._,resolvedPath:$}),console.log(` ${M("\u2713")} ${x(_.label)} ${E(`(${$})`)}`)):console.log(` ${E("\xB7")} ${E(_.label)} ${E("\u2014 not found")}`)}let yi=(t.config.codeAgents?.agents??[]).filter(_=>!Dm.some($=>$.name===_.name));for(let _ of yi)console.log(` ${M("\u2713")} ${x(_.name)} ${E(`(${_.command}) \u2014 from existing config`)}`);let Wt=[];if(Ht.length===0&&yi.length===0)console.log(`
2316
- ${E("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let _=[...Ht.map(F=>({name:F.name,command:F.resolvedPath??F.command,argsTemplate:F.argsTemplate,promptVia:F.promptVia,label:F.label,detected:!0})),...yi.map(F=>({name:F.name,command:F.command,argsTemplate:F.argsTemplate,promptVia:F.promptVia??"arg",label:F.name,detected:!1}))];console.log(`
2317
- ${x("Which agents should Alfred use?")} ${E("(comma-separated, e.g. 1,2)")}`);let $=new Set((t.config.codeAgents?.agents??[]).map(F=>F.name));for(let F=0;F<_.length;F++){let J=_[F],oe=$.has(J.name)?` ${E("(current)")}`:"";console.log(` ${P}${F+1}${v}) ${J.label}${oe}`)}console.log(` ${P}0${v}) None`);let C=_.map((F,J)=>$.size>0?$.has(F.name)?String(J+1):null:F.detected?String(J+1):null).filter(Boolean).join(",")||"0",Z=(await l.question(` ${P}> ${v}${E(`[${C}] `)}`)).trim()||C;Z!=="0"&&(Wt=Z.split(",").map(J=>parseInt(J.trim(),10)).filter(J=>!isNaN(J)&&J>=1&&J<=_.length).map(J=>{let oe=_[J-1];return{name:oe.name,command:oe.command,argsTemplate:oe.argsTemplate,promptVia:oe.promptVia}})),Wt.length>0?console.log(` ${M(">")} ${x(String(Wt.length))} agent(s) selected: ${Wt.map(F=>F.name).join(", ")}`):console.log(` ${E("No agents selected.")}`)}let ro=t.config.codeAgents?.forge,no=ro?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
2318
- ${x("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 rd=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let _ of rd){let $=_.name===no?` ${E("(current)")}`:"";console.log(` ${P}${_.num}${v}) ${_.label}${$}`)}let nd=no==="github"?"2":no==="gitlab"?"3":"1",rf=(await l.question(`${P}> ${v}${E(`[${nd}] `)}`)).trim()||nd,qt=rd.find(_=>_.num===rf)?.name??"",Lr="",xr="";if(qt==="github"){console.log(` ${M(">")} Forge: ${x("GitHub")}`);let _=t.env.ALFRED_GITHUB_TOKEN??ro?.github?.token??"";_&&console.log(` ${E(`Current token: ${Ie(_)}`)}`),console.log(` ${E("Create a token at https://github.com/settings/tokens (scope: repo)")}`),Lr=(await l.question(` ${Y}GitHub Token${v}: ${P}`)).trim(),process.stdout.write(v),!Lr&&_&&(Lr=_)}else if(qt==="gitlab"){console.log(` ${M(">")} Forge: ${x("GitLab")}`);let _=t.env.ALFRED_GITLAB_TOKEN??ro?.gitlab?.token??"";_&&console.log(` ${E(`Current token: ${Ie(_)}`)}`),console.log(` ${E("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),xr=(await l.question(` ${Y}GitLab Token${v}: ${P}`)).trim(),process.stdout.write(v),!xr&&_&&(xr=_)}else console.log(` ${E("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);let nf=t.webUiEnabled!==!1?"Y/n":"y/N";console.log(`
2319
- ${x("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 io=(await l.question(`${P}> ${v}${E(`[${nf}] `)}`)).trim().toLowerCase(),ao=io===""?t.webUiEnabled!==!1:io==="y"||io==="yes";console.log(ao?` ${M(">")} Web Chat UI ${x("enabled")} \u2014 accessible at /alfred/`:` ${E("Web Chat UI disabled.")}`);let id="127.0.0.1",Ti=!1,wi="",ad=(await l.question(`
2316
+ ${E("No coding agents found. You can add them manually in config/default.yml later.")}`);else{let _=[...Ht.map(P=>({name:P.name,command:P.resolvedPath??P.command,argsTemplate:P.argsTemplate,promptVia:P.promptVia,label:P.label,detected:!0})),...yi.map(P=>({name:P.name,command:P.command,argsTemplate:P.argsTemplate,promptVia:P.promptVia??"arg",label:P.name,detected:!1}))];console.log(`
2317
+ ${x("Which agents should Alfred use?")} ${E("(comma-separated, e.g. 1,2)")}`);let $=new Set((t.config.codeAgents?.agents??[]).map(P=>P.name));for(let P=0;P<_.length;P++){let J=_[P],ae=$.has(J.name)?` ${E("(current)")}`:"";console.log(` ${U}${P+1}${v}) ${J.label}${ae}`)}console.log(` ${U}0${v}) None`);let C=_.map((P,J)=>$.size>0?$.has(P.name)?String(J+1):null:P.detected?String(J+1):null).filter(Boolean).join(",")||"0",Z=(await l.question(` ${U}> ${v}${E(`[${C}] `)}`)).trim()||C;Z!=="0"&&(Wt=Z.split(",").map(J=>parseInt(J.trim(),10)).filter(J=>!isNaN(J)&&J>=1&&J<=_.length).map(J=>{let ae=_[J-1];return{name:ae.name,command:ae.command,argsTemplate:ae.argsTemplate,promptVia:ae.promptVia}})),Wt.length>0?console.log(` ${M(">")} ${x(String(Wt.length))} agent(s) selected: ${Wt.map(P=>P.name).join(", ")}`):console.log(` ${E("No agents selected.")}`)}let ro=t.config.codeAgents?.forge,no=ro?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
2318
+ ${x("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 rd=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let _ of rd){let $=_.name===no?` ${E("(current)")}`:"";console.log(` ${U}${_.num}${v}) ${_.label}${$}`)}let nd=no==="github"?"2":no==="gitlab"?"3":"1",rf=(await l.question(`${U}> ${v}${E(`[${nd}] `)}`)).trim()||nd,qt=rd.find(_=>_.num===rf)?.name??"",Lr="",xr="";if(qt==="github"){console.log(` ${M(">")} Forge: ${x("GitHub")}`);let _=t.env.ALFRED_GITHUB_TOKEN??ro?.github?.token??"";_&&console.log(` ${E(`Current token: ${Ie(_)}`)}`),console.log(` ${E("Create a token at https://github.com/settings/tokens (scope: repo)")}`),Lr=(await l.question(` ${G}GitHub Token${v}: ${U}`)).trim(),process.stdout.write(v),!Lr&&_&&(Lr=_)}else if(qt==="gitlab"){console.log(` ${M(">")} Forge: ${x("GitLab")}`);let _=t.env.ALFRED_GITLAB_TOKEN??ro?.gitlab?.token??"";_&&console.log(` ${E(`Current token: ${Ie(_)}`)}`),console.log(` ${E("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),xr=(await l.question(` ${G}GitLab Token${v}: ${U}`)).trim(),process.stdout.write(v),!xr&&_&&(xr=_)}else console.log(` ${E("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);let nf=t.webUiEnabled!==!1?"Y/n":"y/N";console.log(`
2319
+ ${x("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 io=(await l.question(`${U}> ${v}${E(`[${nf}] `)}`)).trim().toLowerCase(),ao=io===""?t.webUiEnabled!==!1:io==="y"||io==="yes";console.log(ao?` ${M(">")} Web Chat UI ${x("enabled")} \u2014 accessible at /alfred/`:` ${E("Web Chat UI disabled.")}`);let id="127.0.0.1",Ti=!1,wi="",ad=(await l.question(`
2320
2320
  ${x("API von anderen Ger\xE4ten erreichbar machen?")}
2321
2321
  ${E("Setzt host auf 0.0.0.0 statt localhost.")}
2322
- ${P}> ${v}${E("[y/N] ")}`)).trim().toLowerCase();if(ad==="y"||ad==="yes"){id="0.0.0.0",console.log(` ${M(">")} API Host: ${x("0.0.0.0")} (alle Interfaces)`),console.log(`
2323
- ${x("TLS/HTTPS aktivieren?")}`),console.log(`${E("Empfohlen bei Remote-Zugriff. Selbstsigniertes Zertifikat wird automatisch generiert.")}`);let _=(await l.question(`${P}> ${v}${E("[Y/n] ")}`)).trim().toLowerCase();Ti=_===""||_==="y"||_==="yes",console.log(Ti?` ${M(">")} TLS ${x("enabled")}`:` ${E("TLS disabled \u2014 API l\xE4uft \xFCber HTTP.")}`),console.log(`
2324
- ${x("API Token setzen?")}`),console.log(`${E("Sch\xFCtzt die API mit Bearer-Token-Authentifizierung.")}`),wi=(await l.question(` ${Y}API Token${v} ${E("[Enter to skip]")}: ${P}`)).trim(),process.stdout.write(v),wi&&console.log(` ${M(">")} API Token gesetzt`)}else console.log(` ${E("API nur auf localhost erreichbar.")}`);let zt=!1,ws="",Ei="primary",_i="",ki="";console.log(`
2325
- ${x("Cluster / Hochverf\xFCgbarkeit?")}`),console.log(`${E("Mehrere Alfred-Nodes f\xFCr Failover und Last-Verteilung.")}`);let od=(await l.question(`${P}> ${v}${E("[y/N] ")}`)).trim().toLowerCase();if(zt=od==="y"||od==="yes",zt)if(console.log(`
2326
- ${x("Ist dies der erste Node (Primary) oder ein weiterer?")}`),console.log(` ${E("1) Erster Node (Primary) \u2014 Redis URL eingeben, Cluster-Token generieren")}`),console.log(` ${E("2) Weiterer Node \u2014 Primary-Adresse + Cluster-Token eingeben")}`),(await l.question(` ${P}> ${v}${E("[1/2] ")}`)).trim()==="2"){Ei="secondary",console.log(`
2327
- ${E("Cluster beitreten:")}`);let $=(await l.question(` ${Y}Primary-Host (IP:Port)${v}: ${P}`)).trim();process.stdout.write(v),ki=(await l.question(` ${Y}Cluster-Token${v}: ${P}`)).trim(),process.stdout.write(v),_i=(await l.question(` ${Y}Redis URL${v} ${E("[redis://localhost:6379]")}: ${P}`)).trim()||"redis://localhost:6379",process.stdout.write(v),ws=`node-${Math.random().toString(36).slice(2,8)}`,console.log(` ${M(">")} Cluster beigetreten als ${x(ws)} (secondary)`)}else Ei="primary",_i=(await l.question(`
2328
- ${Y}Redis URL${v} ${E("[redis://localhost:6379]")}: ${P}`)).trim()||"redis://localhost:6379",process.stdout.write(v),ws=`node-${Math.random().toString(36).slice(2,8)}`,ki=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,console.log(` ${M(">")} Cluster Primary: ${x(ws)}`),console.log(` ${M(">")} Cluster-Token: ${x(ki)}`),console.log(` ${E(" Diesen Token beim 2. Node eingeben.")}`);else console.log(` ${E("Einzelinstanz \u2014 kein Cluster.")}`);let oo="sqlite",Kt="",co=t.config.storage?.backend??"sqlite",cd=t.env.ALFRED_STORAGE_CONNECTION_STRING??t.config.storage?.connectionString??"";if(zt||co==="postgres"){console.log(`
2329
- ${x("Datenbank-Backend")}`),console.log(`${E("SQLite ist Standard. PostgreSQL empfohlen f\xFCr Cluster/HA (gemeinsamer Zustand).")}`),console.log(` ${fe("1)")} SQLite (lokal, Standard)`),console.log(` ${fe("2)")} PostgreSQL (HA, gemeinsame DB)`);let _=co==="postgres"||zt?"2":"1";((await l.question(`${P}> ${v}${E(`[${_}] `)}`)).trim()||_)==="2"?(oo="postgres",Kt=await B(l," PostgreSQL Connection-String",cd||"postgres://alfred:password@localhost:5432/alfred"),console.log(` ${M(">")} PostgreSQL: ${E(Kt.replace(/:[^:@]+@/,":***@"))}`),co==="sqlite"&&cd!==Kt&&console.log(` ${Om("i")} Bestehende SQLite-Daten migrieren: ${x("alfred migrate-db")}`)):console.log(` ${M(">")} SQLite (Standard)`)}let Rt="local",Cr="",Si="",Or="",Dr="",Mr="",Nt=t.config.fileStore;if(zt||Nt){console.log(`
2330
- ${x("Datei-Storage")}`),console.log(`${E("Wo sollen Datei-Uploads (Dokumente, Inbox) gespeichert werden?")}`),console.log(` ${fe("1)")} Lokal (Standard \u2014 ./data/files)`),console.log(` ${fe("2)")} NFS / Netzwerk-Pfad`),console.log(` ${fe("3)")} S3 / MinIO`);let _=Nt?.backend==="s3"?"3":Nt?.backend==="nfs"?"2":"1",$=(await l.question(`${P}> ${v}${E(`[${_}] `)}`)).trim()||_;$==="3"?(Rt="s3",Si=await B(l," S3/MinIO Endpoint (z.B. http://minio:9000)",Nt?.s3Endpoint??""),Or=await B(l," Bucket-Name",Nt?.s3Bucket??"alfred-files"),Dr=await B(l," Access Key",t.env.ALFRED_S3_ACCESS_KEY??Nt?.s3AccessKey??""),Mr=await B(l," Secret Key",t.env.ALFRED_S3_SECRET_KEY??Nt?.s3SecretKey??""),console.log(` ${M(">")} S3: ${E(Si)} / ${Or}`)):$==="2"?(Rt="nfs",Cr=await B(l," NFS-Pfad",Nt?.basePath??"/mnt/alfred-files"),console.log(` ${M(">")} NFS: ${E(Cr)}`)):console.log(` ${M(">")} Lokal (./data/files)`)}console.log(`
2331
- ${x("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${E("Control VMs, containers, network devices, and smart home through Alfred.")}`);let Ur=t.config.proxmox,lo=t.env.ALFRED_PROXMOX_BASE_URL??Ur?.baseUrl??"",af=lo?"Y/n":"y/N",ld=(await l.question(` ${Y}Enable Proxmox VE?${v} ${E(`[${af}]`)}: ${P}`)).trim().toLowerCase()||(lo?"y":"n");process.stdout.write(v);let bi=ld==="y"||ld==="yes",Pr="",uo="",Fr="",po=!0;if(bi){Pr=await B(l," Proxmox URL (e.g. https://pve.local:8006)",lo||"https://pve.local:8006");let _=t.env.ALFRED_PROXMOX_TOKEN_ID??Ur?.tokenId??"";_&&console.log(` ${E(`Current token ID: ${_}`)}`),console.log(` ${E("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),uo=await B(l," API Token ID (user@realm!name)",_);let $=t.env.ALFRED_PROXMOX_TOKEN_SECRET??Ur?.tokenSecret??"";$&&console.log(` ${E(`Current secret: ${Ie($)}`)}`),Fr=(await l.question(` ${Y}API Token Secret${v}: ${P}`)).trim(),process.stdout.write(v),!Fr&&$&&(Fr=$);let C=Ur?.verifyTls===!1?"y/N":"Y/n",Z=(await l.question(` ${Y}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${C}]`)}: ${P}`)).trim().toLowerCase()||(Ur?.verifyTls===!1?"n":"y");process.stdout.write(v),po=Z==="y"||Z==="yes",console.log(` ${M(">")} Proxmox: ${x(Pr)} ${E(`(TLS verify: ${po?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox disabled.")}`);let Es=t.config.proxmoxBackup,ho=t.env.ALFRED_PBS_BASE_URL??Es?.baseUrl??"",of=ho?"Y/n":"y/N",dd=(await l.question(`
2332
- ${Y}Enable Proxmox Backup Server?${v} ${E(`[${of}]`)}: ${P}`)).trim().toLowerCase()||(ho?"y":"n");process.stdout.write(v);let vi=dd==="y"||dd==="yes",jr="",mo="",Br="",Xr=24,Ii=!0;if(vi){jr=await B(l," PBS URL (e.g. https://pbs.local:8007)",ho||"https://pbs.local:8007");let _=t.env.ALFRED_PBS_TOKEN_ID??Es?.tokenId??"";_&&console.log(` ${E(`Current token ID: ${_}`)}`),console.log(` ${E("Create: Configuration \u2192 Access Control \u2192 API Token")}`),mo=await B(l," API Token ID (user@realm!name)",_);let $=t.env.ALFRED_PBS_TOKEN_SECRET??Es?.tokenSecret??"";$&&console.log(` ${E(`Current secret: ${Ie($)}`)}`),Br=(await l.question(` ${Y}API Token Secret${v}: ${P}`)).trim(),process.stdout.write(v),!Br&&$&&(Br=$);let C=t.env.ALFRED_PBS_MAX_AGE_HOURS??Es?.maxAgeHours?.toString()??"24";Xr=parseInt(await B(l," Max backup age (hours, alert if older)",C),10)||24;let Z=Es?.verifyTls===!1?"y/N":"Y/n",F=(await l.question(` ${Y}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${Z}]`)}: ${P}`)).trim().toLowerCase()||(Es?.verifyTls===!1?"n":"y");process.stdout.write(v),Ii=F==="y"||F==="yes",console.log(` ${M(">")} PBS: ${x(jr)} ${E(`(max age: ${Xr}h, TLS verify: ${Ii?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox Backup Server disabled.")}`);let Gt=t.config.unifi,fo=t.env.ALFRED_UNIFI_BASE_URL??Gt?.baseUrl??"",cf=fo?"Y/n":"y/N",ud=(await l.question(`
2333
- ${Y}Enable UniFi Network?${v} ${E(`[${cf}]`)}: ${P}`)).trim().toLowerCase()||(fo?"y":"n");process.stdout.write(v);let Hr=ud==="y"||ud==="yes",_s="",Yt="",go="",Wr="",yo=!0;if(Hr){_s=await B(l," UniFi URL (e.g. https://unifi.local)",fo||"https://unifi.local"),console.log(` ${E("Auth: API Key (recommended) or Username/Password")}`);let _=t.env.ALFRED_UNIFI_API_KEY??Gt?.apiKey??"",$=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],C=_?"1":Gt?.username?"2":"1";for(let oe of $)console.log(` ${P}${oe.num}${v}) ${oe.label}`);if(((await l.question(` ${P}> ${v}${E(`[${C}] `)}`)).trim()||C)==="1")_&&console.log(` ${E(`Current key: ${Ie(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),Yt=(await l.question(` ${Y}API Key${v}: ${P}`)).trim(),process.stdout.write(v),!Yt&&_&&(Yt=_);else{let oe=t.env.ALFRED_UNIFI_USERNAME??Gt?.username??"";go=await B(l," Username",oe||"alfred");let xe=t.env.ALFRED_UNIFI_PASSWORD??Gt?.password??"";xe&&console.log(` ${E(`Current password: ${Ie(xe)}`)}`),Wr=(await l.question(` ${Y}Password${v}: ${P}`)).trim(),process.stdout.write(v),!Wr&&xe&&(Wr=xe)}let F=Gt?.verifyTls===!1?"y/N":"Y/n",J=(await l.question(` ${Y}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${F}]`)}: ${P}`)).trim().toLowerCase()||(Gt?.verifyTls===!1?"n":"y");process.stdout.write(v),yo=J==="y"||J==="yes",console.log(` ${M(">")} UniFi: ${x(_s)} ${E(`(TLS verify: ${yo?"yes":"no"})`)}`)}else console.log(` ${E("UniFi disabled.")}`);let Ai=t.config.homeassistant,To=t.env.ALFRED_HOMEASSISTANT_URL??Ai?.baseUrl??"",lf=To?"Y/n":"y/N",pd=(await l.question(`
2334
- ${Y}Enable Home Assistant?${v} ${E(`[${lf}]`)}: ${P}`)).trim().toLowerCase()||(To?"y":"n");process.stdout.write(v);let $i=pd==="y"||pd==="yes",qr="",zr="",wo=!0;if($i){qr=await B(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",To||"http://homeassistant.local:8123");let _=t.env.ALFRED_HOMEASSISTANT_TOKEN??Ai?.accessToken??"";_&&console.log(` ${E(`Current token: ${Ie(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),zr=(await l.question(` ${Y}Long-Lived Access Token${v}: ${P}`)).trim(),process.stdout.write(v),!zr&&_&&(zr=_);let $=Ai?.verifyTls===!1?"y/N":"Y/n",C=(await l.question(` ${Y}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${$}]`)}: ${P}`)).trim().toLowerCase()||(Ai?.verifyTls===!1?"n":"y");process.stdout.write(v),wo=C==="y"||C==="yes",console.log(` ${M(">")} Home Assistant: ${x(qr)} ${E(`(TLS verify: ${wo?"yes":"no"})`)}`)}else console.log(` ${E("Home Assistant disabled.")}`);let Je=t.config.contacts,Eo=t.env.ALFRED_CONTACTS_PROVIDER??Je?.provider??"",df=Eo?"Y/n":"y/N",hd=(await l.question(`
2335
- ${Y}Enable Contacts management?${v} ${E(`[${df}]`)}: ${P}`)).trim().toLowerCase()||(Eo?"y":"n");process.stdout.write(v);let Ri=hd==="y"||hd==="yes",Ze="",Se={};if(Ri){let _=["carddav","google","microsoft"],$=_.indexOf(Eo),C=$>=0?$+1:1;console.log(` ${fe("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${fe("2)")} Google Contacts`),console.log(` ${fe("3)")} Microsoft 365`);let Z=await fi(l," > ",1,3,C);if(Ze=_[Z-1],Se.ALFRED_CONTACTS_PROVIDER=Ze,Ze==="carddav"){let F=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Je?.carddav?.serverUrl??"";Se.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await B(l," CardDAV Server URL",F||"https://cloud.example.com/remote.php/dav");let J=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Je?.carddav?.username??"";Se.ALFRED_CARDDAV_CONTACTS_USERNAME=await B(l," Username",J);let oe=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Je?.carddav?.password??"";oe&&console.log(` ${E(`Current password: ${Ie(oe)}`)}`);let xe=(await l.question(` ${Y}Password${v}: ${P}`)).trim();process.stdout.write(v),Se.ALFRED_CARDDAV_CONTACTS_PASSWORD=xe||oe}else if(Ze==="google"){let F=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Je?.google?.clientId??"";F&&console.log(` ${E(`Current client ID: ${Ie(F)}`)}`),Se.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${Y}Google Client ID${v}: ${P}`)).trim()||F,process.stdout.write(v);let J=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Je?.google?.clientSecret??"";Se.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${Y}Google Client Secret${v}: ${P}`)).trim()||J,process.stdout.write(v);let oe=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Je?.google?.refreshToken??"";Se.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${Y}Refresh Token${v}: ${P}`)).trim()||oe,process.stdout.write(v)}else if(Ze==="microsoft"){let F=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Je?.microsoft?.clientId??"";F&&console.log(` ${E(`Current client ID: ${Ie(F)}`)}`),Se.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${Y}Microsoft Client ID${v}: ${P}`)).trim()||F,process.stdout.write(v);let J=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Je?.microsoft?.clientSecret??"";Se.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${Y}Microsoft Client Secret${v}: ${P}`)).trim()||J,process.stdout.write(v);let oe=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Je?.microsoft?.tenantId??"";Se.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await B(l," Tenant ID",oe||"common");let xe=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Je?.microsoft?.refreshToken??"";console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),Se.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${Y}Refresh Token${v}: ${P}`)).trim()||xe,process.stdout.write(v)}console.log(` ${M(">")} Contacts: ${x(Ze)}`)}else console.log(` ${E("Contacts disabled.")}`);let md=t.config.docker,_o=t.env.ALFRED_DOCKER_SOCKET_PATH??md?.socketPath??"",ko=t.env.ALFRED_DOCKER_HOST??md?.host??"",uf=_o||ko?"Y/n":"y/N",fd=(await l.question(`
2336
- ${Y}Enable Docker management?${v} ${E(`[${uf}]`)}: ${P}`)).trim().toLowerCase()||(_o||ko?"y":"n");process.stdout.write(v);let Ni=fd==="y"||fd==="yes",Vt="",Jt="";if(Ni){let _=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${E("Use socket path for local Docker, or host URL for remote.")}`),Vt=await B(l," Docker socket path",_o||_);let $=(await l.question(` ${Y}Docker host URL (optional, for remote)${v}: ${P}`)).trim();process.stdout.write(v),Jt=$||ko,console.log(` ${M(">")} Docker: ${x(Jt||Vt)}`)}else console.log(` ${E("Docker disabled.")}`);let pf=t.config.bmw,So=t.env.ALFRED_BMW_CLIENT_ID??pf?.clientId??"",hf=So?"Y/n":"y/N",gd=(await l.question(`
2337
- ${Y}Enable BMW CarData (vehicle status, charging)?${v} ${E(`[${hf}]`)}: ${P}`)).trim().toLowerCase()||(So?"y":"n");process.stdout.write(v);let Li=gd==="y"||gd==="yes",bo="";Li?(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)')}`),bo=await B(l," BMW CarData Client ID",So),console.log(` ${M(">")} BMW CarData: ${x("enabled")}`)):console.log(` ${E("BMW CarData disabled.")}`);let mf=t.config.routing,vo=t.env.ALFRED_ROUTING_API_KEY??mf?.apiKey??"",ff=vo?"Y/n":"y/N",yd=(await l.question(`
2338
- ${Y}Enable route planning with live traffic (Google Routes)?${v} ${E(`[${ff}]`)}: ${P}`)).trim().toLowerCase()||(vo?"y":"n");process.stdout.write(v);let xi=yd==="y"||yd==="yes",Io="";xi?(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")}`),Io=await B(l," Google Maps API Key",vo),console.log(` ${M(">")} Routing: ${x("enabled")}`)):console.log(` ${E("Routing disabled.")}`);let Td=t.config.youtube,Ao=t.env.ALFRED_YOUTUBE_API_KEY??Td?.apiKey??"",gf=t.env.ALFRED_SUPADATA_API_KEY??Td?.supadata?.apiKey??"",yf=Ao?"Y/n":"y/N",wd=(await l.question(`
2339
- ${Y}Enable YouTube (search, video info, transcripts)?${v} ${E(`[${yf}]`)}: ${P}`)).trim().toLowerCase()||(Ao?"y":"n");process.stdout.write(v);let Ci=wd==="y"||wd==="yes",$o="",Zt="";if(Ci){console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${E(" 2. YouTube Data API v3 aktivieren")}`),console.log(` ${E(" 3. API Key erstellen (gleicher Key wie f\xFCr Routing m\xF6glich)")}`),$o=await B(l," YouTube API Key",Ao);let _=(await l.question(` ${Y}Supadata API Key (optional, Transkript-Fallback)?${v} ${E("[Enter to skip]")}: ${P}`)).trim();process.stdout.write(v),Zt=_||gf,console.log(` ${M(">")} YouTube: ${x("enabled")}${Zt?" + Supadata Fallback":""}`)}else console.log(` ${E("YouTube disabled.")}`);let ft=t.config.energy,Tf=t.env.ALFRED_ENERGY_GRID_NAME??ft?.gridName??"",Ro=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(ft?.gridUsageCt!=null?String(ft.gridUsageCt):""),wf=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(ft?.gridLossCt!=null?String(ft.gridLossCt):""),Ef=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(ft?.gridCapacityFee!=null?String(ft.gridCapacityFee):""),_f=t.env.ALFRED_ENERGY_GRID_METER_FEE??(ft?.gridMeterFee!=null?String(ft.gridMeterFee):""),kf=Ro?"Y/n":"y/N",Ed=(await l.question(`
2340
- ${Y}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${v} ${E(`[${kf}]`)}: ${P}`)).trim().toLowerCase()||(Ro?"y":"n");process.stdout.write(v);let Oi=Ed==="y"||Ed==="yes",Qt="",es="",Di="",Kr="",Gr="";Oi?(console.log(` ${E('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${E("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),Qt=await B(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",Tf),es=await B(l," Netznutzungsentgelt (ct/kWh netto)",Ro),Di=await B(l," Netzverlustentgelt (ct/kWh netto)",wf||"0.38"),Kr=await B(l," Leistungspauschale (\u20AC/Monat netto)",Ef),Gr=await B(l," Messentgelt (\u20AC/Monat netto)",_f||"2.22"),console.log(` ${M(">")} Energy: ${x(Qt||"enabled")} (${es} + ${Di} ct/kWh)`)):console.log(` ${E("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
2341
- ${x("Security configuration:")}`);let _d=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",je;if(_d)je=await B(l,"Owner user ID (for elevated permissions)",_d);else{let _=(await l.question(`${Y}Owner user ID${v} ${E("(optional, for elevated permissions)")}: ${P}`)).trim();process.stdout.write(v),je=_}let Yr=!1;if(je){let _=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${x("Enable shell access (admin commands) for the owner?")}`),console.log(` ${E("Allows Alfred to execute shell commands. Only for the owner.")}`);let $=(await l.question(` ${P}> ${v}${E(`[${_}] `)}`)).trim().toLowerCase();$===""?Yr=t.shellEnabled:Yr=$==="y"||$==="yes",console.log(Yr?` ${M(">")} Shell access ${x("enabled")} for owner ${E(je)}`:` ${E("Shell access disabled.")}`)}let Sf=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${x("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${E("By default, write actions are only allowed in DMs.")}`);let No=(await l.question(` ${P}> ${v}${E(`[${Sf}] `)}`)).trim().toLowerCase(),Vr;No===""?Vr=t.writeInGroups:Vr=No==="y"||No==="yes",console.log(Vr?` ${M(">")} Write actions ${x("enabled")} in groups`:` ${E("Write actions only in DMs (default).")}`);let bf=t.rateLimit??30;console.log("");let vf=await B(l," Rate limit (max write actions per hour per user)",String(bf)),Mi=Math.max(1,parseInt(vf,10)||30);console.log(` ${M(">")} Rate limit: ${x(String(Mi))} per hour`),console.log(`
2342
- ${x("Writing configuration files...")}`);let R=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${o.name}`];if(c){let _=o.envKeyName||"ALFRED_OLLAMA_API_KEY";R.push(`${_}=${c}`)}if(f!==o.defaultModel&&R.push(`ALFRED_LLM_MODEL=${f}`),u&&R.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(L).length>0){R.push("","# === Additional Model Tiers ===");for(let[_,$]of Object.entries(L)){let C=`ALFRED_LLM_${_.toUpperCase()}`;R.push(""),R.push(`${C}_PROVIDER=${$.provider}`),R.push(`${C}_MODEL=${$.model}`),$.apiKey&&R.push(`${C}_API_KEY=${$.apiKey}`),$.baseUrl&&R.push(`${C}_BASE_URL=${$.baseUrl}`)}}R.push("","# === Messaging Platforms ===","");for(let[_,$]of Object.entries(Re))R.push(`${_}=${$}`);if(R.push("","# === Web Search ===",""),pe?(R.push(`ALFRED_SEARCH_PROVIDER=${pe}`),he&&R.push(`ALFRED_SEARCH_API_KEY=${he}`),ye&&R.push(`ALFRED_SEARCH_BASE_URL=${ye}`)):(R.push("# ALFRED_SEARCH_PROVIDER=brave"),R.push("# ALFRED_SEARCH_API_KEY=")),R.push("","# === Email ===",""),Ee&&Oe.length>0){let _=Oe[0];_.provider==="microsoft"?(R.push("ALFRED_EMAIL_PROVIDER=microsoft"),_.msClientId?(R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${_.msClientId}`),R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${_.msClientSecret}`),R.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${_.msTenantId}`),R.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${_.msRefreshToken}`)):R.push("# Microsoft email credentials shared from calendar config")):(R.push(`ALFRED_EMAIL_USER=${_.user}`),R.push(`ALFRED_EMAIL_PASS=${_.pass}`)),Oe.length>1&&R.push("# Additional email accounts configured in config/default.yml")}else R.push("# ALFRED_EMAIL_USER="),R.push("# ALFRED_EMAIL_PASS=");if(R.push("","# === Speech ===",""),G?(R.push(`ALFRED_SPEECH_PROVIDER=${G}`),R.push(`ALFRED_SPEECH_API_KEY=${Q}`),Te&&R.push(`ALFRED_SPEECH_BASE_URL=${Te}`),Ne&&(R.push("ALFRED_TTS_ENABLED=true"),R.push(`ALFRED_TTS_VOICE=${Fe}`))):(R.push("# ALFRED_SPEECH_PROVIDER=groq"),R.push("# ALFRED_SPEECH_API_KEY=")),R.push("","# === Forge (GitHub / GitLab) ===",""),qt==="github"?(R.push("ALFRED_FORGE_PROVIDER=github"),R.push(`ALFRED_GITHUB_TOKEN=${Lr}`)):qt==="gitlab"?(R.push("ALFRED_FORGE_PROVIDER=gitlab"),R.push(`ALFRED_GITLAB_TOKEN=${xr}`)):(R.push("# ALFRED_FORGE_PROVIDER=github"),R.push("# ALFRED_GITHUB_TOKEN=")),R.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),bi?(R.push(`ALFRED_PROXMOX_BASE_URL=${Pr}`),R.push(`ALFRED_PROXMOX_TOKEN_ID=${uo}`),R.push(`ALFRED_PROXMOX_TOKEN_SECRET=${Fr}`)):(R.push("# ALFRED_PROXMOX_BASE_URL="),R.push("# ALFRED_PROXMOX_TOKEN_ID="),R.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),vi?(R.push(`ALFRED_PBS_BASE_URL=${jr}`),R.push(`ALFRED_PBS_TOKEN_ID=${mo}`),R.push(`ALFRED_PBS_TOKEN_SECRET=${Br}`),R.push(`ALFRED_PBS_MAX_AGE_HOURS=${Xr}`),Ii||R.push("ALFRED_PBS_VERIFY_TLS=false")):(R.push("# ALFRED_PBS_BASE_URL="),R.push("# ALFRED_PBS_TOKEN_ID="),R.push("# ALFRED_PBS_TOKEN_SECRET=")),Hr&&Yt?(R.push(`ALFRED_UNIFI_BASE_URL=${_s}`),R.push(`ALFRED_UNIFI_API_KEY=${Yt}`)):Hr?(R.push(`ALFRED_UNIFI_BASE_URL=${_s}`),R.push(`ALFRED_UNIFI_USERNAME=${go}`),R.push(`ALFRED_UNIFI_PASSWORD=${Wr}`)):(R.push("# ALFRED_UNIFI_BASE_URL="),R.push("# ALFRED_UNIFI_API_KEY=")),$i?(R.push(`ALFRED_HOMEASSISTANT_URL=${qr}`),R.push(`ALFRED_HOMEASSISTANT_TOKEN=${zr}`)):(R.push("# ALFRED_HOMEASSISTANT_URL="),R.push("# ALFRED_HOMEASSISTANT_TOKEN=")),R.push("","# === Contacts ===",""),Ri)for(let[_,$]of Object.entries(Se))R.push(`${_}=${$}`);else R.push("# ALFRED_CONTACTS_PROVIDER=carddav");R.push("","# === Docker ===",""),Ni?(Vt&&R.push(`ALFRED_DOCKER_SOCKET_PATH=${Vt}`),Jt&&R.push(`ALFRED_DOCKER_HOST=${Jt}`)):(R.push("# ALFRED_DOCKER_SOCKET_PATH="),R.push("# ALFRED_DOCKER_HOST=")),R.push("","# === BMW CarData ===",""),Li?R.push(`ALFRED_BMW_CLIENT_ID=${bo}`):R.push("# ALFRED_BMW_CLIENT_ID="),R.push("","# === Routing ===",""),xi?R.push(`ALFRED_ROUTING_API_KEY=${Io}`):R.push("# ALFRED_ROUTING_API_KEY="),R.push("","# === YouTube ===",""),Ci?(R.push(`ALFRED_YOUTUBE_API_KEY=${$o}`),Zt&&R.push(`ALFRED_SUPADATA_API_KEY=${Zt}`)):(R.push("# ALFRED_YOUTUBE_API_KEY="),R.push("# ALFRED_SUPADATA_API_KEY=")),R.push("","# === Energy / aWATTar ===",""),Oi&&es?(Qt&&R.push(`ALFRED_ENERGY_GRID_NAME=${Qt}`),R.push(`ALFRED_ENERGY_GRID_USAGE_CT=${es}`),R.push(`ALFRED_ENERGY_GRID_LOSS_CT=${Di}`),Kr&&R.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Kr}`),Gr&&R.push(`ALFRED_ENERGY_GRID_METER_FEE=${Gr}`)):(R.push("# ALFRED_ENERGY_GRID_NAME="),R.push("# ALFRED_ENERGY_GRID_USAGE_CT="),R.push("# ALFRED_ENERGY_GRID_LOSS_CT="),R.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),R.push("# ALFRED_ENERGY_GRID_METER_FEE=")),Kt&&(R.push("","# === Storage (PostgreSQL) ===",""),R.push(`ALFRED_STORAGE_CONNECTION_STRING=${Kt}`)),Rt==="s3"&&(R.push("","# === File Store (S3/MinIO) ===",""),Dr&&R.push(`ALFRED_S3_ACCESS_KEY=${Dr}`),Mr&&R.push(`ALFRED_S3_SECRET_KEY=${Mr}`)),R.push("","# === Security ===",""),je?R.push(`ALFRED_OWNER_USER_ID=${je}`):R.push("# ALFRED_OWNER_USER_ID="),R.push("");let If=Me.join(e,".env");Ae.writeFileSync(If,R.join(`
2343
- `),"utf-8"),console.log(` ${M("+")} ${E(".env")} written`);let Ui=Me.join(e,"config");Ae.existsSync(Ui)||Ae.mkdirSync(Ui,{recursive:!0});let kd={name:r,telegram:{token:we.telegram?.token??"",enabled:le.some(_=>_.name==="telegram")},discord:{token:we.discord?.token??"",enabled:le.some(_=>_.name==="discord")},whatsapp:{enabled:le.some(_=>_.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:we.matrix?.homeserverUrl??"https://matrix.org",accessToken:we.matrix?.accessToken??"",userId:we.matrix?.userId??"",enabled:le.some(_=>_.name==="matrix")},signal:{apiUrl:we.signal?.apiUrl??"http://localhost:8080",phoneNumber:we.signal?.phoneNumber??"",enabled:le.some(_=>_.name==="signal")},llm:Object.keys(L).length>0?{default:{provider:o.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...L}:{provider:o.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...pe?{search:{provider:pe,...he?{apiKey:he}:{},...ye?{baseUrl:ye}:{}}}:{},...Ee&&Oe.length>0?{email:{accounts:Oe.map(_=>_.provider==="microsoft"?{name:_.name,provider:"microsoft",..._.msClientId?{microsoft:{clientId:_.msClientId,clientSecret:_.msClientSecret,tenantId:_.msTenantId,refreshToken:_.msRefreshToken}}:{}}:{name:_.name,imap:{host:_.imapHost,port:_.imapPort,secure:_.imapPort===993},smtp:{host:_.smtpHost,port:_.smtpPort,secure:_.smtpPort===465},auth:{user:_.user,pass:_.pass}})}}:{},...G?{speech:{provider:G,apiKey:Q,...Te?{baseUrl:Te}:{},...Ne?{ttsEnabled:!0,ttsVoice:Fe}:{}}}:{},...Ve?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Wt.length>0||qt?{codeAgents:{enabled:Wt.length>0,agents:Wt,...qt==="github"?{forge:{provider:"github",github:{token:Lr}}}:qt==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:xr}}}:{}}}:{},...bi?{proxmox:{baseUrl:Pr,tokenId:uo,tokenSecret:Fr,verifyTls:po}}:{},...vi?{proxmoxBackup:{baseUrl:jr,tokenId:mo,tokenSecret:Br,maxAgeHours:Xr,verifyTls:Ii}}:{},...Hr?{unifi:{baseUrl:_s,...Yt?{apiKey:Yt}:{username:go,password:Wr},site:"default",verifyTls:yo}}:{},...$i?{homeassistant:{baseUrl:qr,accessToken:zr,verifyTls:wo}}:{},...Ri?{contacts:{provider:Ze,...Ze==="carddav"?{carddav:{serverUrl:Se.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:Se.ALFRED_CARDDAV_CONTACTS_USERNAME}}:Ze==="google"?{google:{clientId:Se.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:Ze==="microsoft"?{microsoft:{clientId:Se.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:Se.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Ni?{docker:{...Vt?{socketPath:Vt}:{},...Jt?{host:Jt}:{}}}:{},...Li?{bmw:{clientId:bo}}:{},...xi?{routing:{apiKey:Io}}:{},...Ci?{youtube:{apiKey:$o,...Zt?{supadata:{enabled:!0,apiKey:Zt}}:{}}}:{},...Oi&&es?{energy:{...Qt?{gridName:Qt}:{},gridUsageCt:parseFloat(es),gridLossCt:parseFloat(Di||"0"),...Kr?{gridCapacityFee:parseFloat(Kr)}:{},...Gr?{gridMeterFee:parseFloat(Gr)}:{}}}:{},api:{enabled:!0,port:3420,host:id,webUi:ao,...wi?{token:wi}:{},...Ti?{tls:{enabled:!0}}:{}},...zt?{cluster:{enabled:!0,nodeId:ws,role:Ei,redisUrl:_i,token:ki}}:{},storage:{path:"./data/alfred.db",...oo==="postgres"?{backend:"postgres"}:{},...Kt?{connectionString:Kt}:{}},...Rt!=="local"?{fileStore:{backend:Rt,...Cr?{basePath:Cr}:{},...Si?{s3Endpoint:Si}:{},...Or?{s3Bucket:Or}:{},...Dr?{s3AccessKey:Dr}:{},...Mr?{s3SecretKey:Mr}:{}}}:{},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};je&&(kd.security.ownerUserId=je);let Af="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Ql.dump(kd,{lineWidth:120,noRefs:!0,sortKeys:!1}),$f=Me.join(Ui,"default.yml");Ae.writeFileSync($f,Af,"utf-8"),console.log(` ${M("+")} ${E("config/default.yml")} written`);let Lo=Me.join(Ui,"rules");Ae.existsSync(Lo)||Ae.mkdirSync(Lo,{recursive:!0});let Rf=Yr&&je?`
2322
+ ${U}> ${v}${E("[y/N] ")}`)).trim().toLowerCase();if(ad==="y"||ad==="yes"){id="0.0.0.0",console.log(` ${M(">")} API Host: ${x("0.0.0.0")} (alle Interfaces)`),console.log(`
2323
+ ${x("TLS/HTTPS aktivieren?")}`),console.log(`${E("Empfohlen bei Remote-Zugriff. Selbstsigniertes Zertifikat wird automatisch generiert.")}`);let _=(await l.question(`${U}> ${v}${E("[Y/n] ")}`)).trim().toLowerCase();Ti=_===""||_==="y"||_==="yes",console.log(Ti?` ${M(">")} TLS ${x("enabled")}`:` ${E("TLS disabled \u2014 API l\xE4uft \xFCber HTTP.")}`),console.log(`
2324
+ ${x("API Token setzen?")}`),console.log(`${E("Sch\xFCtzt die API mit Bearer-Token-Authentifizierung.")}`),wi=(await l.question(` ${G}API Token${v} ${E("[Enter to skip]")}: ${U}`)).trim(),process.stdout.write(v),wi&&console.log(` ${M(">")} API Token gesetzt`)}else console.log(` ${E("API nur auf localhost erreichbar.")}`);let zt=!1,ws="",Ei="primary",_i="",ki="";console.log(`
2325
+ ${x("Cluster / Hochverf\xFCgbarkeit?")}`),console.log(`${E("Mehrere Alfred-Nodes f\xFCr Failover und Last-Verteilung.")}`);let od=(await l.question(`${U}> ${v}${E("[y/N] ")}`)).trim().toLowerCase();if(zt=od==="y"||od==="yes",zt)if(console.log(`
2326
+ ${x("Ist dies der erste Node (Primary) oder ein weiterer?")}`),console.log(` ${E("1) Erster Node (Primary) \u2014 Redis URL eingeben, Cluster-Token generieren")}`),console.log(` ${E("2) Weiterer Node \u2014 Primary-Adresse + Cluster-Token eingeben")}`),(await l.question(` ${U}> ${v}${E("[1/2] ")}`)).trim()==="2"){Ei="secondary",console.log(`
2327
+ ${E("Cluster beitreten:")}`);let $=(await l.question(` ${G}Primary-Host (IP:Port)${v}: ${U}`)).trim();process.stdout.write(v),ki=(await l.question(` ${G}Cluster-Token${v}: ${U}`)).trim(),process.stdout.write(v),_i=(await l.question(` ${G}Redis URL${v} ${E("[redis://localhost:6379]")}: ${U}`)).trim()||"redis://localhost:6379",process.stdout.write(v),ws=`node-${Math.random().toString(36).slice(2,8)}`,console.log(` ${M(">")} Cluster beigetreten als ${x(ws)} (secondary)`)}else Ei="primary",_i=(await l.question(`
2328
+ ${G}Redis URL${v} ${E("[redis://localhost:6379]")}: ${U}`)).trim()||"redis://localhost:6379",process.stdout.write(v),ws=`node-${Math.random().toString(36).slice(2,8)}`,ki=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,console.log(` ${M(">")} Cluster Primary: ${x(ws)}`),console.log(` ${M(">")} Cluster-Token: ${x(ki)}`),console.log(` ${E(" Diesen Token beim 2. Node eingeben.")}`);else console.log(` ${E("Einzelinstanz \u2014 kein Cluster.")}`);let oo="sqlite",Kt="",co=t.config.storage?.backend??"sqlite",cd=t.env.ALFRED_STORAGE_CONNECTION_STRING??t.config.storage?.connectionString??"";if(zt||co==="postgres"){console.log(`
2329
+ ${x("Datenbank-Backend")}`),console.log(`${E("SQLite ist Standard. PostgreSQL empfohlen f\xFCr Cluster/HA (gemeinsamer Zustand).")}`),console.log(` ${fe("1)")} SQLite (lokal, Standard)`),console.log(` ${fe("2)")} PostgreSQL (HA, gemeinsame DB)`);let _=co==="postgres"||zt?"2":"1";((await l.question(`${U}> ${v}${E(`[${_}] `)}`)).trim()||_)==="2"?(oo="postgres",Kt=await B(l," PostgreSQL Connection-String",cd||"postgres://alfred:password@localhost:5432/alfred"),console.log(` ${M(">")} PostgreSQL: ${E(Kt.replace(/:[^:@]+@/,":***@"))}`),co==="sqlite"&&cd!==Kt&&console.log(` ${Om("i")} Bestehende SQLite-Daten migrieren: ${x("alfred migrate-db")}`)):console.log(` ${M(">")} SQLite (Standard)`)}let Rt="local",Cr="",Si="",Or="",Dr="",Mr="",Nt=t.config.fileStore;if(zt||Nt){console.log(`
2330
+ ${x("Datei-Storage")}`),console.log(`${E("Wo sollen Datei-Uploads (Dokumente, Inbox) gespeichert werden?")}`),console.log(` ${fe("1)")} Lokal (Standard \u2014 ./data/files)`),console.log(` ${fe("2)")} NFS / Netzwerk-Pfad`),console.log(` ${fe("3)")} S3 / MinIO`);let _=Nt?.backend==="s3"?"3":Nt?.backend==="nfs"?"2":"1",$=(await l.question(`${U}> ${v}${E(`[${_}] `)}`)).trim()||_;$==="3"?(Rt="s3",Si=await B(l," S3/MinIO Endpoint (z.B. http://minio:9000)",Nt?.s3Endpoint??""),Or=await B(l," Bucket-Name",Nt?.s3Bucket??"alfred-files"),Dr=await B(l," Access Key",t.env.ALFRED_S3_ACCESS_KEY??Nt?.s3AccessKey??""),Mr=await B(l," Secret Key",t.env.ALFRED_S3_SECRET_KEY??Nt?.s3SecretKey??""),console.log(` ${M(">")} S3: ${E(Si)} / ${Or}`)):$==="2"?(Rt="nfs",Cr=await B(l," NFS-Pfad",Nt?.basePath??"/mnt/alfred-files"),console.log(` ${M(">")} NFS: ${E(Cr)}`)):console.log(` ${M(">")} Lokal (./data/files)`)}console.log(`
2331
+ ${x("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${E("Control VMs, containers, network devices, and smart home through Alfred.")}`);let Ur=t.config.proxmox,lo=t.env.ALFRED_PROXMOX_BASE_URL??Ur?.baseUrl??"",af=lo?"Y/n":"y/N",ld=(await l.question(` ${G}Enable Proxmox VE?${v} ${E(`[${af}]`)}: ${U}`)).trim().toLowerCase()||(lo?"y":"n");process.stdout.write(v);let bi=ld==="y"||ld==="yes",Pr="",uo="",Fr="",po=!0;if(bi){Pr=await B(l," Proxmox URL (e.g. https://pve.local:8006)",lo||"https://pve.local:8006");let _=t.env.ALFRED_PROXMOX_TOKEN_ID??Ur?.tokenId??"";_&&console.log(` ${E(`Current token ID: ${_}`)}`),console.log(` ${E("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),uo=await B(l," API Token ID (user@realm!name)",_);let $=t.env.ALFRED_PROXMOX_TOKEN_SECRET??Ur?.tokenSecret??"";$&&console.log(` ${E(`Current secret: ${Ie($)}`)}`),Fr=(await l.question(` ${G}API Token Secret${v}: ${U}`)).trim(),process.stdout.write(v),!Fr&&$&&(Fr=$);let C=Ur?.verifyTls===!1?"y/N":"Y/n",Z=(await l.question(` ${G}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${C}]`)}: ${U}`)).trim().toLowerCase()||(Ur?.verifyTls===!1?"n":"y");process.stdout.write(v),po=Z==="y"||Z==="yes",console.log(` ${M(">")} Proxmox: ${x(Pr)} ${E(`(TLS verify: ${po?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox disabled.")}`);let Es=t.config.proxmoxBackup,ho=t.env.ALFRED_PBS_BASE_URL??Es?.baseUrl??"",of=ho?"Y/n":"y/N",dd=(await l.question(`
2332
+ ${G}Enable Proxmox Backup Server?${v} ${E(`[${of}]`)}: ${U}`)).trim().toLowerCase()||(ho?"y":"n");process.stdout.write(v);let vi=dd==="y"||dd==="yes",jr="",mo="",Br="",Xr=24,Ii=!0;if(vi){jr=await B(l," PBS URL (e.g. https://pbs.local:8007)",ho||"https://pbs.local:8007");let _=t.env.ALFRED_PBS_TOKEN_ID??Es?.tokenId??"";_&&console.log(` ${E(`Current token ID: ${_}`)}`),console.log(` ${E("Create: Configuration \u2192 Access Control \u2192 API Token")}`),mo=await B(l," API Token ID (user@realm!name)",_);let $=t.env.ALFRED_PBS_TOKEN_SECRET??Es?.tokenSecret??"";$&&console.log(` ${E(`Current secret: ${Ie($)}`)}`),Br=(await l.question(` ${G}API Token Secret${v}: ${U}`)).trim(),process.stdout.write(v),!Br&&$&&(Br=$);let C=t.env.ALFRED_PBS_MAX_AGE_HOURS??Es?.maxAgeHours?.toString()??"24";Xr=parseInt(await B(l," Max backup age (hours, alert if older)",C),10)||24;let Z=Es?.verifyTls===!1?"y/N":"Y/n",P=(await l.question(` ${G}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${Z}]`)}: ${U}`)).trim().toLowerCase()||(Es?.verifyTls===!1?"n":"y");process.stdout.write(v),Ii=P==="y"||P==="yes",console.log(` ${M(">")} PBS: ${x(jr)} ${E(`(max age: ${Xr}h, TLS verify: ${Ii?"yes":"no"})`)}`)}else console.log(` ${E("Proxmox Backup Server disabled.")}`);let Gt=t.config.unifi,fo=t.env.ALFRED_UNIFI_BASE_URL??Gt?.baseUrl??"",cf=fo?"Y/n":"y/N",ud=(await l.question(`
2333
+ ${G}Enable UniFi Network?${v} ${E(`[${cf}]`)}: ${U}`)).trim().toLowerCase()||(fo?"y":"n");process.stdout.write(v);let Hr=ud==="y"||ud==="yes",_s="",Yt="",go="",Wr="",yo=!0;if(Hr){_s=await B(l," UniFi URL (e.g. https://unifi.local)",fo||"https://unifi.local"),console.log(` ${E("Auth: API Key (recommended) or Username/Password")}`);let _=t.env.ALFRED_UNIFI_API_KEY??Gt?.apiKey??"",$=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],C=_?"1":Gt?.username?"2":"1";for(let ae of $)console.log(` ${U}${ae.num}${v}) ${ae.label}`);if(((await l.question(` ${U}> ${v}${E(`[${C}] `)}`)).trim()||C)==="1")_&&console.log(` ${E(`Current key: ${Ie(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),Yt=(await l.question(` ${G}API Key${v}: ${U}`)).trim(),process.stdout.write(v),!Yt&&_&&(Yt=_);else{let ae=t.env.ALFRED_UNIFI_USERNAME??Gt?.username??"";go=await B(l," Username",ae||"alfred");let Le=t.env.ALFRED_UNIFI_PASSWORD??Gt?.password??"";Le&&console.log(` ${E(`Current password: ${Ie(Le)}`)}`),Wr=(await l.question(` ${G}Password${v}: ${U}`)).trim(),process.stdout.write(v),!Wr&&Le&&(Wr=Le)}let P=Gt?.verifyTls===!1?"y/N":"Y/n",J=(await l.question(` ${G}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${P}]`)}: ${U}`)).trim().toLowerCase()||(Gt?.verifyTls===!1?"n":"y");process.stdout.write(v),yo=J==="y"||J==="yes",console.log(` ${M(">")} UniFi: ${x(_s)} ${E(`(TLS verify: ${yo?"yes":"no"})`)}`)}else console.log(` ${E("UniFi disabled.")}`);let Ai=t.config.homeassistant,To=t.env.ALFRED_HOMEASSISTANT_URL??Ai?.baseUrl??"",lf=To?"Y/n":"y/N",pd=(await l.question(`
2334
+ ${G}Enable Home Assistant?${v} ${E(`[${lf}]`)}: ${U}`)).trim().toLowerCase()||(To?"y":"n");process.stdout.write(v);let $i=pd==="y"||pd==="yes",qr="",zr="",wo=!0;if($i){qr=await B(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",To||"http://homeassistant.local:8123");let _=t.env.ALFRED_HOMEASSISTANT_TOKEN??Ai?.accessToken??"";_&&console.log(` ${E(`Current token: ${Ie(_)}`)}`),console.log(` ${E("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),zr=(await l.question(` ${G}Long-Lived Access Token${v}: ${U}`)).trim(),process.stdout.write(v),!zr&&_&&(zr=_);let $=Ai?.verifyTls===!1?"y/N":"Y/n",C=(await l.question(` ${G}Verify TLS?${v} ${E(`(self-signed? \u2192 no) [${$}]`)}: ${U}`)).trim().toLowerCase()||(Ai?.verifyTls===!1?"n":"y");process.stdout.write(v),wo=C==="y"||C==="yes",console.log(` ${M(">")} Home Assistant: ${x(qr)} ${E(`(TLS verify: ${wo?"yes":"no"})`)}`)}else console.log(` ${E("Home Assistant disabled.")}`);let Je=t.config.contacts,Eo=t.env.ALFRED_CONTACTS_PROVIDER??Je?.provider??"",df=Eo?"Y/n":"y/N",hd=(await l.question(`
2335
+ ${G}Enable Contacts management?${v} ${E(`[${df}]`)}: ${U}`)).trim().toLowerCase()||(Eo?"y":"n");process.stdout.write(v);let Ri=hd==="y"||hd==="yes",Ze="",Se={};if(Ri){let _=["carddav","google","microsoft"],$=_.indexOf(Eo),C=$>=0?$+1:1;console.log(` ${fe("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${fe("2)")} Google Contacts`),console.log(` ${fe("3)")} Microsoft 365`);let Z=await fi(l," > ",1,3,C);if(Ze=_[Z-1],Se.ALFRED_CONTACTS_PROVIDER=Ze,Ze==="carddav"){let P=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Je?.carddav?.serverUrl??"";Se.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await B(l," CardDAV Server URL",P||"https://cloud.example.com/remote.php/dav");let J=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Je?.carddav?.username??"";Se.ALFRED_CARDDAV_CONTACTS_USERNAME=await B(l," Username",J);let ae=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Je?.carddav?.password??"";ae&&console.log(` ${E(`Current password: ${Ie(ae)}`)}`);let Le=(await l.question(` ${G}Password${v}: ${U}`)).trim();process.stdout.write(v),Se.ALFRED_CARDDAV_CONTACTS_PASSWORD=Le||ae}else if(Ze==="google"){let P=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Je?.google?.clientId??"";P&&console.log(` ${E(`Current client ID: ${Ie(P)}`)}`),Se.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${G}Google Client ID${v}: ${U}`)).trim()||P,process.stdout.write(v);let J=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Je?.google?.clientSecret??"";Se.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${G}Google Client Secret${v}: ${U}`)).trim()||J,process.stdout.write(v);let ae=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Je?.google?.refreshToken??"";Se.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${G}Refresh Token${v}: ${U}`)).trim()||ae,process.stdout.write(v)}else if(Ze==="microsoft"){let P=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Je?.microsoft?.clientId??"";P&&console.log(` ${E(`Current client ID: ${Ie(P)}`)}`),Se.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${G}Microsoft Client ID${v}: ${U}`)).trim()||P,process.stdout.write(v);let J=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Je?.microsoft?.clientSecret??"";Se.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${G}Microsoft Client Secret${v}: ${U}`)).trim()||J,process.stdout.write(v);let ae=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Je?.microsoft?.tenantId??"";Se.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await B(l," Tenant ID",ae||"common");let Le=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Je?.microsoft?.refreshToken??"";console.log(` ${E("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),Se.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${G}Refresh Token${v}: ${U}`)).trim()||Le,process.stdout.write(v)}console.log(` ${M(">")} Contacts: ${x(Ze)}`)}else console.log(` ${E("Contacts disabled.")}`);let md=t.config.docker,_o=t.env.ALFRED_DOCKER_SOCKET_PATH??md?.socketPath??"",ko=t.env.ALFRED_DOCKER_HOST??md?.host??"",uf=_o||ko?"Y/n":"y/N",fd=(await l.question(`
2336
+ ${G}Enable Docker management?${v} ${E(`[${uf}]`)}: ${U}`)).trim().toLowerCase()||(_o||ko?"y":"n");process.stdout.write(v);let Ni=fd==="y"||fd==="yes",Vt="",Jt="";if(Ni){let _=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${E("Use socket path for local Docker, or host URL for remote.")}`),Vt=await B(l," Docker socket path",_o||_);let $=(await l.question(` ${G}Docker host URL (optional, for remote)${v}: ${U}`)).trim();process.stdout.write(v),Jt=$||ko,console.log(` ${M(">")} Docker: ${x(Jt||Vt)}`)}else console.log(` ${E("Docker disabled.")}`);let pf=t.config.bmw,So=t.env.ALFRED_BMW_CLIENT_ID??pf?.clientId??"",hf=So?"Y/n":"y/N",gd=(await l.question(`
2337
+ ${G}Enable BMW CarData (vehicle status, charging)?${v} ${E(`[${hf}]`)}: ${U}`)).trim().toLowerCase()||(So?"y":"n");process.stdout.write(v);let Li=gd==="y"||gd==="yes",bo="";Li?(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)')}`),bo=await B(l," BMW CarData Client ID",So),console.log(` ${M(">")} BMW CarData: ${x("enabled")}`)):console.log(` ${E("BMW CarData disabled.")}`);let mf=t.config.routing,vo=t.env.ALFRED_ROUTING_API_KEY??mf?.apiKey??"",ff=vo?"Y/n":"y/N",yd=(await l.question(`
2338
+ ${G}Enable route planning with live traffic (Google Routes)?${v} ${E(`[${ff}]`)}: ${U}`)).trim().toLowerCase()||(vo?"y":"n");process.stdout.write(v);let xi=yd==="y"||yd==="yes",Io="";xi?(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")}`),Io=await B(l," Google Maps API Key",vo),console.log(` ${M(">")} Routing: ${x("enabled")}`)):console.log(` ${E("Routing disabled.")}`);let Td=t.config.youtube,Ao=t.env.ALFRED_YOUTUBE_API_KEY??Td?.apiKey??"",gf=t.env.ALFRED_SUPADATA_API_KEY??Td?.supadata?.apiKey??"",yf=Ao?"Y/n":"y/N",wd=(await l.question(`
2339
+ ${G}Enable YouTube (search, video info, transcripts)?${v} ${E(`[${yf}]`)}: ${U}`)).trim().toLowerCase()||(Ao?"y":"n");process.stdout.write(v);let Ci=wd==="y"||wd==="yes",$o="",Zt="";if(Ci){console.log(` ${E("Setup:")}`),console.log(` ${E(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${E(" 2. YouTube Data API v3 aktivieren")}`),console.log(` ${E(" 3. API Key erstellen (gleicher Key wie f\xFCr Routing m\xF6glich)")}`),$o=await B(l," YouTube API Key",Ao);let _=(await l.question(` ${G}Supadata API Key (optional, Transkript-Fallback)?${v} ${E("[Enter to skip]")}: ${U}`)).trim();process.stdout.write(v),Zt=_||gf,console.log(` ${M(">")} YouTube: ${x("enabled")}${Zt?" + Supadata Fallback":""}`)}else console.log(` ${E("YouTube disabled.")}`);let ft=t.config.energy,Tf=t.env.ALFRED_ENERGY_GRID_NAME??ft?.gridName??"",Ro=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(ft?.gridUsageCt!=null?String(ft.gridUsageCt):""),wf=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(ft?.gridLossCt!=null?String(ft.gridLossCt):""),Ef=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(ft?.gridCapacityFee!=null?String(ft.gridCapacityFee):""),_f=t.env.ALFRED_ENERGY_GRID_METER_FEE??(ft?.gridMeterFee!=null?String(ft.gridMeterFee):""),kf=Ro?"Y/n":"y/N",Ed=(await l.question(`
2340
+ ${G}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${v} ${E(`[${kf}]`)}: ${U}`)).trim().toLowerCase()||(Ro?"y":"n");process.stdout.write(v);let Oi=Ed==="y"||Ed==="yes",Qt="",es="",Di="",Kr="",Gr="";Oi?(console.log(` ${E('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${E("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),Qt=await B(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",Tf),es=await B(l," Netznutzungsentgelt (ct/kWh netto)",Ro),Di=await B(l," Netzverlustentgelt (ct/kWh netto)",wf||"0.38"),Kr=await B(l," Leistungspauschale (\u20AC/Monat netto)",Ef),Gr=await B(l," Messentgelt (\u20AC/Monat netto)",_f||"2.22"),console.log(` ${M(">")} Energy: ${x(Qt||"enabled")} (${es} + ${Di} ct/kWh)`)):console.log(` ${E("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
2341
+ ${x("Security configuration:")}`);let _d=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",Fe;if(_d)Fe=await B(l,"Owner user ID (for elevated permissions)",_d);else{let _=(await l.question(`${G}Owner user ID${v} ${E("(optional, for elevated permissions)")}: ${U}`)).trim();process.stdout.write(v),Fe=_}let Yr=!1;if(Fe){let _=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${x("Enable shell access (admin commands) for the owner?")}`),console.log(` ${E("Allows Alfred to execute shell commands. Only for the owner.")}`);let $=(await l.question(` ${U}> ${v}${E(`[${_}] `)}`)).trim().toLowerCase();$===""?Yr=t.shellEnabled:Yr=$==="y"||$==="yes",console.log(Yr?` ${M(">")} Shell access ${x("enabled")} for owner ${E(Fe)}`:` ${E("Shell access disabled.")}`)}let Sf=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${x("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${E("By default, write actions are only allowed in DMs.")}`);let No=(await l.question(` ${U}> ${v}${E(`[${Sf}] `)}`)).trim().toLowerCase(),Vr;No===""?Vr=t.writeInGroups:Vr=No==="y"||No==="yes",console.log(Vr?` ${M(">")} Write actions ${x("enabled")} in groups`:` ${E("Write actions only in DMs (default).")}`);let bf=t.rateLimit??30;console.log("");let vf=await B(l," Rate limit (max write actions per hour per user)",String(bf)),Mi=Math.max(1,parseInt(vf,10)||30);console.log(` ${M(">")} Rate limit: ${x(String(Mi))} per hour`),console.log(`
2342
+ ${x("Writing configuration files...")}`);let R=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${o.name}`];if(c){let _=o.envKeyName||"ALFRED_OLLAMA_API_KEY";R.push(`${_}=${c}`)}if(f!==o.defaultModel&&R.push(`ALFRED_LLM_MODEL=${f}`),u&&R.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(L).length>0){R.push("","# === Additional Model Tiers ===");for(let[_,$]of Object.entries(L)){let C=`ALFRED_LLM_${_.toUpperCase()}`;R.push(""),R.push(`${C}_PROVIDER=${$.provider}`),R.push(`${C}_MODEL=${$.model}`),$.apiKey&&R.push(`${C}_API_KEY=${$.apiKey}`),$.baseUrl&&R.push(`${C}_BASE_URL=${$.baseUrl}`)}}R.push("","# === Messaging Platforms ===","");for(let[_,$]of Object.entries(Re))R.push(`${_}=${$}`);if(R.push("","# === Web Search ===",""),ue?(R.push(`ALFRED_SEARCH_PROVIDER=${ue}`),he&&R.push(`ALFRED_SEARCH_API_KEY=${he}`),ye&&R.push(`ALFRED_SEARCH_BASE_URL=${ye}`)):(R.push("# ALFRED_SEARCH_PROVIDER=brave"),R.push("# ALFRED_SEARCH_API_KEY=")),R.push("","# === Email ===",""),we&&Ce.length>0){let _=Ce[0];_.provider==="microsoft"?(R.push("ALFRED_EMAIL_PROVIDER=microsoft"),_.msClientId?(R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${_.msClientId}`),R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${_.msClientSecret}`),R.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${_.msTenantId}`),R.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${_.msRefreshToken}`)):R.push("# Microsoft email credentials shared from calendar config")):(R.push(`ALFRED_EMAIL_USER=${_.user}`),R.push(`ALFRED_EMAIL_PASS=${_.pass}`)),Ce.length>1&&R.push("# Additional email accounts configured in config/default.yml")}else R.push("# ALFRED_EMAIL_USER="),R.push("# ALFRED_EMAIL_PASS=");if(R.push("","# === Speech ===",""),V?(R.push(`ALFRED_SPEECH_PROVIDER=${V}`),R.push(`ALFRED_SPEECH_API_KEY=${te}`),Ee&&R.push(`ALFRED_SPEECH_BASE_URL=${Ee}`),Ye&&(R.push("ALFRED_TTS_ENABLED=true"),R.push(`ALFRED_TTS_VOICE=${Pe}`))):(R.push("# ALFRED_SPEECH_PROVIDER=groq"),R.push("# ALFRED_SPEECH_API_KEY=")),R.push("","# === Forge (GitHub / GitLab) ===",""),qt==="github"?(R.push("ALFRED_FORGE_PROVIDER=github"),R.push(`ALFRED_GITHUB_TOKEN=${Lr}`)):qt==="gitlab"?(R.push("ALFRED_FORGE_PROVIDER=gitlab"),R.push(`ALFRED_GITLAB_TOKEN=${xr}`)):(R.push("# ALFRED_FORGE_PROVIDER=github"),R.push("# ALFRED_GITHUB_TOKEN=")),R.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),bi?(R.push(`ALFRED_PROXMOX_BASE_URL=${Pr}`),R.push(`ALFRED_PROXMOX_TOKEN_ID=${uo}`),R.push(`ALFRED_PROXMOX_TOKEN_SECRET=${Fr}`)):(R.push("# ALFRED_PROXMOX_BASE_URL="),R.push("# ALFRED_PROXMOX_TOKEN_ID="),R.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),vi?(R.push(`ALFRED_PBS_BASE_URL=${jr}`),R.push(`ALFRED_PBS_TOKEN_ID=${mo}`),R.push(`ALFRED_PBS_TOKEN_SECRET=${Br}`),R.push(`ALFRED_PBS_MAX_AGE_HOURS=${Xr}`),Ii||R.push("ALFRED_PBS_VERIFY_TLS=false")):(R.push("# ALFRED_PBS_BASE_URL="),R.push("# ALFRED_PBS_TOKEN_ID="),R.push("# ALFRED_PBS_TOKEN_SECRET=")),Hr&&Yt?(R.push(`ALFRED_UNIFI_BASE_URL=${_s}`),R.push(`ALFRED_UNIFI_API_KEY=${Yt}`)):Hr?(R.push(`ALFRED_UNIFI_BASE_URL=${_s}`),R.push(`ALFRED_UNIFI_USERNAME=${go}`),R.push(`ALFRED_UNIFI_PASSWORD=${Wr}`)):(R.push("# ALFRED_UNIFI_BASE_URL="),R.push("# ALFRED_UNIFI_API_KEY=")),$i?(R.push(`ALFRED_HOMEASSISTANT_URL=${qr}`),R.push(`ALFRED_HOMEASSISTANT_TOKEN=${zr}`)):(R.push("# ALFRED_HOMEASSISTANT_URL="),R.push("# ALFRED_HOMEASSISTANT_TOKEN=")),R.push("","# === Contacts ===",""),Ri)for(let[_,$]of Object.entries(Se))R.push(`${_}=${$}`);else R.push("# ALFRED_CONTACTS_PROVIDER=carddav");R.push("","# === Docker ===",""),Ni?(Vt&&R.push(`ALFRED_DOCKER_SOCKET_PATH=${Vt}`),Jt&&R.push(`ALFRED_DOCKER_HOST=${Jt}`)):(R.push("# ALFRED_DOCKER_SOCKET_PATH="),R.push("# ALFRED_DOCKER_HOST=")),R.push("","# === BMW CarData ===",""),Li?R.push(`ALFRED_BMW_CLIENT_ID=${bo}`):R.push("# ALFRED_BMW_CLIENT_ID="),R.push("","# === Routing ===",""),xi?R.push(`ALFRED_ROUTING_API_KEY=${Io}`):R.push("# ALFRED_ROUTING_API_KEY="),R.push("","# === YouTube ===",""),Ci?(R.push(`ALFRED_YOUTUBE_API_KEY=${$o}`),Zt&&R.push(`ALFRED_SUPADATA_API_KEY=${Zt}`)):(R.push("# ALFRED_YOUTUBE_API_KEY="),R.push("# ALFRED_SUPADATA_API_KEY=")),R.push("","# === Energy / aWATTar ===",""),Oi&&es?(Qt&&R.push(`ALFRED_ENERGY_GRID_NAME=${Qt}`),R.push(`ALFRED_ENERGY_GRID_USAGE_CT=${es}`),R.push(`ALFRED_ENERGY_GRID_LOSS_CT=${Di}`),Kr&&R.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Kr}`),Gr&&R.push(`ALFRED_ENERGY_GRID_METER_FEE=${Gr}`)):(R.push("# ALFRED_ENERGY_GRID_NAME="),R.push("# ALFRED_ENERGY_GRID_USAGE_CT="),R.push("# ALFRED_ENERGY_GRID_LOSS_CT="),R.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),R.push("# ALFRED_ENERGY_GRID_METER_FEE=")),Kt&&(R.push("","# === Storage (PostgreSQL) ===",""),R.push(`ALFRED_STORAGE_CONNECTION_STRING=${Kt}`)),Rt==="s3"&&(R.push("","# === File Store (S3/MinIO) ===",""),Dr&&R.push(`ALFRED_S3_ACCESS_KEY=${Dr}`),Mr&&R.push(`ALFRED_S3_SECRET_KEY=${Mr}`)),R.push("","# === Security ===",""),Fe?R.push(`ALFRED_OWNER_USER_ID=${Fe}`):R.push("# ALFRED_OWNER_USER_ID="),R.push("");let If=De.join(e,".env");Ae.writeFileSync(If,R.join(`
2343
+ `),"utf-8"),console.log(` ${M("+")} ${E(".env")} written`);let Ui=De.join(e,"config");Ae.existsSync(Ui)||Ae.mkdirSync(Ui,{recursive:!0});let kd={name:r,telegram:{token:Te.telegram?.token??"",enabled:ce.some(_=>_.name==="telegram")},discord:{token:Te.discord?.token??"",enabled:ce.some(_=>_.name==="discord")},whatsapp:{enabled:ce.some(_=>_.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:Te.matrix?.homeserverUrl??"https://matrix.org",accessToken:Te.matrix?.accessToken??"",userId:Te.matrix?.userId??"",enabled:ce.some(_=>_.name==="matrix")},signal:{apiUrl:Te.signal?.apiUrl??"http://localhost:8080",phoneNumber:Te.signal?.phoneNumber??"",enabled:ce.some(_=>_.name==="signal")},llm:Object.keys(L).length>0?{default:{provider:o.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...L}:{provider:o.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...ue?{search:{provider:ue,...he?{apiKey:he}:{},...ye?{baseUrl:ye}:{}}}:{},...we&&Ce.length>0?{email:{accounts:Ce.map(_=>_.provider==="microsoft"?{name:_.name,provider:"microsoft",..._.msClientId?{microsoft:{clientId:_.msClientId,clientSecret:_.msClientSecret,tenantId:_.msTenantId,refreshToken:_.msRefreshToken}}:{}}:{name:_.name,imap:{host:_.imapHost,port:_.imapPort,secure:_.imapPort===993},smtp:{host:_.smtpHost,port:_.smtpPort,secure:_.smtpPort===465},auth:{user:_.user,pass:_.pass}})}}:{},...V?{speech:{provider:V,apiKey:te,...Ee?{baseUrl:Ee}:{},...Ye?{ttsEnabled:!0,ttsVoice:Pe}:{}}}:{},...Ve?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Wt.length>0||qt?{codeAgents:{enabled:Wt.length>0,agents:Wt,...qt==="github"?{forge:{provider:"github",github:{token:Lr}}}:qt==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:xr}}}:{}}}:{},...bi?{proxmox:{baseUrl:Pr,tokenId:uo,tokenSecret:Fr,verifyTls:po}}:{},...vi?{proxmoxBackup:{baseUrl:jr,tokenId:mo,tokenSecret:Br,maxAgeHours:Xr,verifyTls:Ii}}:{},...Hr?{unifi:{baseUrl:_s,...Yt?{apiKey:Yt}:{username:go,password:Wr},site:"default",verifyTls:yo}}:{},...$i?{homeassistant:{baseUrl:qr,accessToken:zr,verifyTls:wo}}:{},...Ri?{contacts:{provider:Ze,...Ze==="carddav"?{carddav:{serverUrl:Se.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:Se.ALFRED_CARDDAV_CONTACTS_USERNAME}}:Ze==="google"?{google:{clientId:Se.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:Ze==="microsoft"?{microsoft:{clientId:Se.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:Se.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Ni?{docker:{...Vt?{socketPath:Vt}:{},...Jt?{host:Jt}:{}}}:{},...Li?{bmw:{clientId:bo}}:{},...xi?{routing:{apiKey:Io}}:{},...Ci?{youtube:{apiKey:$o,...Zt?{supadata:{enabled:!0,apiKey:Zt}}:{}}}:{},...Oi&&es?{energy:{...Qt?{gridName:Qt}:{},gridUsageCt:parseFloat(es),gridLossCt:parseFloat(Di||"0"),...Kr?{gridCapacityFee:parseFloat(Kr)}:{},...Gr?{gridMeterFee:parseFloat(Gr)}:{}}}:{},api:{enabled:!0,port:3420,host:id,webUi:ao,...wi?{token:wi}:{},...Ti?{tls:{enabled:!0}}:{}},...zt?{cluster:{enabled:!0,nodeId:ws,role:Ei,redisUrl:_i,token:ki}}:{},storage:{path:"./data/alfred.db",...oo==="postgres"?{backend:"postgres"}:{},...Kt?{connectionString:Kt}:{}},...Rt!=="local"?{fileStore:{backend:Rt,...Cr?{basePath:Cr}:{},...Si?{s3Endpoint:Si}:{},...Or?{s3Bucket:Or}:{},...Dr?{s3AccessKey:Dr}:{},...Mr?{s3SecretKey:Mr}:{}}}:{},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};Fe&&(kd.security.ownerUserId=Fe);let Af="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Ql.dump(kd,{lineWidth:120,noRefs:!0,sortKeys:!1}),$f=De.join(Ui,"default.yml");Ae.writeFileSync($f,Af,"utf-8"),console.log(` ${M("+")} ${E("config/default.yml")} written`);let Lo=De.join(Ui,"rules");Ae.existsSync(Lo)||Ae.mkdirSync(Lo,{recursive:!0});let Rf=Yr&&Fe?`
2344
2344
  # Allow admin actions (shell, etc.) for the owner only
2345
2345
  - id: allow-owner-admin
2346
2346
  effect: allow
@@ -2349,7 +2349,7 @@ ${x("Writing configuration files...")}`);let R=["# Alfred Environment Variables"
2349
2349
  actions: ["*"]
2350
2350
  riskLevels: [admin, destructive]
2351
2351
  conditions:
2352
- users: ["${je}"]
2352
+ users: ["${Fe}"]
2353
2353
  `:`
2354
2354
  # Allow admin actions (shell, etc.) for the owner only
2355
2355
  # Uncomment and set your user ID to enable:
@@ -2360,7 +2360,7 @@ ${x("Writing configuration files...")}`);let R=["# Alfred Environment Variables"
2360
2360
  # actions: ["*"]
2361
2361
  # riskLevels: [admin, destructive]
2362
2362
  # conditions:
2363
- # users: ["${je||"YOUR_USER_ID_HERE"}"]
2363
+ # users: ["${Fe||"YOUR_USER_ID_HERE"}"]
2364
2364
  `,Nf=`# Alfred \u2014 Default Security Rules
2365
2365
  # Rules are evaluated in priority order (lower number = higher priority).
2366
2366
  # First matching rule wins.
@@ -2416,14 +2416,14 @@ ${Rf}
2416
2416
  scope: global
2417
2417
  actions: ["*"]
2418
2418
  riskLevels: [read, write, destructive, admin]
2419
- `,Lf=Me.join(Lo,"default-rules.yml");Ae.writeFileSync(Lf,Nf,"utf-8"),console.log(` ${M("+")} ${E("config/rules/default-rules.yml")} written`);let Sd=Me.join(e,"data");Ae.existsSync(Sd)||(Ae.mkdirSync(Sd,{recursive:!0}),console.log(` ${M("+")} ${E("data/")} directory created`)),console.log(""),console.log(`${eo}${"=".repeat(52)}${v}`),console.log(`${eo}${Y} Setup complete!${v}`),console.log(`${eo}${"=".repeat(52)}${v}`),console.log(""),console.log(` ${x("Bot name:")} ${r}`),console.log(` ${x("LLM default:")} ${o.name} (${f})`),c&&console.log(` ${x("API key:")} ${Ie(c)}`);for(let[_,$]of Object.entries(L)){let C=_.charAt(0).toUpperCase()+_.slice(1);console.log(` ${x(`LLM ${C}:`)}${" ".repeat(Math.max(1,10-C.length))}${$.provider} (${$.model})`)}if(le.length>0?console.log(` ${x("Platforms:")} ${le.map(_=>_.label).join(", ")}`):console.log(` ${x("Platforms:")} none (configure later)`),pe){let _={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${ye})`};console.log(` ${x("Web search:")} ${_[pe]}`)}else console.log(` ${x("Web search:")} ${E("disabled")}`);if(Ee&&Oe.length>0){let _=Oe.map($=>$.provider==="microsoft"?`${$.name} (Microsoft 365)${$.msClientId?"":" \u2014 shared from Calendar"}`:`${$.name} (${$.imapHost})`);console.log(` ${x("Email:")} ${_.join(", ")}`)}else console.log(` ${x("Email:")} ${E("disabled")}`);if(G){let _={openai:"OpenAI Whisper",groq:"Groq Whisper"},$=Ne?`, TTS: ${Fe}`:"";console.log(` ${x("Voice:")} ${_[G]}${$}`)}else console.log(` ${x("Voice:")} ${E("disabled")}`);console.log(` ${x("Code Sandbox:")} ${Ve?M("enabled"):E("disabled")}`),console.log(` ${x("Web Chat UI:")} ${ao?M("enabled (/alfred/)"):E("disabled")}`),console.log(` ${x("TLS/HTTPS:")} ${Ti?M("enabled (self-signed)"):E("disabled")}`),oo==="postgres"&&console.log(` ${x("Storage:")} ${M("PostgreSQL")}`),Rt!=="local"&&console.log(` ${x("File Store:")} ${M(Rt.toUpperCase())}${Rt==="s3"?` (${Or})`:` (${Cr})`}`),zt&&(console.log(` ${x("Cluster:")} ${M(`${Ei} (${ws})`)}`),console.log(` ${x("Redis:")} ${_i}`)),Ci&&console.log(` ${x("YouTube:")} ${M("enabled")}${Zt?" + Supadata":""}`),bi&&console.log(` ${x("Proxmox:")} ${M(Pr)}`),vi&&console.log(` ${x("PBS:")} ${M(jr)} ${E(`(max age: ${Xr}h)`)}`),Hr&&console.log(` ${x("UniFi:")} ${M(_s)}`),$i&&console.log(` ${x("Home Assist.:")} ${M(qr)}`),Ri&&console.log(` ${x("Contacts:")} ${M(Ze)}`),Ni&&console.log(` ${x("Docker:")} ${M(Jt||Vt)}`),Li&&console.log(` ${x("BMW CarData:")} ${M("enabled")}`),xi&&console.log(` ${x("Routing:")} ${M("enabled")}`),Oi&&console.log(` ${x("Energy:")} ${M(Qt||"enabled")} ${E(`(${es} ct/kWh)`)}`),je&&(console.log(` ${x("Owner ID:")} ${je}`),console.log(` ${x("Shell access:")} ${Yr?M("enabled"):E("disabled")}`)),console.log(` ${x("Write scope:")} ${Vr?"DMs + Groups":"DMs only"}`),console.log(` ${x("Rate limit:")} ${Mi}/hour per user`),console.log(""),console.log(`${to}Next steps:${v}`),console.log(` ${x("alfred start")} Start Alfred`),console.log(` ${x("alfred status")} Check configuration`),console.log(` ${x("alfred --help")} Show all commands`),console.log(""),console.log(`${Bt}Edit ${x(".env")}${Bt} or ${x("config/default.yml")}${Bt} for manual configuration.${v}`),console.log("")}finally{l.close()}}async function B(l,e,t){let s=(await l.question(`${Y}${e}${v} ${E(`[${t}]`)}: ${P}`)).trim();return process.stdout.write(v),s||t}async function ze(l,e){for(;;){let t=(await l.question(`${Y}${e}${v}: ${P}`)).trim();if(process.stdout.write(v),t)return t;console.log(` ${Mm("!")} This field is required. Please enter a value.`)}}async function fi(l,e,t,s,r){for(;;){let n=(await l.question(`${P}${e}${v}`)).trim();if(!n)return r;let i=parseInt(n,10);if(!Number.isNaN(i)&&i>=t&&i<=s)return i;console.log(` ${Mm("!")} Please enter a number between ${t} and ${s}.`)}}function pw(){console.log(`
2420
- ${cw}${Y} _ _ _____ ____ _____ ____
2419
+ `,Lf=De.join(Lo,"default-rules.yml");Ae.writeFileSync(Lf,Nf,"utf-8"),console.log(` ${M("+")} ${E("config/rules/default-rules.yml")} written`);let Sd=De.join(e,"data");Ae.existsSync(Sd)||(Ae.mkdirSync(Sd,{recursive:!0}),console.log(` ${M("+")} ${E("data/")} directory created`)),console.log(""),console.log(`${eo}${"=".repeat(52)}${v}`),console.log(`${eo}${G} Setup complete!${v}`),console.log(`${eo}${"=".repeat(52)}${v}`),console.log(""),console.log(` ${x("Bot name:")} ${r}`),console.log(` ${x("LLM default:")} ${o.name} (${f})`),c&&console.log(` ${x("API key:")} ${Ie(c)}`);for(let[_,$]of Object.entries(L)){let C=_.charAt(0).toUpperCase()+_.slice(1);console.log(` ${x(`LLM ${C}:`)}${" ".repeat(Math.max(1,10-C.length))}${$.provider} (${$.model})`)}if(ce.length>0?console.log(` ${x("Platforms:")} ${ce.map(_=>_.label).join(", ")}`):console.log(` ${x("Platforms:")} none (configure later)`),ue){let _={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${ye})`};console.log(` ${x("Web search:")} ${_[ue]}`)}else console.log(` ${x("Web search:")} ${E("disabled")}`);if(we&&Ce.length>0){let _=Ce.map($=>$.provider==="microsoft"?`${$.name} (Microsoft 365)${$.msClientId?"":" \u2014 shared from Calendar"}`:`${$.name} (${$.imapHost})`);console.log(` ${x("Email:")} ${_.join(", ")}`)}else console.log(` ${x("Email:")} ${E("disabled")}`);if(V){let _={openai:"OpenAI Whisper",groq:"Groq Whisper"},$=Ye?`, TTS: ${Pe}`:"";console.log(` ${x("Voice:")} ${_[V]}${$}`)}else console.log(` ${x("Voice:")} ${E("disabled")}`);console.log(` ${x("Code Sandbox:")} ${Ve?M("enabled"):E("disabled")}`),console.log(` ${x("Web Chat UI:")} ${ao?M("enabled (/alfred/)"):E("disabled")}`),console.log(` ${x("TLS/HTTPS:")} ${Ti?M("enabled (self-signed)"):E("disabled")}`),oo==="postgres"&&console.log(` ${x("Storage:")} ${M("PostgreSQL")}`),Rt!=="local"&&console.log(` ${x("File Store:")} ${M(Rt.toUpperCase())}${Rt==="s3"?` (${Or})`:` (${Cr})`}`),zt&&(console.log(` ${x("Cluster:")} ${M(`${Ei} (${ws})`)}`),console.log(` ${x("Redis:")} ${_i}`)),Ci&&console.log(` ${x("YouTube:")} ${M("enabled")}${Zt?" + Supadata":""}`),bi&&console.log(` ${x("Proxmox:")} ${M(Pr)}`),vi&&console.log(` ${x("PBS:")} ${M(jr)} ${E(`(max age: ${Xr}h)`)}`),Hr&&console.log(` ${x("UniFi:")} ${M(_s)}`),$i&&console.log(` ${x("Home Assist.:")} ${M(qr)}`),Ri&&console.log(` ${x("Contacts:")} ${M(Ze)}`),Ni&&console.log(` ${x("Docker:")} ${M(Jt||Vt)}`),Li&&console.log(` ${x("BMW CarData:")} ${M("enabled")}`),xi&&console.log(` ${x("Routing:")} ${M("enabled")}`),Oi&&console.log(` ${x("Energy:")} ${M(Qt||"enabled")} ${E(`(${es} ct/kWh)`)}`),Fe&&(console.log(` ${x("Owner ID:")} ${Fe}`),console.log(` ${x("Shell access:")} ${Yr?M("enabled"):E("disabled")}`)),console.log(` ${x("Write scope:")} ${Vr?"DMs + Groups":"DMs only"}`),console.log(` ${x("Rate limit:")} ${Mi}/hour per user`),console.log(""),console.log(`${to}Next steps:${v}`),console.log(` ${x("alfred start")} Start Alfred`),console.log(` ${x("alfred status")} Check configuration`),console.log(` ${x("alfred --help")} Show all commands`),console.log(""),console.log(`${Bt}Edit ${x(".env")}${Bt} or ${x("config/default.yml")}${Bt} for manual configuration.${v}`),console.log("")}finally{l.close()}}async function B(l,e,t){let s=(await l.question(`${G}${e}${v} ${E(`[${t}]`)}: ${U}`)).trim();return process.stdout.write(v),s||t}async function qe(l,e){for(;;){let t=(await l.question(`${G}${e}${v}: ${U}`)).trim();if(process.stdout.write(v),t)return t;console.log(` ${Mm("!")} This field is required. Please enter a value.`)}}async function fi(l,e,t,s,r){for(;;){let n=(await l.question(`${U}${e}${v}`)).trim();if(!n)return r;let i=parseInt(n,10);if(!Number.isNaN(i)&&i>=t&&i<=s)return i;console.log(` ${Mm("!")} Please enter a number between ${t} and ${s}.`)}}function pw(){console.log(`
2420
+ ${cw}${G} _ _ _____ ____ _____ ____
2421
2421
  / \\ | | | ___| _ \\| ____| _ \\
2422
2422
  / _ \\ | | | |_ | |_) | _| | | | |
2423
2423
  / ___ \\| |___| _| | _ <| |___| |_| |
2424
2424
  /_/ \\_\\_____|_| |_| \\_\\_____|____/ ${v}
2425
2425
  ${Bt} Personal AI Assistant \u2014 Setup Wizard${v}
2426
- `)}var v,Y,Bt,eo,P,to,ow,cw,vt,Rr,Dm,Pm=w(()=>{"use strict";Zl();v="\x1B[0m",Y="\x1B[1m",Bt="\x1B[2m",eo="\x1B[32m",P="\x1B[33m",to="\x1B[36m",ow="\x1B[31m",cw="\x1B[35m";p(M,"green");p(Om,"yellow");p(fe,"cyan");p(Mm,"red");p(x,"bold");p(E,"dim");p(Ie,"maskKey");vt=[{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"}]}],Rr=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];p(lw,"findCommand");Dm=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["exec","--dangerously-bypass-approvals-and-sandbox","{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];p(dw,"loadExistingConfig");p(uw,"setupCommand");p(B,"askWithDefault");p(ze,"askRequired");p(fi,"askNumber");p(pw,"printBanner")});var jm={};ie(jm,{configCommand:()=>gw});function mw(l){let e=l.toLowerCase();return hw.some(t=>e.includes(t))}function fw(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function Fm(l){let e={};for(let[t,s]of Object.entries(l))mw(t)?e[t]=fw(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Fm(s):e[t]=s;return e}async function gw(){let l=new ge,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Fm(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var hw,Bm=w(()=>{"use strict";ct();hw=["token","apikey","api_key","accesstoken","secret","password"];p(mw,"isSensitiveKey");p(fw,"redactValue");p(Fm,"redactObject");p(gw,"configCommand")});var Hm={};ie(Hm,{rulesCommand:()=>Tw});import so from"node:fs";import Xm from"node:path";import yw from"js-yaml";async function Tw(){let l=new ge,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=Xm.resolve(e.security.rulesPath);if(!so.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}so.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=so.readdirSync(t).filter(o=>o.endsWith(".yml")||o.endsWith(".yaml"));if(r.length===0){console.log(`No YAML rule files found in: ${t}`);return}let n=new _t,i=[],a=[];for(let o of r){let c=Xm.join(t,o);try{let d=so.readFileSync(c,"utf-8"),u=yw.load(d),h=n.loadFromObject(u);i.push(...h)}catch(d){a.push(` ${o}: ${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: ${i.length}`),console.log(""),a.length>0){console.log("Errors:");for(let o of a)console.log(o);console.log("")}if(i.length!==0){i.sort((o,c)=>o.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let o of i){let c=o.rateLimit?` | rate-limit: ${o.rateLimit.maxInvocations}/${o.rateLimit.windowSeconds}s`:"";console.log(` [${o.priority}] ${o.id}`),console.log(` effect: ${o.effect} | scope: ${o.scope}`),console.log(` actions: ${o.actions.join(", ")}`),console.log(` risk levels: ${o.riskLevels.join(", ")}${c}`),o.conditions&&console.log(` conditions: ${JSON.stringify(o.conditions)}`),console.log("")}}}var Wm=w(()=>{"use strict";ct();Qi();p(Tw,"rulesCommand")});var qm={};ie(qm,{statusCommand:()=>Ew});import gi from"node:fs";import ed from"node:path";import ww from"js-yaml";async function Ew(){let l=new ge,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=ed.resolve(e.storage.path),n=gi.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let i=ed.resolve(e.security.rulesPath),a=0,o=0;if(gi.existsSync(i)&&gi.statSync(i).isDirectory()){let c=gi.readdirSync(i).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));o=c.length;let d=new _t;for(let u of c){let h=ed.join(i,u);try{let m=gi.readFileSync(h,"utf-8"),f=ww.load(m),g=d.loadFromObject(f);a+=g.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${i}`),console.log(` Rule files: ${o}`),console.log(` Rules loaded: ${a}`),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 zm=w(()=>{"use strict";ct();Qi();p(Ew,"statusCommand")});var Ym={};ie(Ym,{authCommand:()=>Mw});import{createServer as _w}from"node:http";import{exec as kw}from"node:child_process";import{readFileSync as Sw,writeFileSync as bw,existsSync as vw}from"node:fs";import{createInterface as Iw}from"node:readline";import{resolve as Aw}from"node:path";async function td(l){let e=Iw({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function Rw(){let l={};try{let s=new ge().loadConfig();for(let i of["email","calendar","contacts"]){let a=s[i];if(!a)continue;let o=a.microsoft;o&&(!l.clientId&&o.clientId&&(l.clientId=o.clientId),!l.clientSecret&&o.clientSecret&&(l.clientSecret=o.clientSecret),!l.tenantId&&o.tenantId&&(l.tenantId=o.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 i of n.accounts){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))}}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 Nw(){let l=Rw(),e=l.clientId||await td(" Client ID: "),t=l.clientSecret||await td(" Client Secret: "),s=l.tenantId||await td(' 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 Lw(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:Km,response_mode:"query",scope:Gm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function xw(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:Km,grant_type:"authorization_code",scope:Gm}),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 Cw(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&kw(t,()=>{})}function Ow(l,e){let t=Aw(process.cwd(),".env"),s=[];vw(t)&&(s=Sw(t,"utf-8").split(`
2426
+ `)}var v,G,Bt,eo,U,to,ow,cw,vt,Rr,Dm,Pm=w(()=>{"use strict";Zl();v="\x1B[0m",G="\x1B[1m",Bt="\x1B[2m",eo="\x1B[32m",U="\x1B[33m",to="\x1B[36m",ow="\x1B[31m",cw="\x1B[35m";p(M,"green");p(Om,"yellow");p(fe,"cyan");p(Mm,"red");p(x,"bold");p(E,"dim");p(Ie,"maskKey");vt=[{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"}]}],Rr=[{name:"telegram",label:"Telegram",configKey:"telegram",credentials:[{envKey:"ALFRED_TELEGRAM_TOKEN",configField:"token",prompt:"Enter your Telegram Bot token (from @BotFather)",required:!0}]},{name:"discord",label:"Discord",configKey:"discord",credentials:[{envKey:"ALFRED_DISCORD_TOKEN",configField:"token",prompt:"Enter your Discord Bot token",required:!0}]},{name:"whatsapp",label:"WhatsApp",configKey:"whatsapp",credentials:[]},{name:"matrix",label:"Matrix",configKey:"matrix",credentials:[{envKey:"ALFRED_MATRIX_HOMESERVER_URL",configField:"homeserverUrl",prompt:"Enter your Matrix homeserver URL",defaultValue:"https://matrix.org",required:!0},{envKey:"ALFRED_MATRIX_ACCESS_TOKEN",configField:"accessToken",prompt:"Enter your Matrix access token",required:!0},{envKey:"ALFRED_MATRIX_USER_ID",configField:"userId",prompt:"Enter your Matrix user ID (e.g. @bot:matrix.org)",required:!0}]},{name:"signal",label:"Signal",configKey:"signal",credentials:[{envKey:"ALFRED_SIGNAL_API_URL",configField:"apiUrl",prompt:"Enter the Signal REST API URL",defaultValue:"http://localhost:8080",required:!0},{envKey:"ALFRED_SIGNAL_PHONE_NUMBER",configField:"phoneNumber",prompt:"Enter the Signal phone number (e.g. +15551234567)",required:!0}]}];p(lw,"findCommand");Dm=[{name:"claude-code",label:"Claude Code",command:"claude",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"claude"},{name:"codex",label:"OpenAI Codex CLI",command:"codex",argsTemplate:["exec","--dangerously-bypass-approvals-and-sandbox","{{prompt}}"],promptVia:"arg",whichCmd:"codex"},{name:"aider",label:"Aider",command:"aider",argsTemplate:["--message","{{prompt}}"],promptVia:"arg",whichCmd:"aider"},{name:"gemini",label:"Gemini CLI",command:"gemini",argsTemplate:["-p","{{prompt}}"],promptVia:"arg",whichCmd:"gemini"}];p(dw,"loadExistingConfig");p(uw,"setupCommand");p(B,"askWithDefault");p(qe,"askRequired");p(fi,"askNumber");p(pw,"printBanner")});var jm={};ie(jm,{configCommand:()=>gw});function mw(l){let e=l.toLowerCase();return hw.some(t=>e.includes(t))}function fw(l){return typeof l!="string"||l.length===0?"(empty)":l.length<=8?"***":l.slice(0,4)+"..."+l.slice(-4)}function Fm(l){let e={};for(let[t,s]of Object.entries(l))mw(t)?e[t]=fw(s):s!=null&&typeof s=="object"&&!Array.isArray(s)?e[t]=Fm(s):e[t]=s;return e}async function gw(){let l=new ge,e;try{e=l.loadConfig()}catch(s){console.error("Failed to load configuration:",s.message),process.exit(1)}let t=Fm(e);console.log("Alfred \u2014 Resolved Configuration"),console.log("================================"),console.log(JSON.stringify(t,null,2))}var hw,Bm=w(()=>{"use strict";ct();hw=["token","apikey","api_key","accesstoken","secret","password"];p(mw,"isSensitiveKey");p(fw,"redactValue");p(Fm,"redactObject");p(gw,"configCommand")});var Hm={};ie(Hm,{rulesCommand:()=>Tw});import so from"node:fs";import Xm from"node:path";import yw from"js-yaml";async function Tw(){let l=new ge,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=Xm.resolve(e.security.rulesPath);if(!so.existsSync(t)){console.log(`Rules directory not found: ${t}`),console.log("No security rules loaded.");return}so.statSync(t).isDirectory()||(console.error(`Rules path is not a directory: ${t}`),process.exit(1));let r=so.readdirSync(t).filter(o=>o.endsWith(".yml")||o.endsWith(".yaml"));if(r.length===0){console.log(`No YAML rule files found in: ${t}`);return}let n=new _t,i=[],a=[];for(let o of r){let c=Xm.join(t,o);try{let d=so.readFileSync(c,"utf-8"),u=yw.load(d),h=n.loadFromObject(u);i.push(...h)}catch(d){a.push(` ${o}: ${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: ${i.length}`),console.log(""),a.length>0){console.log("Errors:");for(let o of a)console.log(o);console.log("")}if(i.length!==0){i.sort((o,c)=>o.priority-c.priority),console.log("Loaded rules (sorted by priority):"),console.log("");for(let o of i){let c=o.rateLimit?` | rate-limit: ${o.rateLimit.maxInvocations}/${o.rateLimit.windowSeconds}s`:"";console.log(` [${o.priority}] ${o.id}`),console.log(` effect: ${o.effect} | scope: ${o.scope}`),console.log(` actions: ${o.actions.join(", ")}`),console.log(` risk levels: ${o.riskLevels.join(", ")}${c}`),o.conditions&&console.log(` conditions: ${JSON.stringify(o.conditions)}`),console.log("")}}}var Wm=w(()=>{"use strict";ct();Qi();p(Tw,"rulesCommand")});var qm={};ie(qm,{statusCommand:()=>Ew});import gi from"node:fs";import ed from"node:path";import ww from"js-yaml";async function Ew(){let l=new ge,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=ed.resolve(e.storage.path),n=gi.existsSync(r);console.log(` Database: ${r}`),console.log(` Status: ${n?"exists":"not yet created"}`),console.log("");let i=ed.resolve(e.security.rulesPath),a=0,o=0;if(gi.existsSync(i)&&gi.statSync(i).isDirectory()){let c=gi.readdirSync(i).filter(u=>u.endsWith(".yml")||u.endsWith(".yaml"));o=c.length;let d=new _t;for(let u of c){let h=ed.join(i,u);try{let m=gi.readFileSync(h,"utf-8"),f=ww.load(m),g=d.loadFromObject(f);a+=g.length}catch{}}}console.log("Security:"),console.log(` Rules path: ${i}`),console.log(` Rule files: ${o}`),console.log(` Rules loaded: ${a}`),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 zm=w(()=>{"use strict";ct();Qi();p(Ew,"statusCommand")});var Ym={};ie(Ym,{authCommand:()=>Mw});import{createServer as _w}from"node:http";import{exec as kw}from"node:child_process";import{readFileSync as Sw,writeFileSync as bw,existsSync as vw}from"node:fs";import{createInterface as Iw}from"node:readline";import{resolve as Aw}from"node:path";async function td(l){let e=Iw({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(l,s=>{e.close(),t(s.trim())})})}function Rw(){let l={};try{let s=new ge().loadConfig();for(let i of["email","calendar","contacts"]){let a=s[i];if(!a)continue;let o=a.microsoft;o&&(!l.clientId&&o.clientId&&(l.clientId=o.clientId),!l.clientSecret&&o.clientSecret&&(l.clientSecret=o.clientSecret),!l.tenantId&&o.tenantId&&(l.tenantId=o.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 i of n.accounts){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))}}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 Nw(){let l=Rw(),e=l.clientId||await td(" Client ID: "),t=l.clientSecret||await td(" Client Secret: "),s=l.tenantId||await td(' 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 Lw(l){let e=new URLSearchParams({client_id:l.clientId,response_type:"code",redirect_uri:Km,response_mode:"query",scope:Gm,prompt:"consent"});return`https://login.microsoftonline.com/${l.tenantId}/oauth2/v2.0/authorize?${e}`}async function xw(l,e){let t=new URLSearchParams({client_id:e.clientId,client_secret:e.clientSecret,code:l,redirect_uri:Km,grant_type:"authorization_code",scope:Gm}),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 Cw(l){let t={win32:`start "" "${l}"`,darwin:`open "${l}"`,linux:`xdg-open "${l}"`}[process.platform];t&&kw(t,()=>{})}function Ow(l,e){let t=Aw(process.cwd(),".env"),s=[];vw(t)&&(s=Sw(t,"utf-8").split(`
2427
2427
  `));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 a=0;a<s.length;a++){let o=s[a].match(/^#?\s*([A-Z_]+)=/);o&&n.has(o[1])&&(s[a]=`${o[1]}=${r[o[1]]}`,n.delete(o[1]))}if(n.size>0){s.length>0&&s[s.length-1]!==""&&s.push("");for(let a of n)s.push(`${a}=${r[a]}`)}let i=s.join(`
2428
2428
  `).replace(/\n*$/,`
2429
2429
  `);bw(t,i)}function Dw(l){return new Promise((e,t)=>{let s=_w(async(r,n)=>{let i=new URL(r.url??"/","http://localhost:3000");if(i.pathname!=="/callback"){n.writeHead(404),n.end("Not found");return}let a=i.searchParams.get("code"),o=i.searchParams.get("error");if(o){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>Fehler: ${o}</h1><p>${i.searchParams.get("error_description")??""}</p>`),s.close(),t(new Error(`OAuth-Fehler: ${o}`));return}if(!a){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>Fehler: Kein Auth-Code erhalten</h1>");return}try{let c=await xw(a,l);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end($w),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 Mw(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 Nw(),t=Lw(e);console.log(""),console.log(" \xD6ffne diese URL im Browser:"),console.log(` ${t}`),console.log(""),Cw(t);try{let s=await Dw(e);console.log(""),console.log(" Refresh Token erhalten! Schreibe in .env ..."),Ow(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(`
@@ -2434,7 +2434,7 @@ ${Bt} Personal AI Assistant \u2014 Setup Wizard${v}
2434
2434
  h1{color:#3fb950;margin-bottom:.5rem}p{color:#8b949e}</style></head>
2435
2435
  <body><div class="card"><h1>Authentifizierung erfolgreich!</h1><p>Du kannst dieses Fenster schliessen und zum Terminal zur\xFCckkehren.</p></div></body></html>`;p(td,"askQuestion");p(Rw,"resolveCredentials");p(Nw,"ensureCredentials");p(Lw,"buildAuthUrl");p(xw,"exchangeCode");p(Cw,"openBrowser");p(Ow,"updateEnvFile");p(Dw,"waitForCallback");p(Mw,"authCommand")});var Zm={};ie(Zm,{migrateDbCommand:()=>Fw});import Uw from"node:fs";import Pw from"node:path";async function Fw(l){let e=new ge,t;try{t=e.loadConfig()}catch(f){console.error("Konfiguration konnte nicht geladen werden:",f.message),process.exit(1)}let s=Pw.resolve(t.storage.path),r=l.connectionString??t.storage.connectionString,n=l.batchSize??500;r||(console.error("Fehler: PostgreSQL Connection-String fehlt."),console.error("Entweder --connection-string angeben oder storage.connectionString in der Config setzen."),process.exit(1)),Uw.existsSync(s)||(console.error(`SQLite-Datenbank nicht gefunden: ${s}`),process.exit(1)),console.log("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.log("\u2551 Alfred \u2014 SQLite \u2192 PostgreSQL Migration \u2551"),console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.log(""),console.log(` Quelle: ${s}`),console.log(` Ziel: ${r.replace(/:[^:@]+@/,":***@")}`),console.log(` Batch: ${n} Zeilen pro INSERT`),l.dryRun&&console.log(" Modus: DRY RUN (keine Schreiboperationen)"),l.skipExisting&&console.log(" Option: Skip tables with existing data"),console.log("");let i=lt.createSync(s),a=i.getAdapter(),o=new Tt(r);try{await o.initialize()}catch(f){console.error(`PostgreSQL-Verbindung fehlgeschlagen: ${f.message}`),await i.close(),process.exit(1)}console.log(`\u2713 Beide Datenbanken verbunden
2436
2436
  `);try{let f=await o.query("SELECT version FROM schema_version ORDER BY version DESC LIMIT 1");if(f.length>0)console.log(`\u2713 PostgreSQL Schema vorhanden (Version ${f[0].version})`);else throw new Error("no schema")}catch{l.dryRun?console.log(" [DRY RUN] W\xFCrde PG Schema erstellen"):(console.log(" PostgreSQL Schema wird erstellt..."),await o.exec(Qr),console.log("\u2713 PostgreSQL Schema erstellt"))}console.log("");let c=await a.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name"),d=new Set(c.map(f=>f.name)),u=0,h=0,m=[];for(let f of Jm)if(d.has(f))try{let y=(await a.queryOne(`SELECT COUNT(*) as cnt FROM "${f}"`))?.cnt??0;if(y===0){console.log(` \u2298 ${f.padEnd(30)} 0 Zeilen (leer, \xFCbersprungen)`);continue}if(l.skipExisting)try{if((await o.queryOne(`SELECT COUNT(*) as cnt FROM "${f}"`))?.cnt>0){console.log(` \u2298 ${f.padEnd(30)} ${y} Zeilen (PG hat bereits Daten, \xFCbersprungen)`);continue}}catch{}if(l.dryRun){console.log(` \u2192 ${f.padEnd(30)} ${y} Zeilen w\xFCrden migriert`),u+=y,h++;continue}let k=await a.query(`SELECT * FROM "${f}"`);if(k.length===0)continue;let b=Object.keys(k[0]);await o.transaction(async L=>{l.skipExisting||await L.execute(`DELETE FROM "${f}"`,[]);let D=0;for(let W=0;W<k.length;W+=n){let q=k.slice(W,W+n);await jw(L,f,b,q),D+=q.length,k.length>n&&process.stdout.write(`\r \u2192 ${f.padEnd(30)} ${D}/${y}`)}});let I=(await o.queryOne(`SELECT COUNT(*) as cnt FROM "${f}"`))?.cnt??0;I===y?console.log(`\r \u2713 ${f.padEnd(30)} ${y} Zeilen migriert`):(console.log(`\r \u26A0 ${f.padEnd(30)} ${y} \u2192 ${I} (Differenz!)`),m.push(`${f}: erwartet ${y}, erhalten ${I}`)),u+=y,h++}catch(g){let y=g instanceof Error?g.message:String(g);console.log(` \u2717 ${f.padEnd(30)} FEHLER: ${y.slice(0,80)}`),m.push(`${f}: ${y}`)}for(let f of d)if(!Jm.includes(f)&&f!=="sqlite_sequence")try{let y=(await a.queryOne(`SELECT COUNT(*) as cnt FROM "${f}"`))?.cnt??0;if(y===0)continue;console.log(` ? ${f.padEnd(30)} ${y} Zeilen (unbekannte Tabelle, \xFCbersprungen)`)}catch{}if(console.log(""),console.log("\u2500".repeat(50)),console.log(` ${l.dryRun?"W\xFCrde migrieren":"Migriert"}: ${h} Tabellen, ${u} Zeilen`),m.length>0){console.log(`
2437
- \u26A0 ${m.length} Fehler:`);for(let f of m)console.log(` \u2022 ${f}`)}else!l.dryRun&&u>0&&(console.log(" \u2713 Migration erfolgreich abgeschlossen"),console.log(""),console.log(" N\xE4chster Schritt:"),console.log(" storage.backend: postgres"),console.log(` storage.connectionString: ${r.replace(/:[^:@]+@/,":***@")}`),console.log(" in der Config setzen und Alfred neu starten."));await o.close(),await i.close()}async function jw(l,e,t,s){if(s.length===0)return;let r=t.map(c=>`"${c}"`).join(", "),n=[],i=[],a=0;for(let c of s){let d=[];for(let u of t)a++,d.push(`$${a}`),n.push(c[u]??null);i.push(`(${d.join(", ")})`)}let o=`INSERT INTO "${e}" (${r}) VALUES ${i.join(", ")} ON CONFLICT DO NOTHING`;await l.execute(o,n)}var Jm,Qm=w(()=>{"use strict";ct();Xe();Jm=["conversations","users","memories","reminders","notes","todos","documents","watches","scheduled_actions","llm_usage","llm_usage_by_user","audit_log","activity_log","skill_health","pending_confirmations","conversation_summaries","calendar_notifications","workflow_chains","feedback_events","alfred_users","database_connections","background_tasks","link_tokens","shared_resources","project_agent_sessions","plugin_skills","messages","embeddings","document_chunks","linked_users","user_services","user_platform_links","workflow_executions","schema_version","_migrations"];p(Fw,"migrateDbCommand");p(jw,"insertBatchTx")});var ef={};ie(ef,{logsCommand:()=>Hw});import Bw from"node:fs";import Xw from"node:path";async function Hw(l,e){let t=new ge,s;try{s=t.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let r=Xw.resolve(s.storage.path);if(!Bw.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=lt.createSync(r);let i=n.getAdapter();e?.activity?await qw(i,l,e):await Ww(i,l)}catch(i){console.error("Failed to read log:",i.message),process.exit(1)}finally{n&&await n.close()}}async function Ww(l,e){let t=new xt(l),s=await t.count({}),r=await 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 i=n.timestamp.toISOString(),a=n.effect==="allow"?"ALLOW":"DENY ";console.log(` ${i} [${a}] ${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("")}}async function qw(l,e,t){let s=new Ot(l);if(t.stats){let i=await s.stats(t.since);if(console.log("Alfred \u2014 Activity Stats"),console.log("========================"),t.since&&console.log(`Since: ${t.since}`),console.log(""),i.length===0){console.log("No activity entries found.");return}let a=Math.max(...i.map(c=>c.eventType.length),10),o=Math.max(...i.map(c=>c.outcome.length),7);console.log(` ${"EVENT TYPE".padEnd(a)} ${"OUTCOME".padEnd(o)} COUNT`),console.log(` ${"\u2500".repeat(a)} ${"\u2500".repeat(o)} \u2500\u2500\u2500\u2500\u2500`);for(let c of i)console.log(` ${c.eventType.padEnd(a)} ${c.outcome.padEnd(o)} ${c.count}`);return}let r=await s.count({eventType:t.type,source:t.source,outcome:t.outcome}),n=await 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 i of n){let a=zw(i.outcome),o=i.durationMs?` (${i.durationMs}ms)`:"";console.log(` ${i.timestamp} [${a}] ${i.eventType}: ${i.action}${o}`),console.log(` source: ${i.source}${i.sourceId?` (${i.sourceId.slice(0,8)})`:""} | platform: ${i.platform??"-"}`),i.userId&&console.log(` user: ${i.userId}`),i.errorMessage&&console.log(` error: ${i.errorMessage.slice(0,200)}`),i.details&&console.log(` details: ${JSON.stringify(i.details)}`),console.log("")}}function zw(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 tf=w(()=>{"use strict";ct();Xe();p(Hw,"logsCommand");p(Ww,"showAuditLog");p(qw,"showActivityLog");p(zw,"formatOutcome")});import{readFileSync as Kw}from"node:fs";import{fileURLToPath as Gw}from"node:url";import{dirname as Yw,join as Vw}from"node:path";function Jw(){try{let l=Yw(Gw(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(Kw(Vw(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}p(Jw,"getVersion");var sf=Jw(),sd=`
2437
+ \u26A0 ${m.length} Fehler:`);for(let f of m)console.log(` \u2022 ${f}`)}else!l.dryRun&&u>0&&(console.log(" \u2713 Migration erfolgreich abgeschlossen"),console.log(""),console.log(" N\xE4chster Schritt:"),console.log(" storage.backend: postgres"),console.log(` storage.connectionString: ${r.replace(/:[^:@]+@/,":***@")}`),console.log(" in der Config setzen und Alfred neu starten."));await o.close(),await i.close()}async function jw(l,e,t,s){if(s.length===0)return;let r=t.map(c=>`"${c}"`).join(", "),n=[],i=[],a=0;for(let c of s){let d=[];for(let u of t)a++,d.push(`$${a}`),n.push(c[u]??null);i.push(`(${d.join(", ")})`)}let o=`INSERT INTO "${e}" (${r}) VALUES ${i.join(", ")} ON CONFLICT DO NOTHING`;await l.execute(o,n)}var Jm,Qm=w(()=>{"use strict";ct();Be();Jm=["conversations","users","memories","reminders","notes","todos","documents","watches","scheduled_actions","llm_usage","llm_usage_by_user","audit_log","activity_log","skill_health","pending_confirmations","conversation_summaries","calendar_notifications","workflow_chains","feedback_events","alfred_users","database_connections","background_tasks","link_tokens","shared_resources","project_agent_sessions","plugin_skills","messages","embeddings","document_chunks","linked_users","user_services","user_platform_links","workflow_executions","schema_version","_migrations"];p(Fw,"migrateDbCommand");p(jw,"insertBatchTx")});var ef={};ie(ef,{logsCommand:()=>Hw});import Bw from"node:fs";import Xw from"node:path";async function Hw(l,e){let t=new ge,s;try{s=t.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let r=Xw.resolve(s.storage.path);if(!Bw.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=lt.createSync(r);let i=n.getAdapter();e?.activity?await qw(i,l,e):await Ww(i,l)}catch(i){console.error("Failed to read log:",i.message),process.exit(1)}finally{n&&await n.close()}}async function Ww(l,e){let t=new xt(l),s=await t.count({}),r=await 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 i=n.timestamp.toISOString(),a=n.effect==="allow"?"ALLOW":"DENY ";console.log(` ${i} [${a}] ${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("")}}async function qw(l,e,t){let s=new Ot(l);if(t.stats){let i=await s.stats(t.since);if(console.log("Alfred \u2014 Activity Stats"),console.log("========================"),t.since&&console.log(`Since: ${t.since}`),console.log(""),i.length===0){console.log("No activity entries found.");return}let a=Math.max(...i.map(c=>c.eventType.length),10),o=Math.max(...i.map(c=>c.outcome.length),7);console.log(` ${"EVENT TYPE".padEnd(a)} ${"OUTCOME".padEnd(o)} COUNT`),console.log(` ${"\u2500".repeat(a)} ${"\u2500".repeat(o)} \u2500\u2500\u2500\u2500\u2500`);for(let c of i)console.log(` ${c.eventType.padEnd(a)} ${c.outcome.padEnd(o)} ${c.count}`);return}let r=await s.count({eventType:t.type,source:t.source,outcome:t.outcome}),n=await 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 i of n){let a=zw(i.outcome),o=i.durationMs?` (${i.durationMs}ms)`:"";console.log(` ${i.timestamp} [${a}] ${i.eventType}: ${i.action}${o}`),console.log(` source: ${i.source}${i.sourceId?` (${i.sourceId.slice(0,8)})`:""} | platform: ${i.platform??"-"}`),i.userId&&console.log(` user: ${i.userId}`),i.errorMessage&&console.log(` error: ${i.errorMessage.slice(0,200)}`),i.details&&console.log(` details: ${JSON.stringify(i.details)}`),console.log("")}}function zw(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 tf=w(()=>{"use strict";ct();Be();p(Hw,"logsCommand");p(Ww,"showAuditLog");p(qw,"showActivityLog");p(zw,"formatOutcome")});import{readFileSync as Kw}from"node:fs";import{fileURLToPath as Gw}from"node:url";import{dirname as Yw,join as Vw}from"node:path";function Jw(){try{let l=Yw(Gw(import.meta.url));for(let e of["../package.json","../../package.json"])try{let t=JSON.parse(Kw(Vw(l,e),"utf-8"));if(t.version)return t.version}catch{}}catch{}return"0.0.0"}p(Jw,"getVersion");var sf=Jw(),sd=`
2438
2438
  Alfred CLI v${sf}
2439
2439
  Personal AI Assistant
2440
2440