@madh-io/alfred-ai 0.15.7 → 0.15.9
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 +60 -60
- package/bundle/web-ui/404/index.html +1 -1
- package/bundle/web-ui/404.html +1 -1
- package/bundle/web-ui/_next/static/chunks/app/layout-ab17f30494d646ca.js +1 -0
- package/bundle/web-ui/_next/static/chunks/webpack-dd89effdde862170.js +1 -0
- package/bundle/web-ui/_next/static/zt6zPgm1qs-6oRSAeGNgv/_buildManifest.js +1 -0
- package/bundle/web-ui/_next/static/zt6zPgm1qs-6oRSAeGNgv/_ssgManifest.js +1 -0
- package/bundle/web-ui/chat/index.html +1 -1
- package/bundle/web-ui/chat/index.txt +3 -3
- package/bundle/web-ui/dashboard/index.html +1 -1
- package/bundle/web-ui/dashboard/index.txt +3 -3
- package/bundle/web-ui/index.html +1 -1
- package/bundle/web-ui/index.txt +3 -3
- package/bundle/web-ui/settings/index.html +1 -1
- package/bundle/web-ui/settings/index.txt +3 -3
- package/package.json +1 -1
package/bundle/index.js
CHANGED
|
@@ -440,7 +440,7 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
440
440
|
|
|
441
441
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_platform
|
|
442
442
|
ON users(platform, platform_user_id);
|
|
443
|
-
`)}runMigrations(){new Mt(this.db).migrate(no)}getDb(){return this.db}close(){this.db.close()}}});import bl from"node:crypto";var
|
|
443
|
+
`)}runMigrations(){new Mt(this.db).migrate(no)}getDb(){return this.db}close(){this.db.close()}}});import bl from"node:crypto";var es,El=T(()=>{"use strict";es=class{static{m(this,"ConversationRepository")}db;constructor(e){this.db=e}create(e,t,s){let r=new Date().toISOString(),n={id:bl.randomUUID(),platform:e,chatId:t,userId:s,createdAt:r,updatedAt:r};return this.db.prepare(`
|
|
444
444
|
INSERT INTO conversations (id, platform, chat_id, user_id, created_at, updated_at)
|
|
445
445
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
446
446
|
`).run(n.id,n.platform,n.chatId,n.userId,n.createdAt,n.updatedAt),n}findById(e){let t=this.db.prepare("SELECT * FROM conversations WHERE id = ?").get(e);if(t)return this.mapRow(t)}findByPlatformChat(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND chat_id = ?").get(e,t);if(s)return this.mapRow(s)}findByPlatformAndUser(e,t){let s=this.db.prepare("SELECT * FROM conversations WHERE platform = ? AND user_id = ? ORDER BY updated_at DESC LIMIT 1").get(e,t);if(s)return this.mapRow(s)}addMessage(e,t,s,r){let n={id:bl.randomUUID(),conversationId:e,role:t,content:s,toolCalls:r,createdAt:new Date().toISOString()};return this.db.prepare(`
|
|
@@ -450,13 +450,13 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
450
450
|
DELETE FROM messages WHERE conversation_id = ? AND id NOT IN (
|
|
451
451
|
SELECT id FROM messages WHERE conversation_id = ? ORDER BY created_at DESC LIMIT ?
|
|
452
452
|
)
|
|
453
|
-
`).run(e,e,t).changes}mapRow(e){return{id:e.id,platform:e.platform,chatId:e.chat_id,userId:e.user_id,createdAt:e.created_at,updatedAt:e.updated_at}}}});import _h from"node:crypto";var
|
|
453
|
+
`).run(e,e,t).changes}mapRow(e){return{id:e.id,platform:e.platform,chatId:e.chat_id,userId:e.user_id,createdAt:e.created_at,updatedAt:e.updated_at}}}});import _h from"node:crypto";var ts,Sl=T(()=>{"use strict";ts=class{static{m(this,"UserRepository")}db;constructor(e){this.db=e}findOrCreate(e,t,s,r){let n=this.db.prepare("SELECT * FROM users WHERE platform = ? AND platform_user_id = ?").get(e,t);if(n)return this.mapRow(n);let o=new Date().toISOString(),i={id:_h.randomUUID(),platform:e,platformUserId:t,username:s,displayName:r,createdAt:o,updatedAt:o};return this.db.prepare(`
|
|
454
454
|
INSERT INTO users (id, platform, platform_user_id, username, display_name, created_at, updated_at)
|
|
455
455
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
456
456
|
`).run(i.id,i.platform,i.platformUserId,i.username??null,i.displayName??null,i.createdAt,i.updatedAt),i}findById(e){let t=this.db.prepare("SELECT * FROM users WHERE id = ?").get(e);if(t)return this.mapRow(t)}update(e,t){let s=[],r=[];t.username!==void 0&&(s.push("username = ?"),r.push(t.username??null)),t.displayName!==void 0&&(s.push("display_name = ?"),r.push(t.displayName??null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}updateProfile(e,t){let s=[],r=[];t.timezone!==void 0&&(s.push("timezone = ?"),r.push(t.timezone??null)),t.language!==void 0&&(s.push("language = ?"),r.push(t.language??null)),t.bio!==void 0&&(s.push("bio = ?"),r.push(t.bio??null)),t.preferences!==void 0&&(s.push("preferences = ?"),r.push(t.preferences?JSON.stringify(t.preferences):null)),s.length!==0&&(s.push("updated_at = ?"),r.push(new Date().toISOString()),r.push(e),this.db.prepare(`UPDATE users SET ${s.join(", ")} WHERE id = ?`).run(...r))}getProfile(e){let t=this.db.prepare("SELECT display_name, timezone, language, bio, preferences FROM users WHERE id = ?").get(e);if(t)return{displayName:t.display_name??void 0,timezone:t.timezone??void 0,language:t.language??void 0,bio:t.bio??void 0,preferences:t.preferences?JSON.parse(t.preferences):void 0}}setMasterUser(e,t){this.db.prepare("UPDATE users SET master_user_id = ?, updated_at = ? WHERE id = ?").run(t,new Date().toISOString(),e)}getLinkedUsers(e){return this.db.prepare("SELECT DISTINCT * FROM users WHERE master_user_id = ? OR id = ?").all(e,e).map(s=>this.mapRow(s))}findFirstByPlatformNotIn(e){let t=e.map(()=>"?").join(", "),s=this.db.prepare(`SELECT * FROM users WHERE platform NOT IN (${t}) LIMIT 1`).get(...e);if(s)return this.mapRow(s)}getMasterUserId(e){return this.db.prepare("SELECT master_user_id FROM users WHERE id = ?").get(e)?.master_user_id??e}mapRow(e){return{id:e.id,platform:e.platform,platformUserId:e.platform_user_id,username:e.username??void 0,displayName:e.display_name??void 0,timezone:e.timezone??void 0,language:e.language??void 0,bio:e.bio??void 0,preferences:e.preferences?JSON.parse(e.preferences):void 0,masterUserId:e.master_user_id??void 0,createdAt:e.created_at,updatedAt:e.updated_at}}}});var pt,vl=T(()=>{"use strict";pt=class{static{m(this,"AuditRepository")}db;constructor(e){this.db=e}log(e){this.db.prepare(`
|
|
457
457
|
INSERT INTO audit_log (id, timestamp, user_id, action, risk_level, rule_id, effect, platform, chat_id, context)
|
|
458
458
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
459
|
-
`).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return s.push(n),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}cleanup(e=90){return this.db.prepare("DELETE FROM audit_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}mapRow(e){return{id:e.id,timestamp:new Date(e.timestamp),userId:e.user_id,action:e.action,riskLevel:e.risk_level,ruleId:e.rule_id??void 0,effect:e.effect,platform:e.platform,chatId:e.chat_id??void 0,context:e.context?JSON.parse(e.context):void 0}}}});import{randomUUID as kh}from"node:crypto";var
|
|
459
|
+
`).run(e.id,e.timestamp.toISOString(),e.userId,e.action,e.riskLevel,e.ruleId??null,e.effect,e.platform,e.chatId??null,e.context?JSON.stringify(e.context):null)}query(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.action&&(t.push("action = ?"),s.push(e.action)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return s.push(n),this.db.prepare(`SELECT * FROM audit_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.effect&&(t.push("effect = ?"),s.push(e.effect));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as count FROM audit_log ${r}`).get(...s).count}cleanup(e=90){return this.db.prepare("DELETE FROM audit_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}mapRow(e){return{id:e.id,timestamp:new Date(e.timestamp),userId:e.user_id,action:e.action,riskLevel:e.risk_level,ruleId:e.rule_id??void 0,effect:e.effect,platform:e.platform,chatId:e.chat_id??void 0,context:e.context?JSON.parse(e.context):void 0}}}});import{randomUUID as kh}from"node:crypto";var ss,$l=T(()=>{"use strict";ss=class{static{m(this,"MemoryRepository")}db;constructor(e){this.db=e}save(e,t,s,r="general"){return this.saveWithMetadata(e,t,s,r,"general",1,"manual")}saveWithMetadata(e,t,s,r,n,o,i){let a=new Date().toISOString(),c=kh();this.db.prepare(`INSERT INTO memories (id, user_id, key, value, category, type, confidence, source, created_at, updated_at)
|
|
460
460
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
461
461
|
ON CONFLICT(user_id, key) DO UPDATE SET
|
|
462
462
|
value = excluded.value,
|
|
@@ -465,13 +465,13 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
465
465
|
confidence = excluded.confidence,
|
|
466
466
|
source = excluded.source,
|
|
467
467
|
updated_at = excluded.updated_at,
|
|
468
|
-
expires_at = NULL`).run(c,e,t,s,r,n,o,i,a,a);let d=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);return this.mapRow(d)}saveWithTTL(e,t,s,r,n){let o=this.saveWithMetadata(e,t,s,r,"general",1,"manual"),i=new Date(Date.now()+n*6e4).toISOString();return this.db.prepare("UPDATE memories SET expires_at = ? WHERE user_id = ? AND key = ?").run(i,e,t),o.expiresAt=i,o}cleanupExpired(){return this.db.prepare("DELETE FROM memories WHERE expires_at IS NOT NULL AND expires_at < datetime('now')").run().changes}recall(e,t){let s=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);if(s)return this.mapRow(s)}search(e,t){let s=`%${t}%`;return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND (key LIKE ? OR value LIKE ?) ORDER BY updated_at DESC").all(e,s,s).map(n=>this.mapRow(n))}keywordSearch(e,t,s=20){let r=t.toLowerCase().split(/\s+/).filter(c=>c.length>=2);if(r.length===0)return[];let n=r.map(()=>"(LOWER(key) LIKE ? OR LOWER(value) LIKE ?)").join(" OR "),o=[e];for(let c of r)o.push(`%${c}%`,`%${c}%`);let a=this.db.prepare(`SELECT * FROM memories WHERE user_id = ? AND (${n}) ORDER BY updated_at DESC`).all(...o).map(c=>{let d=this.mapRow(c),u=`${d.key} ${d.value}`.toLowerCase(),p=0;for(let h of r)u.includes(h)&&(p+=1);return{entry:d,score:p/r.length}});return a.sort((c,d)=>d.score-c.score),a.slice(0,s).map(c=>c.entry)}recordAccess(e){let t=new Date().toISOString();this.db.prepare("UPDATE memories SET last_accessed_at = ?, access_count = access_count + 1 WHERE id = ?").run(t,e)}findStale(e,t,s){let r=new Date(Date.now()-t*24*60*60*1e3).toISOString();return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND updated_at < ? AND confidence <= ? ORDER BY confidence ASC").all(e,r,s).map(o=>this.mapRow(o))}deleteByIds(e){if(e.length===0)return 0;let t=e.map(()=>"?").join(",");return this.db.prepare(`DELETE FROM memories WHERE id IN (${t})`).run(...e).changes}listByCategory(e,t){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND category = ? ORDER BY updated_at DESC").all(e,t).map(r=>this.mapRow(r))}listAll(e){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC").all(e).map(s=>this.mapRow(s))}delete(e,t){return this.db.prepare("DELETE FROM memories WHERE user_id = ? AND key = ?").run(e,t).changes>0}getRecentForPrompt(e,t=20){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}mapRow(e){return{id:e.id,userId:e.user_id,key:e.key,value:e.value,category:e.category||"general",type:e.type||"general",confidence:e.confidence??1,source:e.source||"manual",lastAccessedAt:e.last_accessed_at||null,accessCount:e.access_count??0,createdAt:e.created_at,updatedAt:e.updated_at,expiresAt:e.expires_at??null}}}});import{randomUUID as bh}from"node:crypto";var
|
|
468
|
+
expires_at = NULL`).run(c,e,t,s,r,n,o,i,a,a);let d=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);return this.mapRow(d)}saveWithTTL(e,t,s,r,n){let o=this.saveWithMetadata(e,t,s,r,"general",1,"manual"),i=new Date(Date.now()+n*6e4).toISOString();return this.db.prepare("UPDATE memories SET expires_at = ? WHERE user_id = ? AND key = ?").run(i,e,t),o.expiresAt=i,o}cleanupExpired(){return this.db.prepare("DELETE FROM memories WHERE expires_at IS NOT NULL AND expires_at < datetime('now')").run().changes}recall(e,t){let s=this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND key = ?").get(e,t);if(s)return this.mapRow(s)}search(e,t){let s=`%${t}%`;return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND (key LIKE ? OR value LIKE ?) ORDER BY updated_at DESC").all(e,s,s).map(n=>this.mapRow(n))}keywordSearch(e,t,s=20){let r=t.toLowerCase().split(/\s+/).filter(c=>c.length>=2);if(r.length===0)return[];let n=r.map(()=>"(LOWER(key) LIKE ? OR LOWER(value) LIKE ?)").join(" OR "),o=[e];for(let c of r)o.push(`%${c}%`,`%${c}%`);let a=this.db.prepare(`SELECT * FROM memories WHERE user_id = ? AND (${n}) ORDER BY updated_at DESC`).all(...o).map(c=>{let d=this.mapRow(c),u=`${d.key} ${d.value}`.toLowerCase(),p=0;for(let h of r)u.includes(h)&&(p+=1);return{entry:d,score:p/r.length}});return a.sort((c,d)=>d.score-c.score),a.slice(0,s).map(c=>c.entry)}recordAccess(e){let t=new Date().toISOString();this.db.prepare("UPDATE memories SET last_accessed_at = ?, access_count = access_count + 1 WHERE id = ?").run(t,e)}findStale(e,t,s){let r=new Date(Date.now()-t*24*60*60*1e3).toISOString();return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND updated_at < ? AND confidence <= ? ORDER BY confidence ASC").all(e,r,s).map(o=>this.mapRow(o))}deleteByIds(e){if(e.length===0)return 0;let t=e.map(()=>"?").join(",");return this.db.prepare(`DELETE FROM memories WHERE id IN (${t})`).run(...e).changes}listByCategory(e,t){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? AND category = ? ORDER BY updated_at DESC").all(e,t).map(r=>this.mapRow(r))}listAll(e){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC").all(e).map(s=>this.mapRow(s))}delete(e,t){return this.db.prepare("DELETE FROM memories WHERE user_id = ? AND key = ?").run(e,t).changes>0}getRecentForPrompt(e,t=20){return this.db.prepare("SELECT * FROM memories WHERE user_id = ? ORDER BY updated_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}mapRow(e){return{id:e.id,userId:e.user_id,key:e.key,value:e.value,category:e.category||"general",type:e.type||"general",confidence:e.confidence??1,source:e.source||"manual",lastAccessedAt:e.last_accessed_at||null,accessCount:e.access_count??0,createdAt:e.created_at,updatedAt:e.updated_at,expiresAt:e.expires_at??null}}}});import{randomUUID as bh}from"node:crypto";var rs,Al=T(()=>{"use strict";rs=class{static{m(this,"ReminderRepository")}db;constructor(e){this.db=e}create(e,t,s,r,n){let o={id:bh(),userId:e,platform:t,chatId:s,message:r,triggerAt:n.toISOString(),createdAt:new Date().toISOString(),fired:!1};return this.db.prepare(`
|
|
469
469
|
INSERT INTO reminders (id, user_id, platform, chat_id, message, trigger_at, created_at, fired)
|
|
470
470
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
471
|
-
`).run(o.id,o.userId,o.platform,o.chatId,o.message,o.triggerAt,o.createdAt,0),o}getDue(){let e=new Date().toISOString();return this.db.prepare("SELECT * FROM reminders WHERE fired = 0 AND trigger_at <= ? ORDER BY trigger_at ASC").all(e).map(s=>this.mapRow(s))}getByUser(e){return this.db.prepare("SELECT * FROM reminders WHERE fired = 0 AND user_id = ? ORDER BY trigger_at ASC").all(e).map(s=>this.mapRow(s))}markFired(e){this.db.prepare("UPDATE reminders SET fired = 1 WHERE id = ?").run(e)}cancel(e){return this.db.prepare("DELETE FROM reminders WHERE id = ?").run(e).changes>0}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,message:e.message,triggerAt:e.trigger_at,createdAt:e.created_at,fired:e.fired===1}}}});import{randomUUID as Eh}from"node:crypto";var
|
|
471
|
+
`).run(o.id,o.userId,o.platform,o.chatId,o.message,o.triggerAt,o.createdAt,0),o}getDue(){let e=new Date().toISOString();return this.db.prepare("SELECT * FROM reminders WHERE fired = 0 AND trigger_at <= ? ORDER BY trigger_at ASC").all(e).map(s=>this.mapRow(s))}getByUser(e){return this.db.prepare("SELECT * FROM reminders WHERE fired = 0 AND user_id = ? ORDER BY trigger_at ASC").all(e).map(s=>this.mapRow(s))}markFired(e){this.db.prepare("UPDATE reminders SET fired = 1 WHERE id = ?").run(e)}cancel(e){return this.db.prepare("DELETE FROM reminders WHERE id = ?").run(e).changes>0}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,message:e.message,triggerAt:e.trigger_at,createdAt:e.created_at,fired:e.fired===1}}}});import{randomUUID as Eh}from"node:crypto";var ns,Il=T(()=>{"use strict";ns=class{static{m(this,"NoteRepository")}db;constructor(e){this.db=e}save(e,t,s){let r=new Date().toISOString(),n=Eh();return this.db.prepare("INSERT INTO notes (id, user_id, title, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").run(n,e,t,s,r,r),{id:n,userId:e,title:t,content:s,createdAt:r,updatedAt:r}}getById(e){let t=this.db.prepare("SELECT * FROM notes WHERE id = ?").get(e);return t?this.mapRow(t):void 0}list(e,t=50){return this.db.prepare("SELECT * FROM notes WHERE user_id = ? ORDER BY updated_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}search(e,t){let s=`%${t}%`;return this.db.prepare("SELECT * FROM notes WHERE user_id = ? AND (title LIKE ? OR content LIKE ?) ORDER BY updated_at DESC").all(e,s,s).map(n=>this.mapRow(n))}update(e,t,s){let r=this.getById(e);if(!r)return;let n=new Date().toISOString(),o=t??r.title,i=s??r.content;return this.db.prepare("UPDATE notes SET title = ?, content = ?, updated_at = ? WHERE id = ?").run(o,i,n,e),{...r,title:o,content:i,updatedAt:n}}delete(e){return this.db.prepare("DELETE FROM notes WHERE id = ?").run(e).changes>0}mapRow(e){return{id:e.id,userId:e.user_id,title:e.title,content:e.content,createdAt:e.created_at,updatedAt:e.updated_at}}}});import{randomUUID as Sh}from"node:crypto";var os,Rl=T(()=>{"use strict";os=class{static{m(this,"EmbeddingRepository")}db;constructor(e){this.db=e}store(e){let t=Sh(),s=new Date().toISOString(),r=Buffer.from(new Float32Array(e.embedding).buffer);return this.db.transaction(()=>{this.db.prepare("DELETE FROM embeddings WHERE user_id = ? AND source_type = ? AND source_id = ?").run(e.userId,e.sourceType,e.sourceId),this.db.prepare("INSERT INTO embeddings (id, user_id, source_type, source_id, content, embedding, model, dimensions, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(t,e.userId,e.sourceType,e.sourceId,e.content,r,e.model,e.dimensions,s)})(),{id:t,userId:e.userId,sourceType:e.sourceType,sourceId:e.sourceId,content:e.content,embedding:e.embedding,model:e.model,dimensions:e.dimensions,createdAt:s}}findByUser(e){return this.db.prepare("SELECT * FROM embeddings WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapRow(s))}findBySource(e,t){let s=this.db.prepare("SELECT * FROM embeddings WHERE source_type = ? AND source_id = ?").get(e,t);if(s)return this.mapRow(s)}delete(e,t){return this.db.prepare("DELETE FROM embeddings WHERE source_type = ? AND source_id = ?").run(e,t).changes>0}mapRow(e){let t=e.embedding,s=new Float32Array(t.buffer,t.byteOffset,t.byteLength/4),r=Array.from(s);return{id:e.id,userId:e.user_id,sourceType:e.source_type,sourceId:e.source_id,content:e.content,embedding:r,model:e.model,dimensions:e.dimensions,createdAt:e.created_at}}}});import vh from"node:crypto";var is,xl=T(()=>{"use strict";is=class{static{m(this,"LinkTokenRepository")}db;constructor(e){this.db=e}create(e,t){for(let s=0;s<5;s++){let r={id:vh.randomUUID(),code:String(Math.floor(1e5+Math.random()*9e5)),userId:e,platform:t,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+6e5).toISOString()};try{return this.db.prepare(`
|
|
472
472
|
INSERT INTO link_tokens (id, code, user_id, platform, created_at, expires_at)
|
|
473
473
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
474
|
-
`).run(r.id,r.code,r.userId,r.platform,r.createdAt,r.expiresAt),r}catch(n){if(!(n instanceof Error?n.message:"").includes("UNIQUE")||s===4)throw n}}throw new Error("Failed to generate unique link code after retries")}findByCode(e){let t=this.db.prepare("SELECT * FROM link_tokens WHERE code = ? AND expires_at > ?").get(e,new Date().toISOString());if(t)return{id:t.id,code:t.code,userId:t.user_id,platform:t.platform,createdAt:t.created_at,expiresAt:t.expires_at}}consume(e){this.db.prepare("DELETE FROM link_tokens WHERE id = ?").run(e)}countRecentByUser(e,t=10){let s=new Date(Date.now()-t*6e4).toISOString();return this.db.prepare("SELECT COUNT(*) as cnt FROM link_tokens WHERE user_id = ? AND created_at > ?").get(e,s).cnt}cleanup(){this.db.prepare("DELETE FROM link_tokens WHERE expires_at <= ?").run(new Date().toISOString())}}});import{randomUUID as $h}from"node:crypto";var
|
|
474
|
+
`).run(r.id,r.code,r.userId,r.platform,r.createdAt,r.expiresAt),r}catch(n){if(!(n instanceof Error?n.message:"").includes("UNIQUE")||s===4)throw n}}throw new Error("Failed to generate unique link code after retries")}findByCode(e){let t=this.db.prepare("SELECT * FROM link_tokens WHERE code = ? AND expires_at > ?").get(e,new Date().toISOString());if(t)return{id:t.id,code:t.code,userId:t.user_id,platform:t.platform,createdAt:t.created_at,expiresAt:t.expires_at}}consume(e){this.db.prepare("DELETE FROM link_tokens WHERE id = ?").run(e)}countRecentByUser(e,t=10){let s=new Date(Date.now()-t*6e4).toISOString();return this.db.prepare("SELECT COUNT(*) as cnt FROM link_tokens WHERE user_id = ? AND created_at > ?").get(e,s).cnt}cleanup(){this.db.prepare("DELETE FROM link_tokens WHERE expires_at <= ?").run(new Date().toISOString())}}});import{randomUUID as $h}from"node:crypto";var as,Cl=T(()=>{"use strict";as=class{static{m(this,"BackgroundTaskRepository")}db;constructor(e){this.db=e}create(e,t,s,r,n,o){let i={id:$h(),userId:e,platform:t,chatId:s,description:r,skillName:n,skillInput:o,status:"pending",createdAt:new Date().toISOString()};return this.db.prepare(`
|
|
475
475
|
INSERT INTO background_tasks (id, user_id, platform, chat_id, description, skill_name, skill_input, status, created_at)
|
|
476
476
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
477
477
|
`).run(i.id,i.userId,i.platform,i.chatId,i.description,i.skillName,i.skillInput,i.status,i.createdAt),i}updateStatus(e,t,s,r){let n=new Date().toISOString(),o=null,i=null,a=null;t==="running"&&(o=n),(t==="completed"||t==="failed"||t==="cancelled")&&(i=n),t==="checkpointed"&&(a=n),this.db.prepare(`
|
|
@@ -502,7 +502,7 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
502
502
|
UPDATE background_tasks
|
|
503
503
|
SET status = 'cancelled', completed_at = datetime('now')
|
|
504
504
|
WHERE id = ? AND status IN ('pending', 'running', 'checkpointed', 'resuming')
|
|
505
|
-
`).run(e)}updatePersistentConfig(e,t){this.db.prepare("UPDATE background_tasks SET max_duration_hours = ? WHERE id = ?").run(t,e)}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at,agentState:e.agent_state,checkpointAt:e.checkpoint_at,resumeCount:e.resume_count??0,maxDurationHours:e.max_duration_hours}}}});var Nl=T(()=>{"use strict"});var Ll=T(()=>{"use strict"});var Dl=T(()=>{"use strict"});var Ml=T(()=>{"use strict"});var Ol=T(()=>{"use strict"});var Pl=T(()=>{"use strict"});var Ul=T(()=>{"use strict"});var Fl=T(()=>{"use strict"});function Ah(l,e){let t=l.trim().split(/\s+/);if(t.length!==5)return!1;let s=e.getMinutes(),r=e.getHours(),n=e.getDate(),o=e.getMonth()+1,i=e.getDay();return
|
|
505
|
+
`).run(e)}updatePersistentConfig(e,t){this.db.prepare("UPDATE background_tasks SET max_duration_hours = ? WHERE id = ?").run(t,e)}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,description:e.description,skillName:e.skill_name,skillInput:e.skill_input,status:e.status,result:e.result,error:e.error,createdAt:e.created_at,startedAt:e.started_at,completedAt:e.completed_at,agentState:e.agent_state,checkpointAt:e.checkpoint_at,resumeCount:e.resume_count??0,maxDurationHours:e.max_duration_hours}}}});var Nl=T(()=>{"use strict"});var Ll=T(()=>{"use strict"});var Dl=T(()=>{"use strict"});var Ml=T(()=>{"use strict"});var Ol=T(()=>{"use strict"});var Pl=T(()=>{"use strict"});var Ul=T(()=>{"use strict"});var Fl=T(()=>{"use strict"});function Ah(l,e){let t=l.trim().split(/\s+/);if(t.length!==5)return!1;let s=e.getMinutes(),r=e.getHours(),n=e.getDate(),o=e.getMonth()+1,i=e.getDay();return cs(t[0],s)&&cs(t[1],r)&&cs(t[2],n)&&cs(t[3],o)&&cs(t[4],i)}function io(l,e,t=1440*6e4){let s=e.getTime()+t,r=new Date(e);for(r.setSeconds(0,0),r.setMinutes(r.getMinutes()+1);r.getTime()<=s;){if(Ah(l,r))return r;r.setMinutes(r.getMinutes()+1)}return null}function cs(l,e){if(l.includes(","))return l.split(",").some(n=>cs(n.trim(),e));if(l==="*")return!0;let t=/^\*\/(\d+)$/.exec(l);if(t){let n=parseInt(t[1],10);return n>0&&e%n===0}let s=/^(\d+)-(\d+)(?:\/(\d+))?$/.exec(l);if(s){let n=parseInt(s[1],10),o=parseInt(s[2],10),i=s[3]?parseInt(s[3],10):1;return e<n||e>o?!1:i>0&&(e-n)%i===0}let r=parseInt(l,10);return isNaN(r)?!1:e===r}var jl=T(()=>{"use strict";m(Ah,"matchesCron");m(io,"getNextCronDate");m(cs,"matchCronField")});var Ki=T(()=>{"use strict";Nl();Ll();Dl();Ml();Ol();Pl();Ul();Fl();jl()});import{randomUUID as Ih}from"node:crypto";var ls,Bl=T(()=>{"use strict";Ki();ls=class{static{m(this,"ScheduledActionRepository")}db;constructor(e){this.db=e}countEnabled(){return this.db.prepare("SELECT COUNT(*) as cnt FROM scheduled_actions WHERE enabled = 1").get().cnt}create(e){let t=new Date().toISOString(),s=Ih(),r=this.calculateInitialNextRun(e.scheduleType,e.scheduleValue);return this.db.prepare(`
|
|
506
506
|
INSERT INTO scheduled_actions
|
|
507
507
|
(id, user_id, platform, chat_id, name, description, schedule_type, schedule_value,
|
|
508
508
|
skill_name, skill_input, prompt_template, enabled, next_run_at, created_at)
|
|
@@ -513,7 +513,7 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
513
513
|
UPDATE scheduled_actions
|
|
514
514
|
SET last_run_at = ?, next_run_at = ?
|
|
515
515
|
WHERE id = ?
|
|
516
|
-
`).run(t,s,e)}setEnabled(e,t){return this.db.prepare("UPDATE scheduled_actions SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM scheduled_actions WHERE id = ?").run(e).changes>0}calculateInitialNextRun(e,t){let s=new Date;switch(e){case"interval":{let r=parseInt(t,10);return isNaN(r)||r<=0?null:new Date(s.getTime()+r*6e4).toISOString()}case"once":return new Date(t).toISOString();case"cron":return io(t,s)?.toISOString()??null;default:return null}}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as Hl}from"node:crypto";var
|
|
516
|
+
`).run(t,s,e)}setEnabled(e,t){return this.db.prepare("UPDATE scheduled_actions SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM scheduled_actions WHERE id = ?").run(e).changes>0}calculateInitialNextRun(e,t){let s=new Date;switch(e){case"interval":{let r=parseInt(t,10);return isNaN(r)||r<=0?null:new Date(s.getTime()+r*6e4).toISOString()}case"once":return new Date(t).toISOString();case"cron":return io(t,s)?.toISOString()??null;default:return null}}mapRow(e){return{id:e.id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,name:e.name,description:e.description,scheduleType:e.schedule_type,scheduleValue:e.schedule_value,skillName:e.skill_name,skillInput:e.skill_input,promptTemplate:e.prompt_template,enabled:e.enabled===1,lastRunAt:e.last_run_at,nextRunAt:e.next_run_at,createdAt:e.created_at}}}});import{randomUUID as Hl}from"node:crypto";var ds,Wl=T(()=>{"use strict";ds=class{static{m(this,"DocumentRepository")}db;constructor(e){this.db=e}createDocument(e,t,s,r,n){let o=Hl(),i=new Date().toISOString();return this.db.prepare("INSERT INTO documents (id, user_id, filename, mime_type, size_bytes, chunk_count, content_hash, created_at) VALUES (?, ?, ?, ?, ?, 0, ?, ?)").run(o,e,t,s,r,n??null,i),{id:o,userId:e,filename:t,mimeType:s,sizeBytes:r,chunkCount:0,contentHash:n,createdAt:i}}findByContentHash(e,t){let s=this.db.prepare("SELECT * FROM documents WHERE user_id = ? AND content_hash = ? ORDER BY chunk_count DESC LIMIT 1").get(e,t);return s?this.mapDocumentRow(s):void 0}updateChunkCount(e,t){this.db.prepare("UPDATE documents SET chunk_count = ? WHERE id = ?").run(t,e)}addChunk(e,t,s,r){let n=Hl(),o=new Date().toISOString();return this.db.prepare("INSERT INTO document_chunks (id, document_id, chunk_index, content, embedding_id, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(n,e,t,s,r??null,o),{id:n,documentId:e,chunkIndex:t,content:s,embeddingId:r,createdAt:o}}getDocument(e){let t=this.db.prepare("SELECT * FROM documents WHERE id = ?").get(e);return t?this.mapDocumentRow(t):void 0}getChunks(e){return this.db.prepare("SELECT * FROM document_chunks WHERE document_id = ? ORDER BY chunk_index ASC").all(e).map(s=>this.mapChunkRow(s))}listByUser(e){return this.db.prepare("SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapDocumentRow(s))}deleteDocument(e){this.db.transaction(()=>{let s=this.db.prepare("SELECT embedding_id FROM document_chunks WHERE document_id = ? AND embedding_id IS NOT NULL").all(e);if(s.length>0){let r=s.map(o=>o.embedding_id),n=r.map(()=>"?").join(", ");this.db.prepare(`DELETE FROM embeddings WHERE id IN (${n})`).run(...r)}this.db.prepare("DELETE FROM document_chunks WHERE document_id = ?").run(e),this.db.prepare("DELETE FROM documents WHERE id = ?").run(e)})()}getChunksByEmbeddingIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(", ");return this.db.prepare(`SELECT * FROM document_chunks WHERE embedding_id IN (${t}) ORDER BY chunk_index ASC`).all(...e).map(r=>this.mapChunkRow(r))}mapDocumentRow(e){return{id:e.id,userId:e.user_id,filename:e.filename,mimeType:e.mime_type,sizeBytes:e.size_bytes,chunkCount:e.chunk_count,contentHash:e.content_hash||void 0,createdAt:e.created_at}}mapChunkRow(e){return{id:e.id,documentId:e.document_id,chunkIndex:e.chunk_index,content:e.content,embeddingId:e.embedding_id||void 0,createdAt:e.created_at}}}});import{randomUUID as Rh}from"node:crypto";var us,zl=T(()=>{"use strict";us=class{static{m(this,"TodoRepository")}db;constructor(e){this.db=e}add(e,t,s){let r=new Date().toISOString(),n=Rh(),o=s?.list??"default",i=s?.priority??"normal";return this.db.prepare("INSERT INTO todos (id, user_id, list, title, description, priority, due_date, completed, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)").run(n,e,o,t,s?.description??null,i,s?.dueDate??null,r,r),{id:n,userId:e,list:o,title:t,description:s?.description,priority:i,dueDate:s?.dueDate,completed:!1,createdAt:r,updatedAt:r}}list(e,t,s=!1){let r="SELECT * FROM todos WHERE user_id = ?",n=[e];return t&&(r+=" AND list = ?",n.push(t)),s||(r+=" AND completed = 0"),r+=" ORDER BY CASE priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'normal' THEN 2 WHEN 'low' THEN 3 END, created_at DESC",this.db.prepare(r).all(...n).map(i=>this.mapRow(i))}getById(e){let t=this.db.prepare("SELECT * FROM todos WHERE id = ?").get(e);return t?this.mapRow(t):void 0}complete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 1, updated_at = ? WHERE id = ? AND completed = 0").run(t,e).changes>0}uncomplete(e){let t=new Date().toISOString();return this.db.prepare("UPDATE todos SET completed = 0, updated_at = ? WHERE id = ? AND completed = 1").run(t,e).changes>0}delete(e){return this.db.prepare("DELETE FROM todos WHERE id = ?").run(e).changes>0}clearCompleted(e,t){let s="DELETE FROM todos WHERE user_id = ? AND completed = 1",r=[e];return t&&(s+=" AND list = ?",r.push(t)),this.db.prepare(s).run(...r).changes}getLists(e){return this.db.prepare(`SELECT list,
|
|
517
517
|
SUM(CASE WHEN completed = 0 THEN 1 ELSE 0 END) as open,
|
|
518
518
|
SUM(CASE WHEN completed = 1 THEN 1 ELSE 0 END) as completed,
|
|
519
519
|
COUNT(*) as total
|
|
@@ -522,7 +522,7 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
522
522
|
AND due_date >= ? AND due_date <= ?
|
|
523
523
|
ORDER BY due_date ASC`).all(t,e).map(r=>this.mapRow(r))}getOverdue(){let e=new Date().toISOString();return this.db.prepare(`SELECT * FROM todos
|
|
524
524
|
WHERE completed = 0 AND due_date IS NOT NULL AND due_date < ?
|
|
525
|
-
ORDER BY due_date ASC`).all(e).map(s=>this.mapRow(s))}mapRow(e){return{id:e.id,userId:e.user_id,list:e.list,title:e.title,description:e.description,priority:e.priority,dueDate:e.due_date,completed:e.completed===1,createdAt:e.created_at,updatedAt:e.updated_at}}}});import{randomUUID as xh}from"node:crypto";var
|
|
525
|
+
ORDER BY due_date ASC`).all(e).map(s=>this.mapRow(s))}mapRow(e){return{id:e.id,userId:e.user_id,list:e.list,title:e.title,description:e.description,priority:e.priority,dueDate:e.due_date,completed:e.completed===1,createdAt:e.created_at,updatedAt:e.updated_at}}}});import{randomUUID as xh}from"node:crypto";var ms,ql=T(()=>{"use strict";ms=class{static{m(this,"WatchRepository")}db;constructor(e){this.db=e}create(e){let t=xh(),s=new Date().toISOString();return this.db.prepare(`
|
|
526
526
|
INSERT INTO watches
|
|
527
527
|
(id, chat_id, platform, name, skill_name, skill_params,
|
|
528
528
|
condition_field, condition_operator, condition_value,
|
|
@@ -544,10 +544,10 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
544
544
|
UPDATE watches
|
|
545
545
|
SET last_checked_at = ?, last_value = ?
|
|
546
546
|
WHERE id = ?
|
|
547
|
-
`).run(t.lastCheckedAt,t.lastValue,e)}findByChatId(e,t){return this.db.prepare("SELECT * FROM watches WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapRow(r))}toggle(e,t){return this.db.prepare("UPDATE watches SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM watches WHERE id = ?").run(e).changes>0}updateActionError(e,t){this.db.prepare("UPDATE watches SET last_action_error = ? WHERE id = ?").run(t,e)}getById(e){let t=this.db.prepare("SELECT * FROM watches WHERE id = ?").get(e);return t?this.mapRow(t):void 0}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}let s={field:e.condition_field,operator:e.condition_operator};if(e.condition_value!=null){let n=Number(e.condition_value);s.value=isNaN(n)?e.condition_value:n}let r;if(e.conditions_json)try{r=JSON.parse(e.conditions_json)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,name:e.name,skillName:e.skill_name,skillParams:t,condition:s,intervalMinutes:e.interval_minutes,cooldownMinutes:e.cooldown_minutes,enabled:e.enabled===1,lastCheckedAt:e.last_checked_at??null,lastTriggeredAt:e.last_triggered_at??null,lastValue:e.last_value??null,createdAt:e.created_at,messageTemplate:e.message_template,compositeCondition:r,actionSkillName:e.action_skill_name,actionSkillParams:e.action_skill_params?(()=>{try{return JSON.parse(e.action_skill_params)}catch{return}})():void 0,actionOnTrigger:e.action_on_trigger??"alert",lastActionError:e.last_action_error,requiresConfirmation:e.requires_confirmation===1,triggerWatchId:e.trigger_watch_id}}}});import{randomUUID as Ch}from"node:crypto";var
|
|
547
|
+
`).run(t.lastCheckedAt,t.lastValue,e)}findByChatId(e,t){return this.db.prepare("SELECT * FROM watches WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapRow(r))}toggle(e,t){return this.db.prepare("UPDATE watches SET enabled = ? WHERE id = ?").run(t?1:0,e).changes>0}delete(e){return this.db.prepare("DELETE FROM watches WHERE id = ?").run(e).changes>0}updateActionError(e,t){this.db.prepare("UPDATE watches SET last_action_error = ? WHERE id = ?").run(t,e)}getById(e){let t=this.db.prepare("SELECT * FROM watches WHERE id = ?").get(e);return t?this.mapRow(t):void 0}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}let s={field:e.condition_field,operator:e.condition_operator};if(e.condition_value!=null){let n=Number(e.condition_value);s.value=isNaN(n)?e.condition_value:n}let r;if(e.conditions_json)try{r=JSON.parse(e.conditions_json)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,name:e.name,skillName:e.skill_name,skillParams:t,condition:s,intervalMinutes:e.interval_minutes,cooldownMinutes:e.cooldown_minutes,enabled:e.enabled===1,lastCheckedAt:e.last_checked_at??null,lastTriggeredAt:e.last_triggered_at??null,lastValue:e.last_value??null,createdAt:e.created_at,messageTemplate:e.message_template,compositeCondition:r,actionSkillName:e.action_skill_name,actionSkillParams:e.action_skill_params?(()=>{try{return JSON.parse(e.action_skill_params)}catch{return}})():void 0,actionOnTrigger:e.action_on_trigger??"alert",lastActionError:e.last_action_error,requiresConfirmation:e.requires_confirmation===1,triggerWatchId:e.trigger_watch_id}}}});import{randomUUID as Ch}from"node:crypto";var ps,Gl=T(()=>{"use strict";ps=class{static{m(this,"ConfirmationRepository")}db;constructor(e){this.db=e}create(e){let t=Ch(),s=new Date().toISOString();return this.db.prepare(`
|
|
548
548
|
INSERT INTO pending_confirmations (id, chat_id, platform, source, source_id, description, skill_name, skill_params, status, created_at, expires_at)
|
|
549
549
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)
|
|
550
|
-
`).run(t,e.chatId,e.platform,e.source,e.sourceId,e.description,e.skillName,JSON.stringify(e.skillParams),s,e.expiresAt),{id:t,...e,status:"pending",createdAt:s}}findPending(e,t){let s=this.db.prepare("SELECT * FROM pending_confirmations WHERE chat_id = ? AND platform = ? AND status = 'pending' ORDER BY created_at DESC LIMIT 1").get(e,t);return s?this.mapRow(s):void 0}resolve(e,t){this.db.prepare("UPDATE pending_confirmations SET status = ?, resolved_at = datetime('now') WHERE id = ?").run(t,e)}expireOld(){let e=this.db.prepare("SELECT * FROM pending_confirmations WHERE status = 'pending' AND expires_at <= datetime('now')").all();if(e.length>0){let t=e.map(r=>r.id),s=t.map(()=>"?").join(",");this.db.prepare(`UPDATE pending_confirmations SET status = 'expired', resolved_at = datetime('now') WHERE id IN (${s}) AND status = 'pending'`).run(...t)}return e.map(t=>this.mapRow(t))}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,source:e.source,sourceId:e.source_id,description:e.description,skillName:e.skill_name,skillParams:t,status:e.status,createdAt:e.created_at,expiresAt:e.expires_at,resolvedAt:e.resolved_at}}}});var
|
|
550
|
+
`).run(t,e.chatId,e.platform,e.source,e.sourceId,e.description,e.skillName,JSON.stringify(e.skillParams),s,e.expiresAt),{id:t,...e,status:"pending",createdAt:s}}findPending(e,t){let s=this.db.prepare("SELECT * FROM pending_confirmations WHERE chat_id = ? AND platform = ? AND status = 'pending' ORDER BY created_at DESC LIMIT 1").get(e,t);return s?this.mapRow(s):void 0}resolve(e,t){this.db.prepare("UPDATE pending_confirmations SET status = ?, resolved_at = datetime('now') WHERE id = ?").run(t,e)}expireOld(){let e=this.db.prepare("SELECT * FROM pending_confirmations WHERE status = 'pending' AND expires_at <= datetime('now')").all();if(e.length>0){let t=e.map(r=>r.id),s=t.map(()=>"?").join(",");this.db.prepare(`UPDATE pending_confirmations SET status = 'expired', resolved_at = datetime('now') WHERE id IN (${s}) AND status = 'pending'`).run(...t)}return e.map(t=>this.mapRow(t))}mapRow(e){let t={};try{t=JSON.parse(e.skill_params)}catch{}return{id:e.id,chatId:e.chat_id,platform:e.platform,source:e.source,sourceId:e.source_id,description:e.description,skillName:e.skill_name,skillParams:t,status:e.status,createdAt:e.created_at,expiresAt:e.expires_at,resolvedAt:e.resolved_at}}}});var hs,Xl=T(()=>{"use strict";hs=class{static{m(this,"SummaryRepository")}db;constructor(e){this.db=e}get(e){let t=this.db.prepare("SELECT conversation_id, summary, message_count, last_user_message, last_assistant_message, updated_at FROM conversation_summaries WHERE conversation_id = ?").get(e);if(t)return{conversationId:t.conversation_id,summary:t.summary,messageCount:t.message_count,lastUserMessage:t.last_user_message,lastAssistantMessage:t.last_assistant_message,updatedAt:t.updated_at}}upsert(e){this.db.prepare(`
|
|
551
551
|
INSERT INTO conversation_summaries (conversation_id, summary, message_count, last_user_message, last_assistant_message, updated_at)
|
|
552
552
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
553
553
|
ON CONFLICT(conversation_id) DO UPDATE SET
|
|
@@ -556,7 +556,7 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
556
556
|
last_user_message = excluded.last_user_message,
|
|
557
557
|
last_assistant_message = excluded.last_assistant_message,
|
|
558
558
|
updated_at = excluded.updated_at
|
|
559
|
-
`).run(e.conversationId,e.summary,e.messageCount,e.lastUserMessage??null,e.lastAssistantMessage??null,e.updatedAt)}cleanup(e=180){return this.db.prepare("DELETE FROM conversation_summaries WHERE updated_at < datetime('now', '-' || ? || ' days')").run(e).changes}delete(e){this.db.prepare("DELETE FROM conversation_summaries WHERE conversation_id = ?").run(e)}}});var
|
|
559
|
+
`).run(e.conversationId,e.summary,e.messageCount,e.lastUserMessage??null,e.lastAssistantMessage??null,e.updatedAt)}cleanup(e=180){return this.db.prepare("DELETE FROM conversation_summaries WHERE updated_at < datetime('now', '-' || ? || ' days')").run(e).changes}delete(e){this.db.prepare("DELETE FROM conversation_summaries WHERE conversation_id = ?").run(e)}}});var fs,Kl=T(()=>{"use strict";fs=class{static{m(this,"UsageRepository")}db;stmtUpsert;stmtDaily;stmtRange;stmtTotal;constructor(e){this.db=e,this.stmtUpsert=e.prepare(`
|
|
560
560
|
INSERT INTO llm_usage (date, model, calls, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_usd)
|
|
561
561
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
562
562
|
ON CONFLICT(date, model) DO UPDATE SET
|
|
@@ -587,7 +587,7 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
587
587
|
`).run(e,t,s,r)}cleanup(e){return this.db.prepare("DELETE FROM calendar_notifications WHERE event_start < ?").run(e).changes}}});import{randomUUID as Nh}from"node:crypto";var ft,Yl=T(()=>{"use strict";ft=class{static{m(this,"ActivityRepository")}db;constructor(e){this.db=e}log(e){let t=Nh(),s=new Date().toISOString();this.db.prepare(`
|
|
588
588
|
INSERT INTO activity_log (id, timestamp, event_type, source, source_id, user_id, platform, chat_id, action, outcome, error_message, duration_ms, details)
|
|
589
589
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
590
|
-
`).run(t,s,e.eventType,e.source,e.sourceId??null,e.userId??null,e.platform??null,e.chatId??null,e.action,e.outcome,e.errorMessage??null,e.durationMs??null,e.details?JSON.stringify(e.details):null)}query(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome)),e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.since&&(t.push("timestamp >= ?"),s.push(e.since));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return this.db.prepare(`SELECT * FROM activity_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s,n).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as cnt FROM activity_log ${r}`).get(...s).cnt}stats(e){let t=e?"WHERE timestamp >= ?":"",s=e?[e]:[];return this.db.prepare(`SELECT event_type, outcome, COUNT(*) as cnt FROM activity_log ${t} GROUP BY event_type, outcome ORDER BY cnt DESC`).all(...s).map(n=>({eventType:n.event_type,outcome:n.outcome,count:n.cnt}))}cleanup(e=90){return this.db.prepare("DELETE FROM activity_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}mapRow(e){let t;if(e.details)try{t=JSON.parse(e.details)}catch{}return{id:e.id,timestamp:e.timestamp,eventType:e.event_type,source:e.source,sourceId:e.source_id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,action:e.action,outcome:e.outcome,errorMessage:e.error_message,durationMs:e.duration_ms,details:t}}}});var
|
|
590
|
+
`).run(t,s,e.eventType,e.source,e.sourceId??null,e.userId??null,e.platform??null,e.chatId??null,e.action,e.outcome,e.errorMessage??null,e.durationMs??null,e.details?JSON.stringify(e.details):null)}query(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome)),e.userId&&(t.push("user_id = ?"),s.push(e.userId)),e.since&&(t.push("timestamp >= ?"),s.push(e.since));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"",n=e.limit??100;return this.db.prepare(`SELECT * FROM activity_log ${r} ORDER BY timestamp DESC LIMIT ?`).all(...s,n).map(i=>this.mapRow(i))}count(e){let t=[],s=[];e.eventType&&(t.push("event_type = ?"),s.push(e.eventType)),e.source&&(t.push("source = ?"),s.push(e.source)),e.outcome&&(t.push("outcome = ?"),s.push(e.outcome));let r=t.length>0?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT COUNT(*) as cnt FROM activity_log ${r}`).get(...s).cnt}stats(e){let t=e?"WHERE timestamp >= ?":"",s=e?[e]:[];return this.db.prepare(`SELECT event_type, outcome, COUNT(*) as cnt FROM activity_log ${t} GROUP BY event_type, outcome ORDER BY cnt DESC`).all(...s).map(n=>({eventType:n.event_type,outcome:n.outcome,count:n.cnt}))}cleanup(e=90){return this.db.prepare("DELETE FROM activity_log WHERE timestamp < datetime('now', '-' || ? || ' days')").run(e).changes}mapRow(e){let t;if(e.details)try{t=JSON.parse(e.details)}catch{}return{id:e.id,timestamp:e.timestamp,eventType:e.event_type,source:e.source,sourceId:e.source_id,userId:e.user_id,platform:e.platform,chatId:e.chat_id,action:e.action,outcome:e.outcome,errorMessage:e.error_message,durationMs:e.duration_ms,details:t}}}});var gs,Jl=T(()=>{"use strict";gs=class{static{m(this,"SkillHealthRepository")}db;constructor(e){this.db=e}getByName(e){let t=this.db.prepare("SELECT * FROM skill_health WHERE skill_name = ?").get(e);return t?this.mapRow(t):void 0}getAll(){return this.db.prepare("SELECT * FROM skill_health ORDER BY updated_at DESC").all().map(t=>this.mapRow(t))}recordSuccess(e){this.db.prepare(`
|
|
591
591
|
INSERT INTO skill_health (skill_name, success_count, fail_count, consecutive_fails, updated_at)
|
|
592
592
|
VALUES (?, 1, 0, 0, datetime('now'))
|
|
593
593
|
ON CONFLICT(skill_name) DO UPDATE SET
|
|
@@ -610,21 +610,21 @@ var sl=Object.defineProperty;var m=(l,e)=>sl(l,"name",{value:e,configurable:!0})
|
|
|
610
610
|
`).run(t,e)}enable(e){this.db.prepare(`
|
|
611
611
|
UPDATE skill_health SET disabled_until = NULL, consecutive_fails = 0, updated_at = datetime('now')
|
|
612
612
|
WHERE skill_name = ?
|
|
613
|
-
`).run(e)}isDisabled(e){return!!this.db.prepare("SELECT disabled_until FROM skill_health WHERE skill_name = ? AND disabled_until > datetime('now')").get(e)}getDisabled(){return this.db.prepare("SELECT * FROM skill_health WHERE disabled_until > datetime('now')").all().map(t=>this.mapRow(t))}mapRow(e){return{skillName:e.skill_name,successCount:e.success_count,failCount:e.fail_count,consecutiveFails:e.consecutive_fails,lastError:e.last_error,lastErrorAt:e.last_error_at,disabledUntil:e.disabled_until,updatedAt:e.updated_at}}}});import{randomUUID as Zl}from"node:crypto";var
|
|
613
|
+
`).run(e)}isDisabled(e){return!!this.db.prepare("SELECT disabled_until FROM skill_health WHERE skill_name = ? AND disabled_until > datetime('now')").get(e)}getDisabled(){return this.db.prepare("SELECT * FROM skill_health WHERE disabled_until > datetime('now')").all().map(t=>this.mapRow(t))}mapRow(e){return{skillName:e.skill_name,successCount:e.success_count,failCount:e.fail_count,consecutiveFails:e.consecutive_fails,lastError:e.last_error,lastErrorAt:e.last_error_at,disabledUntil:e.disabled_until,updatedAt:e.updated_at}}}});import{randomUUID as Zl}from"node:crypto";var ys,Ql=T(()=>{"use strict";ys=class{static{m(this,"WorkflowRepository")}db;constructor(e){this.db=e}create(e){let t=Zl(),s=new Date().toISOString();return this.db.prepare(`
|
|
614
614
|
INSERT INTO workflow_chains (id, name, user_id, chat_id, platform, steps, trigger_type, trigger_config, enabled, created_at)
|
|
615
615
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
616
616
|
`).run(t,e.name,e.userId,e.chatId,e.platform,JSON.stringify(e.steps),e.triggerType,e.triggerConfig?JSON.stringify(e.triggerConfig):null,e.enabled?1:0,s),{...e,id:t,createdAt:s}}getById(e){let t=this.db.prepare("SELECT * FROM workflow_chains WHERE id = ?").get(e);return t?this.mapChain(t):void 0}findByUser(e){return this.db.prepare("SELECT * FROM workflow_chains WHERE user_id = ? ORDER BY created_at DESC").all(e).map(s=>this.mapChain(s))}findByChatId(e,t){return this.db.prepare("SELECT * FROM workflow_chains WHERE chat_id = ? AND platform = ? ORDER BY created_at DESC").all(e,t).map(r=>this.mapChain(r))}delete(e){return this.db.prepare("DELETE FROM workflow_chains WHERE id = ?").run(e).changes>0}toggle(e,t){this.db.prepare("UPDATE workflow_chains SET enabled = ? WHERE id = ?").run(t?1:0,e)}createExecution(e,t){let s=Zl(),r=new Date().toISOString();return this.db.prepare(`
|
|
617
617
|
INSERT INTO workflow_executions (id, chain_id, status, steps_completed, total_steps, started_at)
|
|
618
618
|
VALUES (?, ?, 'running', 0, ?, ?)
|
|
619
|
-
`).run(s,e,t,r),{id:s,chainId:e,status:"running",stepsCompleted:0,totalSteps:t,startedAt:r}}updateExecution(e,t){let s=[],r=[];t.status!==void 0&&(s.push("status = ?"),r.push(t.status)),t.stepsCompleted!==void 0&&(s.push("steps_completed = ?"),r.push(t.stepsCompleted)),t.stepResults!==void 0&&(s.push("step_results = ?"),r.push(t.stepResults)),t.error!==void 0&&(s.push("error = ?"),r.push(t.error)),t.completedAt!==void 0&&(s.push("completed_at = ?"),r.push(t.completedAt)),s.length!==0&&(r.push(e),this.db.prepare(`UPDATE workflow_executions SET ${s.join(", ")} WHERE id = ?`).run(...r))}getExecution(e){let t=this.db.prepare("SELECT * FROM workflow_executions WHERE id = ?").get(e);return t?this.mapExecution(t):void 0}getRecentExecutions(e,t=10){return this.db.prepare("SELECT * FROM workflow_executions WHERE chain_id = ? ORDER BY started_at DESC LIMIT ?").all(e,t).map(r=>this.mapExecution(r))}mapChain(e){return{id:e.id,name:e.name,userId:e.user_id,chatId:e.chat_id,platform:e.platform,steps:JSON.parse(e.steps),triggerType:e.trigger_type,triggerConfig:e.trigger_config?JSON.parse(e.trigger_config):void 0,enabled:e.enabled===1,createdAt:e.created_at}}mapExecution(e){return{id:e.id,chainId:e.chain_id,status:e.status,stepsCompleted:e.steps_completed,totalSteps:e.total_steps,stepResults:e.step_results,error:e.error,startedAt:e.started_at,completedAt:e.completed_at}}}});import{randomUUID as Lh}from"node:crypto";var
|
|
619
|
+
`).run(s,e,t,r),{id:s,chainId:e,status:"running",stepsCompleted:0,totalSteps:t,startedAt:r}}updateExecution(e,t){let s=[],r=[];t.status!==void 0&&(s.push("status = ?"),r.push(t.status)),t.stepsCompleted!==void 0&&(s.push("steps_completed = ?"),r.push(t.stepsCompleted)),t.stepResults!==void 0&&(s.push("step_results = ?"),r.push(t.stepResults)),t.error!==void 0&&(s.push("error = ?"),r.push(t.error)),t.completedAt!==void 0&&(s.push("completed_at = ?"),r.push(t.completedAt)),s.length!==0&&(r.push(e),this.db.prepare(`UPDATE workflow_executions SET ${s.join(", ")} WHERE id = ?`).run(...r))}getExecution(e){let t=this.db.prepare("SELECT * FROM workflow_executions WHERE id = ?").get(e);return t?this.mapExecution(t):void 0}getRecentExecutions(e,t=10){return this.db.prepare("SELECT * FROM workflow_executions WHERE chain_id = ? ORDER BY started_at DESC LIMIT ?").all(e,t).map(r=>this.mapExecution(r))}mapChain(e){return{id:e.id,name:e.name,userId:e.user_id,chatId:e.chat_id,platform:e.platform,steps:JSON.parse(e.steps),triggerType:e.trigger_type,triggerConfig:e.trigger_config?JSON.parse(e.trigger_config):void 0,enabled:e.enabled===1,createdAt:e.created_at}}mapExecution(e){return{id:e.id,chainId:e.chain_id,status:e.status,stepsCompleted:e.steps_completed,totalSteps:e.total_steps,stepResults:e.step_results,error:e.error,startedAt:e.started_at,completedAt:e.completed_at}}}});import{randomUUID as Lh}from"node:crypto";var ws,ed=T(()=>{"use strict";ws=class{static{m(this,"FeedbackRepository")}db;constructor(e){this.db=e}recordEvent(e,t,s,r,n,o){let i=Lh(),a=new Date().toISOString();return this.db.prepare(`
|
|
620
620
|
INSERT INTO feedback_events (id, user_id, feedback_type, source_id, context_key, description, raw_context, occurred_at)
|
|
621
621
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
622
622
|
`).run(i,e,t,s??null,r,n,o?JSON.stringify(o):null,a),{id:i,userId:e,feedbackType:t,sourceId:s,contextKey:r,description:n,rawContext:o?JSON.stringify(o):void 0,occurredAt:a}}countEvents(e,t,s){return s?this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ? AND occurred_at >= ?").get(e,t,s).cnt:this.db.prepare("SELECT COUNT(*) as cnt FROM feedback_events WHERE user_id = ? AND context_key = ?").get(e,t).cnt}getRecentEvents(e,t=20){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? ORDER BY occurred_at DESC LIMIT ?").all(e,t).map(r=>this.mapRow(r))}getEventsForKey(e,t){return this.db.prepare("SELECT * FROM feedback_events WHERE user_id = ? AND context_key = ? ORDER BY occurred_at DESC").all(e,t).map(r=>this.mapRow(r))}pruneOldEvents(e=180){let t=new Date(Date.now()-e*24*60*6e4).toISOString();return this.db.prepare("DELETE FROM feedback_events WHERE occurred_at < ?").run(t).changes}mapRow(e){return{id:e.id,userId:e.user_id,feedbackType:e.feedback_type,sourceId:e.source_id,contextKey:e.context_key,description:e.description,rawContext:e.raw_context,occurredAt:e.occurred_at}}}});import{randomUUID as Dh}from"node:crypto";var ao,td=T(()=>{"use strict";ao=class{static{m(this,"ProjectAgentSessionRepository")}db;constructor(e){this.db=e}create(e){let t=Dh(),s=new Date().toISOString();return this.db.prepare(`
|
|
623
623
|
INSERT INTO project_agent_sessions (id, task_id, goal, cwd, agent_name, created_at, updated_at)
|
|
624
624
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
625
|
-
`).run(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}}getByTaskId(e){let t=this.db.prepare("SELECT * FROM project_agent_sessions WHERE task_id = ?").get(e);return t?this.mapRow(t):void 0}updateProgress(e,t){let s=["updated_at = datetime('now')"],r=[];t.currentPhase!==void 0&&(s.push("current_phase = ?"),r.push(t.currentPhase)),t.currentIteration!==void 0&&(s.push("current_iteration = ?"),r.push(t.currentIteration)),t.totalFilesChanged!==void 0&&(s.push("total_files_changed = ?"),r.push(t.totalFilesChanged)),t.lastBuildPassed!==void 0&&(s.push("last_build_passed = ?"),r.push(t.lastBuildPassed?1:0)),t.lastCommitSha!==void 0&&(s.push("last_commit_sha = ?"),r.push(t.lastCommitSha)),s.push("last_progress_at = datetime('now')"),r.push(e),this.db.prepare(`UPDATE project_agent_sessions SET ${s.join(", ")} WHERE task_id = ?`).run(...r)}addMilestone(e,t){let s=this.getByTaskId(e);if(!s)return;let r=[...s.milestones,t];this.db.prepare("UPDATE project_agent_sessions SET milestones = ?, updated_at = datetime('now') WHERE task_id = ?").run(JSON.stringify(r),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 sd={};pe(sd,{ActivityRepository:()=>ft,AuditRepository:()=>pt,BackgroundTaskRepository:()=>is,CalendarNotificationRepository:()=>ht,ConfirmationRepository:()=>ms,ConversationRepository:()=>Qt,Database:()=>mt,DocumentRepository:()=>ls,EmbeddingRepository:()=>ns,FeedbackRepository:()=>ys,LinkTokenRepository:()=>os,MIGRATIONS:()=>no,MemoryRepository:()=>ts,Migrator:()=>Mt,NoteRepository:()=>rs,ProjectAgentSessionRepository:()=>ao,ReminderRepository:()=>ss,ScheduledActionRepository:()=>cs,SkillHealthRepository:()=>fs,SummaryRepository:()=>ps,TodoRepository:()=>ds,UsageRepository:()=>hs,UserRepository:()=>es,WatchRepository:()=>us,WorkflowRepository:()=>gs});var co=T(()=>{"use strict";kl();El();Sl();vl();$l();ro();Xi();Al();Il();Rl();xl();Cl();Bl();Wl();zl();ql();Gl();Xl();Kl();Vl();Yl();Jl();Ql();ed();td()});function ot(l){if(Vi[l])return Vi[l];let e=Object.entries(Vi).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Vi,Mh,Ce,Ot=T(()=>{"use strict";Vi={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Mh={maxInputTokens:128e3,maxOutputTokens:8192};m(ot,"lookupContextWindow");Ce=class{static{m(this,"LLMProvider")}config;contextWindow=Mh;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Oh from"@anthropic-ai/sdk";var Rr,Yi=T(()=>{"use strict";Ot();Rr=class extends Ce{static{m(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Oh({apiKey:this.config.apiKey,maxRetries:5});let e=ot(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s},n=await this.client.messages.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s});for await(let n of r)if(n.type==="content_block_delta")n.delta.type==="text_delta"?yield{type:"text_delta",text:n.delta.text}:n.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:n.delta.partial_json}});else if(n.type==="content_block_start")n.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:n.content_block.id,name:n.content_block.name}});else if(n.type==="message_stop"){let o=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(o)}}}isAvailable(){return!!this.config.apiKey}mapMessages(e){return e.map(t=>{if(typeof t.content=="string")return{role:t.role,content:t.content};let s=t.content.map(r=>{switch(r.type){case"text":return{type:"text",text:r.text};case"image":return{type:"image",source:{type:"base64",media_type:r.source.media_type,data:r.source.data}};case"tool_use":return{type:"tool_use",id:r.id,name:r.name,input:r.input};case"tool_result":return{type:"tool_result",tool_use_id:r.tool_use_id,content:r.content,is_error:r.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(r=>r!==void 0);return{role:t.role,content:s}})}mapTools(e){let t=e.map(s=>({name:s.name,description:s.description,input_schema:s.inputSchema}));return t.length>0&&(t[t.length-1].cache_control={type:"ephemeral"}),t}mapResponse(e){let t="",s=[];for(let r of e.content)r.type==="text"?t+=r.text:r.type==="tool_use"&&s.push({id:r.id,name:r.name,input:r.input});return{content:t,model:e.model??this.config.model,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens,cacheCreationTokens:e.usage.cache_creation_input_tokens??0,cacheReadTokens:e.usage.cache_read_input_tokens??0},stopReason:e.stop_reason}}}});import Ph from"openai";var Be,ws=T(()=>{"use strict";Ot();Be=class extends Ce{static{m(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Ph({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=ot(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},n=await this.client.chat.completions.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.chat.completions.create({model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},stream:!0}),n,o,i="",a="",c=[],d=null,u=0,p=0;for await(let h of r){let f=h.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(a+=g.content,yield{type:"text_delta",text:g.content}),g?.tool_calls)for(let y of g.tool_calls)if(y.id){if(n){let _;try{_=JSON.parse(i||"{}")}catch{_={}}c.push({id:n,name:o,input:_})}n=y.id,o=y.function?.name,i=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:o}}}else y.function?.arguments&&(i+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),h.usage&&(u=h.usage.prompt_tokens,p=h.usage.completion_tokens)}if(n){let h;try{h=JSON.parse(i||"{}")}catch{h={}}c.push({id:n,name:o,input:h})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:p},stopReason:this.mapStopReason(d)}}}isAvailable(){return!!this.config.apiKey}async embed(e){try{let s=(await this.client.embeddings.create({model:"text-embedding-3-small",input:e})).data[0];return{embedding:s.embedding,model:"text-embedding-3-small",dimensions:s.embedding.length}}catch(t){let s=t instanceof Error?t.message:String(t);console.warn(`[OpenAIProvider] embed() failed: ${s}`);return}}supportsEmbeddings(){return!0}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let n=[],o=[],i=[];for(let a of r.content)switch(a.type){case"text":n.push({type:"text",text:a.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":o.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input)}});break;case"tool_result":i.push({tool_call_id:a.tool_use_id,content:a.content});break}if(r.role==="assistant"&&o.length>0){let a=n.map(c=>c.text).join("");s.push({role:"assistant",content:a||null,tool_calls:o})}else if(i.length>0)for(let a of i)s.push({role:"tool",tool_call_id:a.tool_call_id,content:a.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(a=>a.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,r=s?.content??"",n=s?.tool_calls?.map(o=>({id:o.id,name:o.function.name,input:(()=>{try{return JSON.parse(o.function.arguments)}catch{return{}}})()}));return{content:r,model:e.model??this.config.model,toolCalls:n&&n.length>0?n:void 0,usage:{inputTokens:e.usage?.prompt_tokens??0,outputTokens:e.usage?.completion_tokens??0},stopReason:this.mapStopReason(t?.finish_reason??null)}}mapStopReason(e){switch(e){case"stop":return"end_turn";case"tool_calls":return"tool_use";case"length":return"max_tokens";default:return"end_turn"}}}});var xr,Ji=T(()=>{"use strict";ws();xr=class extends Be{static{m(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Cr,Zi=T(()=>{"use strict";Ot();Cr=class extends Ce{static{m(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=ot(this.config.model);t?this.contextWindow=t:await this.fetchModelContextWindow()}async fetchModelContextWindow(){try{let e=await fetch(`${this.baseUrl}/api/show`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:this.config.model})});if(!e.ok)return;let s=(await e.json()).model_info??{},r=Object.keys(s).find(o=>o.includes("context_length")||o==="num_ctx"),n=r?Number(s[r]):0;n>0&&(this.contextWindow={maxInputTokens:n,maxOutputTokens:Math.min(n,4096)})}catch{}}getHeaders(){let e={"Content-Type":"application/json"};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}async complete(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text();throw new Error(`Ollama API error (${n.status}): ${i}`)}let o=await n.json();return this.mapResponse(o)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let h=await n.text();throw new Error(`Ollama API error (${n.status}): ${h}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let o=n.body.getReader(),i=new TextDecoder,a="",c="",d=0,u=0,p=[];try{for(;;){let{done:h,value:f}=await o.read();if(h)break;a+=i.decode(f,{stream:!0});let g=a.split(`
|
|
625
|
+
`).run(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}}getByTaskId(e){let t=this.db.prepare("SELECT * FROM project_agent_sessions WHERE task_id = ?").get(e);return t?this.mapRow(t):void 0}updateProgress(e,t){let s=["updated_at = datetime('now')"],r=[];t.currentPhase!==void 0&&(s.push("current_phase = ?"),r.push(t.currentPhase)),t.currentIteration!==void 0&&(s.push("current_iteration = ?"),r.push(t.currentIteration)),t.totalFilesChanged!==void 0&&(s.push("total_files_changed = ?"),r.push(t.totalFilesChanged)),t.lastBuildPassed!==void 0&&(s.push("last_build_passed = ?"),r.push(t.lastBuildPassed?1:0)),t.lastCommitSha!==void 0&&(s.push("last_commit_sha = ?"),r.push(t.lastCommitSha)),s.push("last_progress_at = datetime('now')"),r.push(e),this.db.prepare(`UPDATE project_agent_sessions SET ${s.join(", ")} WHERE task_id = ?`).run(...r)}addMilestone(e,t){let s=this.getByTaskId(e);if(!s)return;let r=[...s.milestones,t];this.db.prepare("UPDATE project_agent_sessions SET milestones = ?, updated_at = datetime('now') WHERE task_id = ?").run(JSON.stringify(r),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 sd={};pe(sd,{ActivityRepository:()=>ft,AuditRepository:()=>pt,BackgroundTaskRepository:()=>as,CalendarNotificationRepository:()=>ht,ConfirmationRepository:()=>ps,ConversationRepository:()=>es,Database:()=>mt,DocumentRepository:()=>ds,EmbeddingRepository:()=>os,FeedbackRepository:()=>ws,LinkTokenRepository:()=>is,MIGRATIONS:()=>no,MemoryRepository:()=>ss,Migrator:()=>Mt,NoteRepository:()=>ns,ProjectAgentSessionRepository:()=>ao,ReminderRepository:()=>rs,ScheduledActionRepository:()=>ls,SkillHealthRepository:()=>gs,SummaryRepository:()=>hs,TodoRepository:()=>us,UsageRepository:()=>fs,UserRepository:()=>ts,WatchRepository:()=>ms,WorkflowRepository:()=>ys});var co=T(()=>{"use strict";kl();El();Sl();vl();$l();ro();Xi();Al();Il();Rl();xl();Cl();Bl();Wl();zl();ql();Gl();Xl();Kl();Vl();Yl();Jl();Ql();ed();td()});function ot(l){if(Vi[l])return Vi[l];let e=Object.entries(Vi).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(l.startsWith(t))return s}var Vi,Mh,Ce,Ot=T(()=>{"use strict";Vi={"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-opus-4-5-20251101":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-sonnet-4-5-20250929":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-3-5-sonnet-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-sonnet-20240620":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-5-haiku-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-3-5-20241022":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:8192},"claude-3-opus-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-sonnet-20240229":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-3-haiku-20240307":{maxInputTokens:2e5,maxOutputTokens:4096},"claude-":{maxInputTokens:2e5,maxOutputTokens:16e3},"gpt-4.1":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-mini":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4.1-nano":{maxInputTokens:1047576,maxOutputTokens:32768},"gpt-4o":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4o-mini":{maxInputTokens:128e3,maxOutputTokens:16384},"gpt-4-turbo":{maxInputTokens:128e3,maxOutputTokens:4096},"gpt-4":{maxInputTokens:8192,maxOutputTokens:4096},"gpt-3.5-turbo":{maxInputTokens:16384,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"gemini-3.1-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3.1-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-3-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-pro":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.5-flash":{maxInputTokens:1048576,maxOutputTokens:65536},"gemini-2.0-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-2.0-pro":{maxInputTokens:1048576,maxOutputTokens:8192},"gemini-1.5-pro":{maxInputTokens:2097152,maxOutputTokens:8192},"gemini-1.5-flash":{maxInputTokens:1048576,maxOutputTokens:8192},"mistral-large":{maxInputTokens:262144,maxOutputTokens:262144},"mistral-medium":{maxInputTokens:128e3,maxOutputTokens:128e3},"mistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},codestral:{maxInputTokens:262144,maxOutputTokens:262144},"magistral-medium":{maxInputTokens:128e3,maxOutputTokens:131072},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:131072},ministral:{maxInputTokens:128e3,maxOutputTokens:128e3},llama4:{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.2":{maxInputTokens:128e3,maxOutputTokens:4096},"llama3.1":{maxInputTokens:128e3,maxOutputTokens:4096},llama3:{maxInputTokens:8192,maxOutputTokens:4096},gemma3:{maxInputTokens:128e3,maxOutputTokens:8192},gemma2:{maxInputTokens:8192,maxOutputTokens:4096},qwen3:{maxInputTokens:128e3,maxOutputTokens:8192},"qwen2.5":{maxInputTokens:128e3,maxOutputTokens:4096},mixtral:{maxInputTokens:32e3,maxOutputTokens:4096},phi3:{maxInputTokens:128e3,maxOutputTokens:4096},phi4:{maxInputTokens:128e3,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-v3":{maxInputTokens:128e3,maxOutputTokens:8192},"deepseek-chat":{maxInputTokens:128e3,maxOutputTokens:8192},"command-r":{maxInputTokens:128e3,maxOutputTokens:4096},"command-r-plus":{maxInputTokens:128e3,maxOutputTokens:4096}},Mh={maxInputTokens:128e3,maxOutputTokens:8192};m(ot,"lookupContextWindow");Ce=class{static{m(this,"LLMProvider")}config;contextWindow=Mh;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import Oh from"@anthropic-ai/sdk";var Rr,Yi=T(()=>{"use strict";Ot();Rr=class extends Ce{static{m(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Oh({apiKey:this.config.apiKey,maxRetries:5});let e=ot(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s},n=await this.client.messages.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,temperature:e.temperature??this.config.temperature,system:e.system?[{type:"text",text:e.system,cache_control:{type:"ephemeral"}}]:void 0,messages:t,tools:s});for await(let n of r)if(n.type==="content_block_delta")n.delta.type==="text_delta"?yield{type:"text_delta",text:n.delta.text}:n.delta.type==="input_json_delta"&&(yield{type:"tool_use_delta",toolCall:{input:n.delta.partial_json}});else if(n.type==="content_block_start")n.content_block.type==="tool_use"&&(yield{type:"tool_use_start",toolCall:{id:n.content_block.id,name:n.content_block.name}});else if(n.type==="message_stop"){let o=await r.finalMessage();yield{type:"message_complete",response:this.mapResponse(o)}}}isAvailable(){return!!this.config.apiKey}mapMessages(e){return e.map(t=>{if(typeof t.content=="string")return{role:t.role,content:t.content};let s=t.content.map(r=>{switch(r.type){case"text":return{type:"text",text:r.text};case"image":return{type:"image",source:{type:"base64",media_type:r.source.media_type,data:r.source.data}};case"tool_use":return{type:"tool_use",id:r.id,name:r.name,input:r.input};case"tool_result":return{type:"tool_result",tool_use_id:r.tool_use_id,content:r.content,is_error:r.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(r=>r!==void 0);return{role:t.role,content:s}})}mapTools(e){let t=e.map(s=>({name:s.name,description:s.description,input_schema:s.inputSchema}));return t.length>0&&(t[t.length-1].cache_control={type:"ephemeral"}),t}mapResponse(e){let t="",s=[];for(let r of e.content)r.type==="text"?t+=r.text:r.type==="tool_use"&&s.push({id:r.id,name:r.name,input:r.input});return{content:t,model:e.model??this.config.model,toolCalls:s.length>0?s:void 0,usage:{inputTokens:e.usage.input_tokens,outputTokens:e.usage.output_tokens,cacheCreationTokens:e.usage.cache_creation_input_tokens??0,cacheReadTokens:e.usage.cache_read_input_tokens??0},stopReason:e.stop_reason}}}});import Ph from"openai";var Be,Ts=T(()=>{"use strict";Ot();Be=class extends Ce{static{m(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new Ph({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=ot(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{}},n=await this.client.chat.completions.create(r);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.chat.completions.create({model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},stream:!0}),n,o,i="",a="",c=[],d=null,u=0,p=0;for await(let h of r){let f=h.choices[0];if(!f)continue;let g=f.delta;if(g?.content&&(a+=g.content,yield{type:"text_delta",text:g.content}),g?.tool_calls)for(let y of g.tool_calls)if(y.id){if(n){let _;try{_=JSON.parse(i||"{}")}catch{_={}}c.push({id:n,name:o,input:_})}n=y.id,o=y.function?.name,i=y.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:n,name:o}}}else y.function?.arguments&&(i+=y.function.arguments,yield{type:"tool_use_delta",toolCall:{input:y.function.arguments}});f.finish_reason&&(d=f.finish_reason),h.usage&&(u=h.usage.prompt_tokens,p=h.usage.completion_tokens)}if(n){let h;try{h=JSON.parse(i||"{}")}catch{h={}}c.push({id:n,name:o,input:h})}yield{type:"message_complete",response:{content:a,model:this.config.model,toolCalls:c.length>0?c:void 0,usage:{inputTokens:u,outputTokens:p},stopReason:this.mapStopReason(d)}}}isAvailable(){return!!this.config.apiKey}async embed(e){try{let s=(await this.client.embeddings.create({model:"text-embedding-3-small",input:e})).data[0];return{embedding:s.embedding,model:"text-embedding-3-small",dimensions:s.embedding.length}}catch(t){let s=t instanceof Error?t.message:String(t);console.warn(`[OpenAIProvider] embed() failed: ${s}`);return}}supportsEmbeddings(){return!0}isReasoningModel(){return/^(o[1-9]|gpt-5($|[.-][01]))/.test(this.config.model)}tokenLimitParam(e){let t=e??this.config.maxTokens??4096;return/^(gpt-5|o[1-9])/.test(this.config.model)?{max_completion_tokens:t}:{max_tokens:t}}safeTemperature(e){if(!this.isReasoningModel())return e??this.config.temperature}mapMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e){if(typeof r.content=="string"){s.push({role:r.role,content:r.content});continue}let n=[],o=[],i=[];for(let a of r.content)switch(a.type){case"text":n.push({type:"text",text:a.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${a.source.media_type};base64,${a.source.data}`}});break;case"tool_use":o.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input)}});break;case"tool_result":i.push({tool_call_id:a.tool_use_id,content:a.content});break}if(r.role==="assistant"&&o.length>0){let a=n.map(c=>c.text).join("");s.push({role:"assistant",content:a||null,tool_calls:o})}else if(i.length>0)for(let a of i)s.push({role:"tool",tool_call_id:a.tool_call_id,content:a.content});else n.length>0&&(r.role==="user"?s.push({role:"user",content:n}):s.push({role:r.role,content:n.map(a=>a.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,r=s?.content??"",n=s?.tool_calls?.map(o=>({id:o.id,name:o.function.name,input:(()=>{try{return JSON.parse(o.function.arguments)}catch{return{}}})()}));return{content:r,model:e.model??this.config.model,toolCalls:n&&n.length>0?n:void 0,usage:{inputTokens:e.usage?.prompt_tokens??0,outputTokens:e.usage?.completion_tokens??0},stopReason:this.mapStopReason(t?.finish_reason??null)}}mapStopReason(e){switch(e){case"stop":return"end_turn";case"tool_calls":return"tool_use";case"length":return"max_tokens";default:return"end_turn"}}}});var xr,Ji=T(()=>{"use strict";Ts();xr=class extends Be{static{m(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Cr,Zi=T(()=>{"use strict";Ot();Cr=class extends Ce{static{m(this,"OllamaProvider")}baseUrl="";constructor(e){super(e)}apiKey="";async initialize(){let e=this.config.baseUrl??"http://localhost:11434";this.baseUrl=e.replace(/\/v1\/?$/,"").replace(/\/+$/,""),this.apiKey=this.config.apiKey??"";let t=ot(this.config.model);t?this.contextWindow=t:await this.fetchModelContextWindow()}async fetchModelContextWindow(){try{let e=await fetch(`${this.baseUrl}/api/show`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:this.config.model})});if(!e.ok)return;let s=(await e.json()).model_info??{},r=Object.keys(s).find(o=>o.includes("context_length")||o==="num_ctx"),n=r?Number(s[r]):0;n>0&&(this.contextWindow={maxInputTokens:n,maxOutputTokens:Math.min(n,4096)})}catch{}}getHeaders(){let e={"Content-Type":"application/json"};return this.apiKey&&(e.Authorization=`Bearer ${this.apiKey}`),e}async complete(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text();throw new Error(`Ollama API error (${n.status}): ${i}`)}let o=await n.json();return this.mapResponse(o)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,r={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(r.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(r)});if(!n.ok){let h=await n.text();throw new Error(`Ollama API error (${n.status}): ${h}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let o=n.body.getReader(),i=new TextDecoder,a="",c="",d=0,u=0,p=[];try{for(;;){let{done:h,value:f}=await o.read();if(h)break;a+=i.decode(f,{stream:!0});let g=a.split(`
|
|
626
626
|
`);a=g.pop()??"";for(let y of g){let _=y.trim();if(!_)continue;let S;try{S=JSON.parse(_)}catch{continue}if(S.message?.content&&(c+=S.message.content,yield{type:"text_delta",text:S.message.content}),S.message?.tool_calls)for(let E of S.message.tool_calls){let v={id:`ollama_tool_${p.length}`,name:E.function.name,input:E.function.arguments};p.push(v),yield{type:"tool_use_start",toolCall:{id:v.id,name:v.name}},yield{type:"tool_use_delta",toolCall:{input:v.input}}}S.done&&(d=S.prompt_eval_count??0,u=S.eval_count??0,yield{type:"message_complete",response:{content:c,model:this.config.model,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:p.length>0?"tool_use":"end_turn"}})}}if(a.trim()){let h;try{h=JSON.parse(a.trim())}catch{return}if(h.message?.content&&(c+=h.message.content,yield{type:"text_delta",text:h.message.content}),h.message?.tool_calls)for(let f of h.message.tool_calls){let g={id:`ollama_tool_${p.length}`,name:f.function.name,input:f.function.arguments};p.push(g),yield{type:"tool_use_start",toolCall:{id:g.id,name:g.name}},yield{type:"tool_use_delta",toolCall:{input:g.input}}}h.done&&(d=h.prompt_eval_count??0,u=h.eval_count??0,yield{type:"message_complete",response:{content:c,toolCalls:p.length>0?p:void 0,usage:{inputTokens:d,outputTokens:u},stopReason:p.length>0?"tool_use":"end_turn"}})}}finally{o.releaseLock()}}isAvailable(){try{return this.baseUrl.length>0}catch{return!1}}async embed(e){try{let t=await fetch(`${this.baseUrl}/api/embed`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({model:"nomic-embed-text",input:e})});if(!t.ok)return;let s=await t.json();if(!s.embeddings||s.embeddings.length===0)return;let r=s.embeddings[0];return{embedding:r,model:"nomic-embed-text",dimensions:r.length}}catch{return}}supportsEmbeddings(){return!0}buildOptions(e){let t={},s=e.temperature??this.config.temperature;s!==void 0&&(t.temperature=s);let r=e.maxTokens??this.config.maxTokens;return r!==void 0&&(t.num_predict=r),t}buildMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let r of e)typeof r.content=="string"?s.push({role:r.role,content:r.content}):s.push(this.mapContentBlocks(r.role,r.content));return s}mapContentBlocks(e,t){let s=[],r=[];for(let o of t)switch(o.type){case"text":s.push(o.text);break;case"image":r.push(o.source.data);break;case"tool_use":s.push(`[Tool call: ${o.name}(${JSON.stringify(o.input)})]`);break;case"tool_result":s.push(`[Tool result for ${o.tool_use_id}]: ${o.content}`);break}let n={role:e,content:s.join(`
|
|
627
|
-
`)};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 Nr,Qi=T(()=>{"use strict";ws();Nr=class extends Be{static{m(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as Uh}from"@google/genai";var Lr,ea=T(()=>{"use strict";Ot();Lr=class extends Ce{static{m(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Uh({apiKey:this.config.apiKey});let e=ot(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),n="",o=[],i=0,a=0,c;for await(let d of r){c=d;let u=d.text;if(u&&(n+=u,yield{type:"text_delta",text:u}),d.functionCalls)for(let p of d.functionCalls){let h={id:p.id??`google_tool_${o.length}`,name:p.name,input:p.args??{}};o.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:o.length>0?o:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:o.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(n=>n.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let n=this.rawContentCache.keys().next().value;n&&this.rawContentCache.delete(n)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let n of r.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let r of e){let n=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:n,parts:[{text:r.content}]});continue}let o=[],i=[],a=[];for(let c of r.content)switch(c.type){case"text":i.push({text:c.text});break;case"image":i.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":o.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let d=t.get(c.tool_use_id)??c.tool_use_id,u;try{let p=JSON.parse(c.content);u=typeof p=="object"&&p!==null?p:{result:p}}catch{u={result:c.content}}a.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&o.length>0){let c=this.buildCacheKeyFromBlocks(o),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...i];for(let p=0;p<o.length;p++){let h=o[p];u.push({functionCall:{id:h.id,name:h.name,args:h.input},...p===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else i.length>0&&s.push({role:n,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let c=a.functionCall.id??a.functionCall.name??"";c&&t.add(c)}s.push(i)}else{let a=(i.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let c=a.functionResponse.id??a.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&n.push({role:i.role,parts:a})}else n.push(i);if(n.length<=1)return n;let o=[n[0]];for(let i=1;i<n.length;i++){let a=o[o.length-1],c=n[i];a.role===c.role?a.parts=[...a.parts??[],...c.parts??[]]:o.push(c)}return o}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((n,o)=>({id:n.id??`google_tool_${o}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var Dr,ta=T(()=>{"use strict";ws();Dr=class extends Be{static{m(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function sa(l){switch(l.provider){case"anthropic":return new Rr(l);case"openai":return new Be(l);case"openrouter":return new xr(l);case"ollama":return new Cr(l);case"openwebui":return new Nr(l);case"google":return new Lr(l);case"mistral":return new Dr(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var ra=T(()=>{"use strict";Yi();ws();Ji();Zi();Qi();ea();ta();m(sa,"createLLMProvider")});function rd(l){let e=l.toLowerCase();for(let[t,s]of Fh)if(e.startsWith(t.toLowerCase()))return s}function lo(l,e){let t=rd(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=Math.max(0,e.inputTokens-n);return r+=i/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),o>0&&t.cacheWrite&&(r+=o/s*t.cacheWrite),r}var Fh,Mr,na=T(()=>{"use strict";Fh=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];m(rd,"getModelPricing");m(lo,"calculateCost");Mr=class{static{m(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=lo(e,t),r=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=r,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let o=this.data.byModel[e];o||(o={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=o),o.calls++,o.inputTokens+=t.inputTokens,o.outputTokens+=t.outputTokens,o.cacheReadTokens+=r,o.cacheWriteTokens+=n,o.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,r,n,s)}catch{}return s}getSummary(){return{...this.data,totalCostUsd:Math.round(this.data.totalCostUsd*1e6)/1e6,byModel:Object.fromEntries(Object.entries(this.data.byModel).map(([e,t])=>[e,{...t,costUsd:Math.round(t.costUsd*1e6)/1e6}]))}}}});function oa(l,e){return new uo(l,e)}var nd,uo,od=T(()=>{"use strict";Ot();ra();na();nd=["default","strong","fast","embeddings","local"],uo=class extends Ce{static{m(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new Mr;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of nd){let t=this.multiConfig[e];if(t){let s=sa(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}if(!this.providers.has("default"))throw new Error(`ModelRouter: no "default" tier configured. Available tiers: [${[...this.providers.keys()].join(", ")}]`)}resolve(e){if(e&&this.providers.has(e))return{provider:this.providers.get(e),resolvedTier:e};let t=this.providers.get("default");if(!t)throw new Error('ModelRouter: no "default" tier available. Was initialize() called?');return{provider:t,resolvedTier:"default"}}async complete(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=this.multiConfig[s];this.logger?.debug({requestedTier:e.tier??"default",resolvedTier:s,model:r?.model},"LLM routing request");try{return await this.executeComplete(t,s,e)}catch(n){if(!this.isRetryableError(n))throw n;return this.logger?.warn({err:n,tier:s},"Provider failed, attempting fallback"),this.completeWithFallback(e,s,n)}}async executeComplete(e,t,s){let r=this.multiConfig[t],n=await e.complete(s),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:t,model:o,costUsd:Math.round(i*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let r=["default","strong","fast"].filter(n=>n!==t);for(let n of r){let o=this.providers.get(n);if(o)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(o,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=!1;try{for await(let n of t.stream(e))r=!0,yield n}catch(n){if(r||!this.isRetryableError(n))throw n;this.logger?.warn({err:n,tier:s},"Stream provider failed before first chunk, attempting fallback");let o=["default","strong","fast"].filter(i=>i!==s);for(let i of o){let a=this.providers.get(i);if(a)try{this.logger?.info({tier:i},"Stream fallback to tier"),yield*a.stream(e);return}catch{continue}}throw n}}async embed(e){return(this.providers.get("embeddings")??this.resolve().provider).embed(e)}supportsEmbeddings(){return(this.providers.get("embeddings")??this.resolve().provider).supportsEmbeddings()}isAvailable(){return this.resolve().provider.isAvailable()}getContextWindow(){return this.resolve().provider.getContextWindow()}getProviderStatuses(){let e={};for(let t of nd){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};m(oa,"createModelRouter")});function He(l){return Math.ceil(l.length/3.5)}function Pt(l){if(typeof l.content=="string")return He(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=He(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=He(t.name)+He(JSON.stringify(t.input));break;case"tool_result":e+=He(t.content);break}return e}function ia(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let a of l)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&n.set(c.id,c.name);let o=[];for(let a=0;a<l.length;a++){let c=l[a];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&o.push(a)}let i=new Set(o.slice(-t));return l.map((a,c)=>{if(i.has(c)||a.role!=="user"||!Array.isArray(a.content))return a;let d=!1,u=a.content.map(p=>{if(p.type!=="tool_result")return p;let h=p.content;if(typeof h!="string"||h.length<r)return p;d=!0;let f=n.get(p.tool_use_id)||"unknown",g=h.split(`
|
|
627
|
+
`)};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 Nr,Qi=T(()=>{"use strict";Ts();Nr=class extends Be{static{m(this,"OpenWebUIProvider")}constructor(e){super({...e,apiKey:e.apiKey||"openwebui",baseUrl:e.baseUrl??"http://localhost:3000/api/v1"})}isAvailable(){return!0}supportsEmbeddings(){return!1}}});import{GoogleGenAI as Uh}from"@google/genai";var Lr,ea=T(()=>{"use strict";Ot();Lr=class extends Ce{static{m(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new Uh({apiKey:this.config.apiKey});let e=ot(this.config.model);e&&(this.contextWindow=e)}async complete(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContent({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}});return this.cacheRawContent(r),this.mapResponse(r)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,r=await this.client.models.generateContentStream({model:this.config.model,contents:t,config:{systemInstruction:e.system,...s?{tools:[{functionDeclarations:s}]}:{},temperature:e.temperature??this.config.temperature,maxOutputTokens:e.maxTokens??this.config.maxTokens??4096}}),n="",o=[],i=0,a=0,c;for await(let d of r){c=d;let u=d.text;if(u&&(n+=u,yield{type:"text_delta",text:u}),d.functionCalls)for(let p of d.functionCalls){let h={id:p.id??`google_tool_${o.length}`,name:p.name,input:p.args??{}};o.push(h),yield{type:"tool_use_start",toolCall:{id:h.id,name:h.name}}}d.usageMetadata&&(i=d.usageMetadata.promptTokenCount??0,a=d.usageMetadata.candidatesTokenCount??0)}c&&this.cacheRawContent(c),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:o.length>0?o:void 0,usage:{inputTokens:i,outputTokens:a},stopReason:o.length>0?"tool_use":"end_turn"}}}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}cacheRawContent(e){let t=e.candidates?.[0]?.content;if(!t?.parts)return;let s=t.parts.filter(n=>n.functionCall);if(s.length===0)return;let r=this.buildCacheKey(s);if(this.rawContentCache.set(r,t),this.rawContentCache.size>20){let n=this.rawContentCache.keys().next().value;n&&this.rawContentCache.delete(n)}}buildCacheKey(e){return e.map(t=>`${t.functionCall.id??""}:${t.functionCall.name}`).sort().join("|")}buildCacheKeyFromBlocks(e){return e.map(t=>`${t.id}:${t.name}`).sort().join("|")}mapContents(e){let t=new Map;for(let r of e)if(!(r.role!=="assistant"||typeof r.content=="string"))for(let n of r.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let r of e){let n=r.role==="assistant"?"model":"user";if(typeof r.content=="string"){s.push({role:n,parts:[{text:r.content}]});continue}let o=[],i=[],a=[];for(let c of r.content)switch(c.type){case"text":i.push({text:c.text});break;case"image":i.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":o.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let d=t.get(c.tool_use_id)??c.tool_use_id,u;try{let p=JSON.parse(c.content);u=typeof p=="object"&&p!==null?p:{result:p}}catch{u={result:c.content}}a.push({functionResponse:{id:c.tool_use_id,name:d,response:u}});break}}if(r.role==="assistant"&&o.length>0){let c=this.buildCacheKeyFromBlocks(o),d=this.rawContentCache.get(c);if(d)this.rawContentCache.delete(c),this.rawContentCache.set(c,d),s.push(d);else{let u=[...i];for(let p=0;p<o.length;p++){let h=o[p];u.push({functionCall:{id:h.id,name:h.name,args:h.input},...p===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else i.length>0&&s.push({role:n,parts:i});a.length>0&&s.push({role:"user",parts:a})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let i of e)if(i.role==="model"){for(let a of i.parts??[])if(a.functionCall){let c=a.functionCall.id??a.functionCall.name??"";c&&t.add(c)}s.push(i)}else{let a=(i.parts??[]).filter(c=>{if(c.functionResponse){let d=c.functionResponse.id??c.functionResponse.name??"";return d?t.has(d):!1}return!0});a.length>0&&s.push({role:i.role,parts:a})}let r=new Set;for(let i of s)if(i.role!=="model"){for(let a of i.parts??[])if(a.functionResponse){let c=a.functionResponse.id??a.functionResponse.name??"";c&&r.add(c)}}let n=[];for(let i of s)if(i.role==="model"){let a=(i.parts??[]).filter(c=>{if(c.functionCall){let d=c.functionCall.id??c.functionCall.name??"";return d?r.has(d):!1}return!0});a.length>0&&n.push({role:i.role,parts:a})}else n.push(i);if(n.length<=1)return n;let o=[n[0]];for(let i=1;i<n.length;i++){let a=o[o.length-1],c=n[i];a.role===c.role?a.parts=[...a.parts??[],...c.parts??[]]:o.push(c)}return o}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",r=e.functionCalls?.map((n,o)=>({id:n.id??`google_tool_${o}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:r&&r.length>0?r:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0},stopReason:r&&r.length>0?"tool_use":"end_turn"}}}});var Dr,ta=T(()=>{"use strict";Ts();Dr=class extends Be{static{m(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});function sa(l){switch(l.provider){case"anthropic":return new Rr(l);case"openai":return new Be(l);case"openrouter":return new xr(l);case"ollama":return new Cr(l);case"openwebui":return new Nr(l);case"google":return new Lr(l);case"mistral":return new Dr(l);default:throw new Error(`Unknown LLM provider: ${l.provider}`)}}var ra=T(()=>{"use strict";Yi();Ts();Ji();Zi();Qi();ea();ta();m(sa,"createLLMProvider")});function rd(l){let e=l.toLowerCase();for(let[t,s]of Fh)if(e.startsWith(t.toLowerCase()))return s}function lo(l,e){let t=rd(l);if(!t)return 0;let s=1e6,r=0,n=e.cacheReadTokens??0,o=e.cacheCreationTokens??0,i=Math.max(0,e.inputTokens-n);return r+=i/s*t.input,r+=e.outputTokens/s*t.output,n>0&&t.cacheRead&&(r+=n/s*t.cacheRead),o>0&&t.cacheWrite&&(r+=o/s*t.cacheWrite),r}var Fh,Mr,na=T(()=>{"use strict";Fh=[["gpt-5.4",{input:2.5,output:15,cacheRead:1.25}],["gpt-5",{input:2,output:8,cacheRead:.5}],["gpt-4.1-nano",{input:.1,output:.4,cacheRead:.025}],["gpt-4.1-mini",{input:.4,output:1.6,cacheRead:.1}],["gpt-4.1",{input:2,output:8,cacheRead:.5}],["gpt-4o-mini",{input:.15,output:.6,cacheRead:.075}],["gpt-4o",{input:2.5,output:10,cacheRead:1.25}],["o4-mini",{input:1.1,output:4.4,cacheRead:.275}],["o3-mini",{input:1.1,output:4.4,cacheRead:.55}],["o3",{input:2,output:8,cacheRead:.5}],["claude-opus-4",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-sonnet-4",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-haiku-4",{input:1,output:5,cacheRead:.1,cacheWrite:1.25}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.0-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.0-flash",{input:.5,output:3,cacheRead:.05}],["gemini-2.5-pro",{input:1.25,output:10,cacheRead:.125}],["gemini-2.5-flash",{input:.3,output:2.5,cacheRead:.03}],["gemini-2.0-flash",{input:.1,output:.4,cacheRead:.025}],["mistral-large",{input:2,output:6}],["mistral-small",{input:.2,output:.6}]];m(rd,"getModelPricing");m(lo,"calculateCost");Mr=class{static{m(this,"TokenCostTracker")}data={totalInputTokens:0,totalOutputTokens:0,totalCacheReadTokens:0,totalCacheWriteTokens:0,totalCostUsd:0,byModel:{}};persistFn;setPersist(e){this.persistFn=e}record(e,t){let s=lo(e,t),r=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=r,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let o=this.data.byModel[e];o||(o={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=o),o.calls++,o.inputTokens+=t.inputTokens,o.outputTokens+=t.outputTokens,o.cacheReadTokens+=r,o.cacheWriteTokens+=n,o.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,r,n,s)}catch{}return s}getSummary(){return{...this.data,totalCostUsd:Math.round(this.data.totalCostUsd*1e6)/1e6,byModel:Object.fromEntries(Object.entries(this.data.byModel).map(([e,t])=>[e,{...t,costUsd:Math.round(t.costUsd*1e6)/1e6}]))}}}});function oa(l,e){return new uo(l,e)}var nd,uo,od=T(()=>{"use strict";Ot();ra();na();nd=["default","strong","fast","embeddings","local"],uo=class extends Ce{static{m(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new Mr;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of nd){let t=this.multiConfig[e];if(t){let s=sa(t);await s.initialize(),this.providers.set(e,s),this.logger?.info({tier:e,provider:t.provider,model:t.model},"LLM tier initialized")}}if(!this.providers.has("default"))throw new Error(`ModelRouter: no "default" tier configured. Available tiers: [${[...this.providers.keys()].join(", ")}]`)}resolve(e){if(e&&this.providers.has(e))return{provider:this.providers.get(e),resolvedTier:e};let t=this.providers.get("default");if(!t)throw new Error('ModelRouter: no "default" tier available. Was initialize() called?');return{provider:t,resolvedTier:"default"}}async complete(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=this.multiConfig[s];this.logger?.debug({requestedTier:e.tier??"default",resolvedTier:s,model:r?.model},"LLM routing request");try{return await this.executeComplete(t,s,e)}catch(n){if(!this.isRetryableError(n))throw n;return this.logger?.warn({err:n,tier:s},"Provider failed, attempting fallback"),this.completeWithFallback(e,s,n)}}async executeComplete(e,t,s){let r=this.multiConfig[t],n=await e.complete(s),o=n.model??r?.model??"unknown";n.model||(n.model=o);let i=this.costTracker.record(o,n.usage);return this.logger?.info({tier:t,model:o,costUsd:Math.round(i*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let r=["default","strong","fast"].filter(n=>n!==t);for(let n of r){let o=this.providers.get(n);if(o)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(o,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),r=!1;try{for await(let n of t.stream(e))r=!0,yield n}catch(n){if(r||!this.isRetryableError(n))throw n;this.logger?.warn({err:n,tier:s},"Stream provider failed before first chunk, attempting fallback");let o=["default","strong","fast"].filter(i=>i!==s);for(let i of o){let a=this.providers.get(i);if(a)try{this.logger?.info({tier:i},"Stream fallback to tier"),yield*a.stream(e);return}catch{continue}}throw n}}async embed(e){return(this.providers.get("embeddings")??this.resolve().provider).embed(e)}supportsEmbeddings(){return(this.providers.get("embeddings")??this.resolve().provider).supportsEmbeddings()}isAvailable(){return this.resolve().provider.isAvailable()}getContextWindow(){return this.resolve().provider.getContextWindow()}getProviderStatuses(){let e={};for(let t of nd){let s=this.providers.get(t);if(s){let r=this.multiConfig[t];e[t]={model:r?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};m(oa,"createModelRouter")});function He(l){return Math.ceil(l.length/3.5)}function Pt(l){if(typeof l.content=="string")return He(l.content)+4;let e=4;for(let t of l.content)switch(t.type){case"text":e+=He(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=He(t.name)+He(JSON.stringify(t.input));break;case"tool_result":e+=He(t.content);break}return e}function ia(l,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,r=e?.minContentLength??300,n=new Map;for(let a of l)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&n.set(c.id,c.name);let o=[];for(let a=0;a<l.length;a++){let c=l[a];c.role==="user"&&Array.isArray(c.content)&&c.content.some(d=>d.type==="tool_result")&&o.push(a)}let i=new Set(o.slice(-t));return l.map((a,c)=>{if(i.has(c)||a.role!=="user"||!Array.isArray(a.content))return a;let d=!1,u=a.content.map(p=>{if(p.type!=="tool_result")return p;let h=p.content;if(typeof h!="string"||h.length<r)return p;d=!0;let f=n.get(p.tool_use_id)||"unknown",g=h.split(`
|
|
628
628
|
`)[0].slice(0,s),y=p.is_error?"Fehler":"Ergebnis";return{...p,content:`[${y}: ${f} \u2014 ${g}]`}});return d?{...a,content:u}:a})}var Or,id=T(()=>{"use strict";m(He,"estimateTokens");m(Pt,"estimateMessageTokens");m(ia,"trimOldToolResults");Or=class{static{m(this,"PromptBuilder")}buildSystemPrompt(e={}){let{memories:t,skills:s,userProfile:r,todayEvents:n,conversationSummary:o}=e,i=process.platform==="darwin"?"macOS":process.platform==="win32"?"Windows":"Linux",a=process.env.HOME||process.env.USERPROFILE||"~",c=`You are Alfred, a personal AI assistant. You run on ${i} (home: ${a}).
|
|
629
629
|
|
|
630
630
|
## Core principles
|
|
@@ -698,33 +698,33 @@ This summarizes the earlier conversation. Use it to maintain continuity. The mos
|
|
|
698
698
|
`;c+=`
|
|
699
699
|
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+=`
|
|
700
700
|
|
|
701
|
-
When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return c}buildMessages(e){let t=e.filter(s=>s.role==="user"||s.role==="assistant").map(s=>{if(s.toolCalls){let r;try{r=JSON.parse(s.toolCalls)}catch{r=[]}if(s.role==="assistant"){let i=r,a=[];s.content&&a.push({type:"text",text:s.content});for(let c of i)a.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let n=r,o=[];for(let i of n)i.type==="tool_result"&&o.push(i);return o.length>0?{role:"user",content:o}:{role:"user",content:s.content||""}}return{role:s.role,content:s.content}});return this.sanitizeToolMessages(t)}sanitizeToolMessages(e){let t=new Set,s=new Set;for(let a of e)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&t.add(c.id);else if(a.role==="user"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_result"&&t.has(c.tool_use_id)&&s.add(c.tool_use_id);let r=new Set,n=new Set,o=[];for(let a of e){if(!Array.isArray(a.content)){o.push(a);continue}let c=a.content.filter(d=>d.type==="tool_use"?!s.has(d.id)||r.has(d.id)?!1:(r.add(d.id),!0):d.type==="tool_result"?!s.has(d.tool_use_id)||n.has(d.tool_use_id)?!1:(n.add(d.tool_use_id),!0):!0);c.length!==0&&o.push({...a,content:c})}let i=[];for(let a of o){let c=i[i.length-1];if(c&&c.role===a.role){let d=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content,u=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...c,content:[...d,...u]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var aa=T(()=>{"use strict";Ot();Yi();ws();Ji();Zi();Qi();ea();ta();ra();od();id();na()});var Pr,ca=T(()=>{"use strict";Pr=class{static{m(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let o=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:o,resetsAt:n.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);!n||s>n.windowStart+n.windowMs?this.buckets.set(e,{count:1,windowStart:s,windowMs:r}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+s.windowMs*2&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var Ur,ad=T(()=>{"use strict";ca();Ur=class{static{m(this,"RuleEngine")}rules=[];rateLimiter=new Pr;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 cd,ld,dd,it,ud=T(()=>{"use strict";cd=["allow","deny"],ld=["global","user","conversation","platform"],dd=["read","write","destructive","admin"],it=class{static{m(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!cd.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${cd.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"||!ld.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${ld.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(!dd.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${dd.join(", ")}`);let r={id:s.id,effect:s.effect,priority:s.priority,scope:s.scope,actions:s.actions,riskLevels:s.riskLevels};if(s.conditions!==void 0){if(typeof s.conditions!="object"||s.conditions===null)throw new Error(`Rule "${s.id}" has invalid "conditions": expected an object`);let n=s.conditions;if(n.users!==void 0&&!Array.isArray(n.users))throw new Error(`Rule "${s.id}" has invalid "conditions.users": expected an array`);if(n.platforms!==void 0&&!Array.isArray(n.platforms))throw new Error(`Rule "${s.id}" has invalid "conditions.platforms": expected an array`);if(n.chatType!==void 0&&typeof n.chatType!="string")throw new Error(`Rule "${s.id}" has invalid "conditions.chatType": expected a string`);if(n.timeWindow!==void 0){let o=n.timeWindow;if(typeof o!="object"||o===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(o.startHour!==void 0&&(typeof o.startHour!="number"||o.startHour<0||o.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(o.endHour!==void 0&&(typeof o.endHour!="number"||o.endHour<0||o.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(o.daysOfWeek!==void 0&&(!Array.isArray(o.daysOfWeek)||!o.daysOfWeek.every(i=>typeof i=="number"&&i>=0&&i<=6)))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.daysOfWeek": expected array of 0-6`)}r.conditions=s.conditions}if(s.rateLimit!==void 0){if(typeof s.rateLimit!="object"||s.rateLimit===null)throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected an object`);let n=s.rateLimit;if(typeof n.maxInvocations!="number"||typeof n.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import jh from"node:crypto";var Fr,md=T(()=>{"use strict";Fr=class{static{m(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:jh.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 mo=T(()=>{"use strict";ad();ca();ud();md()});var x,H=T(()=>{"use strict";x=class{static{m(this,"Skill")}}});function de(l){return l.masterUserId??l.userId}function Y(l){let e=new Set;if(e.add(de(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Me=T(()=>{"use strict";m(de,"effectiveUserId");m(Y,"allUserIds")});var Ts,pd=T(()=>{"use strict";Ts=class{static{m(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var _s,hd=T(()=>{"use strict";_s=class{static{m(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:o}=e.metadata;return this.logger.info({skill:o,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,o,r,n):this.executeWithHardTimeout(e,t,s,o,r)}async executeWithTracker(e,t,s,r,n,o){return new Promise(i=>{let a=!1,c,d,u,p=m(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),h=m(f=>{a||(a=!0,p(),i(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),h(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),h({success:!1,error:g})}),u=setTimeout(()=>{if(a)return;let f=o.getIdleMs();if(f>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),h({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=o.getSnapshot();this.logger.info({skill:r,idleMs:f,state:g.state,iteration:g.iteration,totalMs:g.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){p();return}let y=o.getIdleMs(),_=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:_.state,iteration:_.iteration,totalMs:_.totalElapsedMs},"Agent went inactive \u2014 aborting"),h({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${_.state})`})):this.logger.debug({skill:r,idleMs:y,state:_.state,iteration:_.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let f=o.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),h({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,n){try{let o,i=await Promise.race([e.execute(t,s),new Promise((a,c)=>{o=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{o&&clearTimeout(o)});return this.logger.info({skill:r,success:i.success,...i.success?{}:{error:i.error}},"Skill execution completed"),i}catch(o){let i=o instanceof Error?o.message:String(o);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var Ut,la=T(()=>{"use strict";Ut=class{static{m(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import Bh from"node:fs";import da from"node:path";var po,fd=T(()=>{"use strict";H();po=class{static{m(this,"PluginLoader")}async loadFromDirectory(e){let t=da.resolve(e),s;try{s=await Bh.promises.readdir(t)}catch(o){let i=o instanceof Error?o.message:String(o);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(o=>o.endsWith(".js")),n=[];for(let o of r){let i=da.join(t,o);try{let a=await this.loadFromFile(i);n.push(a)}catch(a){let c=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${c}`)}}return n}async loadFromFile(e){let t=da.resolve(e),n=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof n!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let o=new n;if(!(o instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(o,t),o}validateMetadata(e,t){let{metadata:s}=e;if(!s)throw new Error(`Plugin "${t}" is missing metadata`);if(!s.name||typeof s.name!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.name`);if(!s.description||typeof s.description!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.description`);if(!["read","write","destructive","admin"].includes(s.riskLevel))throw new Error(`Plugin "${t}" has invalid metadata.riskLevel: "${String(s.riskLevel)}"`);if(!s.version||typeof s.version!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.version`)}}});function Hh(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 gd)e.push({type:"const",value:gd[s]});else if(s in yd)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 Wh(l){let e=Hh(l);if(e.length===0)throw new Error("Empty expression");return new ua(e).parse()}var yd,gd,ua,ks,wd=T(()=>{"use strict";H();yd={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},gd={PI:Math.PI,E:Math.E};m(Hh,"tokenize");ua=class{static{m(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return yd[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};m(Wh,"safeEval");ks=class extends x{static{m(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=Wh(r);return typeof n!="number"||!isFinite(n)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:n,display:`${r} = ${n}`}}catch(n){let o=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${o}`}}}}});var bs,Td=T(()=>{"use strict";H();bs=class extends x{static{m(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=m(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var Es,_d=T(()=>{"use strict";H();Es=class extends x{static{m(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let o;switch(this.config.provider){case"brave":o=await this.searchBrave(s,r);break;case"searxng":o=await this.searchSearXNG(s,r);break;case"tavily":o=await this.searchTavily(s,r);break;case"duckduckgo":o=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(o.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=o.map((a,c)=>`${c+1}. **${a.title}**
|
|
701
|
+
When the user tells you facts about themselves or preferences, use the memory tool to save them for future reference.`;return c}buildMessages(e){let t=e.filter(s=>s.role==="user"||s.role==="assistant").map(s=>{if(s.toolCalls){let r;try{r=JSON.parse(s.toolCalls)}catch{r=[]}if(s.role==="assistant"){let i=r,a=[];s.content&&a.push({type:"text",text:s.content});for(let c of i)a.push({type:"tool_use",id:c.id,name:c.name,input:c.input});return a.length===0&&a.push({type:"text",text:""}),{role:"assistant",content:a}}let n=r,o=[];for(let i of n)i.type==="tool_result"&&o.push(i);return o.length>0?{role:"user",content:o}:{role:"user",content:s.content||""}}return{role:s.role,content:s.content}});return this.sanitizeToolMessages(t)}sanitizeToolMessages(e){let t=new Set,s=new Set;for(let a of e)if(a.role==="assistant"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_use"&&t.add(c.id);else if(a.role==="user"&&Array.isArray(a.content))for(let c of a.content)c.type==="tool_result"&&t.has(c.tool_use_id)&&s.add(c.tool_use_id);let r=new Set,n=new Set,o=[];for(let a of e){if(!Array.isArray(a.content)){o.push(a);continue}let c=a.content.filter(d=>d.type==="tool_use"?!s.has(d.id)||r.has(d.id)?!1:(r.add(d.id),!0):d.type==="tool_result"?!s.has(d.tool_use_id)||n.has(d.tool_use_id)?!1:(n.add(d.tool_use_id),!0):!0);c.length!==0&&o.push({...a,content:c})}let i=[];for(let a of o){let c=i[i.length-1];if(c&&c.role===a.role){let d=typeof c.content=="string"?[{type:"text",text:c.content}]:c.content,u=typeof a.content=="string"?[{type:"text",text:a.content}]:a.content;i[i.length-1]={...c,content:[...d,...u]}}else i.push(a)}return i}buildTools(e){return e.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))}}});var aa=T(()=>{"use strict";Ot();Yi();Ts();Ji();Zi();Qi();ea();ta();ra();od();id();na()});var Pr,ca=T(()=>{"use strict";Pr=class{static{m(this,"RateLimiter")}buckets=new Map;checkCount=0;checkAndIncrement(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);return!n||s>n.windowStart+n.windowMs?(this.buckets.set(e,{count:1,windowStart:s,windowMs:r}),{allowed:!0,remaining:Math.max(0,t.maxInvocations-1),resetsAt:s+r}):n.count<t.maxInvocations?(n.count+=1,{allowed:!0,remaining:Math.max(0,t.maxInvocations-n.count),resetsAt:n.windowStart+r}):{allowed:!1,remaining:0,resetsAt:n.windowStart+r}}check(e,t){this.checkCount++,this.checkCount%100===0&&this.cleanup();let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);if(!n)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};if(s>n.windowStart+n.windowMs)return{allowed:!0,remaining:t.maxInvocations,resetsAt:s+r};let o=Math.max(0,t.maxInvocations-n.count);return{allowed:n.count<t.maxInvocations,remaining:o,resetsAt:n.windowStart+r}}increment(e,t){let s=Date.now(),r=t.windowSeconds*1e3,n=this.buckets.get(e);!n||s>n.windowStart+n.windowMs?this.buckets.set(e,{count:1,windowStart:s,windowMs:r}):n.count+=1}cleanup(){let e=Date.now();for(let[t,s]of this.buckets)e>s.windowStart+s.windowMs*2&&this.buckets.delete(t)}reset(){this.buckets.clear()}}});var Ur,ad=T(()=>{"use strict";ca();Ur=class{static{m(this,"RuleEngine")}rules=[];rateLimiter=new Pr;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 cd,ld,dd,it,ud=T(()=>{"use strict";cd=["allow","deny"],ld=["global","user","conversation","platform"],dd=["read","write","destructive","admin"],it=class{static{m(this,"RuleLoader")}loadFromObject(e){if(!e||!Array.isArray(e.rules))throw new Error('Invalid data: expected an object with a "rules" array');return e.rules.map((t,s)=>this.validateRule(t,s))}validateRule(e,t){if(typeof e!="object"||e===null)throw new Error(`Rule at index ${t} is not an object`);let s=e;if(typeof s.id!="string"||s.id.length===0)throw new Error(`Rule at index ${t} is missing a valid "id" string`);if(typeof s.effect!="string"||!cd.includes(s.effect))throw new Error(`Rule "${s.id}" has invalid "effect": expected one of ${cd.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"||!ld.includes(s.scope))throw new Error(`Rule "${s.id}" has invalid "scope": expected one of ${ld.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(!dd.includes(n))throw new Error(`Rule "${s.id}" has invalid risk level "${n}": expected one of ${dd.join(", ")}`);let r={id:s.id,effect:s.effect,priority:s.priority,scope:s.scope,actions:s.actions,riskLevels:s.riskLevels};if(s.conditions!==void 0){if(typeof s.conditions!="object"||s.conditions===null)throw new Error(`Rule "${s.id}" has invalid "conditions": expected an object`);let n=s.conditions;if(n.users!==void 0&&!Array.isArray(n.users))throw new Error(`Rule "${s.id}" has invalid "conditions.users": expected an array`);if(n.platforms!==void 0&&!Array.isArray(n.platforms))throw new Error(`Rule "${s.id}" has invalid "conditions.platforms": expected an array`);if(n.chatType!==void 0&&typeof n.chatType!="string")throw new Error(`Rule "${s.id}" has invalid "conditions.chatType": expected a string`);if(n.timeWindow!==void 0){let o=n.timeWindow;if(typeof o!="object"||o===null)throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow": expected an object`);if(o.startHour!==void 0&&(typeof o.startHour!="number"||o.startHour<0||o.startHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.startHour": expected 0-23`);if(o.endHour!==void 0&&(typeof o.endHour!="number"||o.endHour<0||o.endHour>23))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.endHour": expected 0-23`);if(o.daysOfWeek!==void 0&&(!Array.isArray(o.daysOfWeek)||!o.daysOfWeek.every(i=>typeof i=="number"&&i>=0&&i<=6)))throw new Error(`Rule "${s.id}" has invalid "conditions.timeWindow.daysOfWeek": expected array of 0-6`)}r.conditions=s.conditions}if(s.rateLimit!==void 0){if(typeof s.rateLimit!="object"||s.rateLimit===null)throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected an object`);let n=s.rateLimit;if(typeof n.maxInvocations!="number"||typeof n.windowSeconds!="number")throw new Error(`Rule "${s.id}" has invalid "rateLimit": expected maxInvocations and windowSeconds numbers`);r.rateLimit=s.rateLimit}return r}}});import jh from"node:crypto";var Fr,md=T(()=>{"use strict";Fr=class{static{m(this,"SecurityManager")}ruleEngine;auditRepository;logger;constructor(e,t,s){this.ruleEngine=e,this.auditRepository=t,this.logger=s}evaluate(e){let t=this.ruleEngine.evaluate(e),s={id:jh.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 mo=T(()=>{"use strict";ad();ca();ud();md()});var x,H=T(()=>{"use strict";x=class{static{m(this,"Skill")}}});function de(l){return l.masterUserId??l.userId}function Y(l){let e=new Set;if(e.add(de(l)),e.add(l.userId),l.linkedPlatformUserIds)for(let t of l.linkedPlatformUserIds)e.add(t);return[...e]}var Me=T(()=>{"use strict";m(de,"effectiveUserId");m(Y,"allUserIds")});var _s,pd=T(()=>{"use strict";_s=class{static{m(this,"SkillRegistry")}skills=new Map;register(e){let{name:t}=e.metadata;if(this.skills.has(t))throw new Error(`Skill "${t}" is already registered`);this.skills.set(t,e)}get(e){return this.skills.get(e)}getAll(){return[...this.skills.values()]}has(e){return this.skills.has(e)}unregister(e){return this.skills.delete(e)}toToolDefinitions(){return this.getAll().map(e=>({name:e.metadata.name,description:e.metadata.description,inputSchema:e.metadata.inputSchema}))}}});var ks,hd=T(()=>{"use strict";ks=class{static{m(this,"SkillSandbox")}logger;constructor(e){this.logger=e}async execute(e,t,s,r,n){r=r??e.metadata.timeoutMs??3e4;let{name:o}=e.metadata;return this.logger.info({skill:o,input:t},"Skill execution started"),n?this.executeWithTracker(e,t,s,o,r,n):this.executeWithHardTimeout(e,t,s,o,r)}async executeWithTracker(e,t,s,r,n,o){return new Promise(i=>{let a=!1,c,d,u,p=m(()=>{c&&clearInterval(c),d&&clearTimeout(d),u&&clearTimeout(u)},"cleanup"),h=m(f=>{a||(a=!0,p(),i(f))},"finish");e.execute(t,s).then(f=>{this.logger.info({skill:r,success:f.success,...f.success?{}:{error:f.error}},"Skill execution completed"),h(f)},f=>{let g=f instanceof Error?f.message:String(f);this.logger.error({skill:r,error:g},"Skill execution failed"),h({success:!1,error:g})}),u=setTimeout(()=>{if(a)return;let f=o.getIdleMs();if(f>=12e4){let y=o.getSnapshot();this.logger.warn({skill:r,idleMs:f,state:y.state,iteration:y.iteration},"Agent inactive after initial timeout \u2014 aborting"),h({success:!1,error:`Skill "${r}" timed out \u2014 inactive for ${Math.round(f/1e3)}s (last state: ${y.state})`});return}let g=o.getSnapshot();this.logger.info({skill:r,idleMs:f,state:g.state,iteration:g.iteration,totalMs:g.totalElapsedMs},"Initial timeout reached but agent is active \u2014 extending"),c=setInterval(()=>{if(a){p();return}let y=o.getIdleMs(),_=o.getSnapshot();y>=12e4?(this.logger.warn({skill:r,idleMs:y,state:_.state,iteration:_.iteration,totalMs:_.totalElapsedMs},"Agent went inactive \u2014 aborting"),h({success:!1,error:`Skill "${r}" killed \u2014 inactive for ${Math.round(y/1e3)}s (last state: ${_.state})`})):this.logger.debug({skill:r,idleMs:y,state:_.state,iteration:_.iteration},"Agent still active, continuing...")},1e4)},n),d=setTimeout(()=>{if(a)return;let f=o.getSnapshot();this.logger.error({skill:r,totalMs:f.totalElapsedMs,state:f.state,iteration:f.iteration},"Absolute time limit reached \u2014 force killing agent"),h({success:!1,error:`Skill "${r}" force-killed after ${Math.round(12e5/6e4)} minutes (safety limit)`})},12e5)})}async executeWithHardTimeout(e,t,s,r,n){try{let o,i=await Promise.race([e.execute(t,s),new Promise((a,c)=>{o=setTimeout(()=>c(new Error(`Skill "${r}" timed out after ${n}ms`)),n)})]).finally(()=>{o&&clearTimeout(o)});return this.logger.info({skill:r,success:i.success,...i.success?{}:{error:i.error}},"Skill execution completed"),i}catch(o){let i=o instanceof Error?o.message:String(o);return this.logger.error({skill:r,error:i},"Skill execution failed"),{success:!1,error:i}}}}});var Ut,la=T(()=>{"use strict";Ut=class{static{m(this,"ActivityTracker")}state="starting";iteration=0;maxIterations=0;currentTool;lastPingAt;startedAt;history=[];onProgress;constructor(e){this.startedAt=Date.now(),this.lastPingAt=Date.now(),this.onProgress=e}ping(e,t){this.state=e,this.lastPingAt=Date.now(),t?.iteration!==void 0&&(this.iteration=t.iteration),t?.maxIterations!==void 0&&(this.maxIterations=t.maxIterations),this.currentTool=t?.tool,this.history.push({state:e,tool:t?.tool,iteration:this.iteration,timestamp:this.lastPingAt}),this.onProgress&&this.onProgress(this.formatStatus())}getIdleMs(){return Date.now()-this.lastPingAt}getTotalElapsedMs(){return Date.now()-this.startedAt}formatStatus(){let e=this.maxIterations>0?` (${this.iteration}/${this.maxIterations})`:"";switch(this.state){case"starting":return"Sub-agent starting...";case"llm_call":return`Sub-agent thinking...${e}`;case"tool_call":return this.currentTool?`Sub-agent using ${this.currentTool}${e}`:`Sub-agent using tool...${e}`;case"processing":return`Sub-agent processing...${e}`;case"done":return`Sub-agent done${e}`;default:return`Sub-agent working...${e}`}}getSnapshot(){return{state:this.state,iteration:this.iteration,maxIterations:this.maxIterations,lastPingAt:this.lastPingAt,idleMs:this.getIdleMs(),currentTool:this.currentTool,totalElapsedMs:this.getTotalElapsedMs(),history:[...this.history]}}}});import Bh from"node:fs";import da from"node:path";var po,fd=T(()=>{"use strict";H();po=class{static{m(this,"PluginLoader")}async loadFromDirectory(e){let t=da.resolve(e),s;try{s=await Bh.promises.readdir(t)}catch(o){let i=o instanceof Error?o.message:String(o);return console.warn(`PluginLoader: failed to read directory "${t}": ${i}`),[]}let r=s.filter(o=>o.endsWith(".js")),n=[];for(let o of r){let i=da.join(t,o);try{let a=await this.loadFromFile(i);n.push(a)}catch(a){let c=a instanceof Error?a.message:String(a);console.warn(`PluginLoader: skipping "${i}": ${c}`)}}return n}async loadFromFile(e){let t=da.resolve(e),n=(await import(`file:///${t.replace(/\\/g,"/")}`)).default;if(typeof n!="function")throw new Error(`Module "${t}" does not have a default export that is a class`);let o=new n;if(!(o instanceof x))throw new Error(`Default export of "${t}" does not extend Skill`);return this.validateMetadata(o,t),o}validateMetadata(e,t){let{metadata:s}=e;if(!s)throw new Error(`Plugin "${t}" is missing metadata`);if(!s.name||typeof s.name!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.name`);if(!s.description||typeof s.description!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.description`);if(!["read","write","destructive","admin"].includes(s.riskLevel))throw new Error(`Plugin "${t}" has invalid metadata.riskLevel: "${String(s.riskLevel)}"`);if(!s.version||typeof s.version!="string")throw new Error(`Plugin "${t}" has invalid or missing metadata.version`)}}});function Hh(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 gd)e.push({type:"const",value:gd[s]});else if(s in yd)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 Wh(l){let e=Hh(l);if(e.length===0)throw new Error("Empty expression");return new ua(e).parse()}var yd,gd,ua,bs,wd=T(()=>{"use strict";H();yd={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},gd={PI:Math.PI,E:Math.E};m(Hh,"tokenize");ua=class{static{m(this,"Parser")}tokens;pos=0;constructor(e){this.tokens=e}parse(){let e=this.expr();if(this.pos<this.tokens.length)throw new Error("Unexpected token after expression");return e}peek(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}peekOp(e){let t=this.peek();return t&&t.type==="op"&&e.includes(t.value)?t.value:null}expr(){let e=this.term(),t;for(;(t=this.peekOp("+-"))!==null;){this.advance();let s=this.term();e=t==="+"?e+s:e-s}return e}term(){let e=this.unary(),t;for(;(t=this.peekOp("*/%"))!==null;){this.advance();let s=this.unary();if(t==="*")e=e*s;else if(t==="/"){if(s===0)throw new Error("Division by zero");e=e/s}else{if(s===0)throw new Error("Division by zero");e=e%s}}return e}unary(){return this.peekOp("-")?(this.advance(),-this.unary()):this.primary()}primary(){let e=this.peek();if(!e)throw new Error("Unexpected end of expression");if(e.type==="num")return this.advance(),e.value;if(e.type==="const")return this.advance(),e.value;if(e.type==="fn"){this.advance();let t=this.advance();if(t?.type!=="paren"||t.value!=="(")throw new Error(`Expected '(' after Math.${e.value}`);let s=this.args(),r=this.advance();if(r?.type!=="paren"||r.value!==")")throw new Error("Expected ')' after arguments");return yd[e.value](...s)}if(e.type==="paren"&&e.value==="("){this.advance();let t=this.expr(),s=this.advance();if(s?.type!=="paren"||s.value!==")")throw new Error("Missing closing parenthesis");return t}throw new Error(`Unexpected token: ${JSON.stringify(e)}`)}args(){let e=[this.expr()];for(;this.peek()?.type==="comma";)this.advance(),e.push(this.expr());return e}};m(Wh,"safeEval");bs=class extends x{static{m(this,"CalculatorSkill")}metadata={name:"calculator",category:"information",description:"Evaluate mathematical expressions. Use for any calculation, unit conversion, or math question the user asks.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{expression:{type:"string",description:"The mathematical expression to evaluate"}},required:["expression"]}};async execute(e,t){let s=e.expression;if(!s||typeof s!="string")return{success:!1,error:"Invalid expression: input must be a non-empty string"};let r=s.trim();try{let n=Wh(r);return typeof n!="number"||!isFinite(n)?{success:!1,error:`Invalid expression: "${r}" did not produce a finite number`}:{success:!0,data:n,display:`${r} = ${n}`}}catch(n){let o=n instanceof Error?n.message:String(n);return{success:!1,error:`Invalid expression: "${r}" \u2014 ${o}`}}}}});var Es,Td=T(()=>{"use strict";H();Es=class extends x{static{m(this,"SystemInfoSkill")}metadata={name:"system_info",category:"information",description:'Get system information: current date/time (datetime), system stats (general), memory usage (memory), or uptime (uptime). Use "datetime" when the user asks what day/time it is.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{category:{type:"string",enum:["general","memory","uptime","datetime"],description:"Category of system info (use datetime for current date/time)"}},required:["category"]}};async execute(e,t){let s=e.category;switch(s){case"general":return this.getGeneralInfo();case"memory":return this.getMemoryInfo();case"uptime":return this.getUptimeInfo();case"datetime":return this.getDateTimeInfo();default:return{success:!1,error:`Unknown category: "${String(s)}". Valid categories: general, memory, uptime`}}}getGeneralInfo(){let e={nodeVersion:process.version,platform:process.platform,arch:process.arch};return{success:!0,data:e,display:`Node.js ${e.nodeVersion} on ${e.platform} (${e.arch})`}}getMemoryInfo(){let e=process.memoryUsage(),t=m(r=>(r/1024/1024).toFixed(2),"toMB"),s={rss:`${t(e.rss)} MB`,heapTotal:`${t(e.heapTotal)} MB`,heapUsed:`${t(e.heapUsed)} MB`,external:`${t(e.external)} MB`};return{success:!0,data:s,display:`Memory \u2014 RSS: ${s.rss}, Heap: ${s.heapUsed} / ${s.heapTotal}, External: ${s.external}`}}getUptimeInfo(){let e=process.uptime(),t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60),n={uptimeSeconds:e,formatted:`${t}h ${s}m ${r}s`};return{success:!0,data:n,display:`Uptime: ${n.formatted}`}}getDateTimeInfo(){let e=new Date,t={iso:e.toISOString(),date:e.toLocaleDateString("de-DE",{weekday:"long",year:"numeric",month:"long",day:"numeric"}),time:e.toLocaleTimeString("de-DE"),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:e.getTime()};return{success:!0,data:t,display:`${t.date}, ${t.time} (${t.timezone})`}}}});var Ss,_d=T(()=>{"use strict";H();Ss=class extends x{static{m(this,"WebSearchSkill")}config;metadata={name:"web_search",category:"information",description:"Search the internet for current information, news, facts, or anything the user asks about that you don't know. Use this whenever you need up-to-date information.",riskLevel:"read",version:"1.1.0",inputSchema:{type:"object",properties:{query:{type:"string",description:"The search query"},count:{type:"number",description:"Number of results to return (default: 5, max: 10)"}},required:["query"]}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.query,r=Math.min(Math.max(1,e.count||5),10);if(!s||typeof s!="string")return{success:!1,error:'Invalid input: "query" must be a non-empty string'};if(!this.config)return{success:!1,error:"Web search is not configured. Run `alfred setup` to configure a search provider."};if((this.config.provider==="brave"||this.config.provider==="tavily")&&!this.config.apiKey)return{success:!1,error:`Web search requires an API key for ${this.config.provider}. Run \`alfred setup\` to configure it.`};try{let o;switch(this.config.provider){case"brave":o=await this.searchBrave(s,r);break;case"searxng":o=await this.searchSearXNG(s,r);break;case"tavily":o=await this.searchTavily(s,r);break;case"duckduckgo":o=await this.searchDuckDuckGo(s,r);break;default:return{success:!1,error:`Unknown search provider: ${this.config.provider}`}}if(o.length===0)return{success:!0,data:{results:[]},display:`No results found for "${s}".`};let i=o.map((a,c)=>`${c+1}. **${a.title}**
|
|
702
702
|
${a.url}
|
|
703
703
|
${a.snippet}`).join(`
|
|
704
704
|
|
|
705
705
|
`);return{success:!0,data:{query:s,results:o},display:`Search results for "${s}":
|
|
706
706
|
|
|
707
|
-
${i}`}}catch(o){return{success:!1,error:`Search failed: ${o instanceof Error?o.message:String(o)}`}}}async searchBrave(e,t){let s=new URL("https://api.search.brave.com/res/v1/web/search");s.searchParams.set("q",e),s.searchParams.set("count",String(t));let r=await fetch(s.toString(),{headers:{Accept:"application/json","Accept-Encoding":"gzip","X-Subscription-Token":this.config.apiKey}});if(!r.ok)throw new Error(`Brave Search API returned ${r.status}: ${r.statusText}`);return((await r.json()).web?.results??[]).slice(0,t).map(o=>({title:o.title,url:o.url,snippet:o.description}))}async searchSearXNG(e,t){let s=(this.config.baseUrl??"http://localhost:8080").replace(/\/+$/,""),r=new URL(`${s}/search`);r.searchParams.set("q",e),r.searchParams.set("format","json"),r.searchParams.set("pageno","1");let n=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`SearXNG returned ${n.status}: ${n.statusText}`);return((await n.json()).results??[]).slice(0,t).map(i=>({title:i.title,url:i.url,snippet:i.content}))}async searchTavily(e,t){let s=await fetch("https://api.tavily.com/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:this.config.apiKey,query:e,max_results:t,include_answer:!1})});if(!s.ok)throw new Error(`Tavily API returned ${s.status}: ${s.statusText}`);return((await s.json()).results??[]).slice(0,t).map(n=>({title:n.title,url:n.url,snippet:n.content}))}async searchDuckDuckGo(e,t){let s=new URL("https://html.duckduckgo.com/html/");s.searchParams.set("q",e);let r=await fetch(s.toString(),{headers:{"User-Agent":"Mozilla/5.0 (compatible; Alfred/1.0)"}});if(!r.ok)throw new Error(`DuckDuckGo returned ${r.status}: ${r.statusText}`);let n=await r.text();return this.parseDuckDuckGoHtml(n,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,n=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,o=[],i;for(;(i=r.exec(e))!==null;){let c=i[1],d=this.stripHtml(i[2]).trim(),u=this.extractDdgUrl(c);d&&u&&o.push({url:u,title:d})}let a=[];for(;(i=n.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let c=0;c<Math.min(o.length,t);c++)s.push({title:o[c].title,url:o[c].url,snippet:a[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ")}}});var
|
|
707
|
+
${i}`}}catch(o){return{success:!1,error:`Search failed: ${o instanceof Error?o.message:String(o)}`}}}async searchBrave(e,t){let s=new URL("https://api.search.brave.com/res/v1/web/search");s.searchParams.set("q",e),s.searchParams.set("count",String(t));let r=await fetch(s.toString(),{headers:{Accept:"application/json","Accept-Encoding":"gzip","X-Subscription-Token":this.config.apiKey}});if(!r.ok)throw new Error(`Brave Search API returned ${r.status}: ${r.statusText}`);return((await r.json()).web?.results??[]).slice(0,t).map(o=>({title:o.title,url:o.url,snippet:o.description}))}async searchSearXNG(e,t){let s=(this.config.baseUrl??"http://localhost:8080").replace(/\/+$/,""),r=new URL(`${s}/search`);r.searchParams.set("q",e),r.searchParams.set("format","json"),r.searchParams.set("pageno","1");let n=await fetch(r.toString(),{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`SearXNG returned ${n.status}: ${n.statusText}`);return((await n.json()).results??[]).slice(0,t).map(i=>({title:i.title,url:i.url,snippet:i.content}))}async searchTavily(e,t){let s=await fetch("https://api.tavily.com/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:this.config.apiKey,query:e,max_results:t,include_answer:!1})});if(!s.ok)throw new Error(`Tavily API returned ${s.status}: ${s.statusText}`);return((await s.json()).results??[]).slice(0,t).map(n=>({title:n.title,url:n.url,snippet:n.content}))}async searchDuckDuckGo(e,t){let s=new URL("https://html.duckduckgo.com/html/");s.searchParams.set("q",e);let r=await fetch(s.toString(),{headers:{"User-Agent":"Mozilla/5.0 (compatible; Alfred/1.0)"}});if(!r.ok)throw new Error(`DuckDuckGo returned ${r.status}: ${r.statusText}`);let n=await r.text();return this.parseDuckDuckGoHtml(n,t)}parseDuckDuckGoHtml(e,t){let s=[],r=/<a[^>]+class="result__a"[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g,n=/<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g,o=[],i;for(;(i=r.exec(e))!==null;){let c=i[1],d=this.stripHtml(i[2]).trim(),u=this.extractDdgUrl(c);d&&u&&o.push({url:u,title:d})}let a=[];for(;(i=n.exec(e))!==null;)a.push(this.stripHtml(i[1]).trim());for(let c=0;c<Math.min(o.length,t);c++)s.push({title:o[c].title,url:o[c].url,snippet:a[c]??""});return s}extractDdgUrl(e){try{if(e.includes("uddg=")){let s=new URL(e,"https://duckduckgo.com").searchParams.get("uddg");if(s)return decodeURIComponent(s)}}catch{}return e.startsWith("http")?e:""}stripHtml(e){return e.replace(/<[^>]*>/g,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ")}}});var vs,kd=T(()=>{"use strict";H();Me();vs=class extends x{static{m(this,"ReminderSkill")}reminderRepo;metadata={name:"reminder",category:"productivity",description:'Set timed reminders that notify the user later. Use when the user says "remind me", "erinnere mich", or asks to be notified about something at a specific time. Prefer triggerAt (absolute time like "14:30" or "2026-02-28 09:00") over delayMinutes \u2014 it is more precise and avoids calculation errors.',riskLevel:"write",version:"3.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["set","list","cancel"],description:"The reminder action to perform"},message:{type:"string",description:"The reminder message (required for set)"},triggerAt:{type:"string",description:'Absolute time for the reminder. Accepts "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date. Preferred over delayMinutes for time-specific reminders.'},delayMinutes:{type:"number",description:"Minutes until the reminder triggers. Use triggerAt instead when the user specifies a clock time."},reminderId:{type:"string",description:"The ID of the reminder to cancel (required for cancel)"}},required:["action"]}};constructor(e){super(),this.reminderRepo=e}getAllReminders(e){let t=new Set,s=[];for(let r of Y(e))for(let n of this.reminderRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"set":return this.setReminder(e,t);case"list":return this.listReminders(t);case"cancel":return this.cancelReminder(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: set, list, cancel`}}}setReminder(e,t){let s=e.message,r=e.triggerAt,n=e.delayMinutes;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "message" for set action'};let o;if(r&&typeof r=="string"){let u=this.parseTriggerAt(r,t.timezone);if(!u)return{success:!1,error:`Could not parse triggerAt "${r}". Use "HH:MM" for today or "YYYY-MM-DD HH:MM" for a specific date.`};if(u.getTime()<=Date.now())return{success:!1,error:`The time "${r}" is in the past. Please specify a future time.`};o=u}else if(n!==void 0&&typeof n=="number"&&n>0)o=new Date(Date.now()+n*60*1e3);else return{success:!1,error:'Provide either "triggerAt" (e.g. "14:30") or "delayMinutes" (positive number) for set action.'};let i=this.reminderRepo.create(de(t),t.platform,t.chatId,s,o),a=o.getTime()-Date.now(),c=Math.round(a/6e4),d=o.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit",...t.timezone?{timeZone:t.timezone}:{}});return{success:!0,data:{reminderId:i.id,message:s,triggerAt:i.triggerAt},display:`Reminder set (${i.id}): "${s}" at ${d} (in ${c} min)`}}parseTriggerAt(e,t){let s=e.trim(),r=/^(\d{1,2}):(\d{2})$/.exec(s);if(r){let o=parseInt(r[1],10),i=parseInt(r[2],10);return o>23||i>59?void 0:this.buildDateInTimezone(o,i,void 0,t)}let n=/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})$/.exec(s);if(n){let o=parseInt(n[1],10),i=parseInt(n[2],10)-1,a=parseInt(n[3],10),c=parseInt(n[4],10),d=parseInt(n[5],10);return c>23||d>59||i>11||a>31?void 0:this.buildDateInTimezone(c,d,{year:o,month:i,day:a},t)}}buildDateInTimezone(e,t,s,r){if(!r){let h=s?new Date(s.year,s.month,s.day,e,t,0,0):new Date;return s||h.setHours(e,t,0,0),h}let n=new Date,o=s?new Date(Date.UTC(s.year,s.month,s.day,e,t,0)):new Date(Date.UTC(n.getFullYear(),n.getMonth(),n.getDate(),e,t,0)),i=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});if(!s){let h=i.formatToParts(n),f=parseInt(h.find(M=>M.type==="year").value,10),g=parseInt(h.find(M=>M.type==="month").value,10)-1,y=parseInt(h.find(M=>M.type==="day").value,10),_=new Date(Date.UTC(f,g,y,e,t,0)),S=i.formatToParts(_),E=parseInt(S.find(M=>M.type==="hour").value,10),v=parseInt(S.find(M=>M.type==="minute").value,10),I=(e-E)*60+(t-v);return _=new Date(_.getTime()+I*6e4),_}let a=o,c=i.formatToParts(a),d=parseInt(c.find(h=>h.type==="hour").value,10),u=parseInt(c.find(h=>h.type==="minute").value,10),p=(e-d)*60+(t-u);return a=new Date(a.getTime()+p*6e4),a}listReminders(e){let s=this.getAllReminders(e).map(r=>({reminderId:r.id,message:r.message,triggerAt:r.triggerAt}));return{success:!0,data:s,display:s.length===0?"No active reminders.":`Active reminders:
|
|
708
708
|
${s.map(r=>`- ${r.reminderId}: "${r.message}" (triggers at ${r.triggerAt})`).join(`
|
|
709
|
-
`)}`}}cancelReminder(e,t){let s=e.reminderId;return!s||typeof s!="string"?{success:!1,error:'Missing required field "reminderId" for cancel action'}:this.getAllReminders(t).some(i=>i.id===s)?this.reminderRepo.cancel(s)?{success:!0,data:{reminderId:s},display:`Reminder "${s}" cancelled.`}:{success:!1,error:`Reminder "${s}" not found`}:{success:!1,error:`Reminder "${s}" not found`}}}});var
|
|
709
|
+
`)}`}}cancelReminder(e,t){let s=e.reminderId;return!s||typeof s!="string"?{success:!1,error:'Missing required field "reminderId" for cancel action'}:this.getAllReminders(t).some(i=>i.id===s)?this.reminderRepo.cancel(s)?{success:!0,data:{reminderId:s},display:`Reminder "${s}" cancelled.`}:{success:!1,error:`Reminder "${s}" not found`}:{success:!1,error:`Reminder "${s}" not found`}}}});var $s,bd=T(()=>{"use strict";H();Me();$s=class extends x{static{m(this,"NoteSkill")}noteRepo;metadata={name:"note",category:"productivity",description:"Save, list, search, or delete persistent notes (stored in SQLite). Use when the user wants to write down or retrieve text notes, lists, or ideas.",riskLevel:"write",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","list","search","delete"],description:"The note action to perform"},title:{type:"string",description:"The note title (required for save)"},content:{type:"string",description:"The note content (required for save)"},noteId:{type:"string",description:"The ID of the note to delete (required for delete)"},query:{type:"string",description:"Search query to filter notes (required for search)"}},required:["action"]}};constructor(e){super(),this.noteRepo=e}async execute(e,t){let s=e.action;switch(s){case"save":return this.saveNote(e,t);case"list":return this.listNotes(t);case"search":return this.searchNotes(e,t);case"delete":return this.deleteNote(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: save, list, search, delete`}}}saveNote(e,t){let s=e.title,r=e.content;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "title" for save action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "content" for save action'};let n=this.noteRepo.save(de(t),s,r);return{success:!0,data:{noteId:n.id,title:n.title},display:`Note saved: "${s}"`}}listNotes(e){let t=new Set,s=[];for(let n of Y(e))for(let o of this.noteRepo.list(n))t.has(o.id)||(t.add(o.id),s.push(o));if(s.length===0)return{success:!0,data:[],display:"No notes found."};let r=s.map(n=>`- **${n.title}** (${n.id.slice(0,8)}\u2026)
|
|
710
710
|
${n.content.slice(0,100)}${n.content.length>100?"\u2026":""}`).join(`
|
|
711
711
|
`);return{success:!0,data:s,display:`${s.length} note(s):
|
|
712
712
|
${r}`}}searchNotes(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for search action'};let r=new Set,n=[];for(let i of Y(t))for(let a of this.noteRepo.search(i,s))r.has(a.id)||(r.add(a.id),n.push(a));if(n.length===0)return{success:!0,data:[],display:`No notes matching "${s}".`};let o=n.map(i=>`- **${i.title}** (${i.id.slice(0,8)}\u2026)
|
|
713
713
|
${i.content.slice(0,100)}${i.content.length>100?"\u2026":""}`).join(`
|
|
714
714
|
`);return{success:!0,data:n,display:`Found ${n.length} note(s):
|
|
715
|
-
${o}`}}deleteNote(e,t){let s=e.noteId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "noteId" for delete action'};let r=this.noteRepo.getById(s);return r?Y(t).includes(r.userId)?this.noteRepo.delete(s)?{success:!0,data:{noteId:s},display:"Note deleted."}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}}}});var zh
|
|
715
|
+
${o}`}}deleteNote(e,t){let s=e.noteId;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "noteId" for delete action'};let r=this.noteRepo.getById(s);return r?Y(t).includes(r.userId)?this.noteRepo.delete(s)?{success:!0,data:{noteId:s},display:"Note deleted."}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}:{success:!1,error:`Note "${s}" not found`}}}});var zh,As,Ed=T(()=>{"use strict";H();zh={0:"Clear sky",1:"Mainly clear",2:"Partly cloudy",3:"Overcast",45:"Foggy",48:"Depositing rime fog",51:"Light drizzle",53:"Moderate drizzle",55:"Dense drizzle",61:"Slight rain",63:"Moderate rain",65:"Heavy rain",71:"Slight snow",73:"Moderate snow",75:"Heavy snow",77:"Snow grains",80:"Slight rain showers",81:"Moderate rain showers",82:"Violent rain showers",85:"Slight snow showers",86:"Heavy snow showers",95:"Thunderstorm",96:"Thunderstorm with slight hail",99:"Thunderstorm with heavy hail"},As=class extends x{static{m(this,"WeatherSkill")}metadata={name:"weather",category:"information",description:"Get current weather for any location. Uses Open-Meteo (free, no API key). Use when the user asks about weather, temperature, or conditions somewhere.",riskLevel:"read",version:"2.0.0",inputSchema:{type:"object",properties:{location:{type:"string",description:'City or place name (e.g. "Vienna", "New York", "Tokyo")'}},required:["location"]}};async execute(e,t){let s=e.location;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "location"'};try{let r=await this.geocode(s);if(!r)return{success:!1,error:`Location "${s}" not found`};let n=await this.fetchWeather(r.latitude,r.longitude),o=zh[n.weathercode]??`Code ${n.weathercode}`,i=r.admin1?`${r.name}, ${r.admin1}, ${r.country}`:`${r.name}, ${r.country}`,a={location:i,temperature:n.temperature,unit:"\xB0C",condition:o,windSpeed:n.windspeed,windDirection:n.winddirection,isDay:n.is_day===1},c=`${i}: ${n.temperature}\xB0C, ${o}
|
|
716
716
|
Wind: ${n.windspeed} km/h`;return{success:!0,data:a,display:c}}catch(r){return{success:!1,error:`Weather fetch failed: ${r instanceof Error?r.message:String(r)}`}}}async geocode(e){let t=`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(e)}&count=1&language=en&format=json`,s=await fetch(t);if(!s.ok)throw new Error(`Geocoding API returned ${s.status}`);return(await s.json()).results?.[0]}async fetchWeather(e,t){let s=`https://api.open-meteo.com/v1/forecast?latitude=${e}&longitude=${t}¤t_weather=true&timezone=auto`,r=await fetch(s);if(!r.ok)throw new Error(`Weather API returned ${r.status}`);return(await r.json()).current_weather}}});import{exec as qh}from"node:child_process";function vd(l){return l.length>Sd?l.slice(0,Sd)+`
|
|
717
|
-
[output truncated]`:l}var Gh,Sd,
|
|
717
|
+
[output truncated]`:l}var Gh,Sd,Is,$d=T(()=>{"use strict";H();Gh=3e4,Sd=1e4;m(vd,"truncate");Is=class extends x{static{m(this,"ShellSkill")}metadata={name:"shell",category:"automation",description:"Execute shell commands on the host system. Use this for ANY task involving files, folders, system operations, or running programs: ls, cat, find, file, du, mkdir, cp, mv, grep, etc. When the user asks about their documents, files, or anything on disk \u2014 use this tool.",riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute"},timeout:{type:"number",description:"Timeout in milliseconds (default: 30000)"},cwd:{type:"string",description:"Working directory for the command"}},required:["command"]}};async execute(e,t){let s=e.command;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "command"'};let r=[/\brm\s+-rf\s+\/(?:\s|$)/,/\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+-[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*\s+-[a-zA-Z]*r)[a-zA-Z]*\s+\/(?:\s|$)/,/\brm\s+-rf\s+\/\*/,/:(){ :|:& };:/,/:\(\)\s*\{.*\|.*&\s*\}\s*;/,/>\s*\/dev\/sd[a-z]/,/\bmkfs\b/,/\bdd\s+.*\bif=/,/\bchmod\s+777\b/,/\bcurl\b.*\|\s*\bbash\b/,/\bwget\b.*\|\s*\bsh\b/,/\bpython[23]?\s+-c\b/,/\bnode\s+-e\b/,/\b(bash|sh)\s+-i\b.*\/dev\/tcp/,/\bnc\s+.*-e\b/,/\b(bash|sh|zsh|dash|ksh|csh|tcsh|fish)\s+-[a-z]*c\b/,/\bdd\b.*\bof=\/dev\//,/\bdd\b.*\bof=\//,/\bchmod\s+777\s+\//,/\bchown\s+.*\s+\/(?:\s|$)/,/\bbase64\b.*\|/,/\bperl\s+-e\b/,/\bruby\s+-e\b/,/\bphp\s+-r\b/,/\btee\s+\/(etc|root|boot|sys|proc)\//,/\bcrontab\b/,/\bmount\b/,/\bstrace\b/,/\bgdb\b/,/\bsudo\b/,/\bchroot\b/,/\beval\s/,/\bsource\s/,/\b\.\s+\//,/`[^`]+`/,/\$\([^)]+\)/,/\/bin\/\w+\s+-rf?\s+\//];for(let i of r)if(i.test(s))return{success:!1,error:"Command blocked: potentially destructive system operation"};let n=typeof e.timeout=="number"&&e.timeout>0?e.timeout:Gh,o=typeof e.cwd=="string"&&e.cwd.length>0?e.cwd:void 0;try{let{stdout:i,stderr:a,exitCode:c}=await this.run(s,n,o),d=[];return i&&d.push(`stdout:
|
|
718
718
|
${vd(i)}`),a&&d.push(`stderr:
|
|
719
719
|
${vd(a)}`),d.length===0&&d.push("(no output)"),d.push(`exit code: ${c}`),{success:c===0,data:{stdout:i,stderr:a,exitCode:c},display:d.join(`
|
|
720
720
|
|
|
721
|
-
`),...c!==0&&{error:`Command exited with code ${c}`}}}catch(i){return{success:!1,error:`Shell execution failed: ${i instanceof Error?i.message:String(i)}`}}}run(e,t,s){return new Promise(r=>{qh(e,{timeout:t,cwd:s},(n,o,i)=>{let a=n&&"code"in n&&typeof n.code=="number"?n.code:n?1:0;r({stdout:typeof o=="string"?o:"",stderr:typeof i=="string"?i:"",exitCode:a})})})}}});var
|
|
721
|
+
`),...c!==0&&{error:`Command exited with code ${c}`}}}catch(i){return{success:!1,error:`Shell execution failed: ${i instanceof Error?i.message:String(i)}`}}}run(e,t,s){return new Promise(r=>{qh(e,{timeout:t,cwd:s},(n,o,i)=>{let a=n&&"code"in n&&typeof n.code=="number"?n.code:n?1:0;r({stdout:typeof o=="string"?o:"",stderr:typeof i=="string"?i:"",exitCode:a})})})}}});var Rs,Ad=T(()=>{"use strict";H();Me();Rs=class extends x{static{m(this,"MemorySkill")}memoryRepo;embeddingService;metadata={name:"memory",category:"core",description:"Store and retrieve persistent memories. Use this to remember user preferences, facts, and important information across conversations.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","recall","search","list","delete","semantic_search"],description:"The memory action to perform"},key:{type:"string",description:"The memory key/label"},value:{type:"string",description:"The value to remember (for save)"},category:{type:"string",description:"Optional category (for save/list)"},query:{type:"string",description:"Search query (for search)"}},required:["action"]}};constructor(e,t){super(),this.memoryRepo=e,this.embeddingService=t}async execute(e,t){let s=e.action;switch(s){case"save":return this.saveMemory(e,t);case"recall":return this.recallMemory(e,t);case"search":return this.searchMemories(e,t);case"list":return this.listMemories(e,t);case"delete":return this.deleteMemory(e,t);case"semantic_search":return this.semanticSearchMemories(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: save, recall, search, list, delete, semantic_search`}}}saveMemory(e,t){let s=e.key,r=e.value,n=e.category;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for save action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "value" for save action'};let o=this.memoryRepo.save(de(t),s,r,n??"general");return this.embeddingService&&this.embeddingService.embedAndStore(de(t),`${s}: ${r}`,"memory",s).catch(()=>{}),{success:!0,data:o,display:`Remembered "${s}" = "${r}" (category: ${o.category})`}}recallMemory(e,t){let s=e.key;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "key" for recall action'};let r;for(let n of Y(t))if(r=this.memoryRepo.recall(n,s),r)break;return r?{success:!0,data:r,display:`${s} = "${r.value}" (category: ${r.category}, updated: ${r.updatedAt})`}:{success:!0,data:null,display:`No memory found for key "${s}".`}}searchMemories(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for search action'};let r=new Set,n=[];for(let o of Y(t))for(let i of this.memoryRepo.search(o,s))r.has(i.id)||(r.add(i.id),n.push(i));return{success:!0,data:n,display:n.length===0?`No memories matching "${s}".`:`Found ${n.length} memory(ies):
|
|
722
722
|
${n.map(o=>`- ${o.key}: "${o.value}"`).join(`
|
|
723
723
|
`)}`}}listMemories(e,t){let s=e.category,r=new Set,n=[];for(let i of Y(t)){let a=s&&typeof s=="string"?this.memoryRepo.listByCategory(i,s):this.memoryRepo.listAll(i);for(let c of a)r.has(c.id)||(r.add(c.id),n.push(c))}let o=s?`in category "${s}"`:"total";return{success:!0,data:n,display:n.length===0?`No memories found${s?` in category "${s}"`:""}.`:`${n.length} memory(ies) ${o}:
|
|
724
724
|
${n.map(i=>`- [${i.category}] ${i.key}: "${i.value}"`).join(`
|
|
725
725
|
`)}`}}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 Y(t))if(this.memoryRepo.delete(n,s)){r=!0;break}return{success:!0,data:{key:s,deleted:r},display:r?`Memory "${s}" deleted.`:`No memory found for key "${s}".`}}async semanticSearchMemories(e,t){let s=e.query;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for semantic_search action'};if(!this.embeddingService)return this.searchMemories(e,t);let r=new Set,n=[];for(let o of Y(t))for(let i of await this.embeddingService.semanticSearch(o,s,10))r.has(i.key)||(r.add(i.key),n.push(i));return n.length===0?this.searchMemories(e,t):{success:!0,data:n,display:`Found ${n.length} semantically related memory(ies):
|
|
726
726
|
${n.map(o=>`- ${o.key}: "${o.value}" (score: ${o.score.toFixed(2)})`).join(`
|
|
727
|
-
`)}`}}}});var Xh,Kh,Vh,
|
|
727
|
+
`)}`}}}});var Xh,Kh,Vh,xs,Id=T(()=>{"use strict";H();la();Xh=15,Kh=25,Vh=12e4,xs=class extends x{static{m(this,"DelegateSkill")}llm;skillRegistry;skillSandbox;securityManager;metadata={name:"delegate",category:"core",description:'Delegate a sub-task to an autonomous sub-agent that requires ITERATIVE work \u2014 multiple rounds of tool calls with intermediate reasoning (e.g. "research X across multiple sources and synthesize", "search emails for invoices and compile a list"). Do NOT use for simple lookups or single-skill queries \u2014 call those skills directly. The sub-agent has full tool access (shell, web search, memory, email, etc.). Control depth with max_iterations (default 15, max 25).',riskLevel:"write",version:"3.0.0",timeoutMs:Vh,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 Ut(this.onProgress)}async execute(e,t){let s=e.task,r=e.context;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task"'};let n=e.max_iterations,o=n?Math.max(1,Math.min(Kh,Math.round(n))):Xh,i=t.onProgress??this.onProgress,a=t.tracker?t.tracker:new Ut(i);a.ping("starting",{maxIterations:o});let c=this.buildSubAgentTools(),d=new Map,u=0;if(t.resumeState?.dataStore)for(let[y,_]of Object.entries(t.resumeState.dataStore)){d.set(y,_);let S=y.match(/^result_(\d+)$/);S&&(u=Math.max(u,Number(S[1])))}let p=`You are a sub-agent of Alfred, a personal AI assistant. Complete the assigned task using the tools available to you. Work step by step: use tools to gather information, then synthesize a clear result. Be concise and return only the final answer when done.
|
|
728
728
|
|
|
729
729
|
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.
|
|
730
730
|
Available JS libraries in code_sandbox (no install needed): exceljs, pdfkit, pdf-parse.`,h=s;r&&typeof r=="string"&&(h=`${s}
|
|
@@ -798,20 +798,20 @@ ${d}`)}}async handleCategorize(e){if(!this.llm)return{success:!1,error:"LLM not
|
|
|
798
798
|
`),c=await this.llm.complete({messages:[{role:"user",content:`Categorize each email into one of: urgent, action_required, fyi, newsletter. Return ONLY valid JSON like: {"1":"urgent","2":"fyi",...}
|
|
799
799
|
|
|
800
800
|
${a}`}],system:"You are an email classifier. Return only a JSON object mapping email number to category. No other text.",tier:"fast"}),d={};try{let h=c.content.match(/\{[^}]+\}/);h&&(d=JSON.parse(h[0]))}catch{}let u={urgent:[],action_required:[],fyi:[],newsletter:[]};for(let[h,f]of Object.entries(d)){let g=parseInt(h,10)-1;g>=0&&g<i.length&&u[f]&&u[f].push({from:i[g].from,subject:i[g].subject})}let p=[];for(let[h,f]of Object.entries(u))if(f.length>0){let g=h==="urgent"?"\u{1F534}":h==="action_required"?"\u{1F7E1}":h==="fyi"?"\u{1F535}":"\u{1F4F0}";p.push(`${g} ${h.toUpperCase()} (${f.length}):`);for(let y of f)p.push(` \u2022 ${y.from}: ${y.subject}`)}return{success:!0,data:{categories:u,totalCategorized:Object.keys(d).length},display:this.accountLabel(r,p.length>0?p.join(`
|
|
801
|
-
`):"Could not categorize emails.")}}async extractText(e,t,s){try{if(t==="application/pdf"){let r=(await import("pdf-parse")).default;return(await r(e)).text?.trim()||null}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")return(await(await import("mammoth")).extractRawText({buffer:e})).value?.trim()||null;if(t.startsWith("text/")||s.endsWith(".csv")||s.endsWith(".json")||s.endsWith(".md"))return e.toString("utf-8")}catch{}return null}formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});import{lookup as Yh}from"node:dns/promises";var Ld,
|
|
801
|
+
`):"Could not categorize emails.")}}async extractText(e,t,s){try{if(t==="application/pdf"){let r=(await import("pdf-parse")).default;return(await r(e)).text?.trim()||null}if(t==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"||t==="application/msword")return(await(await import("mammoth")).extractRawText({buffer:e})).value?.trim()||null;if(t.startsWith("text/")||s.endsWith(".csv")||s.endsWith(".json")||s.endsWith(".md"))return e.toString("utf-8")}catch{}return null}formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}}});import{lookup as Yh}from"node:dns/promises";var Ld,Cs,Dd=T(()=>{"use strict";H();Ld=1e5,Cs=class extends x{static{m(this,"HttpSkill")}metadata={name:"http",category:"files",description:"Make HTTP requests to fetch web pages or call REST APIs. Use when you need to read a URL, call an API endpoint, or fetch data from the web. Supports GET, POST, PUT, PATCH, DELETE methods.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{url:{type:"string",description:"The URL to request"},method:{type:"string",enum:["GET","POST","PUT","PATCH","DELETE"],description:"HTTP method (default: GET)"},headers:{type:"object",description:"Request headers as key-value pairs (optional)"},body:{type:"string",description:"Request body for POST/PUT/PATCH (optional)"}},required:["url"]}};async execute(e,t){let s=e.url,r=(e.method??"GET").toUpperCase(),n=e.headers,o=e.body;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "url"'};let i;try{i=new URL(s)}catch{return{success:!1,error:`Invalid URL: "${s}"`}}if(i.protocol!=="http:"&&i.protocol!=="https:")return{success:!1,error:`Unsupported URL scheme "${i.protocol}". Only http: and https: are allowed.`};if(await this.resolveAndCheckHost(i.hostname))return{success:!1,error:`Access to private/internal network address "${i.hostname}" is blocked.`};try{let a={method:r,headers:{"User-Agent":"Alfred/1.0",...n??{}},signal:AbortSignal.timeout(15e3)};o&&["POST","PUT","PATCH"].includes(r)&&(a.body=o,!n?.["Content-Type"]&&!n?.["content-type"]&&(a.headers["Content-Type"]="application/json"));let c=await fetch(s,a),d=c.headers.get("content-type")??"",u=await c.text(),p=u.length>Ld,h=p?u.slice(0,Ld)+`
|
|
802
802
|
|
|
803
803
|
[... truncated]`:u,f=h;d.includes("text/html")&&(f=this.stripHtml(h).slice(0,1e4));let g={status:c.status,statusText:c.statusText,contentType:d,bodyLength:u.length,truncated:p,body:h};return c.ok?{success:!0,data:g,display:`HTTP ${c.status} OK (${u.length} bytes)
|
|
804
804
|
|
|
805
805
|
${f.slice(0,5e3)}`}:{success:!0,data:g,display:`HTTP ${c.status} ${c.statusText}
|
|
806
806
|
|
|
807
|
-
${f.slice(0,2e3)}`}}catch(a){return{success:!1,error:`HTTP request failed: ${a instanceof Error?a.message:String(a)}`}}}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await Yh(e);if(this.isPrivateIp(t))return!0}catch{}return!1}stripHtml(e){return e.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,"").replace(/<style[^>]*>[\s\S]*?<\/style>/gi,"").replace(/<[^>]+>/g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ").trim()}}});import ae from"node:fs";import yt from"node:path";var ha,Md,Jh,
|
|
807
|
+
${f.slice(0,2e3)}`}}catch(a){return{success:!1,error:`HTTP request failed: ${a instanceof Error?a.message:String(a)}`}}}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await Yh(e);if(this.isPrivateIp(t))return!0}catch{}return!1}stripHtml(e){return e.replace(/<script[^>]*>[\s\S]*?<\/script>/gi,"").replace(/<style[^>]*>[\s\S]*?<\/style>/gi,"").replace(/<[^>]+>/g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /g," ").replace(/\s+/g," ").trim()}}});import ae from"node:fs";import yt from"node:path";var ha,Md,Jh,Ns,Od=T(()=>{"use strict";H();ha=5e5,Md=5e7,Jh={".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"},Ns=class extends x{static{m(this,"FileSkill")}metadata={name:"file",category:"files",description:'Read, write, move, copy, or send files. Use for reading file contents, writing text to files, saving binary data, listing directory contents, moving/copying files, or getting file info. Use "send" to deliver a file to the user in the chat (PDF, images, etc.). Prefer this over shell for file operations. When a user sends a file attachment, it is saved to the inbox \u2014 use "move" to relocate it. IMPORTANT: For large content (HTML pages, long text), use code_sandbox instead to generate the file programmatically.',riskLevel:"write",version:"2.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["read","write","write_binary","append","list","info","exists","move","copy","delete","send"],description:"The file operation to perform"},path:{type:"string",description:"Absolute or relative file/directory path (~ expands to home)"},destination:{type:"string",description:"Destination path for move/copy actions (~ expands to home)"},content:{type:"string",description:"Content to write (required for write/append; base64-encoded for write_binary)"}},required:["action","path"]}};async execute(e,t){let s=e.action,r=e.path,n=e.content,o=e.destination;if(!s||!r)return{success:!1,error:'Missing required fields "action" and "path"'};if((s==="write"||s==="write_binary"||s==="append")&&!n)return{success:!1,error:`Missing "content" field for "${s}" action. The content is likely too large to include in a tool call. Use the code_sandbox skill instead \u2014 write COMPACT data-driven code: define your data as arrays/objects, then build HTML/text programmatically with .map()/.join(). Example: const data = [{h:8,p:5.2},{h:9,p:4.1}]; const rows = data.map(r => \`<tr><td>\${r.h}</td><td>\${r.p}</td></tr>\`).join(''); fs.writeFileSync('output.html', \`<table>\${rows}</table>\`); \u2014 the sandbox collects output files automatically. Do NOT embed large string literals.`};let i=this.resolvePath(r),a=this.checkBlocked(i);if(a)return a;try{if(ae.existsSync(i)&&ae.lstatSync(i).isSymbolicLink()){let c=ae.realpathSync(i);if(this.checkBlocked(c))return{success:!1,error:"Access denied: symlink target is a blocked path"}}}catch{}switch(s){case"read":return this.readFile(i);case"write":return this.writeFile(i,n);case"write_binary":return this.writeBinaryFile(i,n);case"append":return this.appendFile(i,n);case"list":return this.listDir(i);case"info":return this.fileInfo(i);case"exists":return this.fileExists(i);case"move":return this.moveFile(i,o);case"copy":return this.copyFile(i,o);case"delete":return this.deleteFile(i);case"send":return this.sendFile(i);default:return{success:!1,error:`Unknown action "${s}". Valid: read, write, write_binary, append, list, info, exists, move, copy, delete, send`}}}resolvePath(e){let t=process.env.HOME||process.env.USERPROFILE||"",s=e.startsWith("~")?e.replace("~",t):e;return yt.resolve(s)}checkBlocked(e){let t=e.toLowerCase().replace(/\\/g,"/"),s=(process.env.HOME||process.env.USERPROFILE||"").toLowerCase().replace(/\\/g,"/"),r=["/etc/shadow","/etc/passwd","/etc/sudoers","/proc/","/sys/","/dev/","c:/windows/system32","c:/windows/syswow64"],n=["/.ssh","/.aws","/.gnupg"],o=[".env"];if(r.some(a=>t.startsWith(a)||t===a.replace(/\/$/,"")))return{success:!1,error:"Access to system directories/files is blocked for security"};if(s&&n.some(a=>t.startsWith(s+a)))return{success:!1,error:"Access to sensitive user directories is blocked for security"};let i=yt.basename(e);return o.includes(i.toLowerCase())?{success:!1,error:"Access to sensitive files is blocked for security"}:null}readFile(e){try{let t=ae.statSync(e);if(t.isDirectory())return{success:!1,error:`"${e}" is a directory, not a file. Use action "list" instead.`};if(t.size>ha){let r=ae.readFileSync(e,"utf-8").slice(0,ha);return{success:!0,data:{path:e,size:t.size,truncated:!0},display:`${e} (${t.size} bytes, truncated to ${ha}):
|
|
808
808
|
|
|
809
809
|
${r}`}}let s=ae.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=yt.dirname(e);return ae.mkdirSync(s,{recursive:!0}),ae.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 ae.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=ae.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(`
|
|
810
810
|
`);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=ae.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}
|
|
811
811
|
Size: ${t.size} bytes
|
|
812
|
-
Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=ae.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=yt.dirname(e);ae.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return ae.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=yt.dirname(s);return ae.mkdirSync(n,{recursive:!0}),ae.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return ae.copyFileSync(e,s),ae.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(o){return{success:!1,error:`Cannot move "${e}" to "${s}": ${o.message}`}}}}copyFile(e,t){if(!t)return{success:!1,error:'Missing "destination" for copy action'};let s=this.resolvePath(t),r=this.checkBlocked(s);if(r)return r;try{let n=yt.dirname(s);return ae.mkdirSync(n,{recursive:!0}),ae.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(!ae.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=ae.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>Md)return{success:!1,error:`File too large to send (${t.size} bytes, max ${Md})`};let s=ae.readFileSync(e),r=yt.basename(e),n=yt.extname(e).toLowerCase(),o=Jh[n]||"application/octet-stream",i={fileName:r,data:s,mimeType:o};return{success:!0,data:{path:e,size:t.size,fileName:r,mimeType:o},display:`Sending ${r} (${t.size} bytes)`,attachments:[i]}}catch(t){return{success:!1,error:`Cannot send "${e}": ${t.message}`}}}deleteFile(e){try{return ae.existsSync(e)?ae.statSync(e).isDirectory()?{success:!1,error:`"${e}" is a directory. Use shell for directory deletion.`}:(ae.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
|
|
812
|
+
Modified: ${s.modified}`}}catch(t){return{success:!1,error:`Cannot stat "${e}": ${t.message}`}}}fileExists(e){let t=ae.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=yt.dirname(e);ae.mkdirSync(s,{recursive:!0});let r=Buffer.from(t,"base64");return ae.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=yt.dirname(s);return ae.mkdirSync(n,{recursive:!0}),ae.renameSync(e,s),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch{try{return ae.copyFileSync(e,s),ae.unlinkSync(e),{success:!0,data:{from:e,to:s},display:`Moved ${e} \u2192 ${s}`}}catch(o){return{success:!1,error:`Cannot move "${e}" to "${s}": ${o.message}`}}}}copyFile(e,t){if(!t)return{success:!1,error:'Missing "destination" for copy action'};let s=this.resolvePath(t),r=this.checkBlocked(s);if(r)return r;try{let n=yt.dirname(s);return ae.mkdirSync(n,{recursive:!0}),ae.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(!ae.existsSync(e))return{success:!1,error:`"${e}" does not exist`};let t=ae.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>Md)return{success:!1,error:`File too large to send (${t.size} bytes, max ${Md})`};let s=ae.readFileSync(e),r=yt.basename(e),n=yt.extname(e).toLowerCase(),o=Jh[n]||"application/octet-stream",i={fileName:r,data:s,mimeType:o};return{success:!0,data:{path:e,size:t.size,fileName:r,mimeType:o},display:`Sending ${r} (${t.size} bytes)`,attachments:[i]}}catch(t){return{success:!1,error:`Cannot send "${e}": ${t.message}`}}}deleteFile(e){try{return ae.existsSync(e)?ae.statSync(e).isDirectory()?{success:!1,error:`"${e}" is a directory. Use shell for directory deletion.`}:(ae.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 Ls}from"node:child_process";var Ds,Pd=T(()=>{"use strict";H();Ds=class extends x{static{m(this,"ClipboardSkill")}metadata={name:"clipboard",category:"media",description:"Read or write the system clipboard. Use when the user asks to copy something, paste from clipboard, or check what is in their clipboard.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["read","write"],description:'"read" to get clipboard contents, "write" to set clipboard contents'},text:{type:"string",description:"Text to copy to clipboard (required for write)"}},required:["action"]}};async execute(e,t){let s=e.action;switch(s){case"read":return this.readClipboard();case"write":return this.writeClipboard(e.text);default:return{success:!1,error:`Unknown action "${s}". Valid: read, write`}}}readClipboard(){try{let e;switch(process.platform){case"darwin":e=Ls("pbpaste",{encoding:"utf-8",timeout:5e3});break;case"win32":e=Ls("powershell -NoProfile -Command Get-Clipboard",{encoding:"utf-8",timeout:5e3}).replace(/\r\n$/,"");break;default:e=Ls("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)+`
|
|
813
813
|
|
|
814
|
-
[... 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":
|
|
814
|
+
[... 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":Ls("pbcopy",{input:e,timeout:5e3});break;case"win32":Ls('powershell -NoProfile -Command "$input | Set-Clipboard"',{input:e,timeout:5e3});break;default:Ls("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 Br}from"node:child_process";import Ud from"node:path";import Zh from"node:os";var Ms,Fd=T(()=>{"use strict";H();Ms=class extends x{static{m(this,"ScreenshotSkill")}metadata={name:"screenshot",category:"media",description:"Take a screenshot of the current screen and save it to a file. Use when the user asks to capture their screen or take a screenshot.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{path:{type:"string",description:"Output file path (optional, defaults to ~/Desktop/screenshot-<timestamp>.png)"}}}};async execute(e,t){let s=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),r=Ud.join(Zh.homedir(),"Desktop"),n=e.path||Ud.join(r,`screenshot-${s}.png`);try{switch(process.platform){case"darwin":Br(`screencapture -x "${n}"`,{timeout:1e4});break;case"win32":Br(`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{Br(`scrot "${n}"`,{timeout:1e4})}catch{try{Br(`import -window root "${n}"`,{timeout:1e4})}catch{Br(`gnome-screenshot -f "${n}"`,{timeout:1e4})}}break}return{success:!0,data:{path:n},display:`Screenshot saved to ${n}`}}catch(o){return{success:!1,error:`Screenshot failed: ${o.message}`}}}}});import Qh from"node:path";import ef from"node:os";import{lookup as tf}from"node:dns/promises";var jd,Os,Bd=T(()=>{"use strict";H();jd=5e4,Os=class extends x{static{m(this,"BrowserSkill")}browser=null;page=null;metadata={name:"browser",category:"media",description:"Open web pages in a real browser (Puppeteer/Chromium). Renders JavaScript, so it works with SPAs and dynamic sites. Can also interact with pages: click buttons, fill forms, take screenshots. Use when http skill returns empty/broken content, or when you need to interact with a web page.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["open","screenshot","click","type","evaluate","close"],description:"open = navigate to URL and return page text. screenshot = save screenshot of current page. click = click element by CSS selector. type = type text into input by CSS selector. evaluate = run JavaScript on the page. close = close the browser."},url:{type:"string",description:'URL to open (required for "open", optional for "screenshot")'},selector:{type:"string",description:'CSS selector for the element (required for "click" and "type")'},text:{type:"string",description:'Text to type (required for "type")'},script:{type:"string",description:'JavaScript code to evaluate (required for "evaluate")'},path:{type:"string",description:"File path to save screenshot (optional, defaults to Desktop)"}},required:["action"]}};async execute(e,t){let s=e.action;if(s==="close")return this.closeBrowser();let r=await this.loadPuppeteer();if(!r)return{success:!1,error:`Puppeteer is not installed. Run: npm install -g puppeteer
|
|
815
815
|
Or add it to Alfred: npm install puppeteer`};switch(s){case"open":return this.openPage(r,e);case"screenshot":return this.screenshotPage(r,e);case"click":return this.clickElement(e);case"type":return this.typeText(e);case"evaluate":return this.evaluateScript(e);default:return{success:!1,error:`Unknown action "${s}". Valid: open, screenshot, click, type, evaluate, close`}}}async loadPuppeteer(){try{let e=await Function('return import("puppeteer")')();return this.resolvePuppeteerModule(e)}catch{try{let e=await Function('return import("puppeteer-core")')();return this.resolvePuppeteerModule(e)}catch{return null}}}resolvePuppeteerModule(e){let t=e;return typeof t.launch=="function"?t:t.default}async ensureBrowser(e){return this.browser&&this.browser.connected?this.browser:(this.browser=await e.launch({headless:!0,args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage"]}),this.browser)}async ensurePage(e){let t=await this.ensureBrowser(e);return this.page||(this.page=await t.newPage(),await this.page.setViewport({width:1280,height:900})),this.page}async openPage(e,t){let s=t.url;if(!s)return{success:!1,error:'Missing "url" for open action'};let r=await this.validateUrl(s);if(r)return{success:!1,error:r};try{let n=await this.ensurePage(e);await n.goto(s,{waitUntil:"networkidle2",timeout:3e4});let o=await n.title(),i=await n.evaluate(`
|
|
816
816
|
(() => {
|
|
817
817
|
document.querySelectorAll('script, style, noscript').forEach(el => el.remove());
|
|
@@ -823,7 +823,7 @@ Or add it to Alfred: npm install puppeteer`};switch(s){case"open":return this.op
|
|
|
823
823
|
|
|
824
824
|
`).trim();return{success:!0,data:{url:n.url(),title:o,length:i.length},display:`**${o}** (${n.url()})
|
|
825
825
|
|
|
826
|
-
${c}`}}catch(n){return{success:!1,error:`Failed to open "${s}": ${n.message}`}}}async screenshotPage(e,t){try{let s=await this.ensurePage(e),r=t.url;r&&await s.goto(r,{waitUntil:"networkidle2",timeout:3e4});let n=s.url();if(n==="about:blank")return{success:!1,error:'No page is open. Use action "open" with a URL first, or provide a URL.'};let o=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),i=t.path||Qh.join(ef.homedir(),"Desktop",`browser-${o}.png`);return await s.screenshot({path:i,fullPage:!1}),{success:!0,data:{path:i,url:n},display:`Screenshot saved to ${i}`}}catch(s){return{success:!1,error:`Screenshot failed: ${s.message}`}}}async clickElement(e){let t=e.selector;if(!t)return{success:!1,error:'Missing "selector" for click action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t);try{await this.page.waitForNavigation({timeout:3e3})}catch{}let s=await this.page.title();return{success:!0,data:{selector:t,url:this.page.url(),title:s},display:`Clicked "${t}" \u2014 now on: ${s} (${this.page.url()})`}}catch(s){return{success:!1,error:`Click failed on "${t}": ${s.message}`}}}async typeText(e){let t=e.selector,s=e.text;if(!t)return{success:!1,error:'Missing "selector" for type action'};if(!s)return{success:!1,error:'Missing "text" for type action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{return await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t),await this.page.type(t,s,{delay:50}),{success:!0,data:{selector:t,textLength:s.length},display:`Typed ${s.length} characters into "${t}"`}}catch(r){return{success:!1,error:`Type failed on "${t}": ${r.message}`}}}async evaluateScript(e){let t=e.script;if(!t)return{success:!1,error:'Missing "script" for evaluate action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{let s=await this.page.evaluate(t),r=typeof s=="string"?s:JSON.stringify(s,null,2);return{success:!0,data:{result:s},display:r?.slice(0,1e4)??"(no output)"}}catch(s){return{success:!1,error:`Evaluate failed: ${s.message}`}}}async validateUrl(e){let t;try{t=new URL(e)}catch{return`Invalid URL: "${e}"`}if(["file:","chrome:","about:","data:","javascript:"].includes(t.protocol))return`Blocked URL protocol "${t.protocol}". Only http: and https: are allowed.`;if(t.protocol!=="http:"&&t.protocol!=="https:")return`Unsupported URL protocol "${t.protocol}". Only http: and https: are allowed.`;let r=t.hostname;return await this.resolveAndCheckHost(r)?`Access to private/internal network address "${r}" is blocked.`:null}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await tf(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
|
|
826
|
+
${c}`}}catch(n){return{success:!1,error:`Failed to open "${s}": ${n.message}`}}}async screenshotPage(e,t){try{let s=await this.ensurePage(e),r=t.url;r&&await s.goto(r,{waitUntil:"networkidle2",timeout:3e4});let n=s.url();if(n==="about:blank")return{success:!1,error:'No page is open. Use action "open" with a URL first, or provide a URL.'};let o=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),i=t.path||Qh.join(ef.homedir(),"Desktop",`browser-${o}.png`);return await s.screenshot({path:i,fullPage:!1}),{success:!0,data:{path:i,url:n},display:`Screenshot saved to ${i}`}}catch(s){return{success:!1,error:`Screenshot failed: ${s.message}`}}}async clickElement(e){let t=e.selector;if(!t)return{success:!1,error:'Missing "selector" for click action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t);try{await this.page.waitForNavigation({timeout:3e3})}catch{}let s=await this.page.title();return{success:!0,data:{selector:t,url:this.page.url(),title:s},display:`Clicked "${t}" \u2014 now on: ${s} (${this.page.url()})`}}catch(s){return{success:!1,error:`Click failed on "${t}": ${s.message}`}}}async typeText(e){let t=e.selector,s=e.text;if(!t)return{success:!1,error:'Missing "selector" for type action'};if(!s)return{success:!1,error:'Missing "text" for type action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{return await this.page.waitForSelector(t,{timeout:5e3}),await this.page.click(t),await this.page.type(t,s,{delay:50}),{success:!0,data:{selector:t,textLength:s.length},display:`Typed ${s.length} characters into "${t}"`}}catch(r){return{success:!1,error:`Type failed on "${t}": ${r.message}`}}}async evaluateScript(e){let t=e.script;if(!t)return{success:!1,error:'Missing "script" for evaluate action'};if(!this.page)return{success:!1,error:'No page is open. Use action "open" first.'};try{let s=await this.page.evaluate(t),r=typeof s=="string"?s:JSON.stringify(s,null,2);return{success:!0,data:{result:s},display:r?.slice(0,1e4)??"(no output)"}}catch(s){return{success:!1,error:`Evaluate failed: ${s.message}`}}}async validateUrl(e){let t;try{t=new URL(e)}catch{return`Invalid URL: "${e}"`}if(["file:","chrome:","about:","data:","javascript:"].includes(t.protocol))return`Blocked URL protocol "${t.protocol}". Only http: and https: are allowed.`;if(t.protocol!=="http:"&&t.protocol!=="https:")return`Unsupported URL protocol "${t.protocol}". Only http: and https: are allowed.`;let r=t.hostname;return await this.resolveAndCheckHost(r)?`Access to private/internal network address "${r}" is blocked.`:null}isPrivateIp(e){let t=/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i.exec(e);if(t)return this.isPrivateIp(t[1]);let s=e.replace(/[\[\]]/g,"").toLowerCase();if(s==="::1"||s.startsWith("fc")||s.startsWith("fd")||s.startsWith("fe80"))return!0;let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(e);if(r){let[,n,o]=r.map(Number);if(n===10||n===172&&o>=16&&o<=31||n===192&&o===168||n===127||n===169&&o===254||n===0)return!0}return!1}isPrivateHost(e){return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:this.isPrivateIp(e)}async resolveAndCheckHost(e){if(this.isPrivateHost(e))return!0;try{let{address:t}=await tf(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 Ps,Hd=T(()=>{"use strict";H();Me();Ps=class extends x{static{m(this,"ProfileSkill")}userRepo;metadata={name:"profile",category:"core",description:"Manage user profile settings including timezone, language, and bio. Use this to personalize Alfred for each user.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["get","set_timezone","set_language","set_bio","set_preference"],description:"The profile action to perform"},value:{type:"string",description:"The value to set (for set_* actions)"},preference_key:{type:"string",description:"The preference key (for set_preference)"},preference_value:{type:"string",description:"The preference value (for set_preference)"}},required:["action"]}};constructor(e){super(),this.userRepo=e}async execute(e,t){let s=e.action,r=de(t);switch(s){case"get":return this.getProfile(r);case"set_timezone":return this.setField(r,"timezone",e.value);case"set_language":return this.setField(r,"language",e.value);case"set_bio":return this.setField(r,"bio",e.value);case"set_preference":return this.setPreference(r,e.preference_key,e.preference_value);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}getProfile(e){let t=this.userRepo.getProfile(e);if(!t)return{success:!0,data:null,display:"No profile found. Set your timezone, language, or bio to create one."};let s=[];if(t.displayName&&s.push(`Name: ${t.displayName}`),t.timezone&&s.push(`Timezone: ${t.timezone}`),t.language&&s.push(`Language: ${t.language}`),t.bio&&s.push(`Bio: ${t.bio}`),t.preferences)for(let[r,n]of Object.entries(t.preferences))s.push(`${r}: ${String(n)}`);return{success:!0,data:t,display:s.length>0?`Profile:
|
|
827
827
|
${s.map(r=>`- ${r}`).join(`
|
|
828
828
|
`)}`:"Profile is empty."}}setField(e,t,s){return!s||typeof s!="string"?{success:!1,error:`Missing required "value" for ${t}`}:(this.userRepo.updateProfile(e,{[t]:s}),{success:!0,data:{[t]:s},display:`${t} set to "${s}"`})}setPreference(e,t,s){if(!t||typeof t!="string")return{success:!1,error:'Missing required "preference_key"'};let n=this.userRepo.getProfile(e)?.preferences??{};return n[t]=s,this.userRepo.updateProfile(e,{preferences:n}),{success:!0,data:{key:t,value:s},display:`Preference "${t}" set to "${s}"`}}}});var We,Hr=T(()=>{"use strict";We=class{static{m(this,"CalendarProvider")}timezone=Intl.DateTimeFormat().resolvedOptions().timeZone}});var Wd={};pe(Wd,{CalDAVProvider:()=>yo});var yo,fa=T(()=>{"use strict";Hr();yo=class extends We{static{m(this,"CalDAVProvider")}config;client;constructor(e){super(),this.config=e}async initialize(){try{let e=await import("tsdav"),{createDAVClient:t}=e;this.client=await t({serverUrl:this.config.serverUrl,credentials:{username:this.config.username,password:this.config.password},authMethod:"Basic",defaultAccountType:"caldav"})}catch(e){throw new Error(`CalDAV initialization failed: ${e instanceof Error?e.message:String(e)}`)}}async listEvents(e,t){let s=await this.client.fetchCalendars();if(!s||s.length===0)return[];let r=[];for(let n of s){let o=await this.client.fetchCalendarObjects({calendar:n,timeRange:{start:e.toISOString(),end:t.toISOString()}});for(let i of o){let a=this.parseICalEvent(i.data,i.url);a&&r.push(a)}}return r.sort((n,o)=>n.start.getTime()-o.start.getTime())}async createEvent(e){let t=await this.client.fetchCalendars();if(!t||t.length===0)throw new Error("No calendars found");let s=`alfred-${Date.now()}@alfred`,r=this.buildICalEvent(s,e);return await this.client.createCalendarObject({calendar:t[0],filename:`${s}.ics`,iCalString:r}),{id:s,title:e.title,start:e.start,end:e.end,location:e.location,description:e.description,allDay:e.allDay}}async updateEvent(e,t){let s=await this.client.fetchCalendars();for(let r of s){let n=await this.client.fetchCalendarObjects({calendar:r});for(let o of n)if(o.url?.includes(e)||o.data?.includes(e)){let i=this.parseICalEvent(o.data,o.url);if(!i)continue;let a={title:t.title??i.title,start:t.start??i.start,end:t.end??i.end,location:t.location??i.location,description:t.description??i.description,allDay:t.allDay??i.allDay},c=this.buildICalEvent(e,a);return await this.client.updateCalendarObject({calendarObject:{...o,data:c}}),{id:e,...a}}}throw new Error(`Event ${e} not found`)}async deleteEvent(e){let t=await this.client.fetchCalendars();for(let s of t){let r=await this.client.fetchCalendarObjects({calendar:s});for(let n of r)if(n.url?.includes(e)||n.data?.includes(e)){await this.client.deleteCalendarObject({calendarObject:n});return}}throw new Error(`Event ${e} not found`)}async checkAvailability(e,t){let r=(await this.listEvents(e,t)).filter(n=>!n.allDay&&n.start<t&&n.end>e);return{available:r.length===0,conflicts:r}}parseICalEvent(e,t){try{let s=e.split(`
|
|
829
829
|
`).map(p=>p.trim()),r=m(p=>s.find(h=>h.startsWith(p+":"))?.slice(p.length+1),"get"),n=r("SUMMARY"),o=r("DTSTART")??r("DTSTART;VALUE=DATE"),i=r("DTEND")??r("DTEND;VALUE=DATE"),a=r("LOCATION"),c=r("DESCRIPTION"),d=r("UID")??t;if(!n||!o)return;let u=o.length===8;return{id:d,title:n,start:this.parseICalDate(o),end:i?this.parseICalDate(i):this.parseICalDate(o),location:a||void 0,description:c||void 0,allDay:u}}catch(s){console.error("[caldav] Failed to parse iCal event",s);return}}parseICalDate(e){if(e.length===8)return new Date(`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`);let t=e.replace(/[^0-9TZ]/g,"");return t.length>=15?new Date(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T${t.slice(9,11)}:${t.slice(11,13)}:${t.slice(13,15)}Z`):new Date(e)}buildICalEvent(e,t){let s=m((n,o)=>o?n.toISOString().slice(0,10).replace(/-/g,""):n.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,""),"formatDate"),r=`BEGIN:VCALENDAR\r
|
|
@@ -849,7 +849,7 @@ ${r.conflicts.map(o=>this.formatEvent(o)).join(`
|
|
|
849
849
|
${y.join(`
|
|
850
850
|
`)}`}}catch(o){return{success:!1,error:`Failed to find free slots: ${o instanceof Error?o.message:String(o)}`}}}collectSlots(e,t,s,r,n,o,i){let a=e;for(;a+s<=t&&i.length<5;){let c=new Date(a),d=c.getHours(),u=a+s,p=new Date(u).getHours()+new Date(u).getMinutes()/60;if(r){let h=c.getDay();if(h===0||h===6){let f=h===0?1:2;a=new Date(c.getFullYear(),c.getMonth(),c.getDate()+f,n).getTime();continue}if(d<n){a=new Date(c.getFullYear(),c.getMonth(),c.getDate(),n).getTime();continue}if(d>=o||p>o){a=new Date(c.getFullYear(),c.getMonth(),c.getDate()+1,n).getTime();continue}}i.push({start:new Date(a),end:new Date(u)}),a=u}}async checkConflicts(e){let t=e.start,s=e.end,r=e.title??"New Event";if(!t||!s)return{success:!1,error:'Missing required fields "start" and "end"'};try{let n=await this.calendarProvider.checkAvailability(this.parseLocalTime(t),this.parseLocalTime(s));if(n.available)return{success:!0,data:{conflicts:[],available:!0},display:`No conflicts found for "${r}" (${t} \u2013 ${s}). The time slot is free.`};let o=n.conflicts.map(i=>this.formatEvent(i));return{success:!0,data:{conflicts:n.conflicts,available:!1},display:`"${r}" has ${n.conflicts.length} conflict(s):
|
|
851
851
|
${o.join(`
|
|
852
|
-
`)}`}}catch(n){return{success:!1,error:`Failed to check conflicts: ${n instanceof Error?n.message:String(n)}`}}}formatEvent(e){let t=this.calendarProvider.timezone||this.timezone,s={hour:"2-digit",minute:"2-digit",...t?{timeZone:t}:{}},r={weekday:"short",day:"2-digit",month:"2-digit",year:"numeric",...t?{timeZone:t}:{}},n=e.location?` @ ${e.location}`:"",o=e.id?` [id:${e.id}]`:"",i=e.start.toLocaleDateString("de-AT",r);if(e.allDay)return`- ${i} ganzt\xE4gig: ${e.title}${n}${o}`;let a=e.start.toLocaleTimeString("en-GB",s),c=e.end.toLocaleTimeString("en-GB",s);return`- ${i} ${a}-${c}: ${e.title}${n}${o}`}}});var Kd=T(()=>{"use strict";Hr();fa();ga();ya();Gd();Xd()});var
|
|
852
|
+
`)}`}}catch(n){return{success:!1,error:`Failed to check conflicts: ${n instanceof Error?n.message:String(n)}`}}}formatEvent(e){let t=this.calendarProvider.timezone||this.timezone,s={hour:"2-digit",minute:"2-digit",...t?{timeZone:t}:{}},r={weekday:"short",day:"2-digit",month:"2-digit",year:"numeric",...t?{timeZone:t}:{}},n=e.location?` @ ${e.location}`:"",o=e.id?` [id:${e.id}]`:"",i=e.start.toLocaleDateString("de-AT",r);if(e.allDay)return`- ${i} ganzt\xE4gig: ${e.title}${n}${o}`;let a=e.start.toLocaleTimeString("en-GB",s),c=e.end.toLocaleTimeString("en-GB",s);return`- ${i} ${a}-${c}: ${e.title}${n}${o}`}}});var Kd=T(()=>{"use strict";Hr();fa();ga();ya();Gd();Xd()});var Us,Vd=T(()=>{"use strict";H();Us=class extends x{static{m(this,"CrossPlatformSkill")}users;linkTokens;adapters;findConversation;metadata={name:"cross_platform",category:"identity",description:"Manage cross-platform identity linking and messaging. Actions: link_start (generate a linking code on current platform), link_confirm (enter a code from another platform to link accounts), send_message (send a message to a linked platform), list_identities (show all linked platforms), unlink (remove a platform link).",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["link_start","link_confirm","send_message","list_identities","unlink"],description:"The action to perform"},code:{type:"string",description:"The 6-digit linking code (for link_confirm)"},platform:{type:"string",description:"Target platform (for send_message or unlink)"},chat_id:{type:"string",description:"Target chat ID (for send_message)"},message:{type:"string",description:"Message text to send (for send_message)"}},required:["action"]}};constructor(e,t,s,r){super(),this.users=e,this.linkTokens=t,this.adapters=s,this.findConversation=r}resolveInternalId(e){return this.users.findOrCreate(e.platform,e.userId).id}async execute(e,t){let s=e.action;switch(s){case"link_start":return this.linkStart(t);case"link_confirm":return this.linkConfirm(e,t);case"send_message":return this.sendMessage(e,t);case"list_identities":return this.listIdentities(t);case"unlink":return this.unlink(e,t);default:return{success:!1,error:`Unknown action: ${s}`}}}failedConfirmAttempts=new Map;checkConfirmRateLimit(e){let t=Date.now(),s=this.failedConfirmAttempts.get(e);return s&&t<s.resetAt&&s.count>=5?`Too many failed attempts. Please wait ${Math.ceil((s.resetAt-t)/1e3)}s before trying again.`:null}recordFailedConfirm(e){let t=Date.now(),s=this.failedConfirmAttempts.get(e);s&&t<s.resetAt?s.count++:this.failedConfirmAttempts.set(e,{count:1,resetAt:t+5*6e4})}async linkStart(e){this.linkTokens.cleanup();let t=this.resolveInternalId(e);if(this.linkTokens.countRecentByUser(t,10)>=5)return{success:!1,error:"Too many linking codes generated recently. Please wait a few minutes."};let r=this.linkTokens.create(t,e.platform);return{success:!0,data:{code:r.code,expiresAt:r.expiresAt},display:`Your linking code is: **${r.code}**
|
|
853
853
|
|
|
854
854
|
Enter this code on your other platform within 10 minutes using:
|
|
855
855
|
"Link my account with code ${r.code}"`}}async linkConfirm(e,t){let s=e.code;if(!s)return{success:!1,error:'Missing required field "code"'};let r=this.resolveInternalId(t),n=this.checkConfirmRateLimit(r);if(n)return{success:!1,error:n};let o=this.linkTokens.findByCode(s.trim());if(!o)return this.recordFailedConfirm(r),{success:!1,error:"Invalid or expired linking code. Please generate a new one."};let i=o.userId;if(i===r)return{success:!1,error:"Cannot link an account to itself. Use the code on a different platform."};let a=this.users.getMasterUserId(i),c=this.users.getMasterUserId(r),d;if(a!==i?d=a:c!==r?d=c:d=i,a!==i&&c!==r&&a!==c){let h=this.users.getLinkedUsers(c);for(let f of h)this.users.setMasterUser(f.id,d)}i!==d&&this.users.setMasterUser(i,d),r!==d&&this.users.setMasterUser(r,d),this.linkTokens.consume(o.id);let u=this.users.findById(i),p=o.platform;return{success:!0,data:{masterUserId:d,linkedPlatform:p},display:`Account linked successfully! Your ${p} account (${u?.displayName??u?.username??"unknown"}) is now linked to this ${t.platform} account.
|
|
@@ -857,9 +857,9 @@ Enter this code on your other platform within 10 minutes using:
|
|
|
857
857
|
Your memories, preferences, and context are now shared across platforms.`}}async sendMessage(e,t){let s=e.platform,r=e.chat_id,n=e.message;if(!s)return{success:!1,error:'Missing required field "platform"'};if(!n)return{success:!1,error:'Missing required field "message"'};let o=this.adapters.get(s);if(!o)return{success:!1,error:`Platform "${s}" is not connected. Available: ${[...this.adapters.keys()].join(", ")}`};if(!r||!/^[!0-9]/.test(r)){let i=this.resolveInternalId(t),a=this.users.getMasterUserId(i),d=this.users.getLinkedUsers(a).find(u=>u.platform===s);if(d&&this.findConversation){let u=this.findConversation(s,d.id);u&&(r=u.chatId)}!r&&d&&(r=d.platformUserId)}if(!r)return{success:!1,error:"Could not resolve chat_id for target platform. No linked account or conversation found."};try{return{success:!0,data:{messageId:await o.sendMessage(r,n),platform:s,chatId:r},display:`Message sent to ${s}.`}}catch(i){return{success:!1,error:`Failed to send message: ${i instanceof Error?i.message:String(i)}`}}}async listIdentities(e){let t=this.resolveInternalId(e),s=this.users.getMasterUserId(t),r=this.users.getLinkedUsers(s);if(r.length<=1)return{success:!0,data:{identities:r},display:`No linked accounts found. To link another platform, use:
|
|
858
858
|
"Start linking my account" on the platform you want to link from, then enter the code on the other platform.`};let n=r.map(o=>{let i=o.id===t?" (current)":"",a=o.displayName??o.username??o.platformUserId;return`- **${o.platform}**: ${a}${i}`});return{success:!0,data:{identities:r.map(o=>({platform:o.platform,username:o.username,displayName:o.displayName}))},display:`Linked accounts:
|
|
859
859
|
${n.join(`
|
|
860
|
-
`)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=this.resolveInternalId(t),n=this.users.getMasterUserId(r),i=this.users.getLinkedUsers(n).find(a=>a.platform===s&&a.id!==r);return i?(this.users.setMasterUser(i.id,i.id),{success:!0,data:{unlinkedPlatform:s,unlinkedUserId:i.id},display:`Unlinked ${s} account (${i.displayName??i.username??i.platformUserId}).`}):{success:!1,error:`No linked account found on platform "${s}".`}}}});var
|
|
860
|
+
`)}`}}async unlink(e,t){let s=e.platform;if(!s)return{success:!1,error:'Missing required field "platform"'};let r=this.resolveInternalId(t),n=this.users.getMasterUserId(r),i=this.users.getLinkedUsers(n).find(a=>a.platform===s&&a.id!==r);return i?(this.users.setMasterUser(i.id,i.id),{success:!0,data:{unlinkedPlatform:s,unlinkedUserId:i.id},display:`Unlinked ${s} account (${i.displayName??i.username??i.platformUserId}).`}):{success:!1,error:`No linked account found on platform "${s}".`}}}});var Fs,Yd=T(()=>{"use strict";H();Me();Fs=class extends x{static{m(this,"BackgroundTaskSkill")}taskRepo;metadata={name:"background_task",category:"automation",description:'Schedule, list, cancel, pause, or resume background tasks that run a SINGLE skill call asynchronously. Use "schedule" to queue ONE skill execution in the background (user will be notified when done). NOT for multi-step tasks \u2014 use "delegate" instead when a task needs multiple tool calls (e.g. search + read + process + generate). Use "list" to see active/recent tasks. Use "cancel" to stop a pending or running task. Use "pause" to checkpoint a persistent task and "resume" to continue it. Set persistent=true and max_duration_hours for long-running persistent tasks.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["schedule","list","cancel","pause","resume"],description:"The background task action to perform"},description:{type:"string",description:"Human-readable description of what the task does (for schedule)"},skill_name:{type:"string",description:"The skill to run in the background (for schedule)"},skill_input:{type:"object",description:"Input to pass to the skill (for schedule)"},task_id:{type:"string",description:"Task ID (for cancel, pause, resume)"},persistent:{type:"boolean",description:"If true, creates a persistent task with checkpoint/resume support (for schedule)"},max_duration_hours:{type:"number",description:"Maximum duration in hours for persistent tasks (default: 24)"}},required:["action"]}};persistentRunner;constructor(e){super(),this.taskRepo=e}setPersistentRunner(e){this.persistentRunner=e}getAllTasks(e){let t=new Set,s=[];for(let r of Y(e))for(let n of this.taskRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"schedule":return this.scheduleTask(e,t);case"list":return this.listTasks(t);case"cancel":return this.cancelTask(e,t);case"pause":return this.pauseTask(e,t);case"resume":return this.resumeTask(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: schedule, list, cancel`}}}scheduleTask(e,t){let s=e.description,r=e.skill_name,n=e.skill_input,o=e.persistent,i=e.max_duration_hours;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "description" for schedule action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "skill_name" for schedule action'};let a=this.taskRepo.create(de(t),t.platform,t.chatId,s,r,JSON.stringify(n??{}));o&&i?(this.taskRepo.updatePersistentConfig(a.id,i),a.maxDurationHours=i):o&&(this.taskRepo.updatePersistentConfig(a.id,24),a.maxDurationHours=24);let c=o?" (persistent)":"";return{success:!0,data:{taskId:a.id,description:s,skillName:r,status:a.status,persistent:!!o},display:`Background task scheduled${c} (${a.id}): "${s}" using skill "${r}". You'll be notified when it completes.`}}listTasks(e){let t=this.getAllTasks(e);if(t.length===0)return{success:!0,data:[],display:"No active or recent background tasks."};let s={pending:"\u23F3",running:"\u25B6\uFE0F",completed:"\u2705",failed:"\u274C",checkpointed:"\u23F8\uFE0F",resuming:"\u21BB",cancelled:"\u23F9"},r=t.map(n=>`- ${s[n.status]??"?"} ${n.id}: "${n.description}" [${n.status}] (${n.skillName})`);return{success:!0,data:t.map(n=>({taskId:n.id,description:n.description,status:n.status,skillName:n.skillName,createdAt:n.createdAt,completedAt:n.completedAt})),display:`Background tasks:
|
|
861
861
|
${r.join(`
|
|
862
|
-
`)}`}}async cancelTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for cancel action'};let n=this.getAllTasks(t).find(o=>o.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):this.taskRepo.cancel(s)||this.taskRepo.cancelTask(s),{success:!0,data:{taskId:s},display:`Background task "${s}" cancelled.`}):{success:!1,error:`Task "${s}" not found or already completed`}}async pauseTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for pause action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="running"&&n.status!=="resuming"?{success:!1,error:`Task "${s}" is not running (status: ${n.status})`}:(await this.persistentRunner.pause(s),{success:!0,data:{taskId:s},display:`Persistent task "${s}" paused. Use resume to continue.`}):{success:!1,error:`Task "${s}" not found`}}async resumeTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for resume action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="checkpointed"?{success:!1,error:`Task "${s}" is not checkpointed (status: ${n.status})`}:(this.persistentRunner.resume(n).catch(()=>{}),{success:!0,data:{taskId:s},display:`Persistent task "${s}" resuming. You'll be notified when it completes.`}):{success:!1,error:`Task "${s}" not found`}}}});var
|
|
862
|
+
`)}`}}async cancelTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for cancel action'};let n=this.getAllTasks(t).find(o=>o.id===s);return n?(n.maxDurationHours&&this.persistentRunner?await this.persistentRunner.cancel(s):this.taskRepo.cancel(s)||this.taskRepo.cancelTask(s),{success:!0,data:{taskId:s},display:`Background task "${s}" cancelled.`}):{success:!1,error:`Task "${s}" not found or already completed`}}async pauseTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for pause action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="running"&&n.status!=="resuming"?{success:!1,error:`Task "${s}" is not running (status: ${n.status})`}:(await this.persistentRunner.pause(s),{success:!0,data:{taskId:s},display:`Persistent task "${s}" paused. Use resume to continue.`}):{success:!1,error:`Task "${s}" not found`}}async resumeTask(e,t){let s=e.task_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "task_id" for resume action'};if(!this.persistentRunner)return{success:!1,error:"Persistent agent runner is not available"};let n=this.getAllTasks(t).find(o=>o.id===s);return n?n.status!=="checkpointed"?{success:!1,error:`Task "${s}" is not checkpointed (status: ${n.status})`}:(this.persistentRunner.resume(n).catch(()=>{}),{success:!0,data:{taskId:s},display:`Persistent task "${s}" resuming. You'll be notified when it completes.`}):{success:!1,error:`Task "${s}" not found`}}}});var js,Jd=T(()=>{"use strict";H();Me();js=class extends x{static{m(this,"ScheduledTaskSkill")}actionRepo;metadata={name:"scheduled_task",category:"automation",description:'Create, list, enable, disable, or delete scheduled actions that run automatically on a recurring basis. Supports cron expressions (e.g. "0 9 * * *" for daily at 9 AM), intervals (in minutes), and one-time schedules. Each scheduled action executes a skill or sends a prompt to the LLM at the configured time. Use this for time-based tasks (reports, periodic checks, reminders). For condition-based alerts ("notify me WHEN X happens"), use the watch tool instead.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The scheduled task action to perform"},name:{type:"string",description:"Name for the scheduled action (for create)"},description:{type:"string",description:"What the scheduled action does (for create)"},schedule_type:{type:"string",enum:["cron","interval","once"],description:"Type of schedule: cron expression, interval in minutes, or one-time ISO date (for create)"},schedule_value:{type:"string",description:"Schedule value: cron expression, minutes as string, or ISO date (for create)"},skill_name:{type:"string",description:"The skill to execute on schedule (for create)"},skill_input:{type:"object",description:"Input to pass to the skill (for create)"},prompt_template:{type:"string",description:"Optional LLM prompt to run instead of a skill (for create)"},action_id:{type:"string",description:"Scheduled action ID (for enable, disable, delete)"}},required:["action"]}};constructor(e){super(),this.actionRepo=e}getAllActions(e){let t=new Set,s=[];for(let r of Y(e))for(let n of this.actionRepo.getByUser(r))t.has(n.id)||(t.add(n.id),s.push(n));return s}async execute(e,t){let s=e.action;switch(s){case"create":return this.createAction(e,t);case"list":return this.listActions(t);case"enable":return this.toggleAction(e,!0,t);case"disable":return this.toggleAction(e,!1,t);case"delete":return this.deleteAction(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: create, list, enable, disable, delete`}}}createAction(e,t){let s=e.name,r=e.description,n=e.schedule_type,o=e.schedule_value,i=e.skill_name,a=e.skill_input,c=e.prompt_template;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "name" for create action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "description" for create action'};if(!n||!["cron","interval","once"].includes(n))return{success:!1,error:'Missing or invalid "schedule_type". Must be "cron", "interval", or "once"'};if(!o||typeof o!="string")return{success:!1,error:'Missing required field "schedule_value" for create action'};if((!i||typeof i!="string")&&!c)return{success:!1,error:'Missing required field "skill_name" (or "prompt_template") for create action'};if(n==="interval"){let p=parseInt(o,10);if(isNaN(p)||p<=0)return{success:!1,error:"For interval schedule, value must be a positive number of minutes"}}if(n==="cron"&&o.trim().split(/\s+/).length!==5)return{success:!1,error:"Cron expression must have 5 fields: minute hour dayOfMonth month dayOfWeek"};if(n==="once"){let p=new Date(o);if(isNaN(p.getTime()))return{success:!1,error:"For once schedule, value must be a valid ISO date string"};if(p.getTime()<=Date.now())return{success:!1,error:"The scheduled time is in the past. Please specify a future time."}}let d=this.actionRepo.create({userId:de(t),platform:t.platform,chatId:t.chatId,name:s,description:r,scheduleType:n,scheduleValue:o,skillName:i??"llm_prompt",skillInput:JSON.stringify(a??{}),promptTemplate:c}),u=n==="cron"?`cron: ${o}`:n==="interval"?`every ${o} minutes`:`once at ${o}`;return{success:!0,data:{actionId:d.id,name:s,scheduleType:n,scheduleValue:o,skillName:i},display:`Scheduled action created (${d.id}): "${s}" \u2014 ${u}, running "${i}"${d.nextRunAt?`. Next run: ${d.nextRunAt}`:""}`}}listActions(e){let t=this.getAllActions(e);if(t.length===0)return{success:!0,data:[],display:"No scheduled actions."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=r.scheduleType==="cron"?`cron: ${r.scheduleValue}`:r.scheduleType==="interval"?`every ${r.scheduleValue} min`:`once: ${r.scheduleValue}`,i=r.nextRunAt?` | next: ${r.nextRunAt}`:"";return`- ${n} ${r.id}: "${r.name}" [${o}] \u2192 ${r.skillName}${i}`});return{success:!0,data:t.map(r=>({actionId:r.id,name:r.name,scheduleType:r.scheduleType,scheduleValue:r.scheduleValue,skillName:r.skillName,enabled:r.enabled,nextRunAt:r.nextRunAt,lastRunAt:r.lastRunAt})),display:`Scheduled actions:
|
|
863
863
|
${s.join(`
|
|
864
864
|
`)}`}}toggleAction(e,t,s){let r=e.action_id;if(!r||typeof r!="string")return{success:!1,error:`Missing required field "action_id" for ${t?"enable":"disable"} action`};let n=this.actionRepo.findById(r),o=Y(s);return!n||!o.includes(n.userId)?{success:!1,error:`Scheduled action "${r}" not found`}:this.actionRepo.setEnabled(r,t)?{success:!0,data:{actionId:r,enabled:t},display:`Scheduled action "${r}" ${t?"enabled":"disabled"}.`}:{success:!1,error:`Scheduled action "${r}" not found`}}deleteAction(e,t){let s=e.action_id;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "action_id" for delete action'};let r=this.actionRepo.findById(s),n=Y(t);return!r||!n.includes(r.userId)?{success:!1,error:`Scheduled action "${s}" not found`}:this.actionRepo.delete(s)?{success:!0,data:{actionId:s},display:`Scheduled action "${s}" deleted.`}:{success:!1,error:`Scheduled action "${s}" not found`}}}});var jt,wa=T(()=>{"use strict";jt=class{static{m(this,"MCPClient")}serverName;config;logger;client;transport;connected=!1;constructor(e,t,s){this.serverName=e,this.config=t,this.logger=s}async connect(){try{let{Client:e}=await import("@modelcontextprotocol/sdk/client/index.js");if(this.client=new e({name:`alfred-${this.serverName}`,version:"1.0.0"},{capabilities:{}}),this.config.command){let{StdioClientTransport:t}=await import("@modelcontextprotocol/sdk/client/stdio.js"),s={PATH:process.env.PATH??"",HOME:process.env.HOME??process.env.USERPROFILE??"",LANG:process.env.LANG??"en_US.UTF-8",NODE_ENV:process.env.NODE_ENV??"",SYSTEMROOT:process.env.SYSTEMROOT??""};if(this.config.env)for(let[r,n]of Object.entries(this.config.env))s[r]=n.replace(/\$\{(\w+)\}/g,(o,i)=>process.env[i]??"");this.transport=new t({command:this.config.command,args:this.config.args??[],env:s})}else if(this.config.url){let{SSEClientTransport:t}=await import("@modelcontextprotocol/sdk/client/sse.js");this.transport=new t(new URL(this.config.url))}else throw new Error(`MCP server "${this.serverName}": must specify either command or url`);await this.client.connect(this.transport),this.connected=!0,this.logger.info({server:this.serverName},"MCP server connected")}catch(e){throw this.logger.error({server:this.serverName,err:e},"Failed to connect MCP server"),e}}async listTools(){if(!this.connected||!this.client)return[];try{return((await this.client.listTools()).tools??[]).map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema??{type:"object",properties:{}}}))}catch(e){return this.logger.error({server:this.serverName,err:e},"Failed to list MCP tools"),[]}}async callTool(e,t){if(!this.connected||!this.client)return{content:"MCP server not connected",isError:!0};try{let s=await this.client.callTool({name:e,arguments:t});return{content:(s.content??[]).map(n=>n.text??JSON.stringify(n)).join(`
|
|
865
865
|
`),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 sf,Bt,Ta=T(()=>{"use strict";H();sf=["read","write","destructive","admin"],Bt=class extends x{static{m(this,"MCPSkillAdapter")}client;serverName;toolName;metadata;constructor(e,t,s,r,n,o){super(),this.client=e,this.serverName=t,this.toolName=s;let i=o&&sf.includes(o)?o:"write";this.metadata={name:`mcp__${t}__${s}`,category:"mcp",description:`[MCP/${t}] ${r||s}`,riskLevel:i,version:"1.0.0",inputSchema:n}}async execute(e,t){let s=await this.client.callTool(this.toolName,e);return{success:s.isError!==!0,data:s.content,display:s.content,error:s.isError===!0?s.content:void 0}}}});var zr,Zd=T(()=>{"use strict";wa();Ta();zr=class{static{m(this,"MCPManager")}logger;clients=[];skills=[];constructor(e){this.logger=e}async initialize(e){for(let t of e.servers)try{let s=new jt(t.name,t,this.logger.child({mcp:t.name}));await s.connect(),this.clients.push(s);let r=await s.listTools();for(let n of r){let o=new Bt(s,t.name,n.name,n.description??"",n.inputSchema);this.skills.push(o)}this.logger.info({server:t.name,tools:r.length},"MCP server initialized")}catch(s){this.logger.error({server:t.name,err:s},"Failed to initialize MCP server")}}getSkills(){return this.skills}async shutdown(){for(let e of this.clients)await e.disconnect();this.clients.length=0,this.skills.length=0}}});var Qd=T(()=>{"use strict";wa();Ta();Zd()});import{spawn as rf}from"node:child_process";import ze from"node:fs";import qe from"node:path";import nf from"node:os";import of from"node:crypto";var Ht,_a=T(()=>{"use strict";Ht=class{static{m(this,"CodeExecutor")}resolveNodePath(){let e=new Set;for(let s of["pdf-parse","exceljs","pdfkit"])try{let r=rl.resolve(`${s}/package.json`);e.add(qe.dirname(qe.dirname(r)))}catch{}try{let s=ze.realpathSync(process.argv[1]??""),r=qe.dirname(s),n=qe.join(r,"node_modules");ze.existsSync(n)&&e.add(n);let o=qe.join(r,"..","node_modules");ze.existsSync(o)&&e.add(ze.realpathSync(o))}catch{}let t=qe.join(process.cwd(),"node_modules");if(ze.existsSync(t)&&e.add(t),process.env.NODE_PATH)for(let s of process.env.NODE_PATH.split(qe.delimiter))s&&e.add(s);return[...e].join(qe.delimiter)}async execute(e,t,s){let r=Math.min(s?.timeout??3e4,12e4),n=qe.join(nf.tmpdir(),`alfred-sandbox-${of.randomUUID()}`);ze.mkdirSync(n,{recursive:!0});try{let o=t==="javascript"?"js":"py",i=qe.join(n,`script.${o}`);ze.writeFileSync(i,e);let a=t==="javascript"?"node":process.platform==="win32"?"python":"python3",c=[i],d=Date.now();return await new Promise(u=>{let p=rf(a,c,{cwd:n,timeout:r,env:{...process.env,NODE_ENV:"sandbox",PYTHONDONTWRITEBYTECODE:"1",...s?.env,TMPDIR:n,TEMP:n,TMP:n,NODE_PATH:this.resolveNodePath()},stdio:["pipe","pipe","pipe"]}),h="",f="";p.stdout.on("data",g=>{h+=g.toString()}),p.stderr.on("data",g=>{f+=g.toString()}),p.on("close",g=>{let y=Date.now()-d,_=[];try{let S=ze.readdirSync(n).filter(E=>!E.startsWith("script."));for(let E of S){let v=qe.join(n,E),I=ze.statSync(v);if(I.isFile()&&I.size<1e7){let M=ze.readFileSync(v),q=E.endsWith(".png")?"image/png":E.endsWith(".jpg")||E.endsWith(".jpeg")?"image/jpeg":E.endsWith(".svg")?"image/svg+xml":E.endsWith(".csv")?"text/csv":E.endsWith(".json")?"application/json":E.endsWith(".html")||E.endsWith(".htm")?"text/html":E.endsWith(".txt")?"text/plain":E.endsWith(".md")?"text/markdown":E.endsWith(".xml")?"application/xml":E.endsWith(".xlsx")?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":E.endsWith(".xls")?"application/vnd.ms-excel":E.endsWith(".pdf")?"application/pdf":"application/octet-stream";_.push({name:E,data:M,mimeType:q})}}}catch{}u({stdout:h.slice(0,5e4),stderr:f.slice(0,1e4),exitCode:g??1,files:_.length>0?_:void 0,durationMs:y})}),p.on("error",g=>{u({stdout:"",stderr:g.message,exitCode:1,durationMs:Date.now()-d})}),p.stdin.end()})}finally{try{ze.rmSync(n,{recursive:!0,force:!0})}catch{}}}}});var qr,eu=T(()=>{"use strict";H();_a();qr=class extends x{static{m(this,"CodeExecutionSkill")}metadata={name:"code_sandbox",category:"automation",description:"Execute code in a sandboxed environment. Supports JavaScript (Node.js) and Python. Use for calculations, data processing, generating files (PDF, HTML, CSV, images, etc.), or testing code snippets. Code runs in an isolated temp directory with a timeout. Any files written to the working directory are automatically collected and sent to the user as attachments \u2014 do NOT use the file skill to send them afterwards. For PDF generation use pdfkit (Node.js) or reportlab/fpdf (Python). IMPORTANT: When generating large files, write compact data-driven code \u2014 define data as arrays/objects, then build the output programmatically. Never embed large HTML/text as string literals.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["run","run_with_data"],description:"Action to perform"},code:{type:"string",description:"Code to execute"},language:{type:"string",enum:["javascript","python"],description:"Programming language"},data:{type:"string",description:"Input data (available as variable INPUT_DATA, already parsed if JSON). Do NOT use os.environ or process.env \u2014 use INPUT_DATA directly."},timeout:{type:"number",description:"Timeout in ms (max 120000)"}},required:["action","code","language"]}};executor=new Ht;allowedLanguages;maxTimeout;constructor(e){super(),this.allowedLanguages=new Set(e?.allowedLanguages??["javascript","python"]),this.maxTimeout=e?.maxTimeoutMs??12e4}async execute(e,t){let s=e.action,r=e.code,n=e.language,o=e.data,i=Math.min(e.timeout??3e4,this.maxTimeout);if(!r)return{success:!1,error:'Missing required field "code". IMPORTANT: Do NOT embed large HTML/text as string literals \u2014 write compact code that builds content programmatically from data arrays/objects, e.g. rows.map(r => `<tr><td>${r.time}</td><td>${r.price}</td></tr>`).join(""). Keep the code short and data-driven.'};if(!n)return{success:!1,error:'Missing required field "language"'};if(!this.allowedLanguages.has(n))return{success:!1,error:`Language "${n}" is not allowed. Allowed: ${[...this.allowedLanguages].join(", ")}`};if(s==="run"&&r.length>4e3)return{success:!1,error:`Code too large (${r.length} chars, limit 4000 for action "run"). This usually means data is hardcoded in the code. Use action "run_with_data" with the data parameter instead. The data will be available as INPUT_DATA (already parsed). If you received a data reference like "result_1", pass it as the data parameter.`};let a=r;if(s==="run_with_data"&&o){let p=!1;try{JSON.parse(o),p=!0}catch{}n==="javascript"?a=p?`const INPUT_DATA = ${o};
|
|
@@ -871,7 +871,7 @@ ${r}`}let c=await this.executor.execute(a,n,{timeout:i}),d=c.files?.map(p=>({fil
|
|
|
871
871
|
${c.stdout}`:"",c.stderr?`Errors:
|
|
872
872
|
${c.stderr}`:"",`Exit code: ${c.exitCode}`,`Duration: ${c.durationMs}ms`,d&&d.length>0?`Files generated: ${d.map(p=>p.fileName).join(", ")}`:""].filter(Boolean).join(`
|
|
873
873
|
|
|
874
|
-
`);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 tu=T(()=>{"use strict";_a();eu()});var
|
|
874
|
+
`);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 tu=T(()=>{"use strict";_a();eu()});var Bs,su=T(()=>{"use strict";H();Me();Bs=class extends x{static{m(this,"DocumentSkill")}docRepo;processor;embeddingService;metadata={name:"document",category:"files",description:"Ingest, search, summarize, list, or delete documents. Supports PDF, DOCX, TXT, CSV, and Markdown files. Documents are chunked and embedded for semantic search.",riskLevel:"write",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["ingest","search","summarize","list","delete"],description:"Action to perform"},file_path:{type:"string",description:"Path to the file (for ingest)"},filename:{type:"string",description:"Original filename (for ingest)"},mime_type:{type:"string",description:"MIME type of the file (for ingest)"},query:{type:"string",description:"Search query (for search)"},document_id:{type:"string",description:"Document ID (for summarize, delete)"},limit:{type:"number",description:"Max results (for search, list)"}},required:["action"]}};constructor(e,t,s){super(),this.docRepo=e,this.processor=t,this.embeddingService=s}async execute(e,t){let s=e.action;switch(s){case"ingest":return this.ingest(e,t);case"search":return this.search(e,t);case"summarize":return this.summarize(e);case"list":return this.list(e,t);case"delete":return this.deleteDoc(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: ingest, search, summarize, list, delete`}}}async ingest(e,t){let s=e.file_path,r=e.filename,n=e.mime_type;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "file_path" for ingest action'};if(!r||typeof r!="string")return{success:!1,error:'Missing required field "filename" for ingest action'};if(!n||typeof n!="string")return{success:!1,error:'Missing required field "mime_type" for ingest action'};let o=await import("node:path"),i=o.resolve(s);if(i!==o.normalize(s)&&s.includes(".."))return{success:!1,error:"Invalid file path: path traversal not allowed"};let a=i.toLowerCase();if(a.startsWith("/etc/")||a.startsWith("/proc/")||a.startsWith("/sys/")||a.startsWith("c:\\windows\\")||a.startsWith("/root/"))return{success:!1,error:"Access to system directories is not allowed"};try{let c=await this.processor.ingest(de(t),s,r,n),d=c.existing?`Document "${r}" already ingested (${c.chunkCount} chunks). Ready for search. ID: ${c.documentId.slice(0,8)}...`:`Document "${r}" ingested successfully (${c.chunkCount} chunks). ID: ${c.documentId.slice(0,8)}...`;return{success:!0,data:c,display:d}}catch(c){return{success:!1,error:`Failed to ingest document: ${c instanceof Error?c.message:String(c)}`}}}async search(e,t){let s=e.query,r=e.limit||5;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "query" for search action'};if(!this.embeddingService)return{success:!1,error:"Embedding service not available for document search"};let n=Y(t),o=new Set,i=[];for(let d of n)for(let u of await this.embeddingService.semanticSearch(d,s,r))o.has(u.key)||(o.add(u.key),i.push(u));let a=i.filter(d=>d.category==="document");if(a.length===0)return{success:!0,data:[],display:`No document matches found for "${s}".`};let c=a.map((d,u)=>`${u+1}. (score: ${d.score.toFixed(3)}) ${d.value.slice(0,200)}${d.value.length>200?"...":""}`).join(`
|
|
875
875
|
|
|
876
876
|
`);return{success:!0,data:a,display:`Found ${a.length} relevant chunk(s):
|
|
877
877
|
|
|
@@ -883,7 +883,7 @@ ${c}`}}summarize(e){let t=e.document_id;if(!t||typeof t!="string")return{success
|
|
|
883
883
|
|
|
884
884
|
${a}`}}list(e,t){let s=e.limit||50,r=Y(t),n=new Set,o=[];for(let c of r)for(let d of this.docRepo.listByUser(c))n.has(d.id)||(n.add(d.id),o.push(d));let i=o.slice(0,s);if(i.length===0)return{success:!0,data:[],display:"No documents found."};let a=i.map(c=>`- **${c.filename}** [id=${c.id}] \u2014 ${c.mimeType}, ${c.chunkCount} chunks, ${c.sizeBytes} bytes`).join(`
|
|
885
885
|
`);return{success:!0,data:i,display:`${i.length} document(s):
|
|
886
|
-
${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success:!1,error:'Missing required field "document_id" for delete action'};let s=this.docRepo.getDocument(t);return s?(this.docRepo.deleteDocument(t),{success:!0,data:{documentId:t},display:`Document "${s.filename}" deleted.`}):{success:!1,error:`Document "${t}" not found`}}}});var
|
|
886
|
+
${a}`}}deleteDoc(e){let t=e.document_id;if(!t||typeof t!="string")return{success:!1,error:'Missing required field "document_id" for delete action'};let s=this.docRepo.getDocument(t);return s?(this.docRepo.deleteDocument(t),{success:!0,data:{documentId:t},display:`Document "${s.filename}" deleted.`}):{success:!1,error:`Document "${t}" not found`}}}});var Hs,ru=T(()=>{"use strict";H();Hs=class extends x{static{m(this,"TTSSkill")}synthesizer;metadata={name:"text_to_speech",category:"media",description:"Send a voice/audio message to the user. You MUST use this tool whenever the user asks you to respond as a voice message, speak, or reply with audio. Pass the full response text \u2014 it will be converted to speech and delivered as a playable voice message.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{text:{type:"string",description:"The text to convert to speech"}},required:["text"]}};constructor(e){super(),this.synthesizer=e}async execute(e,t){let s=e.text;if(!s)return{success:!1,error:"No text provided for speech synthesis."};try{return{success:!0,display:"Voice message sent.",attachments:[{fileName:"voice.ogg",data:await this.synthesizer.synthesize(s),mimeType:"audio/ogg"}]}}catch(r){return{success:!1,error:`Speech synthesis failed: ${r instanceof Error?r.message:String(r)}`}}}}});var Ws,nu=T(()=>{"use strict";H();Ws=class extends x{static{m(this,"ImageGenerateSkill")}generator;metadata={name:"image_generate",category:"media",description:"Generate an image from a text description. Use this tool when the user asks you to create, generate, draw, or design an image or picture. Returns the generated image that will be sent to the user.",riskLevel:"read",version:"1.0.0",timeoutMs:12e4,inputSchema:{type:"object",properties:{prompt:{type:"string",description:"Detailed description of the image to generate. Be specific about style, composition, colors, and subject matter."},model:{type:"string",description:"Optional model to use (e.g. gpt-image-1, gpt-image-1-mini, gemini-2.0-flash-exp). Uses provider default if omitted."},size:{type:"string",enum:["1024x1024","1536x1024","1024x1536"],description:"Image dimensions. 1024x1024 (square, default), 1536x1024 (landscape), 1024x1536 (portrait)."},quality:{type:"string",enum:["low","medium","high"],description:"Image quality level. Higher quality takes longer and costs more."}},required:["prompt"]}};constructor(e){super(),this.generator=e}async execute(e,t){let s=e.prompt;if(!s)return{success:!1,error:"No prompt provided for image generation."};try{let r=await this.generator.generate(s,{model:e.model,size:e.size,quality:e.quality});return{success:!0,display:"Image generated.",attachments:[{fileName:"image.png",data:r.data,mimeType:r.mimeType}]}}catch(r){return{success:!1,error:`Image generation failed: ${r instanceof Error?r.message:String(r)}`}}}}});function ge(l){return l==null?"-":l<1024?`${l} B`:l<1024**2?`${(l/1024).toFixed(1)} KiB`:l<1024**3?`${(l/1024**2).toFixed(1)} MiB`:`${(l/1024**3).toFixed(2)} GiB`}function Gr(l){return l==null?"-":`${(l*100).toFixed(1)}%`}function _o(l){if(!l)return"-";let e=Math.floor(l/86400),t=Math.floor(l%86400/3600),s=Math.floor(l%3600/60),r=[];return e&&r.push(`${e}d`),t&&r.push(`${t}h`),r.push(`${s}m`),r.join(" ")}var ko,ou=T(()=>{"use strict";H();m(ge,"bytes");m(Gr,"pct");m(_o,"uptimeStr");ko=class l extends x{static{m(this,"ProxmoxSkill")}metadata={name:"proxmox",category:"infrastructure",description:'Manage Proxmox VE virtual machines, containers, and cluster. Use action "list_vms" to see VMs, "start_vm"/"shutdown_vm" to control them, "cluster_status" for health, "create_snapshot" for backups.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["cluster_status","list_nodes","node_stats","list_vms","vm_status","list_snapshots","list_storage","list_tasks","task_status","start_vm","shutdown_vm","reboot_vm","suspend_vm","resume_vm","create_snapshot","backup_vm","migrate_vm","stop_vm","delete_snapshot","rollback_snapshot"],description:"The Proxmox action to perform"},vmid:{type:"number",description:"Virtual machine / container ID"},node:{type:"string",description:"Proxmox node name (optional \u2014 resolved automatically when omitted)"},type:{type:"string",enum:["qemu","lxc"],description:"VM type filter for list_vms (default: both)"},name:{type:"string",description:"Snapshot name (for create/delete/rollback_snapshot)"},description:{type:"string",description:"Snapshot description (optional)"},target:{type:"string",description:"Target node for migration"},storage:{type:"string",description:"Storage target for backup_vm"},upid:{type:"string",description:"Task UPID for task_status"}},required:["action"]}};config;vmCache=null;static VM_CACHE_TTL=3e4;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"cluster_status":return await this.clusterStatus();case"list_nodes":return await this.listNodes();case"node_stats":return await this.nodeStats(e.node);case"list_vms":return await this.listVms(e.node,e.type);case"vm_status":return await this.vmStatus(e.vmid,e.node);case"list_snapshots":return await this.listSnapshots(e.vmid,e.node);case"list_storage":return await this.listStorage(e.node);case"list_tasks":return await this.listTasks(e.node);case"task_status":return await this.taskStatus(e.upid);case"start_vm":return await this.vmPowerAction("start",e);case"shutdown_vm":return await this.vmPowerAction("shutdown",e);case"reboot_vm":return await this.vmPowerAction("reboot",e);case"suspend_vm":return await this.vmPowerAction("suspend",e);case"resume_vm":return await this.vmPowerAction("resume",e);case"stop_vm":return await this.vmPowerAction("stop",e);case"create_snapshot":return await this.createSnapshot(e);case"backup_vm":return await this.backupVm(e);case"migrate_vm":return await this.migrateVm(e);case"delete_snapshot":return await this.deleteSnapshot(e);case"rollback_snapshot":return await this.rollbackSnapshot(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Proxmox API error: ${r instanceof Error?r.message:String(r)}. Check baseUrl and connectivity.`}}}async api(e,t,s){let r=`${this.config.baseUrl}/api2/json${t}`,n={Authorization:`PVEAPIToken=${this.config.tokenId}=${this.config.tokenSecret}`},o={method:e,headers:n};s&&e!=="GET"&&(n["Content-Type"]="application/json",o.body=JSON.stringify(s));let i=this.config.verifyTls===!1;i&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");let a;try{a=await fetch(r,o)}finally{i&&delete process.env.NODE_TLS_REJECT_UNAUTHORIZED}if(!a.ok){let d="";try{d=(await a.text()).slice(0,500)}catch{}throw new Error(`HTTP ${a.status} ${a.statusText} \u2014 ${d}`)}return(await a.json()).data}async get(e){return this.api("GET",e)}async post(e,t){return this.api("POST",e,t)}async del(e){return this.api("DELETE",e)}async resolveVm(e,t){if(t)try{return await this.get(`/nodes/${t}/qemu/${e}/status/current`),{node:t,type:"qemu"}}catch{try{return await this.get(`/nodes/${t}/lxc/${e}/status/current`),{node:t,type:"lxc"}}catch{throw new Error(`VM ${e} not found on node "${t}"`)}}let r=(await this.getAllVms()).find(n=>n.vmid===e);if(!r)throw new Error(`VM ${e} not found on any node. Use "list_vms" to see available VMs.`);return{node:r.node,type:r.type}}async getAllVms(){let e=Date.now();if(this.vmCache&&e-this.vmCache.ts<l.VM_CACHE_TTL)return this.vmCache.entries;let t=await this.get("/nodes"),s=[];for(let r of t){let[n,o]=await Promise.all([this.get(`/nodes/${r.node}/qemu`).catch(()=>[]),this.get(`/nodes/${r.node}/lxc`).catch(()=>[])]);for(let i of n)s.push({...i,node:r.node,type:"qemu"});for(let i of o)s.push({...i,node:r.node,type:"lxc"})}return this.vmCache={entries:s,ts:e},s}async clusterStatus(){let e=await this.get("/cluster/status"),t=["## Cluster Status",""],s=e.find(n=>n.type==="cluster");s&&(t.push(`**Cluster:** ${s.name}`),t.push(`**Quorum:** ${s.quorate?"Yes":"No"}`),t.push(`**Nodes:** ${s.nodes??"-"}`),t.push(`**Version:** ${s.version??"-"}`),t.push(""));let r=e.filter(n=>n.type==="node");if(r.length){t.push("| Node | Online | Level | ID |"),t.push("|------|--------|-------|----|");for(let n of r)t.push(`| ${n.name} | ${n.online?"Yes":"**No**"} | ${n.level??"-"} | ${n.nodeid??"-"} |`)}return{success:!0,data:e,display:t.join(`
|
|
887
887
|
`)}}async listNodes(){let e=await this.get("/nodes"),t=["## Nodes","","| Node | Status | CPU | RAM Used / Total | Uptime |"];t.push("|------|--------|-----|------------------|--------|");for(let s of e){let r=typeof s.cpu=="number"?Gr(s.cpu):"-",n=ge(s.mem),o=ge(s.maxmem);t.push(`| ${s.node} | ${s.status} | ${r} | ${n} / ${o} | ${_o(s.uptime)} |`)}return{success:!0,data:e,display:t.join(`
|
|
888
888
|
`)}}async nodeStats(e){let t=e??this.config.defaultNode;if(!t)return{success:!1,error:'Missing "node" parameter and no defaultNode configured'};let s=await this.get(`/nodes/${t}/status`),r=s.cpu,n=s.memory,o=s.rootfs,i=s.swap,a=[`## Node: ${t}`,"",`**Uptime:** ${_o(s.uptime)}`,`**Kernel:** ${s.kversion??"-"}`,`**PVE Version:** ${s.pveversion??"-"}`,""];return r&&(a.push(`**CPU:** ${r.model??"-"} (${r.cpus??"-"} cores)`),a.push(`**CPU Usage:** ${Gr(r.cpu)}`),a.push(`**Load:** ${Array.isArray(s.loadavg)?s.loadavg.join(", "):"-"}`)),n&&a.push(`**RAM:** ${ge(n.used)} / ${ge(n.total)} (${Gr(n.used/n.total)})`),i&&a.push(`**Swap:** ${ge(i.used)} / ${ge(i.total)}`),o&&a.push(`**Root FS:** ${ge(o.used)} / ${ge(o.total)}`),{success:!0,data:s,display:a.join(`
|
|
889
889
|
`)}}async listVms(e,t){let s;if(e){if(s=[],!t||t==="qemu"){let n=await this.get(`/nodes/${e}/qemu`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"qemu"})}if(!t||t==="lxc"){let n=await this.get(`/nodes/${e}/lxc`).catch(()=>[]);for(let o of n)s.push({...o,node:e,type:"lxc"})}}else s=await this.getAllVms(),t&&(s=s.filter(n=>n.type===t));s.sort((n,o)=>n.vmid-o.vmid);let r=["## Virtual Machines & Containers","","| VMID | Name | Type | Node | Status | CPU | RAM Used / Max | Uptime |","|------|------|------|------|--------|-----|----------------|--------|"];for(let n of s)r.push(`| ${n.vmid} | ${n.name??"-"} | ${n.type} | ${n.node} | ${n.status??"-"} | ${Gr(n.cpu)} | ${ge(n.mem)} / ${ge(n.maxmem)} | ${_o(n.uptime)} |`);return s.length===0&&r.push("| - | No VMs found | - | - | - | - | - | - |"),{success:!0,data:s,display:r.join(`
|
|
@@ -962,7 +962,7 @@ ${r}`}}catch(s){return{success:!1,error:`Failed to list contacts: ${s instanceof
|
|
|
962
962
|
|------|-------|-------|`,s=e.map(r=>{let n=r.emails[0]?.address??"-",o=r.phones[0]?.number??"-";return`| ${r.displayName} | ${n} | ${o} |`});return`${t}
|
|
963
963
|
${s.join(`
|
|
964
964
|
`)}`}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(`
|
|
965
|
-
`)}}});var pu=T(()=>{"use strict";Xr();ba();Ea();Sa();uu();mu()});var
|
|
965
|
+
`)}}});var pu=T(()=>{"use strict";Xr();ba();Ea();Sa();uu();mu()});var zs,hu=T(()=>{"use strict";H();Me();zs=class extends x{static{m(this,"TodoSkill")}todoRepo;metadata={name:"todo",category:"productivity",description:"Manage todo lists with multiple named lists. Actions: add, list, complete, uncomplete, delete, lists, clear.",riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["add","list","complete","uncomplete","delete","lists","clear"],description:"The todo action to perform"},title:{type:"string",description:"The todo title (required for add)"},list:{type:"string",description:'The list name (default: "default")'},description:{type:"string",description:"Optional description for the todo"},priority:{type:"string",enum:["low","normal","high","urgent"],description:'Priority level (default: "normal")'},dueDate:{type:"string",description:"Due date for the todo (ISO string)"},todoId:{type:"string",description:"The ID of the todo (required for complete, uncomplete, delete)"},includeCompleted:{type:"boolean",description:"Include completed todos in list output (default: false)"}},required:["action"]}};constructor(e){super(),this.todoRepo=e}async execute(e,t){let s=e.action;switch(s){case"add":return this.addTodo(e,t);case"list":return this.listTodos(e,t);case"complete":return this.completeTodo(e,t);case"uncomplete":return this.uncompleteTodo(e,t);case"delete":return this.deleteTodo(e,t);case"lists":return this.showLists(t);case"clear":return this.clearCompleted(e,t);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid actions: add, list, complete, uncomplete, delete, lists, clear`}}}addTodo(e,t){let s=e.title;if(!s||typeof s!="string")return{success:!1,error:'Missing required field "title" for add action'};let r=e.list??"default",n=e.description,o=e.priority,i=e.dueDate,a=this.todoRepo.add(de(t),s,{list:r,description:n,priority:o,dueDate:i});return{success:!0,data:{todoId:a.id,title:a.title,list:a.list},display:`Todo added: "${s}"`}}listTodos(e,t){let s=e.list,r=e.includeCompleted??!1,n=new Set,o=[];for(let c of Y(t))for(let d of this.todoRepo.list(c,s,r))n.has(d.id)||(n.add(d.id),o.push(d));if(o.length===0)return{success:!0,data:[],display:"No todos found."};let i=`| | Priority | Title | Due | ID |
|
|
966
966
|
|---|---|---|---|---|`,a=o.map(c=>{let d=c.completed?"\u2611":"\u2610",u=c.dueDate??"";return`| ${d} | ${c.priority} | ${c.title} | ${u} | ${c.id} |`}).join(`
|
|
967
967
|
`);return{success:!0,data:o,display:`${o.length} todo(s):
|
|
968
968
|
${i}
|
|
@@ -996,19 +996,19 @@ ${n}`}}clearCompleted(e,t){let s=e.list,r=this.todoRepo.clearCompleted(de(t),s);
|
|
|
996
996
|
`)}}let y=g.reduce((P,ee)=>P+ee.distance,0),_=g.reduce((P,ee)=>P+ee.kWhUsed,0),S=_/y*100,E=g.map(P=>P.consumption).sort((P,ee)=>P-ee),v=E[0],I=E[E.length-1],M=E[Math.floor(E.length/2)],G=[`## BMW Verbrauchsstatistik \u2014 ${{week:"Letzte Woche",month:"Letzter Monat",year:"Letztes Jahr",all:"Gesamt"}[t??"month"]??"Letzter Monat"}`,"",`**Batteriekapazit\xE4t:** ${h} kWh`,`**Ausgewertete Fahrten:** ${g.length}`,`**Gesamtstrecke:** ${y.toLocaleString("de-AT")} km`,`**Gesamtverbrauch:** ${_.toFixed(1)} kWh`,"",`**Durchschnitt:** ${S.toFixed(1)} kWh/100km`,`**Min:** ${v.toFixed(1)} kWh/100km`,`**Max:** ${I.toFixed(1)} kWh/100km`,`**Median:** ${M.toFixed(1)} kWh/100km`,"","### Einzelne Fahrten","","| Datum | Strecke | Verbrauch | Energie |","|-------|---------|-----------|---------|"];for(let P of g)G.push(`| ${P.date} | ${P.distance} km | ${P.consumption.toFixed(1)} kWh/100km | ${P.kWhUsed.toFixed(1)} kWh |`);return{success:!0,data:{avgConsumption:S,totalDistance:y,totalKwh:_,segments:g},display:G.join(`
|
|
997
997
|
`)}}}});var _f,Co,Au=T(()=>{"use strict";H();_f="https://routes.googleapis.com/directions/v2:computeRoutes",Co=class extends x{static{m(this,"RoutingSkill")}metadata={name:"routing",category:"information",description:'Routenberechnung mit Live-Traffic via Google Routes API. "route" berechnet Route mit Distanz, Dauer und Dauer im aktuellen Verkehr. "departure_time" empfiehlt wann man losfahren soll, um zu einer bestimmten Zeit anzukommen. WICHTIG: Aliase wie "zuhause", "daheim", "home", "bei mir", "im B\xFCro", "work" VOR dem Tool-Call in konkrete Adressen aufl\xF6sen \u2014 daf\xFCr bekannte Adressen aus Memory/Kontext verwenden. Nie rohe Alias-Werte wie "home" oder "work" als origin/destination senden. Wenn keine Adresse im Kontext vorhanden ist, den User nach der Adresse fragen.',riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["route","departure_time"],description:"Routing action"},origin:{type:"string",description:'Start-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},destination:{type:"string",description:'Ziel-Adresse oder "lat,lng" \u2014 IMMER eine konkrete Adresse senden, KEINE Aliase wie "home"'},departure_time:{type:"string",description:"ISO-Zeitpunkt f\xFCr Abfahrt (optional, f\xFCr Traffic-Berechnung)"},arrival_time:{type:"string",description:"ISO-Zeitpunkt gew\xFCnschte Ankunft (f\xFCr departure_time-Action)"},travel_mode:{type:"string",enum:["DRIVE","BICYCLE","WALK","TRANSIT"],description:"Fortbewegungsart (Standard: DRIVE)"}},required:["action","origin","destination"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};let r=e.origin,n=e.destination;if(!r)return{success:!1,error:'Missing required field "origin"'};if(!n)return{success:!1,error:'Missing required field "destination"'};try{switch(s){case"route":return await this.computeRoute(r,n,e.departure_time,e.travel_mode);case"departure_time":return await this.computeDepartureTime(r,n,e.arrival_time,e.travel_mode);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(o){return{success:!1,error:`Google Routes API error: ${o instanceof Error?o.message:String(o)}`}}}async computeRoute(e,t,s,r){let n=this.buildRequestBody(e,t,r,s),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=(i.distanceMeters/1e3).toFixed(1),c=this.parseDuration(i.duration),d=this.parseDuration(i.staticDuration),u=c-d,p=["## Route","",`**${e}** \u2192 **${t}**`,"",`**Distanz:** ${a} km`,`**Fahrzeit (aktuell):** ${this.formatMinutes(c)}`,`**Fahrzeit (ohne Verkehr):** ${this.formatMinutes(d)}`];if(u>1&&p.push(`**Verkehrsverz\xF6gerung:** +${this.formatMinutes(u)}`),s){let h=new Date(new Date(s).getTime()+c*6e4);p.push(`**Gesch\xE4tzte Ankunft:** ${h.toLocaleString("de-AT")}`)}return{success:!0,data:{distanceKm:parseFloat(a),durationMinutes:c,staticDurationMinutes:d},display:p.join(`
|
|
998
998
|
`)}}async computeDepartureTime(e,t,s,r){if(!s)return{success:!1,error:'Missing required field "arrival_time" for departure_time action'};let n=this.buildRequestBody(e,t,r),i=(await this.callRoutesApi(n)).routes?.[0];if(!i)return{success:!1,error:"Keine Route gefunden."};let a=this.parseDuration(i.duration),c=Math.max(5,Math.round(a*.15)),d=new Date(s),u=new Date(d.getTime()-(a+c)*6e4),p=["## Abfahrtszeit-Empfehlung","",`**Route:** ${e} \u2192 ${t}`,`**Gew\xFCnschte Ankunft:** ${d.toLocaleString("de-AT")}`,`**Gesch\xE4tzte Fahrzeit:** ${this.formatMinutes(a)} (inkl. Verkehr)`,`**Puffer:** ${c} min`,"",`**Empfohlene Abfahrt:** ${u.toLocaleString("de-AT")}`];return{success:!0,data:{departureTime:u.toISOString(),durationMinutes:a,bufferMinutes:c},display:p.join(`
|
|
999
|
-
`)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",n=Math.abs(s),o=String(Math.floor(n/60)).padStart(2,"0"),i=String(n%60).padStart(2,"0"),a=m(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())}T${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}${r}${o}:${i}`}buildRequestBody(e,t,s,r,n){let o={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let i=this.normalizeTimestamp(r);new Date(i).getTime()>Date.now()+6e4&&(o.departureTime=i)}if(n){let i=this.normalizeTimestamp(n);new Date(i).getTime()>Date.now()+6e4&&(o.arrivalTime=i)}return o}async callRoutesApi(e){let t=await fetch(_f,{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 Iu,Ru,kf,bf,Ef,
|
|
999
|
+
`)}}buildWaypoint(e){let t=e.match(/^(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)$/);return t?{location:{latLng:{latitude:parseFloat(t[1]),longitude:parseFloat(t[2])}}}:{address:e}}normalizeTimestamp(e){let t=new Date(e);if(isNaN(t.getTime()))return e;if(/[Zz]|[+-]\d{2}:\d{2}$/.test(e))return t.toISOString();let s=t.getTimezoneOffset(),r=s<=0?"+":"-",n=Math.abs(s),o=String(Math.floor(n/60)).padStart(2,"0"),i=String(n%60).padStart(2,"0"),a=m(c=>String(c).padStart(2,"0"),"pad");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())}T${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}${r}${o}:${i}`}buildRequestBody(e,t,s,r,n){let o={origin:this.buildWaypoint(e),destination:this.buildWaypoint(t),travelMode:s??"DRIVE",routingPreference:"TRAFFIC_AWARE"};if(r){let i=this.normalizeTimestamp(r);new Date(i).getTime()>Date.now()+6e4&&(o.departureTime=i)}if(n){let i=this.normalizeTimestamp(n);new Date(i).getTime()>Date.now()+6e4&&(o.arrivalTime=i)}return o}async callRoutesApi(e){let t=await fetch(_f,{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 Iu,Ru,kf,bf,Ef,qs,xu,Cu,Nu,xa,Ca,Lu,No,Du=T(()=>{"use strict";H();Iu=1.5,Ru=4.79,kf=5.75,bf=1.03,Ef=new Date("2026-04-01T00:00:00+02:00"),qs=1.2,xu=.1,Cu=.58,Nu=.04,xa=.32,Ca=1.62,Lu="https://api.awattar.at/v1/marketdata",No=class extends x{static{m(this,"EnergyPriceSkill")}metadata={name:"energy_price",category:"information",description:'Strompreise (aWATTar HOURLY Tarif, EPEX Spot AT). "current" zeigt den aktuellen Strompreis mit Aufschl\xFCsselung (Marktpreis, Netzentgelte, Abgaben, Brutto). "today" zeigt alle Stundenpreise f\xFCr heute. "tomorrow" zeigt Stundenpreise f\xFCr morgen (verf\xFCgbar ab ~14:00). "cheapest" findet die g\xFCnstigsten Stunden (Standard: 3 Stunden in den n\xE4chsten 24h). "average" zeigt den Durchschnittspreis f\xFCr heute oder ein bestimmtes Datum.',riskLevel:"read",version:"1.0.0",timeoutMs:15e3,inputSchema:{type:"object",properties:{action:{type:"string",enum:["current","today","tomorrow","cheapest","average","briefing"],description:"Aktion (briefing = kompakte Tages\xFCbersicht f\xFCr Morgenbriefing)"},hours:{type:"number",description:"F\xFCr cheapest: Anzahl g\xFCnstigster Stunden (Standard: 3)"},date:{type:"string",description:"ISO-Datum f\xFCr average (Standard: heute)"}},required:["action"]}};config;constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"current":return await this.current();case"today":return await this.dayPrices("today");case"tomorrow":return await this.dayPrices("tomorrow");case"cheapest":return await this.cheapest(e.hours);case"average":return await this.average(e.date);case"briefing":return await this.briefingSummary();default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`aWATTar API error: ${r instanceof Error?r.message:String(r)}`}}}async current(){let e=Date.now(),s=(await this.fetchMarketData()).find(i=>i.start_timestamp<=e&&i.end_timestamp>e);if(!s)return{success:!1,error:"Kein Marktpreis f\xFCr die aktuelle Stunde verf\xFCgbar."};let r=this.calculatePrice(s.marketprice),o=[`## Aktueller Strompreis (${this.formatHourRange(s.start_timestamp,s.end_timestamp)})`,""];return o.push(this.formatBreakdown(r)),{success:!0,data:r,display:o.join(`
|
|
1000
1000
|
`)}}async dayPrices(e){let t=new Date,s=new Date(t);e==="tomorrow"&&s.setDate(s.getDate()+1);let r=new Date(s);r.setHours(0,0,0,0);let n=new Date(r);n.setDate(n.getDate()+1);let o=await this.fetchMarketData(r.getTime(),n.getTime());if(o.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${e==="today"?"heute":"morgen"} verf\xFCgbar.${e==="tomorrow"?" Preise f\xFCr morgen sind ab ca. 14:00 verf\xFCgbar.":""}`};let i=e==="today"?"Heute":"Morgen",a=r.toLocaleDateString("de-AT"),c=[`## Strompreise ${i} (${a})`,""];c.push("| Uhrzeit | Markt ct/kWh | Brutto ct/kWh |"),c.push("|---|---|---|");let d=1/0,u=-1/0,p=0;for(let f of o){let g=this.calculatePrice(f.marketprice),y=this.formatHourRange(f.start_timestamp,f.end_timestamp),_=this.spotCtKwh(f.marketprice);c.push(`| ${y} | ${_.toFixed(2)} | ${g.bruttoCt.toFixed(2)} |`),d=Math.min(d,g.bruttoCt),u=Math.max(u,g.bruttoCt),p+=g.bruttoCt}let h=p/o.length;return c.push(""),c.push(`**Min:** ${d.toFixed(2)} ct/kWh | **Max:** ${u.toFixed(2)} ct/kWh | **\xD8:** ${h.toFixed(2)} ct/kWh`),{success:!0,data:{entries:o.length,min:d,max:u,avg:h},display:c.join(`
|
|
1001
1001
|
`)}}async cheapest(e){let t=e??3,s=Date.now(),r=s+1440*60*1e3,n=await this.fetchMarketData(s,r);if(n.length===0)return{success:!1,error:"Keine Preisdaten f\xFCr die n\xE4chsten 24 Stunden verf\xFCgbar."};let o=n.map(c=>({entry:c,breakdown:this.calculatePrice(c.marketprice)}));o.sort((c,d)=>c.breakdown.bruttoCt-d.breakdown.bruttoCt);let i=o.slice(0,Math.min(t,o.length));i.sort((c,d)=>c.entry.start_timestamp-d.entry.start_timestamp);let a=[`## ${t} g\xFCnstigste Stunden (n\xE4chste 24h)`,""];for(let{entry:c,breakdown:d}of i){let u=this.formatHourRange(c.start_timestamp,c.end_timestamp),p=new Date(c.start_timestamp).toLocaleDateString("de-AT",{weekday:"short"});a.push(`- **${p} ${u}**: ${d.bruttoCt.toFixed(2)} ct/kWh brutto (Markt: ${this.spotCtKwh(c.marketprice).toFixed(2)} ct/kWh)`)}return{success:!0,data:i.map(c=>({time:this.formatHourRange(c.entry.start_timestamp,c.entry.end_timestamp),bruttoCt:c.breakdown.bruttoCt})),display:a.join(`
|
|
1002
1002
|
`)}}async average(e){let t;e?(t=new Date(e),t.setHours(0,0,0,0)):(t=new Date,t.setHours(0,0,0,0));let s=new Date(t);s.setDate(s.getDate()+1);let r=await this.fetchMarketData(t.getTime(),s.getTime());if(r.length===0)return{success:!1,error:`Keine Preisdaten f\xFCr ${t.toLocaleDateString("de-AT")} verf\xFCgbar.`};let n=0,o=0;for(let u of r)n+=this.spotCtKwh(u.marketprice),o+=this.calculatePrice(u.marketprice).bruttoCt;let i=n/r.length,a=o/r.length,c=t.toLocaleDateString("de-AT"),d=[`## Durchschnittspreis ${c}`,"",`**\xD8 Marktpreis:** ${i.toFixed(2)} ct/kWh`,`**\xD8 Brutto-Gesamtpreis:** ${a.toFixed(2)} ct/kWh`,"",`Basierend auf ${r.length} Stundenwerten.`];return{success:!0,data:{date:c,avgSpotCt:i,avgBruttoCt:a,hours:r.length},display:d.join(`
|
|
1003
1003
|
`)}}async briefingSummary(){let e=Date.now(),t=new Date;t.setHours(0,0,0,0);let s=new Date(t);s.setDate(s.getDate()+1);let r=await this.fetchMarketData(t.getTime(),s.getTime());if(r.length===0)return{success:!1,error:"Keine Preisdaten f\xFCr heute verf\xFCgbar."};let n=r.map(y=>({time:this.formatHourRange(y.start_timestamp,y.end_timestamp),bruttoCt:this.calculatePrice(y.marketprice).bruttoCt,start:y.start_timestamp,isCurrent:y.start_timestamp<=e&&y.end_timestamp>e,isPast:y.end_timestamp<=e})),o=n.find(y=>y.isCurrent),i=n.filter(y=>!y.isPast),a=n.map(y=>y.bruttoCt),c=a.reduce((y,_)=>y+_,0)/a.length,d=Math.min(...a),u=Math.max(...a),p=[...i].sort((y,_)=>y.bruttoCt-_.bruttoCt),h=p.slice(0,3),f=p.slice(-3).reverse(),g=[];o&&g.push(`**Aktuell (${o.time}):** ${o.bruttoCt.toFixed(2)} ct/kWh brutto`),g.push(`**Tagesdurchschnitt:** ${c.toFixed(2)} ct/kWh | **Min:** ${d.toFixed(2)} | **Max:** ${u.toFixed(2)}`),g.push(""),g.push("**G\xFCnstigste 3 Stunden (Rest des Tages):**");for(let y of h)g.push(`- ${y.time}: ${y.bruttoCt.toFixed(2)} ct/kWh`);g.push(""),g.push("**Teuerste 3 Stunden (Rest des Tages):**");for(let y of f)g.push(`- ${y.time}: ${y.bruttoCt.toFixed(2)} ct/kWh`);return{success:!0,data:{currentCt:o?.bruttoCt,avgCt:c,minCt:d,maxCt:u,cheapest:h.map(y=>({time:y.time,bruttoCt:y.bruttoCt})),expensive:f.map(y=>({time:y.time,bruttoCt:y.bruttoCt}))},display:g.join(`
|
|
1004
|
-
`)}}spotCtKwh(e){return e/10}calculatePrice(e){let t=this.spotCtKwh(e),s=new Date<Ef,n=(s?t*bf:t)+Iu,o=this.getGridCosts(),i=o.usageCt+o.lossCt,a=xu+Cu+Nu,c=n+i+a,d=c*
|
|
1005
|
-
`)}async fetchMarketData(e,t){let s=new URLSearchParams;e!=null&&s.set("start",e.toString()),t!=null&&s.set("end",t.toString());let r=s.toString()?`${Lu}?${s}`:Lu,n=await fetch(r,{signal:AbortSignal.timeout(1e4)});if(!n.ok){let i=await n.text().catch(()=>"");throw new Error(`HTTP ${n.status} \u2014 ${i.slice(0,300)}`)}return(await n.json()).data||[]}formatHourRange(e,t){let s=new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}),r=new Date(t).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"});return`${s}\u2013${r}`}}});var
|
|
1004
|
+
`)}}spotCtKwh(e){return e/10}calculatePrice(e){let t=this.spotCtKwh(e),s=new Date<Ef,n=(s?t*bf:t)+Iu,o=this.getGridCosts(),i=o.usageCt+o.lossCt,a=xu+Cu+Nu,c=n+i+a,d=c*qs;return{spotCt:t,ausgleichCt:s?t*.03:0,aufschlagCt:Iu,energieNettoCt:n,netznutzungCt:o.usageCt,netzverlustCt:o.lossCt,eAbgabeCt:xu,oekoArbeitCt:Cu,oekoVerlustCt:Nu,gesamtNettoCt:c,ustCt:c*.2,bruttoCt:d,gridName:o.name,hasGrid:o.usageCt>0}}getGridCosts(){let e=this.config?.gridUsageCt??0,t=this.config?.gridLossCt??0,s=this.config?.gridName??"";return e>0?{name:s,usageCt:e,lossCt:t}:{name:"",usageCt:0,lossCt:0}}formatBreakdown(e){let t=["| Komponente | ct/kWh |","|---|---:|",`| EPEX Spot Marktpreis | ${e.spotCt.toFixed(2)} |`];e.ausgleichCt>0&&t.push(`| Ausgleichsenergie (3%) | ${e.ausgleichCt.toFixed(2)} |`),t.push(`| aWATTar Aufschlag | ${e.aufschlagCt.toFixed(2)} |`),t.push(`| **Energie netto** | **${e.energieNettoCt.toFixed(2)}** |`),e.hasGrid&&(t.push(`| Netznutzung (${e.gridName}) | ${e.netznutzungCt.toFixed(2)} |`),t.push(`| Netzverlust | ${e.netzverlustCt.toFixed(2)} |`)),t.push(`| Elektrizit\xE4tsabgabe | ${e.eAbgabeCt.toFixed(2)} |`),t.push(`| \xD6kostrom-F\xF6rderbeitrag | ${e.oekoArbeitCt.toFixed(2)} |`),t.push(`| \xD6kostrom-Verlust | ${e.oekoVerlustCt.toFixed(2)} |`),t.push(`| **Gesamt netto** | **${e.gesamtNettoCt.toFixed(2)}** |`),t.push(`| USt (20%) | ${e.ustCt.toFixed(2)} |`),t.push(`| **Gesamt brutto** | **${e.bruttoCt.toFixed(2)}** |`),e.hasGrid||(t.push(""),t.push("*Netzentgelte nicht inkludiert \u2014 Netzkosten via `alfred setup` oder ENV konfigurieren*"));let s=this.config?.gridCapacityFee??0,r=this.config?.gridMeterFee??0;if(t.push(""),t.push("**Fixe Monatskosten (netto \u2192 brutto):**"),t.push(`- aWATTar Grundgeb\xFChr: ${Ru.toFixed(2)} \u20AC \u2192 ${kf.toFixed(2)} \u20AC`),s>0){let i=this.config?.gridName?` (${this.config.gridName})`:"";t.push(`- Leistungspauschale${i}: ${s.toFixed(2)} \u20AC \u2192 ${(s*qs).toFixed(2)} \u20AC`)}r>0&&t.push(`- Messentgelt: ${r.toFixed(2)} \u20AC \u2192 ${(r*qs).toFixed(2)} \u20AC`),t.push(`- \xD6kostrom-F\xF6rderpauschale: ${xa.toFixed(2)} \u20AC \u2192 ${(xa*qs).toFixed(2)} \u20AC`),t.push(`- Erneuerbaren-F\xF6rderpauschale: ${Ca.toFixed(2)} \u20AC \u2192 ${(Ca*qs).toFixed(2)} \u20AC`);let n=Ru+xa+Ca+s+r,o=n*qs;return t.push(`- **Summe:** ${n.toFixed(2)} \u20AC \u2192 **${o.toFixed(2)} \u20AC brutto/Monat**`),t.join(`
|
|
1005
|
+
`)}async fetchMarketData(e,t){let s=new URLSearchParams;e!=null&&s.set("start",e.toString()),t!=null&&s.set("end",t.toString());let r=s.toString()?`${Lu}?${s}`:Lu,n=await fetch(r,{signal:AbortSignal.timeout(1e4)});if(!n.ok){let i=await n.text().catch(()=>"");throw new Error(`HTTP ${n.status} \u2014 ${i.slice(0,300)}`)}return(await n.json()).data||[]}formatHourRange(e,t){let s=new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"}),r=new Date(t).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"});return`${s}\u2013${r}`}}});var Gs,Mu=T(()=>{"use strict";H();Gs=class extends x{static{m(this,"TransitSkill")}metadata={name:"transit_search",category:"information",description:'\xD6ffentlicher Nahverkehr in \xD6sterreich (\xD6BB, Wiener Linien, etc.). "search_stop" sucht Haltestellen nach Name. "journeys" berechnet Verbindungen zwischen zwei Orten (Name oder Stop-ID). "departures" zeigt Abfahrten an einer Haltestelle (Stop-ID erforderlich, zuerst search_stop verwenden). Deckt Busse, Stra\xDFenbahnen, U-Bahn, S-Bahn, Regionalz\xFCge und Fernz\xFCge ab.',riskLevel:"read",version:"1.0.0",timeoutMs:3e4,inputSchema:{type:"object",properties:{action:{type:"string",enum:["journeys","departures","search_stop"],description:"Transit action"},query:{type:"string",description:"Haltestellenname f\xFCr search_stop"},from:{type:"string",description:"Start-Haltestelle (Name oder ID) f\xFCr journeys"},to:{type:"string",description:"Ziel-Haltestelle (Name oder ID) f\xFCr journeys"},stop_id:{type:"string",description:"Stop-ID f\xFCr departures (von search_stop erhalten)"},departure:{type:"string",description:"ISO-Zeitpunkt f\xFCr gew\xFCnschte Abfahrt (optional)"},arrival:{type:"string",description:"ISO-Zeitpunkt f\xFCr gew\xFCnschte Ankunft (optional, nur f\xFCr journeys)"},results:{type:"number",description:"Anzahl Ergebnisse (Standard: 3)"},duration:{type:"number",description:"Zeitfenster in Minuten f\xFCr departures (Standard: 30)"}},required:["action"]}};client;constructor(e){super(),this.client=e}async execute(e,t){let s=e.action;if(!s)return{success:!1,error:'Missing required field "action"'};try{switch(s){case"search_stop":return await this.searchStop(e);case"journeys":return await this.findJourneys(e);case"departures":return await this.findDepartures(e);default:return{success:!1,error:`Unknown action "${s}"`}}}catch(r){return{success:!1,error:`Transit API error: ${r instanceof Error?r.message:String(r)}`}}}async searchStop(e){let t=e.query;if(!t)return{success:!1,error:'Missing required field "query" for search_stop'};let s=await this.client.searchStops(t);if(s.length===0)return{success:!0,data:[],display:`Keine Haltestellen gefunden f\xFCr "${t}".`};let r=["## Haltestellen",""];for(let n of s.slice(0,10))r.push(`- **${n.name}** (ID: \`${n.id}\`)`);return{success:!0,data:s,display:r.join(`
|
|
1006
1006
|
`)}}async findJourneys(e){let t=e.from,s=e.to;if(!t)return{success:!1,error:'Missing required field "from" for journeys'};if(!s)return{success:!1,error:'Missing required field "to" for journeys'};let r={};e.departure&&(r.departure=new Date(e.departure)),e.arrival&&(r.arrival=new Date(e.arrival)),e.results&&(r.results=e.results);let n=await this.client.journeys(t,s,r);if(n.length===0)return{success:!0,data:[],display:`Keine Verbindungen gefunden von ${t} nach ${s}.`};let o=[`## Verbindungen: ${t} \u2192 ${s}`,""];for(let i=0;i<n.length;i++){let a=n[i],c=this.formatTime(a.departure),d=this.formatTime(a.arrival);o.push(`### Verbindung ${i+1}: ${c} \u2192 ${d} (${a.duration} min, ${a.transfers} Umstieg${a.transfers!==1?"e":""})`);for(let u of a.legs)u.walking?o.push(` - \u{1F6B6} Fu\xDFweg \u2192 ${u.destination} (${this.formatTime(u.departure)}\u2013${this.formatTime(u.arrival)})`):o.push(` - ${u.line||u.mode} Ri. ${u.direction||u.destination}: ${u.origin} ${this.formatTime(u.departure)} \u2192 ${u.destination} ${this.formatTime(u.arrival)}`);o.push("")}return{success:!0,data:n,display:o.join(`
|
|
1007
1007
|
`)}}async findDepartures(e){let t=e.stop_id;if(!t)return{success:!1,error:'Missing required field "stop_id" for departures. Use search_stop first to find the stop ID.'};let s={};e.departure&&(s.when=new Date(e.departure)),e.duration&&(s.duration=e.duration);let r=await this.client.departures(t,s);if(r.length===0)return{success:!0,data:[],display:"Keine Abfahrten gefunden."};let n=["## Abfahrten",""];for(let o of r){let i=this.formatTime(o.when),a=o.delay?` (+${o.delay} min)`:"",c=o.platform?` [Steig ${o.platform}]`:"";n.push(`- **${i}${a}** ${o.line} \u2192 ${o.direction}${c}`)}return{success:!0,data:r,display:n.join(`
|
|
1008
|
-
`)}}formatTime(e){try{return new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"})}catch{return e}}}});import Na from"node:fs";import Ou from"node:path";function Pu(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function Sf(){let l=process.cwd();for(let e=0;e<10;e++){let t=Ou.join(l,".env");if(Na.existsSync(t))return t;let s=Ou.dirname(l);if(s===l)break;l=s}return null}var
|
|
1009
|
-
`)}}showService(e){let t=
|
|
1008
|
+
`)}}formatTime(e){try{return new Date(e).toLocaleTimeString("de-AT",{hour:"2-digit",minute:"2-digit"})}catch{return e}}}});import Na from"node:fs";import Ou from"node:path";function Pu(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function Sf(){let l=process.cwd();for(let e=0;e<10;e++){let t=Ou.join(l,".env");if(Na.existsSync(t))return t;let s=Ou.dirname(l);if(s===l)break;l=s}return null}var Xs,Ks,Uu=T(()=>{"use strict";H();Xs={proxmox:{label:"Proxmox VE",fields:[{env:"ALFRED_PROXMOX_BASE_URL",label:"Base URL (e.g. https://pve.local:8006)",required:!0},{env:"ALFRED_PROXMOX_TOKEN_ID",label:"API Token ID (user@realm!name)",required:!0},{env:"ALFRED_PROXMOX_TOKEN_SECRET",label:"API Token Secret",required:!0,secret:!0}]},unifi:{label:"UniFi Network",fields:[{env:"ALFRED_UNIFI_BASE_URL",label:"Base URL (e.g. https://unifi.local)",required:!0},{env:"ALFRED_UNIFI_API_KEY",label:"API Key (preferred, UniFi OS)",secret:!0},{env:"ALFRED_UNIFI_USERNAME",label:"Username (alternative to API key)"},{env:"ALFRED_UNIFI_PASSWORD",label:"Password (alternative to API key)",secret:!0},{env:"ALFRED_UNIFI_SITE",label:'Site name (default: "default")'}]},homeassistant:{label:"Home Assistant",fields:[{env:"ALFRED_HOMEASSISTANT_URL",label:"Base URL (e.g. http://homeassistant.local:8123)",required:!0},{env:"ALFRED_HOMEASSISTANT_TOKEN",label:"Long-Lived Access Token",required:!0,secret:!0}]},contacts:{label:"Contacts",fields:[{env:"ALFRED_CONTACTS_PROVIDER",label:"Provider (carddav, google, microsoft)",required:!0},{env:"ALFRED_CARDDAV_CONTACTS_SERVER_URL",label:"CardDAV Server URL (if carddav)"},{env:"ALFRED_CARDDAV_CONTACTS_USERNAME",label:"CardDAV Username (if carddav)"},{env:"ALFRED_CARDDAV_CONTACTS_PASSWORD",label:"CardDAV Password (if carddav)",secret:!0},{env:"ALFRED_GOOGLE_CONTACTS_CLIENT_ID",label:"Google Client ID (if google)",secret:!0},{env:"ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET",label:"Google Client Secret (if google)",secret:!0},{env:"ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN",label:"Google Refresh Token (if google)",secret:!0},{env:"ALFRED_MICROSOFT_CONTACTS_CLIENT_ID",label:"Microsoft Client ID (if microsoft)",secret:!0},{env:"ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET",label:"Microsoft Client Secret (if microsoft)",secret:!0},{env:"ALFRED_MICROSOFT_CONTACTS_TENANT_ID",label:"Microsoft Tenant ID (if microsoft)"},{env:"ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN",label:"Microsoft Refresh Token (if microsoft)",secret:!0}]},docker:{label:"Docker",fields:[{env:"ALFRED_DOCKER_SOCKET_PATH",label:"Docker socket path (e.g. /var/run/docker.sock)"},{env:"ALFRED_DOCKER_HOST",label:"Docker host (e.g. http://192.168.1.10:2375)"}]}},Ks=class extends x{static{m(this,"ConfigureSkill")}reloadCallback;setReloadCallback(e){this.reloadCallback=e}metadata={name:"configure",category:"core",description:'Configure Alfred services (Proxmox, UniFi, Home Assistant, Contacts, Docker) by writing environment variables. Use action "list_services" to see available services. Use action "show" to check current config of a service. Use action "set" to write config \u2014 provide service name and values. After setting config, the service is activated immediately \u2014 no restart needed.',riskLevel:"admin",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list_services","show","set"],description:"Action to perform"},service:{type:"string",enum:["proxmox","unifi","homeassistant","contacts","docker"],description:"Service to configure (required for show/set)"},values:{type:"object",description:'Key-value pairs to set. Keys are the ENV variable names (e.g. ALFRED_PROXMOX_BASE_URL). Only for action "set".'}},required:["action"]}};async execute(e,t){let s=e.action;switch(s){case"list_services":return this.listServices();case"show":return this.showService(e.service);case"set":return this.setService(e.service,e.values);default:return{success:!1,error:`Unknown action "${s}". Use list_services, show, or set.`}}}listServices(){let e=["| Service | Status | ENV Prefix |","|---|---|---|"];for(let[t,s]of Object.entries(Xs)){let n=s.fields.filter(i=>i.required).every(i=>!!process.env[i.env])?"configured":"not configured",o=`ALFRED_${t.toUpperCase()}_*`;e.push(`| ${s.label} | ${n} | \`${o}\` |`)}return{success:!0,data:Object.keys(Xs),display:e.join(`
|
|
1009
|
+
`)}}showService(e){let t=Xs[e];if(!t)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Xs).join(", ")}`};let s=[`**${t.label}** configuration:
|
|
1010
1010
|
`],r={};for(let n of t.fields){let o=process.env[n.env];r[n.env]=o;let i=o?n.secret?Pu(o):o:"_not set_",a=n.required?" (required)":"";s.push(`- \`${n.env}\`: ${i}${a}`)}return{success:!0,data:r,display:s.join(`
|
|
1011
|
-
`)}}async setService(e,t){let s=
|
|
1011
|
+
`)}}async setService(e,t){let s=Xs[e];if(!s)return{success:!1,error:`Unknown service "${e}". Available: ${Object.keys(Xs).join(", ")}`};if(!t||Object.keys(t).length===0)return{success:!1,error:`No values provided. Pass an object with ENV variable names as keys.
|
|
1012
1012
|
|
|
1013
1013
|
Available keys for ${s.label}:
|
|
1014
1014
|
${s.fields.map(d=>`- \`${d.env}\`: ${d.label}${d.required?" (required)":""}`).join(`
|
|
@@ -1024,9 +1024,9 @@ ${d}=${p}
|
|
|
1024
1024
|
`)}}async checkProxmox(){let e=this.config.proxmox,t=[],s=await this.proxmoxGet(e,"/cluster/status");for(let n of s)n.type==="node"&&!n.online&&t.push({source:"proxmox",message:`Node "${n.name}" is offline`});let r=await this.proxmoxGet(e,"/cluster/resources?type=vm");for(let n of r){let o=n.name??`VMID ${n.vmid}`,i=n.status,a=n.maxdisk,c=n.disk;if(a&&a>0&&c!=null){let d=c/a*100;d>90&&t.push({source:"proxmox",message:`${o} disk usage ${d.toFixed(1)}%`})}if(i==="running"){let d=n.maxmem,u=n.mem;if(d&&d>0&&u!=null){let p=u/d*100;p>95&&t.push({source:"proxmox",message:`${o} RAM usage ${p.toFixed(1)}%`})}}}return t}async proxmoxGet(e,t){let s=`${e.baseUrl}/api2/json${t}`,r={Authorization:`PVEAPIToken=${e.tokenId}=${e.tokenSecret}`},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`Proxmox HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return(await n.json()).data}async checkUnifi(){let e=this.config.unifi,t=[],s=e.site??"default",r,n=[],o;if(e.apiKey)r={"X-API-Key":e.apiKey,"Content-Type":"application/json"};else{let c=e.baseUrl.replace(/\/+$/,""),d=JSON.stringify({username:e.username,password:e.password}),u=await this.apiFetch(`${c}/api/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls),p;if(u.status===200)p="unifi-os",n=(u.headers.getSetCookie?.()??[]).map(h=>h.split(";")[0]),o=u.headers.get("x-csrf-token")??void 0;else if(u.status===404){let h=await this.apiFetch(`${c}/api/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:d},e.verifyTls);if(!h.ok)throw new Error(`UniFi login failed: HTTP ${h.status}`);p="classic",n=(h.headers.getSetCookie?.()??[]).map(f=>f.split(";")[0])}else throw new Error(`UniFi login failed: HTTP ${u.status}`);r={"Content-Type":"application/json"},n.length>0&&(r.Cookie=n.join("; ")),o&&(r["X-CSRF-Token"]=o)}let i=m(c=>`${e.baseUrl.replace(/\/+$/,"")}/proxy/network/api/s/${s}/${c}`,"apiUrl"),a=m(async c=>{let d=await this.apiFetch(i(c),{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!d.ok)throw new Error(`UniFi HTTP ${d.status}`);return(await d.json()).data},"unifiGet");try{let c=await a("stat/health");for(let d of c??[])d.status&&d.status!=="ok"&&t.push({source:"unifi",message:`Subsystem "${d.subsystem}" status: ${d.status}`})}catch{}try{let c=await a("stat/device");for(let d of c??[])if(d.state!==1){let u=d.name??d.hostname??d.mac??"unknown";t.push({source:"unifi",message:`Device "${u}" is not connected (state: ${d.state})`})}}catch{}try{let c=await a("rest/alarm?archived=false");c&&c.length>0&&t.push({source:"unifi",message:`${c.length} open alert(s): ${c.slice(0,3).map(d=>d.key??d.msg??"unknown").join(", ")}`})}catch{}return t}async checkHomeAssistant(){let e=this.config.homeassistant,t=[],s=await this.haGet(e,"/api/states"),r=0,n=[];for(let o of s){let i=o.entity_id;if(i.startsWith("update."))continue;if(o.state==="unavailable"&&(r++,n.length<5)){let d=o.attributes?.friendly_name??i;n.push(d)}let a=o.attributes?.device_class??"",c=o.attributes?.unit_of_measurement??"";if(i.startsWith("sensor.")&&a==="battery"&&c==="%"){let d=parseFloat(o.state);if(!isNaN(d)&&d>=0&&d<20){let u=o.attributes?.friendly_name??i;t.push({source:"homeassistant",message:`Low battery: ${u} at ${d}%`})}}}if(r>0){let o=n.join(", "),i=r>5?` (and ${r-5} more)`:"";t.push({source:"homeassistant",message:`${r} unavailable entities: ${o}${i}`})}return t}async haGet(e,t){let s=`${e.baseUrl.replace(/\/+$/,"")}${t}`,r={Authorization:`Bearer ${e.accessToken}`,"Content-Type":"application/json"},n=await this.apiFetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!n.ok)throw new Error(`HA HTTP ${n.status}: ${(await n.text()).slice(0,200)}`);return await n.json()}async checkProxmoxBackup(){let e=this.config.proxmoxBackup,t=[],s=e.maxAgeHours??24,r=`${e.baseUrl.replace(/\/+$/,"")}/api2/json/nodes/localhost/tasks`,n={Authorization:`PBSAPIToken=${e.tokenId}:${e.tokenSecret}`},o=await this.apiFetch(r,{method:"GET",headers:n,signal:AbortSignal.timeout(15e3)},e.verifyTls);if(!o.ok)return t.push({source:"proxmox_backup",message:`PBS unreachable: HTTP ${o.status}`}),t;let c=((await o.json()).data??[]).filter(h=>h.worker_type==="backup"),d=Date.now()/1e3,u=c.filter(h=>h.status==="OK").sort((h,f)=>(f.endtime??f.starttime)-(h.endtime??h.starttime));if(u.length===0)t.push({source:"proxmox_backup",message:"No successful backups found"});else{let h=u[0].endtime??u[0].starttime,f=(d-h)/3600;f>s&&t.push({source:"proxmox_backup",message:`Last successful backup is ${f.toFixed(1)}h old (threshold: ${s}h)`})}let p=c.filter(h=>h.status!=="OK"&&d-(h.endtime??h.starttime)<s*3600);return p.length>0&&t.push({source:"proxmox_backup",message:`${p.length} failed backup(s) in the last ${s}h`}),t}async apiFetch(e,t,s){let r=s===!1,n=process.env.NODE_TLS_REJECT_UNAUTHORIZED;r&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0");try{return await fetch(e,t)}finally{r&&(n===void 0?delete process.env.NODE_TLS_REJECT_UNAUTHORIZED:process.env.NODE_TLS_REJECT_UNAUTHORIZED=n)}}}});var Do,ju=T(()=>{"use strict";H();Do=class extends x{static{m(this,"MicrosoftTodoSkill")}config;accessToken="";metadata={name:"microsoft_todo",description:"Manage Microsoft To Do lists and tasks \u2014 list, create, complete, update and delete tasks across all lists.",version:"1.0.0",riskLevel:"write",category:"productivity",inputSchema:{type:"object",required:["action"],properties:{action:{type:"string",enum:["list_lists","list_tasks","add_task","complete_task","uncomplete_task","delete_task","update_task","create_list"],description:"Action to perform."},listId:{type:"string",description:"To Do list ID. Either listId or list (display name) is required for task actions."},list:{type:"string",description:'To Do list display name (resolved to listId automatically). E.g. "Einkaufsliste".'},taskId:{type:"string",description:"Task ID (required for complete/uncomplete/delete/update)."},title:{type:"string",description:"Task or list title (required for add_task, create_list; optional for update_task)."},body:{type:"string",description:"Task body/notes."},dueDate:{type:"string",description:"Due date in YYYY-MM-DD format."},importance:{type:"string",enum:["low","normal","high"],description:"Task importance."},includeCompleted:{type:"boolean",description:"Include completed tasks in list_tasks (default: false)."}}}};constructor(e){super(),this.config=e}async execute(e,t){let s=e.action;try{switch(s){case"list_lists":return await this.listLists();case"list_tasks":return await this.listTasks(e);case"add_task":return await this.addTask(e);case"complete_task":return await this.completeTask(e);case"uncomplete_task":return await this.uncompleteTask(e);case"delete_task":return await this.deleteTask(e);case"update_task":return await this.updateTask(e);case"create_list":return await this.createList(e);default:return{success:!1,error:`Unknown action: ${s}`}}}catch(r){return{success:!1,error:r instanceof Error?r.message:String(r)}}}async refreshAccessToken(){let e=`https://login.microsoftonline.com/${this.config.tenantId}/oauth2/v2.0/token`,t=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token",scope:"https://graph.microsoft.com/Tasks.ReadWrite offline_access"}),s=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()});if(!s.ok)throw new Error(`Microsoft token refresh failed: ${s.status}`);let r=await s.json();this.accessToken=r.access_token}async graphRequest(e,t={}){let s=m(()=>fetch(`https://graph.microsoft.com/v1.0${e}`,{...t,headers:{Authorization:`Bearer ${this.accessToken}`,"Content-Type":"application/json",...t.headers}}),"doFetch"),r=await s();if(r.status===401){if(await this.refreshAccessToken(),r=await s(),!r.ok)throw new Error(`Graph API error: ${r.status}`)}else if(!r.ok)throw new Error(`Graph API error: ${r.status}`);if(r.status!==204)return r.json()}async resolveListId(e){if(e.listId)return e.listId;let s=(await this.graphRequest("/me/todo/lists")).value??[];if(e.list){let n=e.list.toLowerCase(),o=s.find(i=>i.displayName.toLowerCase()===n);if(!o){let i=s.map(a=>a.displayName).join(", ");throw new Error(`List "${e.list}" not found. Available lists: ${i}`)}return o.id}let r=s.find(n=>n.wellknownListName==="defaultList");if(r)return r.id;if(s.length>0)return s[0].id;throw new Error("No To Do lists found.")}async listLists(){let t=(await this.graphRequest("/me/todo/lists")).value??[],s=t.map(r=>`\u2022 **${r.displayName}**${r.wellknownListName==="defaultList"?" (Standard)":""} [listId=${r.id}]`).join(`
|
|
1025
1025
|
`);return{success:!0,data:t,display:s||"Keine Listen gefunden."}}async listTasks(e){let t=await this.resolveListId(e),s=e.includeCompleted===!0,r=`/me/todo/lists/${t}/tasks`;s||(r+="?$filter=status ne 'completed'");let o=(await this.graphRequest(r)).value??[],i=o.map(a=>{let c=a.status==="completed"?"\u2611":"\u2610",d=a.importance==="high"?" \u2757":"",u=a.dueDateTime?` (f\xE4llig: ${a.dueDateTime.dateTime.slice(0,10)})`:"";return`${c} ${a.title}${d}${u} [taskId=${a.id}]`});return{success:!0,data:o,display:i.length>0?`listId=${t}
|
|
1026
1026
|
${i.join(`
|
|
1027
|
-
`)}`:"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});var Mo,Ks,Bu=T(()=>{"use strict";H();Mo=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Ks=class extends x{static{m(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,!0);case"disable":return this.toggleWatch(e,!1);case"delete":return this.deleteWatch(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},o=e.condition_field,i=e.condition_operator,a=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,p=e.action_skill_name,h=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,_=e.conditions,S=e.conditions_logic??"and";if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};let E=Array.isArray(_)&&_.length>0,v=!!o&&!!i;if(!E&&!v)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let I;if(E){for(let L of _){if(!L.field||!L.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!Mo.includes(L.operator))return{success:!1,error:`Invalid operator "${L.operator}" in conditions. Must be one of: ${Mo.join(", ")}`}}I={logic:S,conditions:_.map(L=>({field:L.field,operator:L.operator,value:L.value}))}}if(v&&!Mo.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${Mo.join(", ")}`};if(c<1)return{success:!1,error:"interval_minutes must be >= 1"};if(d<0)return{success:!1,error:"cooldown_minutes must be >= 0"};if(f==="trigger_watch"&&!y)return{success:!1,error:'Missing "trigger_watch_id" \u2014 required when action_on_trigger is "trigger_watch"'};if(y&&!this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let L=this.skillRegistry.get(r);if(!L)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let ne=L.metadata.inputSchema;if(ne&&Array.isArray(ne.required)){let ie=ne.required.filter(Q=>!(Q in n));if(ie.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${ie.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(ne.required)}`}}}let M=o??(I?I.conditions[0].field:""),q=i??(I?I.conditions[0].operator:"changed"),G=a??(I?I.conditions[0].value:void 0),P=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:M,operator:q,value:G},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:I,actionSkillName:p,actionSkillParams:h,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),ee=I?`${I.logic.toUpperCase()}(${I.conditions.map(L=>`${L.field} ${L.operator}${L.value!=null?" "+L.value:""}`).join(", ")})`:`${M} ${q}${G!=null?" "+G:""}`,ue=y?` \u2192 Chain \u2192 Watch ${y}`:p?` \u2192 Aktion: ${p} (${f})`:"";return{success:!0,data:{watchId:P.id,name:s,skillName:r,conditionField:M,conditionOperator:q,conditionValue:G,intervalMinutes:c,compositeCondition:I,triggerWatchId:y},display:`Watch erstellt (${P.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${ee}${ue}`}}listWatches(e){let t=this.watchRepo.findByChatId(e.chatId,e.platform);if(t.length===0)return{success:!0,data:[],display:"Keine Watches vorhanden."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,i=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",a=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${a}${i}`});return{success:!0,data:t.map(r=>({watchId:r.id,name:r.name,skillName:r.skillName,condition:r.condition,intervalMinutes:r.intervalMinutes,enabled:r.enabled,lastCheckedAt:r.lastCheckedAt,lastTriggeredAt:r.lastTriggeredAt})),display:`Watches:
|
|
1027
|
+
`)}`:"Keine Aufgaben in dieser Liste."}}async addTask(e){let t=await this.resolveListId(e);if(!e.title)return{success:!1,error:"title is required for add_task."};let s={title:e.title};return e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks`,{method:"POST",body:JSON.stringify(s)}),display:`Aufgabe \u201E${e.title}" hinzugef\xFCgt.`}}async completeTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"completed"})}),{success:!0,display:"Aufgabe als erledigt markiert."}):{success:!1,error:"taskId is required."}}async uncompleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify({status:"notStarted"})}),{success:!0,display:"Aufgabe als nicht erledigt markiert."}):{success:!1,error:"taskId is required."}}async deleteTask(e){let t=await this.resolveListId(e);return e.taskId?(await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"DELETE"}),{success:!0,display:"Aufgabe gel\xF6scht."}):{success:!1,error:"taskId is required."}}async updateTask(e){let t=await this.resolveListId(e);if(!e.taskId)return{success:!1,error:"taskId is required."};let s={};return e.title&&(s.title=e.title),e.body&&(s.body={content:e.body,contentType:"text"}),e.dueDate&&(s.dueDateTime={dateTime:`${e.dueDate}T00:00:00`,timeZone:"UTC"}),e.importance&&(s.importance=e.importance),Object.keys(s).length===0?{success:!1,error:"Nothing to update \u2014 provide title, body, dueDate, or importance."}:{success:!0,data:await this.graphRequest(`/me/todo/lists/${t}/tasks/${e.taskId}`,{method:"PATCH",body:JSON.stringify(s)}),display:"Aufgabe aktualisiert."}}async createList(e){return e.title?{success:!0,data:await this.graphRequest("/me/todo/lists",{method:"POST",body:JSON.stringify({displayName:e.title})}),display:`Liste \u201E${e.title}" erstellt.`}:{success:!1,error:"title is required for create_list."}}}});var Mo,Vs,Bu=T(()=>{"use strict";H();Mo=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],Vs=class extends x{static{m(this,"WatchSkill")}watchRepo;metadata={name:"watch",category:"automation",description:'Create and manage condition-based alerts (watches). A watch polls a skill at regular intervals, extracts a field from the result, and sends a notification when a condition is met \u2014 no LLM involved. Operators: lt, gt, lte, gte (numeric), eq, neq (string), contains, not_contains (substring), changed, increased, decreased (vs. last value). The first check stores a baseline and never triggers. IMPORTANT: skill_params must contain ALL parameters the target skill needs (action, query, etc.). The watch engine calls the skill with ONLY skill_params as input. Common condition_field paths by skill: marketplace {action:"search", query:"...", platform:"willhaben"} \u2192 "minPrice" (lt for price drop), "count" (increased for new listings); energy_prices \u2192 "bruttoCt" (current price ct/kWh); bmw {action:"status"} \u2192 "telematic.CHARGING_STATUS.value", "telematic.BATTERY_SIZE_MAX.value"; todo {action:"list",list:"..."} \u2192 use "length" for item count; email {action:"inbox"} \u2192 "unreadCount" or "messages.length"; monitor \u2192 returns alerts array, use "length" with gt 0. Use scheduled_task instead when you need to run a prompt through the LLM or when the user asks for a time-based report rather than a condition-based alert.',riskLevel:"write",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","enable","disable","delete"],description:"The watch action to perform"},name:{type:"string",description:"Short description of the watch (for create)"},skill_name:{type:"string",description:'Which skill to poll, e.g. "energy_prices", "email_list", "bmw" (for create)'},skill_params:{type:"object",description:'COMPLETE parameters object passed to the skill. Must include ALL required fields (e.g. {action:"search", query:"RTX 5090", platform:"willhaben"} for marketplace). The watch engine calls the skill with ONLY this object.'},condition_field:{type:"string",description:'Dot-path to extract from skill result data, e.g. "brutto_ct", "items.length", "battery.level" (for create)'},condition_operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"],description:"Comparison operator (for create)"},condition_value:{type:["string","number"],description:"Threshold value \u2014 optional for changed/increased/decreased (for create)"},interval_minutes:{type:"number",description:"Poll interval in minutes (default 15) (for create)"},cooldown_minutes:{type:"number",description:"Minimum minutes between alerts (default 30) (for create)"},message_template:{type:"string",description:"Custom alert message (for create)"},action_skill_name:{type:"string",description:"Skill to execute when condition triggers (for create). Enables automation: watch detects condition \u2192 executes action."},action_skill_params:{type:"object",description:"Parameters for the action skill (for create)"},action_on_trigger:{type:"string",enum:["alert","action_only","alert_and_action","trigger_watch"],description:"What to do on trigger: alert (default), action_only, alert_and_action, or trigger_watch to chain watches (for create)"},trigger_watch_id:{type:"string",description:'ID of another watch to trigger when this watch fires. Use with action_on_trigger: "trigger_watch" to create watch chains (A fires \u2192 immediately evaluates B).'},requires_confirmation:{type:"boolean",description:"If true, action requires user confirmation before execution (for create)"},conditions:{type:"array",description:"Array of conditions for composite logic (alternative to single condition_field/operator/value). Each: {field, operator, value?}",items:{type:"object",properties:{field:{type:"string"},operator:{type:"string",enum:["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"]},value:{type:["string","number"]}},required:["field","operator"]}},conditions_logic:{type:"string",enum:["and","or"],description:'Logic for composite conditions: "and" (all must match) or "or" (any must match). Default: "and"'},watch_id:{type:"string",description:"Watch ID (for enable, disable, delete)"}},required:["action"]}};skillRegistry=null;constructor(e,t){super(),this.watchRepo=e,this.skillRegistry=t??null}setSkillRegistry(e){this.skillRegistry=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWatch(e,t);case"list":return this.listWatches(t);case"enable":return this.toggleWatch(e,!0);case"disable":return this.toggleWatch(e,!1);case"delete":return this.deleteWatch(e);default:return{success:!1,error:`Unknown action: "${String(s)}". Valid: create, list, enable, disable, delete`}}}createWatch(e,t){let s=e.name,r=e.skill_name,n=e.skill_params??{},o=e.condition_field,i=e.condition_operator,a=e.condition_value,c=e.interval_minutes??15,d=e.cooldown_minutes??30,u=e.message_template,p=e.action_skill_name,h=e.action_skill_params,f=e.action_on_trigger??"alert",g=e.requires_confirmation,y=e.trigger_watch_id,_=e.conditions,S=e.conditions_logic??"and";if(!s)return{success:!1,error:'Missing required field "name"'};if(!r)return{success:!1,error:'Missing required field "skill_name"'};let E=Array.isArray(_)&&_.length>0,v=!!o&&!!i;if(!E&&!v)return{success:!1,error:'Missing conditions: provide either "condition_field"+"condition_operator" or a "conditions" array'};let I;if(E){for(let L of _){if(!L.field||!L.operator)return{success:!1,error:'Each condition must have "field" and "operator"'};if(!Mo.includes(L.operator))return{success:!1,error:`Invalid operator "${L.operator}" in conditions. Must be one of: ${Mo.join(", ")}`}}I={logic:S,conditions:_.map(L=>({field:L.field,operator:L.operator,value:L.value}))}}if(v&&!Mo.includes(i))return{success:!1,error:`Invalid "condition_operator". Must be one of: ${Mo.join(", ")}`};if(c<1)return{success:!1,error:"interval_minutes must be >= 1"};if(d<0)return{success:!1,error:"cooldown_minutes must be >= 0"};if(f==="trigger_watch"&&!y)return{success:!1,error:'Missing "trigger_watch_id" \u2014 required when action_on_trigger is "trigger_watch"'};if(y&&!this.watchRepo.getById(y))return{success:!1,error:`Chained watch "${y}" does not exist`};if(this.skillRegistry){let L=this.skillRegistry.get(r);if(!L)return{success:!1,error:`Unknown skill "${r}". The skill must be registered before creating a watch.`};let ne=L.metadata.inputSchema;if(ne&&Array.isArray(ne.required)){let ie=ne.required.filter(Q=>!(Q in n));if(ie.length>0)return{success:!1,error:`skill_params is missing required fields for "${r}": ${ie.join(", ")}. skill_params must contain the COMPLETE input for the skill. Expected: ${JSON.stringify(ne.required)}`}}}let M=o??(I?I.conditions[0].field:""),q=i??(I?I.conditions[0].operator:"changed"),G=a??(I?I.conditions[0].value:void 0),P=this.watchRepo.create({chatId:t.chatId,platform:t.platform,name:s,skillName:r,skillParams:n,condition:{field:M,operator:q,value:G},intervalMinutes:c,cooldownMinutes:d,enabled:!0,messageTemplate:u,compositeCondition:I,actionSkillName:p,actionSkillParams:h,actionOnTrigger:f,requiresConfirmation:g,triggerWatchId:y}),ee=I?`${I.logic.toUpperCase()}(${I.conditions.map(L=>`${L.field} ${L.operator}${L.value!=null?" "+L.value:""}`).join(", ")})`:`${M} ${q}${G!=null?" "+G:""}`,ue=y?` \u2192 Chain \u2192 Watch ${y}`:p?` \u2192 Aktion: ${p} (${f})`:"";return{success:!0,data:{watchId:P.id,name:s,skillName:r,conditionField:M,conditionOperator:q,conditionValue:G,intervalMinutes:c,compositeCondition:I,triggerWatchId:y},display:`Watch erstellt (${P.id}): "${s}" \u2014 pollt "${r}" alle ${c}min, Bedingung: ${ee}${ue}`}}listWatches(e){let t=this.watchRepo.findByChatId(e.chatId,e.platform);if(t.length===0)return{success:!0,data:[],display:"Keine Watches vorhanden."};let s=t.map(r=>{let n=r.enabled?"\u2705":"\u23F8\uFE0F",o=`${r.condition.field} ${r.condition.operator}${r.condition.value!=null?" "+r.condition.value:""}`,i=r.lastCheckedAt?` | letzter Check: ${r.lastCheckedAt}`:"",a=r.actionSkillName?` \u2192 Aktion: ${r.actionSkillName}`:"";return`- ${n} ${r.id}: "${r.name}" [${r.skillName}, ${r.intervalMinutes}min] ${o}${a}${i}`});return{success:!0,data:t.map(r=>({watchId:r.id,name:r.name,skillName:r.skillName,condition:r.condition,intervalMinutes:r.intervalMinutes,enabled:r.enabled,lastCheckedAt:r.lastCheckedAt,lastTriggeredAt:r.lastTriggeredAt})),display:`Watches:
|
|
1028
1028
|
${s.join(`
|
|
1029
|
-
`)}`}}toggleWatch(e,t){let s=e.watch_id;return s?this.watchRepo.toggle(s,t)?{success:!0,data:{watchId:s,enabled:t},display:`Watch "${s}" ${t?"aktiviert":"deaktiviert"}.`}:{success:!1,error:`Watch "${s}" not found`}:{success:!1,error:`Missing "watch_id" for ${t?"enable":"disable"}`}}deleteWatch(e){let t=e.watch_id;return t?this.watchRepo.delete(t)?{success:!0,data:{watchId:t},display:`Watch "${t}" gel\xF6scht.`}:{success:!1,error:`Watch "${t}" not found`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var
|
|
1029
|
+
`)}`}}toggleWatch(e,t){let s=e.watch_id;return s?this.watchRepo.toggle(s,t)?{success:!0,data:{watchId:s,enabled:t},display:`Watch "${s}" ${t?"aktiviert":"deaktiviert"}.`}:{success:!1,error:`Watch "${s}" not found`}:{success:!1,error:`Missing "watch_id" for ${t?"enable":"disable"}`}}deleteWatch(e){let t=e.watch_id;return t?this.watchRepo.delete(t)?{success:!0,data:{watchId:t},display:`Watch "${t}" gel\xF6scht.`}:{success:!1,error:`Watch "${t}" not found`}:{success:!1,error:'Missing "watch_id" for delete'}}}});var Ys,Hu=T(()=>{"use strict";H();Me();Ys=class extends x{static{m(this,"WorkflowSkill")}workflowRepo;metadata={name:"workflow",category:"automation",description:'Create and manage multi-step workflows (skill chains). Use "create" to define a workflow with sequential steps. Each step runs a skill and can pass data to the next via {{prev.field}} or {{steps.0.field}} templates. Use "run" to execute a workflow, "list" to see all workflows, "delete" to remove, "history" to see recent executions.',riskLevel:"write",version:"1.0.0",timeoutMs:3e5,inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","list","run","delete","history"],description:"Workflow action"},name:{type:"string",description:"Workflow name (for create)"},steps:{type:"array",description:'Workflow steps (for create). Action step: { skillName, inputMapping: { paramName: "{{prev.field}}" }, onError: "stop"|"skip"|"retry", jumpTo?: stepIndex|"end" }. Condition step: { type: "condition", condition: { field: "prev.rain", operator: "eq", value: "true" }, then: stepIndex|"end"|null, else: stepIndex|"end"|null, label?: "Regen?" }. Jump targets are 0-based step indices, "end" finishes the workflow, null proceeds to next step.',items:{type:"object"}},workflow_id:{type:"string",description:"Workflow ID (for run/delete/history)"}},required:["action"]}};runner;constructor(e){super(),this.workflowRepo=e}setRunner(e){this.runner=e}async execute(e,t){let s=e.action;switch(s){case"create":return this.createWorkflow(e,t);case"list":return this.listWorkflows(t);case"run":return this.runWorkflow(e,t);case"delete":return this.deleteWorkflow(e,t);case"history":return this.getHistory(e);default:return{success:!1,error:`Unknown action: "${String(s)}"`}}}createWorkflow(e,t){let s=e.name,r=e.steps;if(!s)return{success:!1,error:'Missing required field "name"'};if(!r||!Array.isArray(r)||r.length===0)return{success:!1,error:'Missing or empty "steps" array'};let n=["lt","gt","lte","gte","eq","neq","contains","not_contains","changed","increased","decreased"];for(let i=0;i<r.length;i++){let a=r[i];if(a.type==="condition"){if(!a.condition||typeof a.condition!="object")return{success:!1,error:`Step ${i}: condition step missing "condition" object`};if(!a.condition.field||typeof a.condition.field!="string")return{success:!1,error:`Step ${i}: condition.field must be a non-empty string`};if(!n.includes(a.condition.operator))return{success:!1,error:`Step ${i}: condition.operator must be one of: ${n.join(", ")}`};for(let c of["then","else"]){let d=a[c];if(d!==null&&d!=="end"&&(typeof d!="number"||d<0||d>=r.length))return{success:!1,error:`Step ${i}: "${c}" must be null, "end", or a step index (0-${r.length-1})`}}}else{if(!a.skillName)return{success:!1,error:`Step ${i}: missing skillName`};if(!a.inputMapping||typeof a.inputMapping!="object")return{success:!1,error:`Step ${i}: missing inputMapping`};if(!["stop","skip","retry"].includes(a.onError))return{success:!1,error:`Step ${i}: onError must be stop|skip|retry`};if(a.jumpTo!==void 0&&a.jumpTo!=="end"&&(typeof a.jumpTo!="number"||a.jumpTo<0||a.jumpTo>=r.length))return{success:!1,error:`Step ${i}: jumpTo must be "end" or a step index (0-${r.length-1})`}}}let o=this.workflowRepo.create({name:s,userId:de(t),chatId:t.chatId,platform:t.platform,steps:r,triggerType:"manual",enabled:!0});return{success:!0,data:{workflowId:o.id,name:s,stepCount:r.length},display:`Workflow "${s}" erstellt (${o.id}) mit ${r.length} Schritten.`}}listWorkflows(e){let t=[],s=new Set;for(let n of Y(e))for(let o of this.workflowRepo.findByUser(n))s.has(o.id)||(s.add(o.id),t.push(o));if(t.length===0)return{success:!0,data:[],display:"Keine Workflows vorhanden."};let r=t.map(n=>`- ${n.enabled?"\u2705":"\u23F8\uFE0F"} ${n.name} (${n.id.slice(0,8)}) \u2014 ${n.steps.length} Schritte, Trigger: ${n.triggerType}`);return{success:!0,data:t.map(n=>({id:n.id,name:n.name,steps:n.steps.length,triggerType:n.triggerType,enabled:n.enabled})),display:`Workflows:
|
|
1030
1030
|
${r.join(`
|
|
1031
1031
|
`)}`}}async runWorkflow(e,t){if(!this.runner)return{success:!1,error:"WorkflowRunner not available"};let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);if(!r)return{success:!1,error:`Workflow "${s}" not found`};if(!r.enabled)return{success:!1,error:`Workflow "${r.name}" is disabled`};let n=await this.runner.run(r,t),i=[`${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} Workflow "${r.name}": ${n.status}`];i.push(`Schritte: ${n.stepsCompleted}/${n.totalSteps}`),n.error&&i.push(`Fehler: ${n.error}`);for(let a=0;a<n.stepResults.length;a++){let c=n.stepResults[a];i.push(` ${a+1}. ${c.skillName}: ${c.success?"\u2705":"\u274C "+(c.error??"")}`)}return{success:n.status==="completed",data:n,display:i.join(`
|
|
1032
1032
|
`)}}deleteWorkflow(e,t){let s=e.workflow_id;if(!s)return{success:!1,error:'Missing "workflow_id"'};let r=this.workflowRepo.getById(s);return r?Y(t).includes(r.userId)?(this.workflowRepo.delete(s),{success:!0,data:{workflowId:s},display:`Workflow "${r.name}" gel\xF6scht.`}):{success:!1,error:"Not authorized to delete this workflow"}:{success:!1,error:`Workflow "${s}" not found`}}getHistory(e){let t=e.workflow_id;if(!t)return{success:!1,error:'Missing "workflow_id"'};let s=this.workflowRepo.getRecentExecutions(t);if(s.length===0)return{success:!0,data:[],display:"Keine Ausf\xFChrungen vorhanden."};let r=s.map(n=>`- ${n.status==="completed"?"\u2705":n.status==="partial"?"\u26A0\uFE0F":"\u274C"} ${n.startedAt} \u2014 ${n.stepsCompleted}/${n.totalSteps} Schritte (${n.status})`);return{success:!0,data:s,display:`Letzte Ausf\xFChrungen:
|
|
@@ -1057,7 +1057,7 @@ ${a.display}`):a.error&&d.push(`**Route:** \u26A0\uFE0F ${a.error}`),c?.success&
|
|
|
1057
1057
|
`)}}resolveAddresses(e){let t=this.alfredConfig.briefing?.homeAddress,s=this.alfredConfig.briefing?.officeAddress;if(!this.memoryRepo)return{home:t,office:s};let r=t,n=s;for(let o of Y(e)){let i=this.memoryRepo.search(o,"adresse");for(let a of i){let c=a.key.toLowerCase(),d=a.value;!r&&/heim|home|wohn|zuhause|privat/.test(c)&&(r=d),!n&&/büro|office|arbeit|firma|work/.test(c)&&(n=d)}if(r&&n)break}return{home:r,office:n}}resolveHaPreferences(e){let t=this.alfredConfig.briefing?.homeAssistant?.entities,s=this.alfredConfig.briefing?.homeAssistant?.domains;if(t?.length||s?.length)return{entities:t,domains:s};if(!this.memoryRepo)return{};for(let r of Y(e)){let n=this.memoryRepo.search(r,"briefing");for(let o of n){let i=o.key.toLowerCase();if(/ha_entit|home.?assistant.*entit|briefing.*entit/.test(i)){let a=o.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(a.length)return{entities:a}}if(/ha_domain|home.?assistant.*domain|briefing.*domain/.test(i)){let a=o.value.split(/[,;]\s*/).map(c=>c.trim()).filter(Boolean);if(a.length)return{domains:a}}}}return{}}detectExternalAppointment(e){return Array.isArray(e)?e.some(t=>{let s=t.location??t.loc??"";return!s||typeof s!="string"||/teams|zoom|meet\.google|webex|skype/i.test(s)?!1:s.trim().length>0}):!1}cleanDisplay(e,t){let s=t;return s=s.replace(/\s*\[(?:id:)?[A-Za-z0-9+/=\-]{20,}\]/g,""),e==="email"&&(s=s.replace(/^\d+\.\s*/gm,"- ").replace(/\[UNREAD\]/g,"\u{1F4E9}").replace(/\[ATT\]/g,"\u{1F4CE}").replace(/\n\s+Date:\s+\S+/g,"")),e==="calendar"&&(s=s.replace(/^\d+\s+event\(s\):\n?/i,"")),e==="todo"&&(s=s.replace(/^\|.*\|$/gm,r=>{if(/^[\|\s\-:]+$/.test(r))return"";let n=r.split("|").map(o=>o.trim()).filter(Boolean);if(n.length>=3){let o=n[0],i=n[1]&&n[1]!==""?` [${n[1]}]`:"",a=n[2];return`${o}${i} ${a}`}return r}),s=s.replace(/^\d+\s+todo\(s\):\n?/i,""),s=s.replace(/\n{2,}/g,`
|
|
1058
1058
|
`)),e==="mstodo"&&(s=s.replace(/\s*\[(?:taskId|listId)=[^\]]+\]/g,"")),s=s.replace(/^\[[\w-]+\]\s*/gm,""),s=s.replace(/\n{3,}/g,`
|
|
1059
1059
|
|
|
1060
|
-
`),s.trim()}buildHighlights(e){let t=[],s=e.find(i=>i.module==="bmw")?.data;if(s){let i=this.extractBatteryLevel(s);i!=null&&i<30&&t.push(`\u{1F697} BMW Akku bei ${i}% \u2014 laden empfohlen`)}let r=e.find(i=>i.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(i=>i.module==="energy")?.data;if(n){let i=n.currentCt,a=n.avgCt;i!=null&&a!=null&&i<a&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${i} ct/kWh)`)}let o=e.find(i=>i.module==="calendar")?.data;return Array.isArray(o)&&o.length>0&&t.push(`\u{1F4C5} ${o.length} Termin(e) heute`),t}extractBatteryLevel(e){if(!e||typeof e!="object")return null;let t=e,s=t.chargingLevelPercent??t.batterySoc??t.soc??t.chargingState?.chargingLevelPercent;if(typeof s=="number")return s;if(typeof s=="string"){let r=parseFloat(s);return isNaN(r)?null:r}return null}}});var
|
|
1060
|
+
`),s.trim()}buildHighlights(e){let t=[],s=e.find(i=>i.module==="bmw")?.data;if(s){let i=this.extractBatteryLevel(s);i!=null&&i<30&&t.push(`\u{1F697} BMW Akku bei ${i}% \u2014 laden empfohlen`)}let r=e.find(i=>i.module==="infra");r&&(!r.success||r.display?.includes("\u26A0\uFE0F"))&&t.push("\u{1F534} Infrastruktur-Warnung vorhanden");let n=e.find(i=>i.module==="energy")?.data;if(n){let i=n.currentCt,a=n.avgCt;i!=null&&a!=null&&i<a&&t.push(`\u26A1 Aktuell g\xFCnstiger Strom (${i} ct/kWh)`)}let o=e.find(i=>i.module==="calendar")?.data;return Array.isArray(o)&&o.length>0&&t.push(`\u{1F4C5} ${o.length} Termin(e) heute`),t}extractBatteryLevel(e){if(!e||typeof e!="object")return null;let t=e,s=t.chargingLevelPercent??t.batterySoc??t.soc??t.chargingState?.chargingLevelPercent;if(typeof s=="number")return s;if(typeof s=="string"){let r=parseFloat(s);return isNaN(r)?null:r}return null}}});var Js,Xu=T(()=>{"use strict";H();Js=class extends x{static{m(this,"FeedReaderSkill")}memoryRepo;metadata={name:"feed_reader",category:"information",description:"Subscribe to RSS/Atom feeds and check for new entries. Actions: subscribe, unsubscribe, list_feeds, check.",riskLevel:"read",version:"1.0.0",inputSchema:{type:"object",properties:{action:{type:"string",enum:["subscribe","unsubscribe","list_feeds","check","check_all"],description:"The action to perform"},url:{type:"string",description:"Feed URL (for subscribe, unsubscribe, check)"},label:{type:"string",description:"Human-readable label for the feed (for subscribe)"}},required:["action"]}};constructor(e){super(),this.memoryRepo=e}async execute(e,t){let s=e.action,r=e.url,n=t.userId;switch(s){case"subscribe":return this.subscribe(n,r,e.label);case"unsubscribe":return this.unsubscribe(n,r);case"list_feeds":return this.listFeeds(n);case"check":case"check_all":return this.check(n,r);default:return{success:!1,error:`Unknown action: ${s}`}}}async subscribe(e,t,s){if(!t)return{success:!1,error:"URL is required for subscribe"};let r={url:t,label:s??t,lastCheckedAt:null,lastEntryId:null};return this.memoryRepo.save(e,`feed:${t}`,JSON.stringify(r),"feed"),{success:!0,data:r,display:`Subscribed to feed: ${r.label} (${t})`}}async unsubscribe(e,t){return t?this.memoryRepo.delete(e,`feed:${t}`)?{success:!0,display:`Unsubscribed from feed: ${t}`}:{success:!1,error:`No subscription found for ${t}`}:{success:!1,error:"URL is required for unsubscribe"}}async listFeeds(e){let s=this.memoryRepo.listByCategory(e,"feed").map(n=>{try{return JSON.parse(n.value)}catch{return null}}).filter(Boolean);if(s.length===0)return{success:!0,data:[],display:"No feed subscriptions found."};let r=s.map(n=>`\u2022 ${n.label} \u2014 ${n.url} (last checked: ${n.lastCheckedAt??"never"})`);return{success:!0,data:s,display:`Feed subscriptions:
|
|
1061
1061
|
${r.join(`
|
|
1062
1062
|
`)}`}}async check(e,t){if(!t){let i=this.memoryRepo.listByCategory(e,"feed");if(i.length===0)return{success:!0,data:{newCount:0},display:"No feed subscriptions to check."};let a=0,c=[];for(let u of i)try{let p=JSON.parse(u.value),h=await this.checkSingleFeed(e,p);h.newCount>0&&(a+=h.newCount,c.push(h))}catch{}let d=c.map(u=>`${u.label}: ${u.newCount} new
|
|
1063
1063
|
${u.items.map(p=>` \u2022 ${p.title}${p.link?` \u2014 ${p.link}`:""}${p.snippet?`
|
|
@@ -1072,7 +1072,7 @@ ${o.join(`
|
|
|
1072
1072
|
`+l.slice(-Vu)}function Yu(l){let e=new Map;function t(s){let r;try{r=Ku.readdirSync(s,{withFileTypes:!0})}catch{return}for(let n of r){if(Cf.has(n.name))continue;let o=Ju.join(s,n.name);if(n.isDirectory())t(o);else if(n.isFile())try{let i=Ku.statSync(o);e.set(o,i.mtimeMs)}catch{}}}return m(t,"walk"),t(l),e}function Df(l,e,t){let s=[];for(let[r,n]of e){let o=l.get(r);(o===void 0||n>o)&&s.push(Ju.relative(t,r))}return s.sort()}async function Je(l,e,t={}){let s=t.cwd??l.cwd??process.cwd(),r=t.timeoutMs??l.timeoutMs??Rf,n=Math.min(r,xf),o=Lf(l.argsTemplate,e),i={...process.env,...l.env?Nf(l.env):{}},a=process.platform==="win32",c=Yu(s),d=Date.now();return new Promise(u=>{let p=If(l.command,o,{cwd:s,env:i,shell:a,stdio:l.promptVia==="stdin"?["pipe","pipe","pipe"]:["ignore","pipe","pipe"]}),h="",f="",g=!1,y=setTimeout(()=>{g=!0,p.kill("SIGTERM"),setTimeout(()=>p.kill("SIGKILL"),5e3)},n);p.stdout?.on("data",_=>{h+=_.toString()}),p.stderr?.on("data",_=>{let S=_.toString();if(f+=S,t.onProgress){let E=S.trim().split(`
|
|
1073
1073
|
`).pop();E&&t.onProgress(`[${l.name}] ${E}`)}}),l.promptVia==="stdin"&&p.stdin&&(p.stdin.write(e),p.stdin.end()),p.on("close",_=>{clearTimeout(y);let S=Date.now()-d,E=Yu(s),v=Df(c,E,s);u({stdout:Fo(h),stderr:Fo(f),exitCode:g?124:_??1,durationMs:S,modifiedFiles:v})}),p.on("error",_=>{clearTimeout(y);let S=Date.now()-d;u({stdout:Fo(h),stderr:Fo(f+`
|
|
1074
1074
|
`+_.message),exitCode:127,durationMs:S,modifiedFiles:[]})})})}var Rf,xf,Vu,Cf,jo=T(()=>{"use strict";Rf=3e5,xf=9e5,Vu=1e5,Cf=new Set([".git","node_modules",".next","dist",".cache"]);m(Nf,"resolveEnv");m(Lf,"buildArgs");m(Fo,"truncateOutput");m(Yu,"snapshotMtimes");m(Df,"detectModifiedFiles");m(Je,"executeAgent")});import{execFile as Mf}from"node:child_process";function Xe(l,e){return new Promise((t,s)=>{Mf("git",l,{cwd:e.cwd,maxBuffer:10*1024*1024},(r,n,o)=>{if(r){let i=o?.trim()||r.message;s(new Error(`git ${l[0]} failed: ${i}`));return}t(n.trim())})})}async function Bo(l){try{let e=await Xe(["rev-parse","--abbrev-ref","HEAD"],l),t=await Xe(["status","--porcelain"],l);return{isRepo:!0,branch:e,dirty:t.length>0}}catch{return{isRepo:!1,branch:"",dirty:!1}}}async function Pa(l,e){await Xe(["checkout","-b",l],e)}async function Ua(l){await Xe(["add","-A"],l)}async function Fa(l,e){await Xe(["commit","-m",l],e);let t=await Xe(["rev-parse","--short","HEAD"],e),r=(await Xe(["diff","--stat","HEAD~1","HEAD"],e)).split(`
|
|
1075
|
-
`).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function ja(l,e,t){await Xe(["push","-u",l,e],t)}function Ba(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function
|
|
1075
|
+
`).length-1;return{sha:t,message:l,filesChanged:Math.max(r,0)}}async function ja(l,e,t){await Xe(["push","-u",l,e],t)}function Ba(l){return`alfred/${l.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}`}async function Zs(l,e){try{return await Xe(["remote","get-url",l],e)}catch{return null}}function Qs(l){let e=l.match(/^git@([^:]+):(.+?)(?:\.git)?$/);if(e){let s=e[1],n=e[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}let t=l.match(/^https?:\/\/([^/]+)\/(.+?)(?:\.git)?$/);if(t){let s=t[1],n=t[2].split("/");if(n.length<2)return null;let o=n.pop();return{owner:n.join("/"),repo:o,baseUrl:`https://${s}`}}return null}async function Qr(l){await Xe(["init"],l)}async function en(l,e,t){await Xe(["remote","add",l,e],t)}var Ha=T(()=>{"use strict";m(Xe,"git");m(Bo,"gitStatus");m(Pa,"gitCreateBranch");m(Ua,"gitStageAll");m(Fa,"gitCommit");m(ja,"gitPush");m(Ba,"slugifyBranch");m(Zs,"gitGetRemoteUrl");m(Qs,"parseRemoteUrl");m(Qr,"gitInitRepo");m(en,"gitAddRemote")});function er(l){switch(l.provider){case"github":{if(!l.github)throw new Error('ForgeConfig.github is required when provider is "github"');return new Wa(l.github)}case"gitlab":{if(!l.gitlab)throw new Error('ForgeConfig.gitlab is required when provider is "gitlab"');return new za(l.gitlab)}default:throw new Error(`Unknown forge provider: ${l.provider}`)}}var qt,Wa,za,qa=T(()=>{"use strict";qt=class{static{m(this,"ForgeClient")}},Wa=class extends qt{static{m(this,"GitHubForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://api.github.com"}async createPullRequest(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/pulls`,r=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({title:t.title,body:t.body,head:t.head,base:t.base})});if(!r.ok){let o=await r.text();throw new Error(`GitHub PR creation failed (${r.status}): ${o}`)}let n=await r.json();return{id:n.id,url:n.html_url,number:n.number,state:n.state}}async getPipelineStatus(e,t){let s=`${this.baseUrl}/repos/${e.owner}/${e.repo}/commits/${t}/status`,r=await fetch(s,{headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json"}});if(!r.ok)return{state:"unknown"};let o=(await r.json()).state;return{state:{pending:"pending",success:"success",failure:"failure",error:"failure"}[o]??"unknown"}}async createProject(e){let t=`${this.baseUrl}/user/repos`,s=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,Accept:"application/vnd.github+json","Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",private:(e.visibility??"private")==="private"})});if(!s.ok){let n=await s.text();throw new Error(`GitHub project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.html_url,cloneUrl:r.clone_url}}},za=class extends qt{static{m(this,"GitLabForgeClient")}config;baseUrl;constructor(e){super(),this.config=e,this.baseUrl=e.baseUrl?.replace(/\/+$/,"")??"https://gitlab.com"}async createPullRequest(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/merge_requests`,n=await fetch(r,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({title:t.title,description:t.body,source_branch:t.head,target_branch:t.base})});if(!n.ok){let i=await n.text();throw new Error(`GitLab MR creation failed (${n.status}): ${i}`)}let o=await n.json();return{id:o.id,url:o.web_url,number:o.iid,state:o.state}}async getPipelineStatus(e,t){let s=encodeURIComponent(`${e.owner}/${e.repo}`),r=`${this.baseUrl}/api/v4/projects/${s}/pipelines?ref=${encodeURIComponent(t)}&per_page=1`,n=await fetch(r,{headers:{"PRIVATE-TOKEN":this.config.token}});if(!n.ok)return{state:"unknown"};let o=await n.json();if(o.length===0)return{state:"unknown"};let i=o[0],a=i.status;return{state:{pending:"pending",running:"running",success:"success",failed:"failure",canceled:"failure"}[a]??"unknown",url:i.web_url}}async createProject(e){let t=`${this.baseUrl}/api/v4/projects`,s=await fetch(t,{method:"POST",headers:{"PRIVATE-TOKEN":this.config.token,"Content-Type":"application/json"},body:JSON.stringify({name:e.name,description:e.description??"",visibility:e.visibility??"private"})});if(!s.ok){let n=await s.text();throw new Error(`GitLab project creation failed (${s.status}): ${n}`)}let r=await s.json();return{id:r.id,url:r.web_url,cloneUrl:r.http_url_to_repo}}};m(er,"createForgeClient")});function Zu(l,e){return l.length<=e?l:l.slice(0,e)+`
|
|
1076
1076
|
[...truncated]`}function Qu(l){let e=l.replace(/^```(?:json)?\s*\n?/m,"").replace(/\n?```\s*$/m,"");return JSON.parse(e)}async function Wf(l,e,t){let r=`Available agents:
|
|
1077
1077
|
${e.map(a=>`- ${a.name}: command="${a.command}"`).join(`
|
|
1078
1078
|
`)}
|
|
@@ -1087,9 +1087,9 @@ ${a}`:""].filter(Boolean).join(`
|
|
|
1087
1087
|
${l}
|
|
1088
1088
|
|
|
1089
1089
|
Results:
|
|
1090
|
-
${s}`,n=await t.complete({system:Hf,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=Qu(n.content);return{approved:o.approved??!0,summary:o.summary??"",fixTasks:Array.isArray(o.fixTasks)?o.fixTasks:[]}}catch{return{approved:!0,summary:n.content,fixTasks:[]}}}async function Gt(l,e,t,s={}){let r=Math.min(s.maxIterations??Of,Pf),n=s.maxConcurrent??Uf,o=s.onProgress,i=Date.now(),a=new Map(e.map(g=>[g.name,g]));o?.("Planning subtasks...");let c=await Wf(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,p=0,h="";for(;p<r;){p++,o?.(`Iteration ${p}: executing ${u.length} subtask(s)...`);let g=await zf(u,a,n,o);d=d.concat(g),o?.(`Iteration ${p}: validating results...`);let y=await qf(l,d,t);if(h=y.summary,y.approved||y.fixTasks.length===0)break;let _=y.fixTasks.filter(S=>a.has(S.agent)?!0:(o?.(`Warning: fix task "${S.id}" references unknown agent "${S.agent}", skipping`),!1));if(_.length===0)break;u=_,o?.(`Validation requested ${_.length} fix task(s), iterating...`)}let f=[...new Set(d.flatMap(g=>g.execution.modifiedFiles))].sort();return{plan:c,iterations:p,subtaskResults:d,allModifiedFiles:f,summary:h,totalDurationMs:Date.now()-i}}async function tn(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await Bo({cwd:n});if(!i.isRepo)try{await Qr({cwd:n}),i=await Bo({cwd:n}),r?.("Initialised new git repository")}catch{return o.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await Gt(l,e,t,s),git:o}}let a=null,c=await
|
|
1090
|
+
${s}`,n=await t.complete({system:Hf,messages:[{role:"user",content:r}],temperature:.2,tier:"strong"});try{let o=Qu(n.content);return{approved:o.approved??!0,summary:o.summary??"",fixTasks:Array.isArray(o.fixTasks)?o.fixTasks:[]}}catch{return{approved:!0,summary:n.content,fixTasks:[]}}}async function Gt(l,e,t,s={}){let r=Math.min(s.maxIterations??Of,Pf),n=s.maxConcurrent??Uf,o=s.onProgress,i=Date.now(),a=new Map(e.map(g=>[g.name,g]));o?.("Planning subtasks...");let c=await Wf(l,e,t);o?.(`Plan created: ${c.subtasks.length} subtask(s) \u2014 ${c.reasoning}`);let d=[],u=c.subtasks,p=0,h="";for(;p<r;){p++,o?.(`Iteration ${p}: executing ${u.length} subtask(s)...`);let g=await zf(u,a,n,o);d=d.concat(g),o?.(`Iteration ${p}: validating results...`);let y=await qf(l,d,t);if(h=y.summary,y.approved||y.fixTasks.length===0)break;let _=y.fixTasks.filter(S=>a.has(S.agent)?!0:(o?.(`Warning: fix task "${S.id}" references unknown agent "${S.agent}", skipping`),!1));if(_.length===0)break;u=_,o?.(`Validation requested ${_.length} fix task(s), iterating...`)}let f=[...new Set(d.flatMap(g=>g.execution.modifiedFiles))].sort();return{plan:c,iterations:p,subtaskResults:d,allModifiedFiles:f,summary:h,totalDurationMs:Date.now()-i}}async function tn(l,e,t,s={}){let r=s.onProgress,n=s.cwd??process.cwd(),o={warnings:[]},i=await Bo({cwd:n});if(!i.isRepo)try{await Qr({cwd:n}),i=await Bo({cwd:n}),r?.("Initialised new git repository")}catch{return o.warnings.push("Not a git repository and init failed \u2014 skipping git operations"),r?.("Warning: not a git repository, skipping git operations"),{...await Gt(l,e,t,s),git:o}}let a=null,c=await Zs("origin",{cwd:n});if(c){let f=Qs(c);f?(a={owner:f.owner,repo:f.repo},r?.(`Detected remote: ${f.owner}/${f.repo} (${f.baseUrl})`)):o.warnings.push(`Could not parse remote URL: ${c}`)}let d=s.forge;if(!c&&d)try{let f=er(d),g=n.split(/[\\/]/).pop()??"alfred-project";r?.(`No remote found \u2014 creating project "${g}" on forge...`);let y=await f.createProject({name:g,visibility:"private"});await en("origin",y.cloneUrl,{cwd:n});let _=Qs(y.cloneUrl);_&&(a={owner:_.owner,repo:_.repo}),r?.(`Project created: ${y.url} \u2014 remote "origin" set`)}catch(f){let g=f instanceof Error?f.message:String(f);o.warnings.push(`Project creation failed: ${g}`),r?.(`Warning: project creation failed \u2014 ${g}`)}let u=Ba(l);try{await Pa(u,{cwd:n}),o.branch=u,r?.(`Created branch: ${u}`)}catch(f){throw new Error(`Failed to create branch "${u}": ${f instanceof Error?f.message:String(f)}`)}let p=await Gt(l,e,t,s);try{await Ua({cwd:n});let f=`feat: ${l.slice(0,72)}
|
|
1091
1091
|
|
|
1092
|
-
Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,g=await Fa(f,{cwd:n});o.commit=g,r?.(`Committed: ${g.sha} (${g.filesChanged} files changed)`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Commit failed: ${g}`),r?.(`Warning: commit failed \u2014 ${g}`),{...p,git:o}}if(!await
|
|
1092
|
+
Orchestrated by Alfred (${p.iterations} iteration(s), ${p.allModifiedFiles.length} file(s))`,g=await Fa(f,{cwd:n});o.commit=g,r?.(`Committed: ${g.sha} (${g.filesChanged} files changed)`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Commit failed: ${g}`),r?.(`Warning: commit failed \u2014 ${g}`),{...p,git:o}}if(!await Zs("origin",{cwd:n}))return o.warnings.push("No remote configured \u2014 skipping push and PR creation"),r?.("No remote configured, skipping push and PR"),{...p,git:o};try{await ja("origin",u,{cwd:n}),r?.(`Pushed branch: ${u}`)}catch(f){let g=f instanceof Error?f.message:String(f);return o.warnings.push(`Push failed: ${g}`),r?.(`Warning: push failed \u2014 ${g}`),{...p,git:o}}if(d&&a)try{let f=er(d),g=s.baseBranch??d.baseBranch??"main",y=s.prTitle??`feat: ${l.slice(0,72)}`,_=["## Summary",p.summary,"",`**Iterations:** ${p.iterations}`,`**Modified files:** ${p.allModifiedFiles.length}`,p.allModifiedFiles.map(E=>`- \`${E}\``).join(`
|
|
1093
1093
|
`),"","_Automated by Alfred_"].join(`
|
|
1094
1094
|
`),S=await f.createPullRequest(a,{title:y,body:_,head:u,base:g});o.pullRequest=S,r?.(`PR created: ${S.url}`)}catch(f){let g=f instanceof Error?f.message:String(f);o.warnings.push(`PR creation failed: ${g}`),r?.(`Warning: PR creation failed \u2014 ${g}`)}else d||(o.warnings.push("No forge configured \u2014 skipping PR creation"),r?.("No forge configured, skipping PR creation"));return{...p,git:o}}var Of,Pf,Uf,Ff,jf,Bf,Hf,Ga,Xa=T(()=>{"use strict";jo();Ha();qa();Of=3,Pf=5,Uf=3,Ff=2048,jf=1024,Bf=`You are a task planner for a multi-agent coding system.
|
|
1095
1095
|
You receive a high-level task and a list of available coding agents.
|
|
@@ -1178,7 +1178,7 @@ Antworte als JSON:
|
|
|
1178
1178
|
"phases": ["Phase 1: ...", "Phase 2: ...", ...],
|
|
1179
1179
|
"buildStrategy": "npm install && npm run build && npm test",
|
|
1180
1180
|
"estimatedIterations": 4
|
|
1181
|
-
}`;m(un,"createProjectPlan")});var nm=T(()=>{"use strict";em();jo();Xa();Ha();qa();tm();sm();rm()});var ce={};pe(ce,{ActivityTracker:()=>Ut,BMWSkill:()=>xo,BackgroundTaskSkill:()=>
|
|
1181
|
+
}`;m(un,"createProjectPlan")});var nm=T(()=>{"use strict";em();jo();Xa();Ha();qa();tm();sm();rm()});var ce={};pe(ce,{ActivityTracker:()=>Ut,BMWSkill:()=>xo,BackgroundTaskSkill:()=>Fs,BriefingSkill:()=>Uo,BrowserSkill:()=>Os,CalculatorSkill:()=>bs,CalendarProvider:()=>We,CalendarSkill:()=>Ft,ClipboardSkill:()=>Ds,CodeAgentSkill:()=>sn,CodeExecutionSkill:()=>qr,CodeExecutor:()=>Ht,ConfigureSkill:()=>Ks,ContactsProvider:()=>Ge,ContactsSkill:()=>Kr,CrossPlatformSkill:()=>Us,DelegateSkill:()=>xs,DockerSkill:()=>Io,DocumentSkill:()=>Bs,EmailProvider:()=>at,EmailSkill:()=>gt,EnergyPriceSkill:()=>No,FeedReaderSkill:()=>Js,FileSkill:()=>Ns,ForgeClient:()=>qt,HomeAssistantSkill:()=>Eo,HttpSkill:()=>Cs,ImageGenerateSkill:()=>Ws,MCPClient:()=>jt,MCPManager:()=>zr,MCPSkillAdapter:()=>Bt,MarketplaceSkill:()=>Zr,MemorySkill:()=>Rs,MicrosoftTodoSkill:()=>Do,MonitorSkill:()=>Lo,NoteSkill:()=>$s,PluginLoader:()=>po,ProfileSkill:()=>Ps,ProjectAgentSkill:()=>nn,ProxmoxSkill:()=>ko,ReminderSkill:()=>vs,RoutingSkill:()=>Co,ScheduledTaskSkill:()=>js,ScreenshotSkill:()=>Ms,ShellSkill:()=>Is,Skill:()=>x,SkillRegistry:()=>_s,SkillSandbox:()=>ks,SystemInfoSkill:()=>Es,TTSSkill:()=>Hs,TodoSkill:()=>zs,TransitSkill:()=>Gs,UniFiSkill:()=>bo,WatchSkill:()=>Vs,WeatherSkill:()=>As,WebSearchSkill:()=>Ss,WorkflowSkill:()=>Ys,allUserIds:()=>Y,createCalendarProvider:()=>Wr,createContactsProvider:()=>va,createEmailProvider:()=>jr,createForgeClient:()=>er,createProjectPlan:()=>un,drainInterjections:()=>on,effectiveUserId:()=>de,executeAgent:()=>Je,gitAddRemote:()=>en,gitGetRemoteUrl:()=>Zs,gitInitRepo:()=>Qr,orchestrate:()=>Gt,orchestrateWithGit:()=>tn,parseRemoteUrl:()=>Qs,pushInterjection:()=>rn,registerAbortController:()=>an,removeAbortController:()=>cn,validateBuild:()=>dn});var re=T(()=>{"use strict";H();Me();pd();hd();la();fd();wd();Td();_d();kd();bd();Ed();$d();Ad();Id();Nd();Dd();Od();Pd();Fd();Bd();Hd();Kd();Vd();Yd();Jd();Qd();tu();su();ru();nu();ou();iu();au();pu();hu();Tu();$u();Au();Du();Mu();Uu();Fu();ju();Bu();Hu();qu();Gu();Xu();nm()});var mn,Va=T(()=>{"use strict";mn=class{static{m(this,"ConversationManager")}conversations;constructor(e){this.conversations=e}getOrCreateConversation(e,t,s){let r=this.conversations.findByPlatformChat(e,t);return r?(this.conversations.updateTimestamp(r.id),r):this.conversations.create(e,t,s)}addMessage(e,t,s,r){return this.conversations.addMessage(e,t,s,r)}getHistory(e,t=20){return this.conversations.getMessages(e,t)}pruneMessages(e,t){return this.conversations.pruneMessages(e,t)}}});function Ae(l,e){let t;if(e.platformUserId)t=l.findOrCreate(e.platform,e.platformUserId,e.userName,e.displayName);else if(e.userId)t=l.findById(e.userId)??l.findOrCreate(e.platform,e.userId);else throw new Error("ContextSource must provide either platformUserId or userId");let s="getMasterUserId"in l?l.getMasterUserId(t.id):t.id,r=[];"getLinkedUsers"in l&&(r=l.getLinkedUsers(s).map(a=>a.platformUserId));let n;try{"getProfile"in l?n=l.getProfile(s)?.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone:n=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{n=Intl.DateTimeFormat().resolvedOptions().timeZone}return{context:{userId:t.platformUserId,masterUserId:s,linkedPlatformUserIds:r,chatId:e.chatId,chatType:e.chatType,platform:e.platform,conversationId:e.conversationId??"",timezone:n},user:t,masterUserId:s,linkedPlatformUserIds:r}}var wt=T(()=>{"use strict";m(Ae,"buildSkillContext")});function om(l,e){let t=new Set(["core"]),s=!1;for(let[r,n]of Object.entries(Jf))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 im(l,e){return l.filter(t=>e.has(t.category??"core"))}var Jf,am=T(()=>{"use strict";Jf={productivity:/\b(todo|note|notiz|remind|erinner|calendar|kalender|termin|event|email|e-mail|mail|contact|kontakt|briefing|morgenbriefing|tagesbriefing)\b/i,information:/\b(search|such|weather|wetter|calculat|rechn|time|date|zeit|datum|uhrzeit|system.?info|transit|bahn|zug|bus|tram|u.?bahn|s.?bahn|abfahrt|verbindung|haltestelle|öffi|fahrplan|strom|energy|preis|price|kwh|awattar|marktpreis|spot|günstig|cheapest|netzentgelt|rss|feed|atom|news|nachricht|schlagzeil|headline)\b/i,media:/\b(voice|stimme|tts|speak|sprech|sprich|screenshot|clipboard|zwischenablage|brows|bild|image|generier|photo|foto)\b/i,automation:/\b(background|hintergrund|shell|bash|cron|schedul|code.?agent|sandbox|automat|watch|alert|benachrichtig|bescheid|meld|überwach|monitor|script|skript|befehl|kommando|tägliche?r?s?|stündliche?r?s?|wöchentliche?r?s?|monatliche?r?s?|jeden\s+(tag|morgen|abend|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag)|um\s+\d{1,2}\s*(uhr|:|h)|alle\s+\d+\s*(min|stund|sekund)|in\s+\d+\s*(minuten?|stunden?|sekunden?|hours?|minutes?|seconds?|min)|daily|hourly|weekly|every\s+(day|hour|morning|evening|night|\d+\s*min)|führ.{0,5}aus|execut|ausführ)\b/i,files:/\b(file|datei|document|dokument|pdf|http|download|upload|herunterlad|hochlad|anhang|attachment)\b/i,infrastructure:/\b(proxmox|vm|container|docker|unifi|wifi|wlan|netzwerk|network|homeassistant|home.?assistant|smarthome|smart.?home|licht|light|schalter|switch|solar|photovoltaik|pv|wechselrichter|inverter|batterie.?speicher|wallbox|energieverbrauch|stromverbrauch|verbrauch.{0,5}kwh|einspeis|netzeinspeis|autarkie|eigenverbrauch|bmw|auto|fahrzeug|ladestand|reichweite|laden(?!e)|charging|vehicle|soc|ladehistorie|ladesession|ladevorgang|ladezyklus|ladekurve|km|kilometer|kilometerstand|mileage|tachostand)\b/i,identity:/\b(link|verknüpf|cross.?platform|identity|identität)\b/i,mcp:/\bmcp\b/i};m(om,"selectCategories");m(im,"filterSkills")});import Ya from"node:fs";import cm from"node:path";function sg(l,e){if(l.length<=e)return l;let t=l.split(`
|
|
1182
1182
|
`);if(t.length<=10)return l.slice(0,e)+`
|
|
1183
1183
|
|
|
1184
1184
|
[... truncated, total `+l.length+" chars]";let s=Math.floor(t.length*.7),r=Math.max(Math.floor(t.length*.2),5),n=t.length-s-r,o=t.slice(0,s),i=t.slice(t.length-r),a=`
|
|
@@ -1276,7 +1276,7 @@ Extract memories from this conversation:
|
|
|
1276
1276
|
User: {USER_MESSAGE}
|
|
1277
1277
|
Assistant: {ASSISTANT_RESPONSE}
|
|
1278
1278
|
|
|
1279
|
-
Return ONLY a valid JSON array, no explanation:`,In=class{static{m(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,n=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=n}async extract(e,t,s){try{let r=gg.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),n=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),o=this.parseResponse(n.content);if(o.length===0)return 0;let i=0;for(let a of o)if(!(a.confidence<this.minConfidence))try{let c=this.memoryRepo.saveWithMetadata(e,a.key,a.value,a.category,a.type,a.confidence,"auto");this.embeddingService&&this.embeddingService.embedAndStore(e,`${a.key}: ${a.value}`,"memory",c.id).catch(d=>this.logger.debug({err:d},"Auto-embed failed")),i++,this.logger.info({key:a.key,type:a.type,confidence:a.confidence},"Auto-extracted memory saved")}catch(c){this.logger.warn({err:c,key:a.key},"Failed to save extracted memory")}return i}catch(r){return this.logger.error({err:r},"Memory extraction failed"),0}}parseResponse(e){try{let t=e.match(/\[[\s\S]*\]/);if(!t)return[];let s=JSON.parse(t[0]);return Array.isArray(s)?s.filter(r=>typeof r=="object"&&r!==null).map(r=>({key:String(r.key||""),value:String(r.value||""),type:this.validateType(String(r.type||"fact")),confidence:this.clampConfidence(Number(r.confidence)||.5),category:String(r.category||"general")})).filter(r=>r.key&&r.value):[]}catch{return this.logger.debug({content:e.slice(0,200)},"Failed to parse extraction response"),[]}}validateType(e){return fg.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});function Go(l){let e=l.trim();if(e.length<8)return{level:"low"};for(let t of yg)if(t.test(e))return{level:"high"};return{level:"low"}}var yg,hc=T(()=>{"use strict";yg=[/\b(nein,?\s*(nicht so|das ist falsch|das stimmt nicht|anders))\b/i,/\b(das war falsch|das ist falsch|das solltest du nicht)\b/i,/\b(ich meinte|ich wollte|ich habe gemeint)\b/i,/\b(tu das nicht|mach das nicht|lass das)\b/i,/\b(beim nächsten [Mm]al|in [Zz]ukunft|ab jetzt|ab sofort)\b/i,/\b(nicht wenn|nur wenn|nur falls|nur dann)\b/i,/\b(hör auf|stop|stopp).*\b(damit|das|mit)\b/i,/\b(das will ich nicht|das brauche ich nicht)\b/i,/\b(falsche?r?\s+(antwort|ergebnis|aktion|reaktion))\b/i,/\b(zu (oft|viel|aggressiv|häufig|früh|spät))\b/i,/\b(schwellenwert|threshold|grenzwert).*(ändern|anpassen|erhöhen|senken)\b/i,/\b(no,?\s*(not like that|that's wrong|don't do that))\b/i,/\b(that was wrong|that's incorrect|that's not what I)\b/i,/\b(I meant|I wanted|what I meant was)\b/i,/\b(don't do that|stop doing|never do)\b/i,/\b(next time|from now on|in the future|going forward)\b/i,/\b(not when|only when|only if|only then)\b/i,/\b(too (often|much|aggressive|frequent|early|late))\b/i];m(Go,"scanCorrectionSignal")});var Rn,fc=T(()=>{"use strict";mc();pc();hc();Rn=class{static{m(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;feedbackService;setFeedbackService(e){this.feedbackService=e}constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new In(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;this.feedbackService&&Go(t).level==="high"&&this.feedbackService.onConversationCorrection({userId:e,userMessage:t,assistantResponse:s});let r=uc(t);if(r.level==="low"){this.logger.debug({signal:"low"},"Skipping extraction \u2014 low signal");return}if(!this.checkRateLimit(e)){this.logger.debug({userId:e},"Skipping extraction \u2014 rate limit reached");return}this.logger.info({signal:r.level,patterns:r.matchedPatterns},"High signal detected, triggering extraction"),this.extractor.extract(e,t,s).then(n=>{n>0&&this.logger.info({userId:e,extractedCount:n},"Auto-extraction complete")}).catch(n=>{this.logger.error({err:n},"Auto-extraction failed")})}checkRateLimit(e){let t=Date.now(),s=t-6e4,r=this.extractionTimestamps.get(e);r||(r=[],this.extractionTimestamps.set(e,r));let n=r.filter(o=>o>s);return n.length===0?(this.extractionTimestamps.delete(e),!0):(this.extractionTimestamps.set(e,n),n.length>=this.maxExtractionsPerMinute?!1:(n.push(t),!0))}}});var
|
|
1279
|
+
Return ONLY a valid JSON array, no explanation:`,In=class{static{m(this,"MemoryExtractor")}llm;memoryRepo;logger;embeddingService;minConfidence;constructor(e,t,s,r,n=.4){this.llm=e,this.memoryRepo=t,this.logger=s,this.embeddingService=r,this.minConfidence=n}async extract(e,t,s){try{let r=gg.replace("{USER_MESSAGE}",t).replace("{ASSISTANT_RESPONSE}",s),n=await this.llm.complete({messages:[{role:"user",content:r}],temperature:.1,tier:"fast",maxTokens:1024}),o=this.parseResponse(n.content);if(o.length===0)return 0;let i=0;for(let a of o)if(!(a.confidence<this.minConfidence))try{let c=this.memoryRepo.saveWithMetadata(e,a.key,a.value,a.category,a.type,a.confidence,"auto");this.embeddingService&&this.embeddingService.embedAndStore(e,`${a.key}: ${a.value}`,"memory",c.id).catch(d=>this.logger.debug({err:d},"Auto-embed failed")),i++,this.logger.info({key:a.key,type:a.type,confidence:a.confidence},"Auto-extracted memory saved")}catch(c){this.logger.warn({err:c,key:a.key},"Failed to save extracted memory")}return i}catch(r){return this.logger.error({err:r},"Memory extraction failed"),0}}parseResponse(e){try{let t=e.match(/\[[\s\S]*\]/);if(!t)return[];let s=JSON.parse(t[0]);return Array.isArray(s)?s.filter(r=>typeof r=="object"&&r!==null).map(r=>({key:String(r.key||""),value:String(r.value||""),type:this.validateType(String(r.type||"fact")),confidence:this.clampConfidence(Number(r.confidence)||.5),category:String(r.category||"general")})).filter(r=>r.key&&r.value):[]}catch{return this.logger.debug({content:e.slice(0,200)},"Failed to parse extraction response"),[]}}validateType(e){return fg.includes(e)?e:"fact"}clampConfidence(e){return Math.max(0,Math.min(1,e))}}});function Go(l){let e=l.trim();if(e.length<8)return{level:"low"};for(let t of yg)if(t.test(e))return{level:"high"};return{level:"low"}}var yg,hc=T(()=>{"use strict";yg=[/\b(nein,?\s*(nicht so|das ist falsch|das stimmt nicht|anders))\b/i,/\b(das war falsch|das ist falsch|das solltest du nicht)\b/i,/\b(ich meinte|ich wollte|ich habe gemeint)\b/i,/\b(tu das nicht|mach das nicht|lass das)\b/i,/\b(beim nächsten [Mm]al|in [Zz]ukunft|ab jetzt|ab sofort)\b/i,/\b(nicht wenn|nur wenn|nur falls|nur dann)\b/i,/\b(hör auf|stop|stopp).*\b(damit|das|mit)\b/i,/\b(das will ich nicht|das brauche ich nicht)\b/i,/\b(falsche?r?\s+(antwort|ergebnis|aktion|reaktion))\b/i,/\b(zu (oft|viel|aggressiv|häufig|früh|spät))\b/i,/\b(schwellenwert|threshold|grenzwert).*(ändern|anpassen|erhöhen|senken)\b/i,/\b(no,?\s*(not like that|that's wrong|don't do that))\b/i,/\b(that was wrong|that's incorrect|that's not what I)\b/i,/\b(I meant|I wanted|what I meant was)\b/i,/\b(don't do that|stop doing|never do)\b/i,/\b(next time|from now on|in the future|going forward)\b/i,/\b(not when|only when|only if|only then)\b/i,/\b(too (often|much|aggressive|frequent|early|late))\b/i];m(Go,"scanCorrectionSignal")});var Rn,fc=T(()=>{"use strict";mc();pc();hc();Rn=class{static{m(this,"ActiveLearningService")}extractor;logger;minMessageLength;maxExtractionsPerMinute;extractionTimestamps=new Map;feedbackService;setFeedbackService(e){this.feedbackService=e}constructor(e){this.logger=e.logger,this.minMessageLength=e.minMessageLength??15,this.maxExtractionsPerMinute=e.maxExtractionsPerMinute??5,this.extractor=new In(e.llm,e.memoryRepo,this.logger,e.embeddingService,e.minConfidence??.4)}onMessageProcessed(e,t,s){if(!t||t.length<this.minMessageLength)return;this.feedbackService&&Go(t).level==="high"&&this.feedbackService.onConversationCorrection({userId:e,userMessage:t,assistantResponse:s});let r=uc(t);if(r.level==="low"){this.logger.debug({signal:"low"},"Skipping extraction \u2014 low signal");return}if(!this.checkRateLimit(e)){this.logger.debug({userId:e},"Skipping extraction \u2014 rate limit reached");return}this.logger.info({signal:r.level,patterns:r.matchedPatterns},"High signal detected, triggering extraction"),this.extractor.extract(e,t,s).then(n=>{n>0&&this.logger.info({userId:e,extractedCount:n},"Auto-extraction complete")}).catch(n=>{this.logger.error({err:n},"Auto-extraction failed")})}checkRateLimit(e){let t=Date.now(),s=t-6e4,r=this.extractionTimestamps.get(e);r||(r=[],this.extractionTimestamps.set(e,r));let n=r.filter(o=>o>s);return n.length===0?(this.extractionTimestamps.delete(e),!0):(this.extractionTimestamps.set(e,n),n.length>=this.maxExtractionsPerMinute?!1:(n.push(t),!0))}}});var tr,gc=T(()=>{"use strict";tr=class{static{m(this,"FeedbackService")}feedbackRepo;memoryRepo;logger;threshold;staleDays;constructor(e,t,s,r){this.feedbackRepo=e,this.memoryRepo=t,this.logger=s,this.threshold=r?.rejectionThreshold??3,this.staleDays=r?.staleDays??90}onWatchRejected(e){this.handleWatchRejection(e).catch(t=>{this.logger.error({err:t},"Feedback: watch rejection handling failed")})}onConversationCorrection(e){this.handleCorrection(e).catch(t=>{this.logger.error({err:t},"Feedback: conversation correction handling failed")})}async runMaintenance(){try{let e=this.feedbackRepo.pruneOldEvents(this.staleDays*2);e>0&&this.logger.info({pruned:e},"Feedback: pruned old events")}catch(e){this.logger.error({err:e},"Feedback: maintenance failed")}}async handleWatchRejection(e){let t=`watch:${e.watchName.toLowerCase().replace(/\s+/g,"_")}:${e.skillName}`;this.feedbackRepo.recordEvent(e.userId,"watch_rejection",e.watchId,t,e.description,{skillName:e.skillName,skillParams:e.skillParams});let s=this.feedbackRepo.countEvents(e.userId,t);if(this.logger.debug({contextKey:t,count:s,threshold:this.threshold},"Feedback: watch rejection recorded"),s>=this.threshold){let r=`feedback:${t}`,n=`Watch "${e.watchName}" wurde ${s}\xD7 abgelehnt. Schwellenwert oder Parameter \xFCberpr\xFCfen bevor diese Aktion vorgeschlagen wird.`;this.memoryRepo.saveWithMetadata(e.userId,r,n,"automation","feedback",.9,"auto"),this.logger.info({contextKey:t,count:s,memoryKey:r},"Feedback: watch rejection promoted to feedback memory")}}async handleCorrection(e){let t=new Date().toISOString().slice(0,10),s=`correction:${e.userId}:${t}`,r=this.extractCorrectionRule(e.userMessage);if(!r)return;this.feedbackRepo.recordEvent(e.userId,"conversation_correction",void 0,s,r,{userMessage:e.userMessage.slice(0,500)});let n=`feedback:correction:${Date.now()}`;this.memoryRepo.saveWithMetadata(e.userId,n,r,"general","feedback",.8,"auto"),this.logger.info({rule:r},"Feedback: conversation correction saved as feedback memory")}extractCorrectionRule(e){let t=e.trim();return t.length>10&&t.length<300?`Nutzer-Korrektur: ${t}`:t.length>=300?`Nutzer-Korrektur: ${t.slice(0,280)}...`:null}}});var wg,Tg,_g,kg,xn,yc=T(()=>{"use strict";wg=Math.LN2,Tg=.3,_g=.7,kg=3,xn=class{static{m(this,"MemoryRetriever")}memoryRepo;logger;embeddingService;constructor(e,t,s){this.memoryRepo=e,this.logger=t,this.embeddingService=s}async retrieve(e,t,s=15,r){let n=[e];if(r)for(let o of r)o!==e&&n.push(o);try{let o=new Set,i=[];for(let g of n)for(let y of this.memoryRepo.keywordSearch(g,t,30))o.has(y.id)||(o.add(y.id),i.push(y));let a=[],c=!1;if(this.embeddingService)try{let g=new Set;for(let y of n)for(let _ of await this.embeddingService.semanticSearch(y,t,30))g.has(_.key)||(g.add(_.key),a.push(_));c=a.length>0}catch(g){this.logger.debug({err:g},"Semantic search failed, falling back to keyword-only")}let d=new Map,u=i.length;for(let g=0;g<i.length;g++){let y=i[g],_=u>0?1-g/u:0,S=c?Tg:1,E=this.applyBoosts(_*S,y);d.set(y.key,{memory:{key:y.key,value:y.value,category:y.category,type:y.type,score:E},score:E}),this.memoryRepo.recordAccess(y.id)}if(c)for(let g of a){let y=g.score*_g,_=d.get(g.key);if(_)_.score+=y,_.memory.score=_.score;else{let S=this.memoryRepo.recall(e,g.key),E=this.applyBoosts(y,S||void 0);d.set(g.key,{memory:{key:g.key,value:g.value,category:g.category,type:S?.type||"general",score:E},score:E}),S&&this.memoryRepo.recordAccess(S.id)}}let p=Array.from(d.values()).sort((g,y)=>y.score-g.score),h=new Map,f=[];for(let{memory:g}of p){let y=h.get(g.type)||0;if(!(y>=kg)&&(h.set(g.type,y+1),f.push(g),f.length>=s))break}return this.logger.debug({keywordCount:i.length,semanticCount:a.length,resultCount:f.length,hasSemanticSearch:c},"Hybrid memory retrieval complete"),f}catch(o){this.logger.error({err:o},"Memory retrieval failed");let i=new Set,a=[];for(let c of n)for(let d of this.memoryRepo.getRecentForPrompt(c,s))i.has(d.key)||(i.add(d.key),a.push({key:d.key,value:d.value,category:d.category,type:d.type,score:0}));return a.slice(0,s)}}applyBoosts(e,t){let s=e;if(t){s*=.5+.5*t.confidence;let r=new Date(t.updatedAt).getTime(),n=Date.now()-r,o=Math.exp(-wg*n/2592e6);s*=o}return s}}});var Cn,wc=T(()=>{"use strict";Cn=class{static{m(this,"ConversationSummarizer")}llm;summaryRepo;logger;constructor(e,t,s){this.llm=e,this.summaryRepo=t,this.logger=s}getSummary(e){return this.summaryRepo.get(e)}onMessageProcessed(e,t,s,r,n){let o=this.summaryRepo.get(e);!o&&t<6||o&&t-o.messageCount<3||this.updateSummary(e,t,s,r,n,o).catch(i=>this.logger.warn({err:i,conversationId:e},"Failed to update conversation summary"))}async updateSummary(e,t,s,r,n,o){let i=this.buildSummaryPrompt(o?.summary,n,s,r),c=(await this.llm.complete({messages:[{role:"user",content:i}],temperature:.1,tier:"fast",maxTokens:512})).content?.trim();if(!c||c.length<10){this.logger.debug({conversationId:e},"Summary response too short, skipping upsert");return}this.summaryRepo.upsert({conversationId:e,summary:c,messageCount:t,lastUserMessage:s.slice(0,500),lastAssistantMessage:r.slice(0,500),updatedAt:new Date().toISOString()}),this.logger.debug({conversationId:e,messageCount:t,summaryLength:c.length},"Conversation summary updated")}buildSummaryPrompt(e,t,s,r){let n=`Du bist ein Zusammenfassungs-Assistent. Erstelle eine strukturierte Zusammenfassung des Gespr\xE4chsverlaufs.
|
|
1280
1280
|
`;if(e&&(n+=`
|
|
1281
1281
|
## Bisherige Zusammenfassung
|
|
1282
1282
|
${e}
|
|
@@ -1399,11 +1399,11 @@ Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leav
|
|
|
1399
1399
|
Goodbye!
|
|
1400
1400
|
`),this.emit("disconnected");return}this.messageCounter++;let s={id:`cli-${this.messageCounter}`,platform:"cli",chatId:"cli-chat",chatType:"dm",userId:"cli-user",userName:"cli-user",displayName:"You",text:t,timestamp:new Date};this.emit("message",s)}),this.rl.on("close",()=>{this.emit("disconnected")}),this.status="connected",this.emit("connected"),this.prompt()}async disconnect(){this.rl?.close(),this.rl=void 0,this.status="disconnected"}async sendMessage(e,t,s){let r=`cli-resp-${++this.messageCounter}`;return process.stdout.write(`
|
|
1401
1401
|
Alfred: ${t}
|
|
1402
|
-
`),this.prompt(),r}async editMessage(e,t,s,r){xc.clearLine(process.stdout,0),xc.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import Ng from"node:http";import
|
|
1402
|
+
`),this.prompt(),r}async editMessage(e,t,s,r){xc.clearLine(process.stdout,0),xc.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import Ng from"node:http";import Kt from"node:fs";import sr from"node:path";import ti from"node:crypto";var Lg,Sm,si,vm=T(()=>{"use strict";ct();Lg={".html":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".js":"application/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".txt":"text/plain; charset=utf-8"},Sm=1048576,si=class extends ye{static{m(this,"HttpAdapter")}platform="api";server=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;dashboardFn;webUiPath;webhooks=new Map;constructor(e,t,s){if(super(),this.port=e,this.host=t,this.apiToken=s?.apiToken,this.corsOrigin=s?.corsOrigin??"http://localhost:3420",this.healthCheckFn=s?.healthCheck,this.metricsFn=s?.metricsCallback,this.dashboardFn=s?.dashboardCallback,this.webUiPath=s?.webUiPath,s?.webhooks)for(let r of s.webhooks)this.webhooks.set(r.name,r)}addWebhook(e){this.webhooks.set(e.name,e)}async connect(){this.status="connecting",this.server=Ng.createServer((e,t)=>{this.handleRequest(e,t)}),await new Promise((e,t)=>{this.server.listen(this.port,this.host,()=>{e()}),this.server.once("error",t)}),this.status="connected",this.emit("connected")}async disconnect(){for(let[e,t]of this.streams)this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e);this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.status="disconnected",this.emit("disconnected")}async sendMessage(e,t,s){let r=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),r}async editMessage(e,t,s,r){let n=this.streams.get(e);n&&this.writeSseEvent(n,"status",{type:"status",text:s})}async deleteMessage(e,t){}async sendPhoto(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,r){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:r}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let r=this.streams.get(e);return r&&this.writeSseEvent(r,"attachment",{type:"attachment",attachmentType:"voice",data:t.toString("base64"),caption:s}),`api-voice-${++this.messageCounter}`}endStream(e){let t=this.streams.get(e);t&&(this.writeSseEvent(t,"done",{type:"done"}),t.end(),this.streams.delete(e))}handleRequest(e,t){if(t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Access-Control-Allow-Origin",this.corsOrigin),t.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.method==="OPTIONS"){t.writeHead(204),t.end();return}let s=new URL(e.url??"/",`http://${e.headers.host??"localhost"}`);if(s.pathname==="/api/health"&&e.method==="GET")this.handleHealth(t);else if(s.pathname==="/api/metrics"&&e.method==="GET")this.handleMetrics(t);else if(s.pathname==="/api/message"&&e.method==="POST")this.handleMessage(e,t);else if(s.pathname==="/api/dashboard"&&e.method==="GET")this.handleDashboard(e,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let r=s.pathname.slice(13);this.handleWebhook(e,t,r)}else this.webUiPath&&s.pathname.startsWith("/alfred/")&&e.method==="GET"?this.serveStaticFile(s.pathname,t):this.webUiPath&&s.pathname==="/alfred"&&e.method==="GET"?(t.writeHead(302,{Location:"/alfred/"}),t.end()):(t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"})))}checkAuth(e,t){if(!this.apiToken)return!0;let s=e.headers.authorization,r=`Bearer ${this.apiToken}`;return!s||s.length!==r.length||!ti.timingSafeEqual(Buffer.from(s),Buffer.from(r))?(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1):!0}handleDashboard(e,t){if(this.checkAuth(e,t)){if(!this.dashboardFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard not configured"}));return}try{let s=this.dashboardFn();t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}catch{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Dashboard data fetch failed"}))}}}serveStaticFile(e,t){if(!this.webUiPath){t.writeHead(404),t.end();return}let s=e.replace(/^\/alfred/,"");(!s||s==="/")&&(s="/index.html");let r=sr.resolve(this.webUiPath,"."+s);if(!r.startsWith(sr.resolve(this.webUiPath))){t.writeHead(403),t.end();return}let n=r;if(!Kt.existsSync(n))if(Kt.existsSync(n+".html"))n=n+".html";else if(Kt.existsSync(sr.join(n,"index.html")))n=sr.join(n,"index.html");else{t.writeHead(404,{"Content-Type":"text/html"}),t.end("Not found");return}try{if(Kt.statSync(n).isDirectory()){let u=sr.join(n,"index.html");if(Kt.existsSync(u))n=u;else{t.writeHead(404),t.end();return}}}catch{t.writeHead(404),t.end();return}let o=Kt.statSync(n),i=sr.extname(n).toLowerCase(),a=Lg[i]??"application/octet-stream",c=i===".html"?"no-cache":"public, max-age=31536000, immutable";t.writeHead(200,{"Content-Type":a,"Content-Length":o.size,"Cache-Control":c}),Kt.createReadStream(n).pipe(t)}handleHealth(e){let t=this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",r=s==="ok"?200:503;e.writeHead(r,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(this.metricsFn())):this.handleHealth(e)}handleMessage(e,t){if(!this.checkAuth(e,t))return;let s="",r=0,n=!1;e.on("data",o=>{if(!n){if(r+=o.length,r>Sm){n=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}s+=o.toString()}}),e.on("end",()=>{if(!n)try{let o=JSON.parse(s),i=o.text;if(!i||typeof i!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:'Missing or invalid "text" field'}));return}let a=o.chatId??`api-chat-${ti.randomUUID()}`,c=o.userId??"api-user",d=this.streams.get(a);d&&(this.writeSseEvent(d,"done",{type:"done"}),d.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),this.streams.set(a,t),e.on("close",()=>{this.streams.delete(a)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:a,chatType:"dm",userId:c,userName:c,displayName:"API User",text:i,timestamp:new Date};this.emit("message",u)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON body"}))}})}handleWebhook(e,t,s){let r=this.webhooks.get(s);if(!r){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`Webhook "${s}" not found`}));return}let n="",o=0,i=!1;e.on("data",a=>{if(!i){if(o+=a.length,o>Sm){i=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}n+=a.toString()}}),e.on("end",async()=>{if(i)return;let a=e.headers["x-webhook-signature"];if(!a){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing X-Webhook-Signature header"}));return}let c=ti.createHmac("sha256",r.secret).update(n).digest(),d=Buffer.from(a,"hex");if(d.length!==c.length||!ti.timingSafeEqual(d,c)){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid signature"}));return}try{let u=JSON.parse(n);await r.callback(u),t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({ok:!0}))}catch(u){t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:u instanceof Error?u.message:"Internal error"}))}})}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
|
|
1403
1403
|
data: ${JSON.stringify(s)}
|
|
1404
1404
|
|
|
1405
|
-
`)}}});var _t={};pe(_t,{CLIAdapter:()=>ei,DiscordAdapter:()=>Yo,HttpAdapter:()=>si,MatrixAdapter:()=>Jo,MessagingAdapter:()=>ye,SignalAdapter:()=>Qo,TelegramAdapter:()=>Ko,WhatsAppAdapter:()=>Zo});var kt=T(()=>{"use strict";ct();wm();Tm();_m();km();bm();Em();vm()});import rr from"node:fs";import Oe from"node:path";import Dg from"js-yaml";var Kt,$m=T(()=>{"use strict";Gi();co();nt();aa();mo();re();Va();Ja();Za();Qa();ec();tc();sc();rc();nc();oc();ic();ac();cc();mm();dc();fc();gc();yc();wc();Tc();_c();kc();bc();vc();$c();Kt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new Tn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=Ar("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new mt(this.config.storage.path);let e=this.database.getDb(),t=new Qt(e),s=new es(e);this.userRepo=s;let r=new pt(e);this.auditRepo=r;let n=new ts(e);this.memoryRepo=n;let o=new ss(e),i=new rs(e),a=new ns(e),c=new os(e),d=new is(e),u=new cs(e);this.scheduledActionRepo=u;let p=new ft(e);this.activityRepo=p;let h=new Dn(p,this.logger.child({component:"activity"})),f=new fs(e);this.skillHealthRepo=f;let g=new Mn(f,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new Ur,_=this.loadSecurityRules();y.loadRules(_);let S=new Fr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:_.length},"Security engine initialized");let E=oa(this.config.llm,this.logger.child({component:"llm"}));await E.initialize(),this.llmProvider=E;let v=new hs(e);this.usageRepo=v,E.setPersist((C,j,Z,te,Se,or)=>{v.record(C,j,Z,te,Se,or)});let I=new _n(E,a,this.logger.child({component:"embeddings"})),M=this.config.activeLearning?.enabled!==!1,q,G;M&&(q=new Rn({llm:E,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:I,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),G=new xn(n,this.logger.child({component:"memory-retriever"}),I),this.logger.info("Active learning & memory retriever initialized"));let P=new ps(e);this.summaryRepo=P;let ee=new Cn(E,P,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ue=new _s(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new Ts;L.register(new ks),L.register(new bs),L.register(new Es(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new Ss(o)),L.register(new vs(i));let ne=new ds(e);if(L.register(new Ws(ne)),L.register(new $s),L.register(new As),L.register(new Is(n,I)),L.register(new Rs(E,L,ue,S)),this.config.email?.accounts?.length){let C=new Map;for(let Z of this.config.email.accounts)try{Z.provider==="microsoft"&&!Z.microsoft?.clientId&&this.config.calendar?.microsoft&&(Z.microsoft={...this.config.calendar.microsoft});let te=await jr(Z);C.set(Z.name,te),this.logger.info({account:Z.name,provider:Z.provider??"imap-smtp"},"Email account initialized")}catch(te){this.logger.warn({err:te,account:Z.name},"Email account initialization failed, skipping")}let j=C.size>0?new gt(C):new gt;j.setLLM(E),L.register(j)}else{let C=new gt;C.setLLM(E),L.register(C)}L.register(new xs),L.register(new Cs);let ie=new Xs;ie.setReloadCallback(C=>this.reloadService(C)),L.register(ie),L.register(new Ls),L.register(new Ds),L.register(new Ms),L.register(new Os(s)),L.register(new Ps(s,c,this.adapters,(C,j)=>t.findByPlatformAndUser(C,j)));let Q=new Us(d);L.register(Q),L.register(new Fs(u));let B=new ls(e),he=new kn(B,I,this.logger.child({component:"documents"}));L.register(new js(B,he,I));let Ke,le;if(this.config.calendar)try{le=await Wr(this.config.calendar),Ke=new Ft(le),L.register(Ke),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(C){this.logger.warn({err:C},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Ke,le&&this.config.calendar?.vorlauf?.enabled){let C=new ht(e),j=this.config.security?.ownerUserId;j&&(this.calendarWatcher=new Nn(le,C,this.adapters,j,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let C=this.config.security?.ownerUserId;if(C){let j=new ht(e);this.todoWatcher=new Ln(ne,j,this.adapters,C,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(re(),ce));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let j of this.mcpManager.getSkills())L.register(j);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},E)),this.logger.info({agents:this.config.codeAgents.agents.map(j=>j.name)},"Code agent skill enabled")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:C}=await Promise.resolve().then(()=>(re(),ce)),{ProjectAgentSessionRepository:j}=await Promise.resolve().then(()=>(co(),sd)),Z=new j(e),te=new C({...this.config.projectAgents,agents:this.config.codeAgents.agents},E,Z),{ProjectAgentRunner:Se}=await Promise.resolve().then(()=>(Ac(),gm)),or=new Se(new Map(this.config.codeAgents.agents.map(ir=>[ir.name,ir])),E,Z,this.adapters,this.logger.child({component:"project-agent"}));te.setRunner(or),L.register(te),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:C,createContactsProvider:j}=await Promise.resolve().then(()=>(re(),ce)),Z=await j(this.config.contacts);L.register(new C(Z)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(C){this.logger.warn({err:C},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant,proxmoxBackup:this.config.proxmoxBackup})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(L,this.config,n)),this.logger.info("Briefing skill registered")}L.register(new Ys(n)),this.logger.info("Feed reader skill registered"),this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let Ee;if(this.config.speech?.apiKey&&(Ee=new fn(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let C=new gn(this.config.speech,this.logger.child({component:"tts"}));L.register(new Bs(C)),this.logger.info("Text-to-speech skill registered")}let me=this.detectImageGenProvider();if(me){let C=new yn(me,this.logger.child({component:"image-gen"}));L.register(new Hs(C)),this.logger.info({provider:me.provider},"Image generation skill registered")}try{let C=new wn(this.logger.child({component:"transit"}));L.register(new qs(C)),this.logger.info("Public transit skill registered")}catch(C){this.logger.warn({err:C},"Failed to register transit skill")}let Pe=new mn(t),Ze=Oe.resolve(Oe.dirname(this.config.storage.path),"inbox");this.pipeline=new pn({llm:E,conversationManager:Pe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:ue,securityManager:S,memoryRepo:n,speechTranscriber:Ee,inboxPath:Ze,embeddingService:I,activeLearning:q,memoryRetriever:G,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:he,conversationSummarizer:ee}),this.reminderScheduler=new hn(o,async(C,j,Z)=>{let te=this.adapters.get(C);te?await te.sendMessage(j,Z):this.logger.warn({platform:C,chatId:j},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:m(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:m((C,j)=>t.findByPlatformAndUser(C,j),"findConversation")}),this.backgroundTaskRunner=new bn(L,ue,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,g);let Ve=new En(L,ue,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ve),Q.setPersistentRunner(Ve),this.proactiveScheduler=new Sn(u,L,ue,E,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Pe,h);let Qe=new us(e);this.watchRepo=Qe,L.register(new Ks(Qe,L));let De=new ms(e);this.confirmationQueue=new An(De,L,ue,this.adapters,this.logger.child({component:"confirmation-queue"}),h);let Et=new ys(e),St=new er(Et,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(St),q&&q.setFeedbackService(St),this.watchEngine=new qo(Qe,L,ue,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,g,E);let et=new gs(e),X=new Vs(et);L.register(X);let z=new On(et,L,ue,this.logger.child({component:"workflow-runner"}),h,g);X.setRunner(z);{let C=this.config.security?.ownerUserId;if(C&&this.config.reasoning?.enabled!==!1){let j=new ht(e);this.reasoningEngine=new Un(le,ne,Qe,n,p,f,j,L,ue,E,this.adapters,s,C,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h,this.config.briefing?.location,Et,this.confirmationQueue)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(g),await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>{let n;try{let o=this.config.storage.path,i=rr.statSync(o);n={path:o,sizeBytes:i.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([o,i])=>[o,i.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:this.watchRepo?.countEnabled()??0,schedulersActive:this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:m(()=>({watches:this.watchRepo?.getEnabled()??[],scheduled:this.scheduledActionRepo?.getAll()??[],skillHealth:this.skillHealthRepo?.getAll()??[]}),"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:r,webUi:e.api?.webUi!==!1},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:m(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let o=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,o)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:this.auditRepo?.cleanup(90)??0,summaries:this.summaryRepo?.cleanup(180)??0,activity:this.activityRepo?.cleanup(90)??0,usage:this.usageRepo?.cleanup(365)??0,expiredMemories:this.memoryRepo?.cleanupExpired()??0};(e.audit||e.summaries||e.activity||e.usage)&&this.logger.info(e,"Startup DB cleanup completed")}catch(e){this.logger.warn({err:e},"Startup DB cleanup failed")}this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.adapters.size===0&&this.logger.warn("No messaging adapters enabled. Configure at least one platform."),this.logger.info(`Alfred is running with ${this.adapters.size} adapter(s)`)}async startWithCLI(){this.adapters.clear();let{CLIAdapter:e}=await Promise.resolve().then(()=>(kt(),_t)),t=new e;this.adapters.set("cli",t),t.on("disconnected",()=>{this.stop().then(()=>process.exit(0))}),await this.start()}async stop(){this.logger.info("Stopping Alfred..."),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(r=>setTimeout(r,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(r){this.logger.error({platform:t,err:r},"Failed to disconnect adapter")}try{this.database&&(this.database.getDb().pragma("wal_checkpoint(TRUNCATE)"),this.database.close())}catch{}this.logger.info("Alfred stopped")}async reloadService(e){try{zi();let t=new fe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce)),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(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce));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=Oe.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Oe.join(process.cwd(),"web-ui"),Oe.join(e,"..","web-ui"),Oe.join(e,"web-ui"),Oe.join(e,"..","..","web-ui"),Oe.join(e,"..","..","apps","web","out")];for(let s of t)try{let r=Oe.resolve(s);if(rr.existsSync(Oe.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")}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),o=this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${o.totalCostUsd}`),e.push("# HELP alfred_llm_today_calls Total LLM calls today (persisted)"),e.push("# TYPE alfred_llm_today_calls gauge"),e.push(`alfred_llm_today_calls ${o.totalCalls}`)}return e.push(""),e.join(`
|
|
1406
|
-
`)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async a=>{if(a!==n){n=a;try{r?await t.editMessage(s.chatId,r,a):r=await t.sendMessage(s.chatId,a)}catch(c){this.logger.debug({err:c,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o);if(i.text){let a=this.formatter.format(i.text,s.platform),c=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,c)}catch(d){this.logger.debug({err:d,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,a.text,c)}else await t.sendMessage(s.chatId,a.text,c)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let u=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,u.text)}}if(i.attachments)for(let a of i.attachments)try{let c=a.mimeType?.startsWith("image/")??!1,d=a.mimeType==="audio/ogg"||a.mimeType==="audio/opus";c?await t.sendPhoto(s.chatId,a.data,a.fileName):d?await t.sendVoice(s.chatId,a.data):await t.sendFile(s.chatId,a.data,a.fileName)}catch(c){this.logger.warn({err:c,fileName:a.fileName,chatId:s.chatId},"Failed to send attachment")}t.endStream(s.chatId)}catch(r){this.logger.error({platform:e,err:r,chatId:s.chatId},"Failed to handle message");try{await t.sendMessage(s.chatId,"Sorry, I encountered an error processing your message. Please try again.")}catch(n){this.logger.error({err:n},"Failed to send error message")}t.endStream(s.chatId)}}),t.on("error",s=>{this.logger.error({platform:e,err:s},"Adapter error")}),t.on("connected",()=>{this.logger.info({platform:e},"Adapter connected")}),t.on("disconnected",()=>{this.logger.warn({platform:e},"Adapter disconnected")})}detectImageGenProvider(){let e=["default","strong","fast","embeddings","local"];for(let t of["openai","google"])for(let s of e){let r=this.config.llm[s];if(r?.provider===t&&r.apiKey)return{provider:t,apiKey:r.apiKey,baseUrl:r.baseUrl}}}loadSecurityRules(){let e=Oe.resolve(this.config.security.rulesPath),t=[];if(!rr.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!rr.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=rr.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=Oe.join(e,n),i=rr.readFileSync(o,"utf-8"),a=Dg.load(i);if(a?.rules&&Array.isArray(a.rules)){let d=new it().loadFromObject({rules:a.rules});t.push(...d),this.logger.info({file:n,count:d.length},"Loaded security rules")}}catch(o){this.logger.error({err:o,file:n},"Failed to load security rules file")}return t}}});var Am=T(()=>{"use strict"});var Cc=T(()=>{"use strict";gc();hc()});var Nc=T(()=>{"use strict";$m();Ja();Va();Za();Qa();ec();rc();nc();ic();ac();cc();wt();oc();tc();sc();fc();yc();pc();Am();mc();wc();vn();Sc();dc();Cc();Ac();Cc();Tc();_c();kc();zo();bc();vc();$c()});import ri from"node:fs";import Im from"node:path";import Mg from"node:os";function Rm(){try{let l=ri.readFileSync(Lc,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function xm(l){try{let e=Im.dirname(Lc);ri.existsSync(e)||ri.mkdirSync(e,{recursive:!0}),ri.writeFileSync(Lc,JSON.stringify(l,null,2),"utf-8")}catch{}}async function
|
|
1405
|
+
`)}}});var _t={};pe(_t,{CLIAdapter:()=>ei,DiscordAdapter:()=>Yo,HttpAdapter:()=>si,MatrixAdapter:()=>Jo,MessagingAdapter:()=>ye,SignalAdapter:()=>Qo,TelegramAdapter:()=>Ko,WhatsAppAdapter:()=>Zo});var kt=T(()=>{"use strict";ct();wm();Tm();_m();km();bm();Em();vm()});import rr from"node:fs";import Oe from"node:path";import Dg from"js-yaml";var Vt,$m=T(()=>{"use strict";Gi();co();nt();aa();mo();re();Va();Ja();Za();Qa();ec();tc();sc();rc();nc();oc();ic();ac();cc();mm();dc();fc();gc();yc();wc();Tc();_c();kc();bc();vc();$c();Vt=class{static{m(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;confirmationQueue;adapters=new Map;formatter=new Tn;userRepo;skillRegistry;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;usageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;watchRepo;scheduledActionRepo;skillHealthRepo;skillHealthTracker;healthCheckTimer;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=Ar("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=new mt(this.config.storage.path);let e=this.database.getDb(),t=new es(e),s=new ts(e);this.userRepo=s;let r=new pt(e);this.auditRepo=r;let n=new ss(e);this.memoryRepo=n;let o=new rs(e),i=new ns(e),a=new os(e),c=new is(e),d=new as(e),u=new ls(e);this.scheduledActionRepo=u;let p=new ft(e);this.activityRepo=p;let h=new Dn(p,this.logger.child({component:"activity"})),f=new gs(e);this.skillHealthRepo=f;let g=new Mn(f,this.logger.child({component:"skill-health"}),h);this.skillHealthTracker=g,this.logger.info("Storage initialized");let y=new Ur,_=this.loadSecurityRules();y.loadRules(_);let S=new Fr(y,r,this.logger.child({component:"security"}));this.logger.info({ruleCount:_.length},"Security engine initialized");let E=oa(this.config.llm,this.logger.child({component:"llm"}));await E.initialize(),this.llmProvider=E;let v=new fs(e);this.usageRepo=v,E.setPersist((C,j,Z,te,Se,or)=>{v.record(C,j,Z,te,Se,or)});let I=new _n(E,a,this.logger.child({component:"embeddings"})),M=this.config.activeLearning?.enabled!==!1,q,G;M&&(q=new Rn({llm:E,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:I,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),G=new xn(n,this.logger.child({component:"memory-retriever"}),I),this.logger.info("Active learning & memory retriever initialized"));let P=new hs(e);this.summaryRepo=P;let ee=new Cn(E,P,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let ue=new ks(this.logger.child({component:"sandbox"})),L=this.skillRegistry=new _s;L.register(new bs),L.register(new Es),L.register(new Ss(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),L.register(new vs(o)),L.register(new $s(i));let ne=new us(e);if(L.register(new zs(ne)),L.register(new As),L.register(new Is),L.register(new Rs(n,I)),L.register(new xs(E,L,ue,S)),this.config.email?.accounts?.length){let C=new Map;for(let Z of this.config.email.accounts)try{Z.provider==="microsoft"&&!Z.microsoft?.clientId&&this.config.calendar?.microsoft&&(Z.microsoft={...this.config.calendar.microsoft});let te=await jr(Z);C.set(Z.name,te),this.logger.info({account:Z.name,provider:Z.provider??"imap-smtp"},"Email account initialized")}catch(te){this.logger.warn({err:te,account:Z.name},"Email account initialization failed, skipping")}let j=C.size>0?new gt(C):new gt;j.setLLM(E),L.register(j)}else{let C=new gt;C.setLLM(E),L.register(C)}L.register(new Cs),L.register(new Ns);let ie=new Ks;ie.setReloadCallback(C=>this.reloadService(C)),L.register(ie),L.register(new Ds),L.register(new Ms),L.register(new Os),L.register(new Ps(s)),L.register(new Us(s,c,this.adapters,(C,j)=>t.findByPlatformAndUser(C,j)));let Q=new Fs(d);L.register(Q),L.register(new js(u));let B=new ds(e),he=new kn(B,I,this.logger.child({component:"documents"}));L.register(new Bs(B,he,I));let Ke,le;if(this.config.calendar)try{le=await Wr(this.config.calendar),Ke=new Ft(le),L.register(Ke),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(C){this.logger.warn({err:C},"Calendar initialization failed, continuing without calendar")}if(this.calendarSkill=Ke,le&&this.config.calendar?.vorlauf?.enabled){let C=new ht(e),j=this.config.security?.ownerUserId;j&&(this.calendarWatcher=new Nn(le,C,this.adapters,j,"telegram",this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),h))}{let C=this.config.security?.ownerUserId;if(C){let j=new ht(e);this.todoWatcher=new Ln(ne,j,this.adapters,C,"telegram",{minutesBefore:30},this.logger.child({component:"todo-watcher"}),h)}}if(this.config.mcp?.servers?.length){let{MCPManager:C}=await Promise.resolve().then(()=>(re(),ce));this.mcpManager=new C(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let j of this.mcpManager.getSkills())L.register(j);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},E)),this.logger.info({agents:this.config.codeAgents.agents.map(j=>j.name)},"Code agent skill enabled")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:C}=await Promise.resolve().then(()=>(re(),ce)),{ProjectAgentSessionRepository:j}=await Promise.resolve().then(()=>(co(),sd)),Z=new j(e),te=new C({...this.config.projectAgents,agents:this.config.codeAgents.agents},E,Z),{ProjectAgentRunner:Se}=await Promise.resolve().then(()=>(Ac(),gm)),or=new Se(new Map(this.config.codeAgents.agents.map(ir=>[ir.name,ir])),E,Z,this.adapters,this.logger.child({component:"project-agent"}));te.setRunner(or),L.register(te),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.proxmox)),this.logger.info({baseUrl:this.config.proxmox.baseUrl},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:C,createContactsProvider:j}=await Promise.resolve().then(()=>(re(),ce)),Z=await j(this.config.contacts);L.register(new C(Z)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(C){this.logger.warn({err:C},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.bmw)),this.logger.info("BMW CarData skill enabled")}if(this.config.routing){let{RoutingSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C({proxmox:this.config.proxmox,unifi:this.config.unifi,homeassistant:this.config.homeassistant,proxmoxBackup:this.config.proxmoxBackup})),this.logger.info("Infrastructure monitor skill enabled")}{let{EnergyPriceSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{MarketplaceSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{BriefingSkill:C}=await Promise.resolve().then(()=>(re(),ce));L.register(new C(L,this.config,n)),this.logger.info("Briefing skill registered")}L.register(new Js(n)),this.logger.info("Feed reader skill registered"),this.logger.info({skills:L.getAll().map(C=>C.metadata.name)},"Skills registered");let Ee;if(this.config.speech?.apiKey&&(Ee=new fn(this.config.speech,this.logger.child({component:"speech"})),this.logger.info({provider:this.config.speech.provider},"Speech-to-text initialized")),this.config.speech?.ttsEnabled){let C=new gn(this.config.speech,this.logger.child({component:"tts"}));L.register(new Hs(C)),this.logger.info("Text-to-speech skill registered")}let me=this.detectImageGenProvider();if(me){let C=new yn(me,this.logger.child({component:"image-gen"}));L.register(new Ws(C)),this.logger.info({provider:me.provider},"Image generation skill registered")}try{let C=new wn(this.logger.child({component:"transit"}));L.register(new Gs(C)),this.logger.info("Public transit skill registered")}catch(C){this.logger.warn({err:C},"Failed to register transit skill")}let Pe=new mn(t),Ze=Oe.resolve(Oe.dirname(this.config.storage.path),"inbox");this.pipeline=new pn({llm:E,conversationManager:Pe,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:L,skillSandbox:ue,securityManager:S,memoryRepo:n,speechTranscriber:Ee,inboxPath:Ze,embeddingService:I,activeLearning:q,memoryRetriever:G,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:he,conversationSummarizer:ee}),this.reminderScheduler=new hn(o,async(C,j,Z)=>{let te=this.adapters.get(C);te?await te.sendMessage(j,Z):this.logger.warn({platform:C,chatId:j},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:m(C=>s.getMasterUserId(C),"getMasterUserId"),getLinkedUsers:m(C=>s.getLinkedUsers(C),"getLinkedUsers"),findConversation:m((C,j)=>t.findByPlatformAndUser(C,j),"findConversation")}),this.backgroundTaskRunner=new bn(L,ue,d,this.adapters,s,this.logger.child({component:"background-tasks"}),h,g);let Ve=new En(L,ue,d,this.adapters,s,this.logger.child({component:"persistent-agents"}),h);this.backgroundTaskRunner.setPersistentRunner(Ve),Q.setPersistentRunner(Ve),this.proactiveScheduler=new Sn(u,L,ue,E,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,Pe,h);let Qe=new ms(e);this.watchRepo=Qe,L.register(new Vs(Qe,L));let De=new ps(e);this.confirmationQueue=new An(De,L,ue,this.adapters,this.logger.child({component:"confirmation-queue"}),h);let Et=new ws(e),St=new tr(Et,n,this.logger.child({component:"feedback"}));this.confirmationQueue.setFeedbackService(St),q&&q.setFeedbackService(St),this.watchEngine=new qo(Qe,L,ue,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,h,g,E);let et=new ys(e),X=new Ys(et);L.register(X);let z=new On(et,L,ue,this.logger.child({component:"workflow-runner"}),h,g);X.setRunner(z);{let C=this.config.security?.ownerUserId;if(C&&this.config.reasoning?.enabled!==!1){let j=new ht(e);this.reasoningEngine=new Un(le,ne,Qe,n,p,f,j,L,ue,E,this.adapters,s,C,"telegram",this.config.reasoning,this.logger.child({component:"reasoning-engine"}),h,this.config.briefing?.location,Et,this.confirmationQueue)}}this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(h),this.pipeline.setSkillHealthTracker(g),await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t));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(()=>(kt(),_t)),s=e.api?.port??3420,r=e.api?.host??"127.0.0.1";e.api?.token?this.logger.info("HTTP API authentication enabled"):this.logger.warn("HTTP API has no authentication token configured (api.token). API is open."),this.adapters.set("api",new t(s,r,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,healthCheck:m(()=>{let n;try{let o=this.config.storage.path,i=rr.statSync(o);n={path:o,sizeBytes:i.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([o,i])=>[o,i.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:this.watchRepo?.countEnabled()??0,schedulersActive:this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:m(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:m(()=>({watches:this.watchRepo?.getEnabled()??[],scheduled:this.scheduledActionRepo?.getAll()??[],skillHealth:this.skillHealthRepo?.getAll()??[]}),"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:r,webUi:e.api?.webUi!==!1},"HTTP API adapter registered")}}async start(){this.logger.info("Starting Alfred...");for(let[e,t]of this.adapters){this.setupAdapterHandlers(e,t);try{await t.connect(),this.logger.info({platform:e},"Adapter connected")}catch(s){this.logger.error({platform:e,err:s},"Adapter connection failed \u2014 skipping")}}if(this.reminderScheduler?.start(),this.backgroundTaskRunner?.start(),this.proactiveScheduler?.start(),this.watchEngine?.start(),this.confirmationQueue?.start(),this.calendarWatcher?.start(),this.todoWatcher?.start(),this.reasoningEngine?.start(),this.config.webhooks?.length&&this.watchEngine){let e=this.adapters.get("api");if(e&&"addWebhook"in e){let t=e;for(let s of this.config.webhooks)t.addWebhook({name:s.name,secret:s.secret,callback:m(async r=>{if(s.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(s.watchId),s.chatId&&s.platform){let n=this.adapters.get(s.platform);if(n){let o=`\u{1F514} Webhook "${s.name}" triggered`+(r.action?`: ${r.action}`:"");await n.sendMessage(s.chatId,o)}}},"callback")}),this.logger.info({name:s.name,watchId:s.watchId},"Webhook registered")}}try{let e={audit:this.auditRepo?.cleanup(90)??0,summaries:this.summaryRepo?.cleanup(180)??0,activity:this.activityRepo?.cleanup(90)??0,usage:this.usageRepo?.cleanup(365)??0,expiredMemories:this.memoryRepo?.cleanupExpired()??0};(e.audit||e.summaries||e.activity||e.usage)&&this.logger.info(e,"Startup DB cleanup completed")}catch(e){this.logger.warn({err:e},"Startup DB cleanup failed")}this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.adapters.size===0&&this.logger.warn("No messaging adapters enabled. Configure at least one platform."),this.logger.info(`Alfred is running with ${this.adapters.size} adapter(s)`)}async startWithCLI(){this.adapters.clear();let{CLIAdapter:e}=await Promise.resolve().then(()=>(kt(),_t)),t=new e;this.adapters.set("cli",t),t.on("disconnected",()=>{this.stop().then(()=>process.exit(0))}),await this.start()}async stop(){this.logger.info("Stopping Alfred..."),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(r=>setTimeout(r,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(r){this.logger.error({platform:t,err:r},"Failed to disconnect adapter")}try{this.database&&(this.database.getDb().pragma("wal_checkpoint(TRUNCATE)"),this.database.close())}catch{}this.logger.info("Alfred stopped")}async reloadService(e){try{zi();let t=new fe().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce)),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(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce));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(()=>(re(),ce));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=Oe.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Oe.join(process.cwd(),"web-ui"),Oe.join(e,"..","web-ui"),Oe.join(e,"web-ui"),Oe.join(e,"..","..","web-ui"),Oe.join(e,"..","..","apps","web","out")];for(let s of t)try{let r=Oe.resolve(s);if(rr.existsSync(Oe.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")}buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let r=this.llmProvider.getCostSummary();e.push("# HELP alfred_llm_input_tokens_total Total LLM input tokens (session)"),e.push("# TYPE alfred_llm_input_tokens_total counter"),e.push(`alfred_llm_input_tokens_total ${r.totalInputTokens}`),e.push("# HELP alfred_llm_output_tokens_total Total LLM output tokens (session)"),e.push("# TYPE alfred_llm_output_tokens_total counter"),e.push(`alfred_llm_output_tokens_total ${r.totalOutputTokens}`),e.push("# HELP alfred_llm_cost_usd_total Total LLM cost in USD (session)"),e.push("# TYPE alfred_llm_cost_usd_total counter"),e.push(`alfred_llm_cost_usd_total ${r.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,o]of Object.entries(r.byModel)){let i=`model="${n}"`;e.push(`alfred_llm_calls_total{${i}} ${o.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${o.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${o.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,o]of Object.entries(r.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${o.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),o=this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${o.totalCostUsd}`),e.push("# HELP alfred_llm_today_calls Total LLM calls today (persisted)"),e.push("# TYPE alfred_llm_today_calls gauge"),e.push(`alfred_llm_today_calls ${o.totalCalls}`)}return e.push(""),e.join(`
|
|
1406
|
+
`)}autoLinkApiUser(e){if(e.platform==="api")try{let t=this.userRepo.findOrCreate("api",e.userId,e.userName);if(this.userRepo.getMasterUserId(t.id)!==t.id)return;let r=this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(r){let n=this.userRepo.getMasterUserId(r.id);this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{this.autoLinkApiUser(s);let r,n="",o=m(async a=>{if(a!==n){n=a;try{r?await t.editMessage(s.chatId,r,a):r=await t.sendMessage(s.chatId,a)}catch(c){this.logger.debug({err:c,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),i=await this.pipeline.process(s,o);if(i.text){let a=this.formatter.format(i.text,s.platform),c=a.parseMode!=="text"?{parseMode:a.parseMode}:void 0;try{if(r&&e!=="api")try{await t.editMessage(s.chatId,r,a.text,c)}catch(d){this.logger.debug({err:d,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,a.text,c)}else await t.sendMessage(s.chatId,a.text,c)}catch(d){this.logger.warn({err:d,chatId:s.chatId},"Formatted send failed, retrying as plain text");let u=this.formatter.format(i.text,"signal");await t.sendMessage(s.chatId,u.text)}}if(i.attachments)for(let a of i.attachments)try{let c=a.mimeType?.startsWith("image/")??!1,d=a.mimeType==="audio/ogg"||a.mimeType==="audio/opus";c?await t.sendPhoto(s.chatId,a.data,a.fileName):d?await t.sendVoice(s.chatId,a.data):await t.sendFile(s.chatId,a.data,a.fileName)}catch(c){this.logger.warn({err:c,fileName:a.fileName,chatId:s.chatId},"Failed to send attachment")}t.endStream(s.chatId)}catch(r){this.logger.error({platform:e,err:r,chatId:s.chatId},"Failed to handle message");try{await t.sendMessage(s.chatId,"Sorry, I encountered an error processing your message. Please try again.")}catch(n){this.logger.error({err:n},"Failed to send error message")}t.endStream(s.chatId)}}),t.on("error",s=>{this.logger.error({platform:e,err:s},"Adapter error")}),t.on("connected",()=>{this.logger.info({platform:e},"Adapter connected")}),t.on("disconnected",()=>{this.logger.warn({platform:e},"Adapter disconnected")})}detectImageGenProvider(){let e=["default","strong","fast","embeddings","local"];for(let t of["openai","google"])for(let s of e){let r=this.config.llm[s];if(r?.provider===t&&r.apiKey)return{provider:t,apiKey:r.apiKey,baseUrl:r.baseUrl}}}loadSecurityRules(){let e=Oe.resolve(this.config.security.rulesPath),t=[];if(!rr.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!rr.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let r=rr.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of r)try{let o=Oe.join(e,n),i=rr.readFileSync(o,"utf-8"),a=Dg.load(i);if(a?.rules&&Array.isArray(a.rules)){let d=new it().loadFromObject({rules:a.rules});t.push(...d),this.logger.info({file:n,count:d.length},"Loaded security rules")}}catch(o){this.logger.error({err:o,file:n},"Failed to load security rules file")}return t}}});var Am=T(()=>{"use strict"});var Cc=T(()=>{"use strict";gc();hc()});var Nc=T(()=>{"use strict";$m();Ja();Va();Za();Qa();ec();rc();nc();ic();ac();cc();wt();oc();tc();sc();fc();yc();pc();Am();mc();wc();vn();Sc();dc();Cc();Ac();Cc();Tc();_c();kc();zo();bc();vc();$c()});import ri from"node:fs";import Im from"node:path";import Mg from"node:os";function Rm(){try{let l=ri.readFileSync(Lc,"utf-8"),e=JSON.parse(l);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function xm(l){try{let e=Im.dirname(Lc);ri.existsSync(e)||ri.mkdirSync(e,{recursive:!0}),ri.writeFileSync(Lc,JSON.stringify(l,null,2),"utf-8")}catch{}}async function Yt(l,e){let t=new AbortController,s=setTimeout(()=>t.abort(),Pg);try{return await fetch(l,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function Cm(l,e,t){switch(l){case"anthropic":{let s=await Yt("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 Yt(s,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,r=await Yt(s);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name.replace(/^models\//,""),name:o.displayName})):[]}case"mistral":{let s=await Yt("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 Yt("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 Yt(`${s}/api/tags`);return r.ok?((await r.json()).models??[]).map(o=>({id:o.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),r=await Yt(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return r.ok?((await r.json()).data??[]).map(o=>({id:o.id})):[]}default:return[]}}async function Dc(l,e,t){let s=Rm(),r=s.providers[l];if(r&&Date.now()-r.fetchedAt<Og)return r.models;try{let n=await Cm(l,e,t);if(n.length>0)return s.providers[l]={fetchedAt:Date.now(),models:n},xm(s),n}catch{}return r?r.models:[]}function ni(l,e,t){Cm(l,e,t).then(s=>{if(s.length>0){let r=Rm();r.providers[l]={fetchedAt:Date.now(),models:s},xm(r)}}).catch(()=>{})}function Mc(l,e){let t=new Set,s=[];for(let r of l)if(!t.has(r.id)){t.add(r.id);let n=e.find(o=>o.id===r.id);s.push({id:r.id,name:r.name,desc:n?.desc})}for(let r of e)t.has(r.id)||(t.add(r.id),s.push({id:r.id,desc:r.desc}));return s}var Og,Pg,Lc,Oc=T(()=>{"use strict";Og=1440*60*1e3,Pg=5e3,Lc=Im.join(Mg.homedir(),".alfred","model-cache.json");m(Rm,"readCache");m(xm,"writeCache");m(Yt,"fetchWithTimeout");m(Cm,"fetchModelsFromAPI");m(Dc,"getModels");m(ni,"refreshCacheInBackground");m(Mc,"mergeModels")});var Nm={};pe(Nm,{startCommand:()=>Ug});async function Ug(){let l=new fe,e;try{e=l.loadConfig()}catch(o){console.error("Failed to load configuration:",o.message),process.exit(1)}let t=Ar("cli",e.logger.level);t.info({name:e.name},"Configuration loaded");let s=new Vt(e),r=!1,n=m(async o=>{if(!r){r=!0,t.info({signal:o},"Received shutdown signal");try{await s.stop(),t.info("Graceful shutdown complete"),process.exit(0)}catch(i){t.error({error:i},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>n("SIGINT")),process.on("SIGTERM",()=>n("SIGTERM")),process.on("uncaughtException",o=>{t.fatal({error:o},"Uncaught exception"),n("uncaughtException")}),process.on("unhandledRejection",o=>{t.fatal({reason:o},"Unhandled rejection"),n("unhandledRejection")});try{await s.initialize(),await s.start(),t.info("Alfred is ready");let o=e.llm;o?.default?.provider?ni(o.default.provider,o.default.apiKey,o.default.baseUrl):o?.provider&&ni(o.provider,void 0,o.baseUrl);for(let i of["strong","fast"]){let a=o?.[i];a?.provider&&ni(a.provider,a.apiKey,a.baseUrl)}}catch(o){let i=o instanceof Error?o:new Error(String(o));t.fatal({err:i},"Failed to start Alfred"),process.exit(1)}}var Lm=T(()=>{"use strict";nt();Gi();Nc();Oc();m(Ug,"startCommand")});var Mm={};pe(Mm,{chatCommand:()=>Bg});import Dm from"node:http";import Fn from"node:readline";function Fg(l,e){return new Promise(t=>{let s=Dm.get(`http://${l}:${e}/api/health`,{timeout:2e3},r=>{let n="";r.on("data",o=>{n+=o.toString()}),r.on("end",()=>{try{let o=JSON.parse(n);t(o.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function jg(l,e){let t=Fn.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
|
|
1407
1407
|
Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
|
|
1408
1408
|
`),t.prompt(),t.on("line",s=>{let r=s.trim();if(!r){t.prompt();return}(r==="/quit"||r==="/exit")&&(console.log(`
|
|
1409
1409
|
Goodbye!
|
|
@@ -1418,7 +1418,7 @@ Error: ${h.text??"Unknown error"}
|
|
|
1418
1418
|
`),t.prompt();break}}catch{}}}),i.on("end",()=>{if(a.length>0){let c=a.split(`
|
|
1419
1419
|
`).find(d=>d.startsWith("data: "));if(c)try{let d=JSON.parse(c.slice(6));(d.type==="done"||d.type==="error")&&t.prompt()}catch{}}}),i.on("error",c=>{console.error(`
|
|
1420
1420
|
Connection error: ${c.message}`),t.prompt()})});o.on("error",i=>{console.error(`
|
|
1421
|
-
Failed to send message: ${i.message}`),t.prompt()}),o.write(n),o.end()}),t.on("close",()=>{process.exit(0)})}async function Bg(l){let e=new fe,t;try{t=e.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let s=t.api?.host??"127.0.0.1",r=t.api?.port??3420;if(await Fg(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),jg(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let i=t.llm[l.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let o=new
|
|
1421
|
+
Failed to send message: ${i.message}`),t.prompt()}),o.write(n),o.end()}),t.on("close",()=>{process.exit(0)})}async function Bg(l){let e=new fe,t;try{t=e.loadConfig()}catch(i){console.error("Failed to load configuration:",i.message),process.exit(1)}let s=t.api?.host??"127.0.0.1",r=t.api?.port??3420;if(await Fg(s,r)){console.log(`Connected to Alfred server at ${s}:${r}`),jg(s,r);return}if(t.logger.level="warn",l.model&&(t.llm.default.model=l.model),l.tier){let i=t.llm[l.tier];i?t.llm.default=i:(console.error(`Unknown tier: ${l.tier}. Available tiers: default, strong, fast, embeddings, local`),process.exit(1))}let o=new Vt(t);try{await o.initialize(),await o.startWithCLI()}catch(i){console.error("Failed to start chat:",i.message),process.exit(1)}}var Om=T(()=>{"use strict";nt();Nc();m(Fg,"checkHealth");m(jg,"startClientMode");m(Bg,"chatCommand")});var Fm={};pe(Fm,{setupCommand:()=>Zg});import{createInterface as Hg}from"node:readline/promises";import{stdin as Wg,stdout as zg}from"node:process";import{execFileSync as qg}from"node:child_process";import be from"node:fs";import Gg from"node:os";import Ie from"node:path";import Pc from"js-yaml";function U(l){return`${oi}${l}${A}`}function Vg(l){return`${F}${l}${A}`}function _e(l){return`${ii}${l}${A}`}function Um(l){return`${Xg}${l}${A}`}function D(l){return`${J}${l}${A}`}function b(l){return`${bt}${l}${A}`}function ke(l){return l.length<=4?"****":"*".repeat(l.length-4)+l.slice(-4)}function Yg(l){let e=process.platform==="win32",t=e?"where":"which";try{let n=qg(t,[l],{stdio:"pipe"}).toString().trim();if(n)return n.split(/\r?\n/)[0]}catch{}let s=Gg.homedir(),r=e?[Ie.join(s,".local","bin",`${l}.exe`),Ie.join(s,"AppData","Roaming","npm",`${l}.cmd`),Ie.join(s,"AppData","Roaming","npm",`${l}`)]:[Ie.join(s,".local","bin",l),"/usr/local/bin/"+l,"/opt/homebrew/bin/"+l,Ie.join(s,".npm-global","bin",l)];for(let n of r)try{return be.accessSync(n,be.constants.X_OK),n}catch{}return null}function Jg(l){let e={},t={},s=!1,r=!1,n=30,o=Ie.join(l,"config","default.yml");if(be.existsSync(o))try{let h=Pc.load(be.readFileSync(o,"utf-8"));h&&typeof h=="object"&&Object.assign(e,h)}catch{}let i=Ie.join(l,".env");if(be.existsSync(i))try{let h=be.readFileSync(i,"utf-8").split(`
|
|
1422
1422
|
`);for(let f of h){let g=f.trim();if(!g||g.startsWith("#"))continue;let y=g.indexOf("=");y>0&&(t[g.slice(0,y)]=g.slice(y+1))}}catch{}let a=Ie.join(l,"config","rules","default-rules.yml");if(be.existsSync(a))try{let h=Pc.load(be.readFileSync(a,"utf-8"));if(h?.rules){s=h.rules.some(y=>y.id==="allow-owner-admin"&&y.effect==="allow"),h.rules.find(y=>y.id==="allow-write-for-dm"||y.id==="allow-write-all")?.id==="allow-write-all"&&(r=!0);let g=h.rules.find(y=>y.id==="rate-limit-write");g?.rateLimit?.maxInvocations&&(n=g.rateLimit.maxInvocations)}}catch{}let c=!!e.codeSandbox?.enabled,d=e.api?.webUi!==!1,u=e.llm,p={};if(u){for(let h of["strong","fast","embeddings","local"])u[h]?.provider&&u[h]?.model&&(p[h]=u[h]);u.default?.provider&&(e.llm={...e.llm,provider:u.default.provider,model:u.default.model,baseUrl:u.default.baseUrl})}return{config:e,env:t,shellEnabled:s,writeInGroups:r,rateLimit:n,codeSandboxEnabled:c,webUiEnabled:d,multiModelTiers:p}}async function Zg(){let l=Hg({input:Wg,output:zg}),e=process.cwd(),t=Jg(e),s=Object.keys(t.config).length>0;try{Qg(),console.log(s?`${ii}Existing configuration found \u2014 press Enter to keep current values.${A}
|
|
1423
1423
|
${bt}Only change what you need to update.${A}
|
|
1424
1424
|
`:`${ii}Welcome to the Alfred setup wizard!${A}
|
|
@@ -1427,7 +1427,7 @@ ${bt}Press Enter to accept defaults shown in [brackets].${A}
|
|
|
1427
1427
|
`);let r=await W(l,"What should your bot be called?",t.config.name??"Alfred"),n=t.config.llm?.provider?lt.findIndex(k=>k.name===t.config.llm?.provider):-1,o=n>=0?n+1:1;console.log(`
|
|
1428
1428
|
${D("Which LLM provider would you like to use?")}`);for(let k=0;k<lt.length;k++){let $=k===n?` ${b("(current)")}`:"";console.log(` ${_e(String(k+1)+")")} ${lt[k].label}${$}`)}let i=await jn(l,"> ",1,lt.length,o),a=lt[i-1];console.log(` ${U(">")} Selected: ${D(a.label)}`);let c="",d=t.env[a.envKeyName]??"";a.needsApiKey&&(console.log(""),d?c=await W(l,`${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`,d):c=await Le(l,`Enter your ${a.name.charAt(0).toUpperCase()+a.name.slice(1)} API key`),console.log(` ${U(">")} API key set: ${b(ke(c))}`));let u=a.baseUrl??"";if(["ollama","openwebui","openai","openrouter","google"].includes(a.name)){let $=(t.config.llm?.baseUrl??t.env.ALFRED_LLM_BASE_URL??"")||a.baseUrl||"";if($){let N={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 W(l,N[a.name]??"API Base URL",$.replace(/\/+$/,"")),u=u.replace(/\/+$/,""),console.log(` ${U(">")} URL: ${b(u)}`)}}let h=t.config.llm?.model??a.defaultModel;console.log("");let f,g=await Dc(a.name,c,u),y=Mc(g,a.models??[]);if(y.length>0){console.log(`${D("Available models:")}`);for(let N=0;N<y.length;N++){let V=y[N],O=V.desc??V.name??"",K=V.id===h?` ${U("(current)")}`:"";console.log(` ${_e(`${N+1})`)} ${V.id}${O?` ${b(`\u2014 ${O}`)}`:""}${K}`)}console.log(` ${_e(`${y.length+1})`)} ${b("Other (enter manually)")}`);let k=await W(l,"Choose model","1"),$=parseInt(k,10)-1;$>=0&&$<y.length?f=y[$].id:f=await W(l,"Model ID",h)}else f=await W(l,"Which model?",h);let _=Object.keys(t.multiModelTiers).length>0,S=_?"Y/n":"y/N";console.log(`
|
|
1429
1429
|
${D("Configure additional model tiers for specialized tasks?")}`),console.log(`${b("Optional: use different models for complex tasks, quick replies, embeddings, or offline.")}`);let E=(await l.question(`${F}> ${A}${b(`[${S}] `)}`)).trim().toLowerCase(),v=E===""?_:E==="y"||E==="yes",I={};if(v){let k=[{key:"strong",label:"Strong",hint:"complex reasoning, coding, long documents",defaultModel:"claude-opus-4-20250514"},{key:"fast",label:"Fast",hint:"quick responses, simple tasks",defaultModel:"claude-haiku-4-5-20251001"},{key:"embeddings",label:"Embeddings",hint:"semantic search & memory",defaultModel:"text-embedding-3-small"},{key:"local",label:"Local",hint:"offline fallback via Ollama",defaultModel:"llama3.2"}];for(let $ of k){let N=t.multiModelTiers[$.key],V=!!N?.model;console.log(`
|
|
1430
|
-
${D(`${$.label} model`)} ${b(`(${$.hint})`)}`),V&&console.log(` ${b(`Current: ${N.provider}/${N.model}`)}`);let O=N?.provider??a.name,K=lt.map(xe=>xe.name).join(", ");console.log(` ${b(`Providers: ${K}`)}`);let ve=(await l.question(` ${F}Provider: ${A}${b(`[${O}] `)}`)).trim()||O;if(!ve&&!V){console.log(` ${b("Skipped.")}`);continue}let se=ve,$e,je;if(se!==a.name){let xe=N?.apiKey??t.env[`ALFRED_LLM_${$.key.toUpperCase()}_API_KEY`]??"";if(xe?$e=await W(l,` API key for ${se}`,xe):(lt.find(rt=>rt.name===se)?.needsApiKey??!0)&&($e=await Le(l,` API key for ${se}`)),["ollama","openwebui"].includes(se)){let rt=(N?.baseUrl??"")||lt.find(so=>so.name===se)?.baseUrl||"";rt&&(je=await W(l,` ${se} URL`,rt))}}let Lt=$e??(se===a.name?c:void 0),$r=je??(se===a.name?u:void 0),Pi=lt.find(xe=>xe.name===se),Ui=await Dc(se,Lt,$r),ut=Mc(Ui,Pi?.models??[]),st;if(ut.length>0){console.log(` ${D("Available models:")}`);for(let
|
|
1430
|
+
${D(`${$.label} model`)} ${b(`(${$.hint})`)}`),V&&console.log(` ${b(`Current: ${N.provider}/${N.model}`)}`);let O=N?.provider??a.name,K=lt.map(xe=>xe.name).join(", ");console.log(` ${b(`Providers: ${K}`)}`);let ve=(await l.question(` ${F}Provider: ${A}${b(`[${O}] `)}`)).trim()||O;if(!ve&&!V){console.log(` ${b("Skipped.")}`);continue}let se=ve,$e,je;if(se!==a.name){let xe=N?.apiKey??t.env[`ALFRED_LLM_${$.key.toUpperCase()}_API_KEY`]??"";if(xe?$e=await W(l,` API key for ${se}`,xe):(lt.find(rt=>rt.name===se)?.needsApiKey??!0)&&($e=await Le(l,` API key for ${se}`)),["ollama","openwebui"].includes(se)){let rt=(N?.baseUrl??"")||lt.find(so=>so.name===se)?.baseUrl||"";rt&&(je=await W(l,` ${se} URL`,rt))}}let Lt=$e??(se===a.name?c:void 0),$r=je??(se===a.name?u:void 0),Pi=lt.find(xe=>xe.name===se),Ui=await Dc(se,Lt,$r),ut=Mc(Ui,Pi?.models??[]),st;if(ut.length>0){console.log(` ${D("Available models:")}`);for(let Qt=0;Qt<ut.length;Qt++){let rt=ut[Qt],so=rt.desc??rt.name??"",Rp=rt.id===N?.model?` ${U("(current)")}`:"";console.log(` ${_e(`${Qt+1})`)} ${rt.id}${so?` ${b(`\u2014 ${so}`)}`:""}${Rp}`)}console.log(` ${_e(`${ut.length+1})`)} ${b("Other (enter manually)")}`),console.log(` ${_e("0)")} ${b("Skip this tier")}`);let xe=(await l.question(` ${F}> ${A}${V?b(`[${N.model}] `):""}`)).trim();if(xe==="0"){console.log(` ${b("Skipped.")}`);continue}let to=parseInt(xe,10)-1;to>=0&&to<ut.length?st=ut[to].id:!xe&&V?st=N.model:st=await W(l," Model ID",V?N.model:$.defaultModel)}else if(console.log(` ${b("Press Enter to skip.")}`),st=(await l.question(` ${F}Model: ${A}${V?b(`[${N.model}] `):""}`)).trim()||(V?N.model:""),!st){console.log(` ${b("Skipped.")}`);continue}I[$.key]={provider:se,model:st,...$e?{apiKey:$e}:{},...je?{baseUrl:je}:{}},console.log(` ${U(">")} ${$.label}: ${D(se)}/${D(st)}`)}Object.keys(I).length===0&&console.log(`
|
|
1431
1431
|
${b("No additional tiers configured \u2014 using single model.")}`)}else console.log(` ${b("Using single model for all tasks.")}`);let M=["brave","tavily","duckduckgo","searxng"],q=t.config.search?.provider??t.env.ALFRED_SEARCH_PROVIDER??"",G=M.indexOf(q),P=G>=0?G+1:0;console.log(`
|
|
1432
1432
|
${D("Web Search provider (for searching the internet):")}`);let ee=["Brave Search \u2014 recommended, free tier (2,000/month)","Tavily \u2014 built for AI agents, free tier (1,000/month)","DuckDuckGo \u2014 free, no API key needed","SearXNG \u2014 self-hosted, no API key needed"],ue=m(k=>G===k?` ${b("(current)")}`:"","mark");console.log(` ${_e("0)")} None (disable web search)${G===-1&&q===""?` ${b("(current)")}`:""}`);for(let k=0;k<ee.length;k++)console.log(` ${_e(String(k+1)+")")} ${ee[k]}${ue(k)}`);let L=await jn(l,"> ",0,M.length,P),ne,ie="",Q="";if(L>=1&&L<=M.length&&(ne=M[L-1]),ne==="brave"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ie=await W(l," Brave Search API key",k):(console.log(` ${b("Get your free API key at: https://brave.com/search/api/")}`),ie=await Le(l," Brave Search API key")),console.log(` ${U(">")} Brave Search: ${b(ke(ie))}`)}else if(ne==="tavily"){let k=t.env.ALFRED_SEARCH_API_KEY??"";k?ie=await W(l," Tavily API key",k):(console.log(` ${b("Get your free API key at: https://tavily.com/")}`),ie=await Le(l," Tavily API key")),console.log(` ${U(">")} Tavily: ${b(ke(ie))}`)}else if(ne==="duckduckgo")console.log(` ${U(">")} DuckDuckGo: ${b("no API key needed")}`);else if(ne==="searxng"){let k=t.config.search?.baseUrl??t.env.ALFRED_SEARCH_BASE_URL??"http://localhost:8080";Q=await W(l," SearXNG URL",k),Q=Q.replace(/\/+$/,""),console.log(` ${U(">")} SearXNG: ${b(Q)}`)}else console.log(` ${b("Web search disabled \u2014 you can configure it later.")}`);let B=[];for(let k=0;k<nr.length;k++){let $=nr[k];t.config[$.configKey]?.enabled&&B.push(k+1)}let he=B.length>0?B.join(","):"";console.log(`
|
|
1433
1433
|
${D("Which messaging platforms do you want to enable?")}`),console.log(`${b("(Enter comma-separated numbers, e.g. 1,3)")}`);for(let k=0;k<nr.length;k++){let $=B.includes(k+1)?` ${b("(enabled)")}`:"";console.log(` ${_e(String(k+1)+")")} ${nr[k].label}${$}`)}console.log(` ${_e("0)")} None (configure later)`);let Ke=(await l.question(`${F}> ${A}${he?b(`[${he}] `):""}`)).trim(),le=[],Ee=Ke||he;if(Ee&&Ee!=="0"){let k=Ee.split(",").map($=>parseInt($.trim(),10));for(let $ of k)if($>=1&&$<=nr.length){let N=nr[$-1];le.includes(N)||le.push(N)}}le.length>0?console.log(` ${U(">")} Enabling: ${le.map(k=>D(k.label)).join(", ")}`):console.log(` ${b("No platforms selected \u2014 you can configure them later.")}`);let me={},Pe={};for(let k of le){if(k.credentials.length===0){k.name==="whatsapp"&&console.log(`
|
|
@@ -1444,9 +1444,9 @@ ${D("Code Agents (CLI-based coding agents for automated tasks)?")}`),console.log
|
|
|
1444
1444
|
${D("Which agents should Alfred use?")} ${b("(comma-separated, e.g. 1,2)")}`);let $=new Set((t.config.codeAgents?.agents??[]).map(O=>O.name));for(let O=0;O<k.length;O++){let K=k[O],oe=$.has(K.name)?` ${b("(current)")}`:"";console.log(` ${F}${O+1}${A}) ${K.label}${oe}`)}console.log(` ${F}0${A}) None`);let N=k.map((O,K)=>$.size>0?$.has(O.name)?String(K+1):null:O.detected?String(K+1):null).filter(Boolean).join(",")||"0",V=(await l.question(` ${F}> ${A}${b(`[${N}] `)}`)).trim()||N;V!=="0"&&(vt=V.split(",").map(K=>parseInt(K.trim(),10)).filter(K=>!isNaN(K)&&K>=1&&K<=k.length).map(K=>{let oe=k[K-1];return{name:oe.name,command:oe.command,argsTemplate:oe.argsTemplate,promptVia:oe.promptVia}})),vt.length>0?console.log(` ${U(">")} ${D(String(vt.length))} agent(s) selected: ${vt.map(O=>O.name).join(", ")}`):console.log(` ${b("No agents selected.")}`)}let pi=t.config.codeAgents?.forge,hi=pi?.provider??t.env.ALFRED_FORGE_PROVIDER??"";console.log(`
|
|
1445
1445
|
${D("Forge Integration (auto-create PRs/MRs after code agent orchestration)?")}`),console.log(`${b("Connects to GitHub or GitLab to push branches and create pull/merge requests.")}`),console.log(`${b("Owner/repo are detected automatically from the git remote at runtime.")}`);let Bc=[{num:"1",name:"",label:"None \u2014 skip forge integration"},{num:"2",name:"github",label:"GitHub"},{num:"3",name:"gitlab",label:"GitLab"}];for(let k of Bc){let $=k.name===hi?` ${b("(current)")}`:"";console.log(` ${F}${k.num}${A}) ${k.label}${$}`)}let Hc=hi==="github"?"2":hi==="gitlab"?"3":"1",rp=(await l.question(`${F}> ${A}${b(`[${Hc}] `)}`)).trim()||Hc,$t=Bc.find(k=>k.num===rp)?.name??"",dr="",ur="";if($t==="github"){console.log(` ${U(">")} Forge: ${D("GitHub")}`);let k=t.env.ALFRED_GITHUB_TOKEN??pi?.github?.token??"";k&&console.log(` ${b(`Current token: ${ke(k)}`)}`),console.log(` ${b("Create a token at https://github.com/settings/tokens (scope: repo)")}`),dr=(await l.question(` ${J}GitHub Token${A}: ${F}`)).trim(),process.stdout.write(A),!dr&&k&&(dr=k)}else if($t==="gitlab"){console.log(` ${U(">")} Forge: ${D("GitLab")}`);let k=t.env.ALFRED_GITLAB_TOKEN??pi?.gitlab?.token??"";k&&console.log(` ${b(`Current token: ${ke(k)}`)}`),console.log(` ${b("Create a token at https://gitlab.com/-/user_settings/personal_access_tokens (scope: api)")}`),ur=(await l.question(` ${J}GitLab Token${A}: ${F}`)).trim(),process.stdout.write(A),!ur&&k&&(ur=k)}else console.log(` ${b("Forge integration disabled \u2014 you can enable it later in config/default.yml.")}`);let np=t.webUiEnabled!==!1?"Y/n":"y/N";console.log(`
|
|
1446
1446
|
${D("Web Chat UI (browser-based chat interface)?")}`),console.log(`${b("Serves a web UI at http://host:port/alfred/ \u2014 chat, dashboard, skill health.")}`);let fi=(await l.question(`${F}> ${A}${b(`[${np}] `)}`)).trim().toLowerCase(),gi=fi===""?t.webUiEnabled!==!1:fi==="y"||fi==="yes";console.log(gi?` ${U(">")} Web Chat UI ${D("enabled")} \u2014 accessible at /alfred/`:` ${b("Web Chat UI disabled.")}`),console.log(`
|
|
1447
|
-
${D("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${b("Control VMs, containers, network devices, and smart home through Alfred.")}`);let mr=t.config.proxmox,yi=t.env.ALFRED_PROXMOX_BASE_URL??mr?.baseUrl??"",op=yi?"Y/n":"y/N",Wc=(await l.question(` ${J}Enable Proxmox VE?${A} ${b(`[${op}]`)}: ${F}`)).trim().toLowerCase()||(yi?"y":"n");process.stdout.write(A);let Hn=Wc==="y"||Wc==="yes",pr="",wi="",hr="",Ti=!0;if(Hn){pr=await W(l," Proxmox URL (e.g. https://pve.local:8006)",yi||"https://pve.local:8006");let k=t.env.ALFRED_PROXMOX_TOKEN_ID??mr?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),wi=await W(l," API Token ID (user@realm!name)",k);let $=t.env.ALFRED_PROXMOX_TOKEN_SECRET??mr?.tokenSecret??"";$&&console.log(` ${b(`Current secret: ${ke($)}`)}`),hr=(await l.question(` ${J}API Token Secret${A}: ${F}`)).trim(),process.stdout.write(A),!hr&&$&&(hr=$);let N=mr?.verifyTls===!1?"y/N":"Y/n",V=(await l.question(` ${J}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${N}]`)}: ${F}`)).trim().toLowerCase()||(mr?.verifyTls===!1?"n":"y");process.stdout.write(A),Ti=V==="y"||V==="yes",console.log(` ${U(">")} Proxmox: ${D(pr)} ${b(`(TLS verify: ${Ti?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox disabled.")}`);let
|
|
1448
|
-
${J}Enable Proxmox Backup Server?${A} ${b(`[${ip}]`)}: ${F}`)).trim().toLowerCase()||(_i?"y":"n");process.stdout.write(A);let Wn=zc==="y"||zc==="yes",fr="",ki="",gr="",yr=24,zn=!0;if(Wn){fr=await W(l," PBS URL (e.g. https://pbs.local:8007)",_i||"https://pbs.local:8007");let k=t.env.ALFRED_PBS_TOKEN_ID??
|
|
1449
|
-
${J}Enable UniFi Network?${A} ${b(`[${ap}]`)}: ${F}`)).trim().toLowerCase()||(bi?"y":"n");process.stdout.write(A);let wr=qc==="y"||qc==="yes",
|
|
1447
|
+
${D("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${b("Control VMs, containers, network devices, and smart home through Alfred.")}`);let mr=t.config.proxmox,yi=t.env.ALFRED_PROXMOX_BASE_URL??mr?.baseUrl??"",op=yi?"Y/n":"y/N",Wc=(await l.question(` ${J}Enable Proxmox VE?${A} ${b(`[${op}]`)}: ${F}`)).trim().toLowerCase()||(yi?"y":"n");process.stdout.write(A);let Hn=Wc==="y"||Wc==="yes",pr="",wi="",hr="",Ti=!0;if(Hn){pr=await W(l," Proxmox URL (e.g. https://pve.local:8006)",yi||"https://pve.local:8006");let k=t.env.ALFRED_PROXMOX_TOKEN_ID??mr?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),wi=await W(l," API Token ID (user@realm!name)",k);let $=t.env.ALFRED_PROXMOX_TOKEN_SECRET??mr?.tokenSecret??"";$&&console.log(` ${b(`Current secret: ${ke($)}`)}`),hr=(await l.question(` ${J}API Token Secret${A}: ${F}`)).trim(),process.stdout.write(A),!hr&&$&&(hr=$);let N=mr?.verifyTls===!1?"y/N":"Y/n",V=(await l.question(` ${J}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${N}]`)}: ${F}`)).trim().toLowerCase()||(mr?.verifyTls===!1?"n":"y");process.stdout.write(A),Ti=V==="y"||V==="yes",console.log(` ${U(">")} Proxmox: ${D(pr)} ${b(`(TLS verify: ${Ti?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox disabled.")}`);let Jt=t.config.proxmoxBackup,_i=t.env.ALFRED_PBS_BASE_URL??Jt?.baseUrl??"",ip=_i?"Y/n":"y/N",zc=(await l.question(`
|
|
1448
|
+
${J}Enable Proxmox Backup Server?${A} ${b(`[${ip}]`)}: ${F}`)).trim().toLowerCase()||(_i?"y":"n");process.stdout.write(A);let Wn=zc==="y"||zc==="yes",fr="",ki="",gr="",yr=24,zn=!0;if(Wn){fr=await W(l," PBS URL (e.g. https://pbs.local:8007)",_i||"https://pbs.local:8007");let k=t.env.ALFRED_PBS_TOKEN_ID??Jt?.tokenId??"";k&&console.log(` ${b(`Current token ID: ${k}`)}`),console.log(` ${b("Create: Configuration \u2192 Access Control \u2192 API Token")}`),ki=await W(l," API Token ID (user@realm!name)",k);let $=t.env.ALFRED_PBS_TOKEN_SECRET??Jt?.tokenSecret??"";$&&console.log(` ${b(`Current secret: ${ke($)}`)}`),gr=(await l.question(` ${J}API Token Secret${A}: ${F}`)).trim(),process.stdout.write(A),!gr&&$&&(gr=$);let N=t.env.ALFRED_PBS_MAX_AGE_HOURS??Jt?.maxAgeHours?.toString()??"24";yr=parseInt(await W(l," Max backup age (hours, alert if older)",N),10)||24;let V=Jt?.verifyTls===!1?"y/N":"Y/n",O=(await l.question(` ${J}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${V}]`)}: ${F}`)).trim().toLowerCase()||(Jt?.verifyTls===!1?"n":"y");process.stdout.write(A),zn=O==="y"||O==="yes",console.log(` ${U(">")} PBS: ${D(fr)} ${b(`(max age: ${yr}h, TLS verify: ${zn?"yes":"no"})`)}`)}else console.log(` ${b("Proxmox Backup Server disabled.")}`);let At=t.config.unifi,bi=t.env.ALFRED_UNIFI_BASE_URL??At?.baseUrl??"",ap=bi?"Y/n":"y/N",qc=(await l.question(`
|
|
1449
|
+
${J}Enable UniFi Network?${A} ${b(`[${ap}]`)}: ${F}`)).trim().toLowerCase()||(bi?"y":"n");process.stdout.write(A);let wr=qc==="y"||qc==="yes",Zt="",It="",Ei="",Tr="",Si=!0;if(wr){Zt=await W(l," UniFi URL (e.g. https://unifi.local)",bi||"https://unifi.local"),console.log(` ${b("Auth: API Key (recommended) or Username/Password")}`);let k=t.env.ALFRED_UNIFI_API_KEY??At?.apiKey??"",$=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],N=k?"1":At?.username?"2":"1";for(let oe of $)console.log(` ${F}${oe.num}${A}) ${oe.label}`);if(((await l.question(` ${F}> ${A}${b(`[${N}] `)}`)).trim()||N)==="1")k&&console.log(` ${b(`Current key: ${ke(k)}`)}`),console.log(` ${b("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),It=(await l.question(` ${J}API Key${A}: ${F}`)).trim(),process.stdout.write(A),!It&&k&&(It=k);else{let oe=t.env.ALFRED_UNIFI_USERNAME??At?.username??"";Ei=await W(l," Username",oe||"alfred");let ve=t.env.ALFRED_UNIFI_PASSWORD??At?.password??"";ve&&console.log(` ${b(`Current password: ${ke(ve)}`)}`),Tr=(await l.question(` ${J}Password${A}: ${F}`)).trim(),process.stdout.write(A),!Tr&&ve&&(Tr=ve)}let O=At?.verifyTls===!1?"y/N":"Y/n",K=(await l.question(` ${J}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${O}]`)}: ${F}`)).trim().toLowerCase()||(At?.verifyTls===!1?"n":"y");process.stdout.write(A),Si=K==="y"||K==="yes",console.log(` ${U(">")} UniFi: ${D(Zt)} ${b(`(TLS verify: ${Si?"yes":"no"})`)}`)}else console.log(` ${b("UniFi disabled.")}`);let qn=t.config.homeassistant,vi=t.env.ALFRED_HOMEASSISTANT_URL??qn?.baseUrl??"",cp=vi?"Y/n":"y/N",Gc=(await l.question(`
|
|
1450
1450
|
${J}Enable Home Assistant?${A} ${b(`[${cp}]`)}: ${F}`)).trim().toLowerCase()||(vi?"y":"n");process.stdout.write(A);let Gn=Gc==="y"||Gc==="yes",_r="",kr="",$i=!0;if(Gn){_r=await W(l," Home Assistant URL (e.g. http://homeassistant.local:8123)",vi||"http://homeassistant.local:8123");let k=t.env.ALFRED_HOMEASSISTANT_TOKEN??qn?.accessToken??"";k&&console.log(` ${b(`Current token: ${ke(k)}`)}`),console.log(` ${b("Create: Settings \u2192 Security \u2192 Long-Lived Access Tokens")}`),kr=(await l.question(` ${J}Long-Lived Access Token${A}: ${F}`)).trim(),process.stdout.write(A),!kr&&k&&(kr=k);let $=qn?.verifyTls===!1?"y/N":"Y/n",N=(await l.question(` ${J}Verify TLS?${A} ${b(`(self-signed? \u2192 no) [${$}]`)}: ${F}`)).trim().toLowerCase()||(qn?.verifyTls===!1?"n":"y");process.stdout.write(A),$i=N==="y"||N==="yes",console.log(` ${U(">")} Home Assistant: ${D(_r)} ${b(`(TLS verify: ${$i?"yes":"no"})`)}`)}else console.log(` ${b("Home Assistant disabled.")}`);let Ue=t.config.contacts,Ai=t.env.ALFRED_CONTACTS_PROVIDER??Ue?.provider??"",lp=Ai?"Y/n":"y/N",Xc=(await l.question(`
|
|
1451
1451
|
${J}Enable Contacts management?${A} ${b(`[${lp}]`)}: ${F}`)).trim().toLowerCase()||(Ai?"y":"n");process.stdout.write(A);let Xn=Xc==="y"||Xc==="yes",Fe="",we={};if(Xn){let k=["carddav","google","microsoft"],$=k.indexOf(Ai),N=$>=0?$+1:1;console.log(` ${_e("1)")} CardDAV (Nextcloud, Radicale, etc.)`),console.log(` ${_e("2)")} Google Contacts`),console.log(` ${_e("3)")} Microsoft 365`);let V=await jn(l," > ",1,3,N);if(Fe=k[V-1],we.ALFRED_CONTACTS_PROVIDER=Fe,Fe==="carddav"){let O=t.env.ALFRED_CARDDAV_CONTACTS_SERVER_URL??Ue?.carddav?.serverUrl??"";we.ALFRED_CARDDAV_CONTACTS_SERVER_URL=await W(l," CardDAV Server URL",O||"https://cloud.example.com/remote.php/dav");let K=t.env.ALFRED_CARDDAV_CONTACTS_USERNAME??Ue?.carddav?.username??"";we.ALFRED_CARDDAV_CONTACTS_USERNAME=await W(l," Username",K);let oe=t.env.ALFRED_CARDDAV_CONTACTS_PASSWORD??Ue?.carddav?.password??"";oe&&console.log(` ${b(`Current password: ${ke(oe)}`)}`);let ve=(await l.question(` ${J}Password${A}: ${F}`)).trim();process.stdout.write(A),we.ALFRED_CARDDAV_CONTACTS_PASSWORD=ve||oe}else if(Fe==="google"){let O=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_ID??Ue?.google?.clientId??"";O&&console.log(` ${b(`Current client ID: ${ke(O)}`)}`),we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID=(await l.question(` ${J}Google Client ID${A}: ${F}`)).trim()||O,process.stdout.write(A);let K=t.env.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET??Ue?.google?.clientSecret??"";we.ALFRED_GOOGLE_CONTACTS_CLIENT_SECRET=(await l.question(` ${J}Google Client Secret${A}: ${F}`)).trim()||K,process.stdout.write(A);let oe=t.env.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN??Ue?.google?.refreshToken??"";we.ALFRED_GOOGLE_CONTACTS_REFRESH_TOKEN=(await l.question(` ${J}Refresh Token${A}: ${F}`)).trim()||oe,process.stdout.write(A)}else if(Fe==="microsoft"){let O=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID??Ue?.microsoft?.clientId??"";O&&console.log(` ${b(`Current client ID: ${ke(O)}`)}`),we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID=(await l.question(` ${J}Microsoft Client ID${A}: ${F}`)).trim()||O,process.stdout.write(A);let K=t.env.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET??Ue?.microsoft?.clientSecret??"";we.ALFRED_MICROSOFT_CONTACTS_CLIENT_SECRET=(await l.question(` ${J}Microsoft Client Secret${A}: ${F}`)).trim()||K,process.stdout.write(A);let oe=t.env.ALFRED_MICROSOFT_CONTACTS_TENANT_ID??Ue?.microsoft?.tenantId??"";we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID=await W(l," Tenant ID",oe||"common");let ve=t.env.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN??Ue?.microsoft?.refreshToken??"";console.log(` ${b("Tipp: Du kannst `alfred auth microsoft` ausf\xFChren um den Refresh Token automatisch zu holen.")}`),we.ALFRED_MICROSOFT_CONTACTS_REFRESH_TOKEN=(await l.question(` ${J}Refresh Token${A}: ${F}`)).trim()||ve,process.stdout.write(A)}console.log(` ${U(">")} Contacts: ${D(Fe)}`)}else console.log(` ${b("Contacts disabled.")}`);let Kc=t.config.docker,Ii=t.env.ALFRED_DOCKER_SOCKET_PATH??Kc?.socketPath??"",Ri=t.env.ALFRED_DOCKER_HOST??Kc?.host??"",dp=Ii||Ri?"Y/n":"y/N",Vc=(await l.question(`
|
|
1452
1452
|
${J}Enable Docker management?${A} ${b(`[${dp}]`)}: ${F}`)).trim().toLowerCase()||(Ii||Ri?"y":"n");process.stdout.write(A);let Kn=Vc==="y"||Vc==="yes",Rt="",xt="";if(Kn){let k=process.platform==="win32"?"//./pipe/docker_engine":"/var/run/docker.sock";console.log(` ${b("Use socket path for local Docker, or host URL for remote.")}`),Rt=await W(l," Docker socket path",Ii||k);let $=(await l.question(` ${J}Docker host URL (optional, for remote)${A}: ${F}`)).trim();process.stdout.write(A),xt=$||Ri,console.log(` ${U(">")} Docker: ${D(xt||Rt)}`)}else console.log(` ${b("Docker disabled.")}`);let up=t.config.bmw,xi=t.env.ALFRED_BMW_CLIENT_ID??up?.clientId??"",mp=xi?"Y/n":"y/N",Yc=(await l.question(`
|
|
@@ -1454,8 +1454,8 @@ ${D("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.
|
|
|
1454
1454
|
${J}Enable route planning with live traffic (Google Routes)?${A} ${b(`[${hp}]`)}: ${F}`)).trim().toLowerCase()||(Ni?"y":"n");process.stdout.write(A);let Yn=Jc==="y"||Jc==="yes",Li="";Yn?(console.log(` ${b("Setup:")}`),console.log(` ${b(" 1. \xD6ffne https://console.cloud.google.com")}`),console.log(` ${b(" 2. Routes API aktivieren")}`),console.log(` ${b(" 3. API Key erstellen")}`),Li=await W(l," Google Maps API Key",Ni),console.log(` ${U(">")} Routing: ${D("enabled")}`)):console.log(` ${b("Routing disabled.")}`);let tt=t.config.energy,fp=t.env.ALFRED_ENERGY_GRID_NAME??tt?.gridName??"",Di=t.env.ALFRED_ENERGY_GRID_USAGE_CT??(tt?.gridUsageCt!=null?String(tt.gridUsageCt):""),gp=t.env.ALFRED_ENERGY_GRID_LOSS_CT??(tt?.gridLossCt!=null?String(tt.gridLossCt):""),yp=t.env.ALFRED_ENERGY_GRID_CAPACITY_FEE??(tt?.gridCapacityFee!=null?String(tt.gridCapacityFee):""),wp=t.env.ALFRED_ENERGY_GRID_METER_FEE??(tt?.gridMeterFee!=null?String(tt.gridMeterFee):""),Tp=Di?"Y/n":"y/N",Zc=(await l.question(`
|
|
1455
1455
|
${J}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${A} ${b(`[${Tp}]`)}: ${F}`)).trim().toLowerCase()||(Di?"y":"n");process.stdout.write(A);let Jn=Zc==="y"||Zc==="yes",Ct="",Nt="",Zn="",br="",Er="";Jn?(console.log(` ${b('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${b("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),Ct=await W(l," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",fp),Nt=await W(l," Netznutzungsentgelt (ct/kWh netto)",Di),Zn=await W(l," Netzverlustentgelt (ct/kWh netto)",gp||"0.38"),br=await W(l," Leistungspauschale (\u20AC/Monat netto)",yp),Er=await W(l," Messentgelt (\u20AC/Monat netto)",wp||"2.22"),console.log(` ${U(">")} Energy: ${D(Ct||"enabled")} (${Nt} + ${Zn} ct/kWh)`)):console.log(` ${b("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
|
|
1456
1456
|
${D("Security configuration:")}`);let Qc=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",Re;if(Qc)Re=await W(l,"Owner user ID (for elevated permissions)",Qc);else{let k=(await l.question(`${J}Owner user ID${A} ${b("(optional, for elevated permissions)")}: ${F}`)).trim();process.stdout.write(A),Re=k}let Sr=!1;if(Re){let k=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${D("Enable shell access (admin commands) for the owner?")}`),console.log(` ${b("Allows Alfred to execute shell commands. Only for the owner.")}`);let $=(await l.question(` ${F}> ${A}${b(`[${k}] `)}`)).trim().toLowerCase();$===""?Sr=t.shellEnabled:Sr=$==="y"||$==="yes",console.log(Sr?` ${U(">")} Shell access ${D("enabled")} for owner ${b(Re)}`:` ${b("Shell access disabled.")}`)}let _p=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${D("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${b("By default, write actions are only allowed in DMs.")}`);let Mi=(await l.question(` ${F}> ${A}${b(`[${_p}] `)}`)).trim().toLowerCase(),vr;Mi===""?vr=t.writeInGroups:vr=Mi==="y"||Mi==="yes",console.log(vr?` ${U(">")} Write actions ${D("enabled")} in groups`:` ${b("Write actions only in DMs (default).")}`);let kp=t.rateLimit??30;console.log("");let bp=await W(l," Rate limit (max write actions per hour per user)",String(kp)),Qn=Math.max(1,parseInt(bp,10)||30);console.log(` ${U(">")} Rate limit: ${D(String(Qn))} per hour`),console.log(`
|
|
1457
|
-
${D("Writing configuration files...")}`);let R=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let k=a.envKeyName||"ALFRED_OLLAMA_API_KEY";R.push(`${k}=${c}`)}if(f!==a.defaultModel&&R.push(`ALFRED_LLM_MODEL=${f}`),u&&R.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(I).length>0){R.push("","# === Additional Model Tiers ===");for(let[k,$]of Object.entries(I)){let N=`ALFRED_LLM_${k.toUpperCase()}`;R.push(""),R.push(`${N}_PROVIDER=${$.provider}`),R.push(`${N}_MODEL=${$.model}`),$.apiKey&&R.push(`${N}_API_KEY=${$.apiKey}`),$.baseUrl&&R.push(`${N}_BASE_URL=${$.baseUrl}`)}}R.push("","# === Messaging Platforms ===","");for(let[k,$]of Object.entries(Pe))R.push(`${k}=${$}`);if(R.push("","# === Web Search ===",""),ne?(R.push(`ALFRED_SEARCH_PROVIDER=${ne}`),ie&&R.push(`ALFRED_SEARCH_API_KEY=${ie}`),Q&&R.push(`ALFRED_SEARCH_BASE_URL=${Q}`)):(R.push("# ALFRED_SEARCH_PROVIDER=brave"),R.push("# ALFRED_SEARCH_API_KEY=")),R.push("","# === Email ===",""),X&&z.length>0){let k=z[0];k.provider==="microsoft"?(R.push("ALFRED_EMAIL_PROVIDER=microsoft"),k.msClientId?(R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${k.msClientId}`),R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${k.msClientSecret}`),R.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${k.msTenantId}`),R.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${k.msRefreshToken}`)):R.push("# Microsoft email credentials shared from calendar config")):(R.push(`ALFRED_EMAIL_USER=${k.user}`),R.push(`ALFRED_EMAIL_PASS=${k.pass}`)),z.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 ===",""),Ye?(R.push(`ALFRED_SPEECH_PROVIDER=${Ye}`),R.push(`ALFRED_SPEECH_API_KEY=${dt}`),ar&&R.push(`ALFRED_SPEECH_BASE_URL=${ar}`),cr&&(R.push("ALFRED_TTS_ENABLED=true"),R.push(`ALFRED_TTS_VOICE=${lr}`))):(R.push("# ALFRED_SPEECH_PROVIDER=groq"),R.push("# ALFRED_SPEECH_API_KEY=")),R.push("","# === Forge (GitHub / GitLab) ===",""),$t==="github"?(R.push("ALFRED_FORGE_PROVIDER=github"),R.push(`ALFRED_GITHUB_TOKEN=${dr}`)):$t==="gitlab"?(R.push("ALFRED_FORGE_PROVIDER=gitlab"),R.push(`ALFRED_GITLAB_TOKEN=${ur}`)):(R.push("# ALFRED_FORGE_PROVIDER=github"),R.push("# ALFRED_GITHUB_TOKEN=")),R.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),Hn?(R.push(`ALFRED_PROXMOX_BASE_URL=${pr}`),R.push(`ALFRED_PROXMOX_TOKEN_ID=${wi}`),R.push(`ALFRED_PROXMOX_TOKEN_SECRET=${hr}`)):(R.push("# ALFRED_PROXMOX_BASE_URL="),R.push("# ALFRED_PROXMOX_TOKEN_ID="),R.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),Wn?(R.push(`ALFRED_PBS_BASE_URL=${fr}`),R.push(`ALFRED_PBS_TOKEN_ID=${ki}`),R.push(`ALFRED_PBS_TOKEN_SECRET=${gr}`),R.push(`ALFRED_PBS_MAX_AGE_HOURS=${yr}`),zn||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=")),wr&&It?(R.push(`ALFRED_UNIFI_BASE_URL=${
|
|
1458
|
-
`),"utf-8"),console.log(` ${U("+")} ${b(".env")} written`);let eo=Ie.join(e,"config");be.existsSync(eo)||be.mkdirSync(eo,{recursive:!0});let el={name:r,telegram:{token:me.telegram?.token??"",enabled:le.some(k=>k.name==="telegram")},discord:{token:me.discord?.token??"",enabled:le.some(k=>k.name==="discord")},whatsapp:{enabled:le.some(k=>k.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:me.matrix?.homeserverUrl??"https://matrix.org",accessToken:me.matrix?.accessToken??"",userId:me.matrix?.userId??"",enabled:le.some(k=>k.name==="matrix")},signal:{apiUrl:me.signal?.apiUrl??"http://localhost:8080",phoneNumber:me.signal?.phoneNumber??"",enabled:le.some(k=>k.name==="signal")},llm:Object.keys(I).length>0?{default:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...I}:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...ne?{search:{provider:ne,...ie?{apiKey:ie}:{},...Q?{baseUrl:Q}:{}}}:{},...X&&z.length>0?{email:{accounts:z.map(k=>k.provider==="microsoft"?{name:k.name,provider:"microsoft",...k.msClientId?{microsoft:{clientId:k.msClientId,clientSecret:k.msClientSecret,tenantId:k.msTenantId,refreshToken:k.msRefreshToken}}:{}}:{name:k.name,imap:{host:k.imapHost,port:k.imapPort,secure:k.imapPort===993},smtp:{host:k.smtpHost,port:k.smtpPort,secure:k.smtpPort===465},auth:{user:k.user,pass:k.pass}})}}:{},...Ye?{speech:{provider:Ye,apiKey:dt,...ar?{baseUrl:ar}:{},...cr?{ttsEnabled:!0,ttsVoice:lr}:{}}}:{},...di?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...vt.length>0||$t?{codeAgents:{enabled:vt.length>0,agents:vt,...$t==="github"?{forge:{provider:"github",github:{token:dr}}}:$t==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:ur}}}:{}}}:{},...Hn?{proxmox:{baseUrl:pr,tokenId:wi,tokenSecret:hr,verifyTls:Ti}}:{},...Wn?{proxmoxBackup:{baseUrl:fr,tokenId:ki,tokenSecret:gr,maxAgeHours:yr,verifyTls:zn}}:{},...wr?{unifi:{baseUrl:
|
|
1457
|
+
${D("Writing configuration files...")}`);let R=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${a.name}`];if(c){let k=a.envKeyName||"ALFRED_OLLAMA_API_KEY";R.push(`${k}=${c}`)}if(f!==a.defaultModel&&R.push(`ALFRED_LLM_MODEL=${f}`),u&&R.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(I).length>0){R.push("","# === Additional Model Tiers ===");for(let[k,$]of Object.entries(I)){let N=`ALFRED_LLM_${k.toUpperCase()}`;R.push(""),R.push(`${N}_PROVIDER=${$.provider}`),R.push(`${N}_MODEL=${$.model}`),$.apiKey&&R.push(`${N}_API_KEY=${$.apiKey}`),$.baseUrl&&R.push(`${N}_BASE_URL=${$.baseUrl}`)}}R.push("","# === Messaging Platforms ===","");for(let[k,$]of Object.entries(Pe))R.push(`${k}=${$}`);if(R.push("","# === Web Search ===",""),ne?(R.push(`ALFRED_SEARCH_PROVIDER=${ne}`),ie&&R.push(`ALFRED_SEARCH_API_KEY=${ie}`),Q&&R.push(`ALFRED_SEARCH_BASE_URL=${Q}`)):(R.push("# ALFRED_SEARCH_PROVIDER=brave"),R.push("# ALFRED_SEARCH_API_KEY=")),R.push("","# === Email ===",""),X&&z.length>0){let k=z[0];k.provider==="microsoft"?(R.push("ALFRED_EMAIL_PROVIDER=microsoft"),k.msClientId?(R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${k.msClientId}`),R.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${k.msClientSecret}`),R.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${k.msTenantId}`),R.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${k.msRefreshToken}`)):R.push("# Microsoft email credentials shared from calendar config")):(R.push(`ALFRED_EMAIL_USER=${k.user}`),R.push(`ALFRED_EMAIL_PASS=${k.pass}`)),z.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 ===",""),Ye?(R.push(`ALFRED_SPEECH_PROVIDER=${Ye}`),R.push(`ALFRED_SPEECH_API_KEY=${dt}`),ar&&R.push(`ALFRED_SPEECH_BASE_URL=${ar}`),cr&&(R.push("ALFRED_TTS_ENABLED=true"),R.push(`ALFRED_TTS_VOICE=${lr}`))):(R.push("# ALFRED_SPEECH_PROVIDER=groq"),R.push("# ALFRED_SPEECH_API_KEY=")),R.push("","# === Forge (GitHub / GitLab) ===",""),$t==="github"?(R.push("ALFRED_FORGE_PROVIDER=github"),R.push(`ALFRED_GITHUB_TOKEN=${dr}`)):$t==="gitlab"?(R.push("ALFRED_FORGE_PROVIDER=gitlab"),R.push(`ALFRED_GITLAB_TOKEN=${ur}`)):(R.push("# ALFRED_FORGE_PROVIDER=github"),R.push("# ALFRED_GITHUB_TOKEN=")),R.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),Hn?(R.push(`ALFRED_PROXMOX_BASE_URL=${pr}`),R.push(`ALFRED_PROXMOX_TOKEN_ID=${wi}`),R.push(`ALFRED_PROXMOX_TOKEN_SECRET=${hr}`)):(R.push("# ALFRED_PROXMOX_BASE_URL="),R.push("# ALFRED_PROXMOX_TOKEN_ID="),R.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),Wn?(R.push(`ALFRED_PBS_BASE_URL=${fr}`),R.push(`ALFRED_PBS_TOKEN_ID=${ki}`),R.push(`ALFRED_PBS_TOKEN_SECRET=${gr}`),R.push(`ALFRED_PBS_MAX_AGE_HOURS=${yr}`),zn||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=")),wr&&It?(R.push(`ALFRED_UNIFI_BASE_URL=${Zt}`),R.push(`ALFRED_UNIFI_API_KEY=${It}`)):wr?(R.push(`ALFRED_UNIFI_BASE_URL=${Zt}`),R.push(`ALFRED_UNIFI_USERNAME=${Ei}`),R.push(`ALFRED_UNIFI_PASSWORD=${Tr}`)):(R.push("# ALFRED_UNIFI_BASE_URL="),R.push("# ALFRED_UNIFI_API_KEY=")),Gn?(R.push(`ALFRED_HOMEASSISTANT_URL=${_r}`),R.push(`ALFRED_HOMEASSISTANT_TOKEN=${kr}`)):(R.push("# ALFRED_HOMEASSISTANT_URL="),R.push("# ALFRED_HOMEASSISTANT_TOKEN=")),R.push("","# === Contacts ===",""),Xn)for(let[k,$]of Object.entries(we))R.push(`${k}=${$}`);else R.push("# ALFRED_CONTACTS_PROVIDER=carddav");R.push("","# === Docker ===",""),Kn?(Rt&&R.push(`ALFRED_DOCKER_SOCKET_PATH=${Rt}`),xt&&R.push(`ALFRED_DOCKER_HOST=${xt}`)):(R.push("# ALFRED_DOCKER_SOCKET_PATH="),R.push("# ALFRED_DOCKER_HOST=")),R.push("","# === BMW CarData ===",""),Vn?R.push(`ALFRED_BMW_CLIENT_ID=${Ci}`):R.push("# ALFRED_BMW_CLIENT_ID="),R.push("","# === Routing ===",""),Yn?R.push(`ALFRED_ROUTING_API_KEY=${Li}`):R.push("# ALFRED_ROUTING_API_KEY="),R.push("","# === Energy / aWATTar ===",""),Jn&&Nt?(Ct&&R.push(`ALFRED_ENERGY_GRID_NAME=${Ct}`),R.push(`ALFRED_ENERGY_GRID_USAGE_CT=${Nt}`),R.push(`ALFRED_ENERGY_GRID_LOSS_CT=${Zn}`),br&&R.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${br}`),Er&&R.push(`ALFRED_ENERGY_GRID_METER_FEE=${Er}`)):(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=")),R.push("","# === Security ===",""),Re?R.push(`ALFRED_OWNER_USER_ID=${Re}`):R.push("# ALFRED_OWNER_USER_ID="),R.push("");let Ep=Ie.join(e,".env");be.writeFileSync(Ep,R.join(`
|
|
1458
|
+
`),"utf-8"),console.log(` ${U("+")} ${b(".env")} written`);let eo=Ie.join(e,"config");be.existsSync(eo)||be.mkdirSync(eo,{recursive:!0});let el={name:r,telegram:{token:me.telegram?.token??"",enabled:le.some(k=>k.name==="telegram")},discord:{token:me.discord?.token??"",enabled:le.some(k=>k.name==="discord")},whatsapp:{enabled:le.some(k=>k.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:me.matrix?.homeserverUrl??"https://matrix.org",accessToken:me.matrix?.accessToken??"",userId:me.matrix?.userId??"",enabled:le.some(k=>k.name==="matrix")},signal:{apiUrl:me.signal?.apiUrl??"http://localhost:8080",phoneNumber:me.signal?.phoneNumber??"",enabled:le.some(k=>k.name==="signal")},llm:Object.keys(I).length>0?{default:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...I}:{provider:a.name,model:f,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...ne?{search:{provider:ne,...ie?{apiKey:ie}:{},...Q?{baseUrl:Q}:{}}}:{},...X&&z.length>0?{email:{accounts:z.map(k=>k.provider==="microsoft"?{name:k.name,provider:"microsoft",...k.msClientId?{microsoft:{clientId:k.msClientId,clientSecret:k.msClientSecret,tenantId:k.msTenantId,refreshToken:k.msRefreshToken}}:{}}:{name:k.name,imap:{host:k.imapHost,port:k.imapPort,secure:k.imapPort===993},smtp:{host:k.smtpHost,port:k.smtpPort,secure:k.smtpPort===465},auth:{user:k.user,pass:k.pass}})}}:{},...Ye?{speech:{provider:Ye,apiKey:dt,...ar?{baseUrl:ar}:{},...cr?{ttsEnabled:!0,ttsVoice:lr}:{}}}:{},...di?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...vt.length>0||$t?{codeAgents:{enabled:vt.length>0,agents:vt,...$t==="github"?{forge:{provider:"github",github:{token:dr}}}:$t==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:ur}}}:{}}}:{},...Hn?{proxmox:{baseUrl:pr,tokenId:wi,tokenSecret:hr,verifyTls:Ti}}:{},...Wn?{proxmoxBackup:{baseUrl:fr,tokenId:ki,tokenSecret:gr,maxAgeHours:yr,verifyTls:zn}}:{},...wr?{unifi:{baseUrl:Zt,...It?{apiKey:It}:{username:Ei,password:Tr},site:"default",verifyTls:Si}}:{},...Gn?{homeassistant:{baseUrl:_r,accessToken:kr,verifyTls:$i}}:{},...Xn?{contacts:{provider:Fe,...Fe==="carddav"?{carddav:{serverUrl:we.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:we.ALFRED_CARDDAV_CONTACTS_USERNAME}}:Fe==="google"?{google:{clientId:we.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:Fe==="microsoft"?{microsoft:{clientId:we.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:we.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Kn?{docker:{...Rt?{socketPath:Rt}:{},...xt?{host:xt}:{}}}:{},...Vn?{bmw:{clientId:Ci}}:{},...Yn?{routing:{apiKey:Li}}:{},...Jn&&Nt?{energy:{...Ct?{gridName:Ct}:{},gridUsageCt:parseFloat(Nt),gridLossCt:parseFloat(Zn||"0"),...br?{gridCapacityFee:parseFloat(br)}:{},...Er?{gridMeterFee:parseFloat(Er)}:{}}}:{},api:{enabled:!0,port:3420,host:"127.0.0.1",webUi:gi},storage:{path:"./data/alfred.db"},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};Re&&(el.security.ownerUserId=Re);let Sp="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+Pc.dump(el,{lineWidth:120,noRefs:!0,sortKeys:!1}),vp=Ie.join(eo,"default.yml");be.writeFileSync(vp,Sp,"utf-8"),console.log(` ${U("+")} ${b("config/default.yml")} written`);let Oi=Ie.join(eo,"rules");be.existsSync(Oi)||be.mkdirSync(Oi,{recursive:!0});let $p=Sr&&Re?`
|
|
1459
1459
|
# Allow admin actions (shell, etc.) for the owner only
|
|
1460
1460
|
- id: allow-owner-admin
|
|
1461
1461
|
effect: allow
|
|
@@ -1531,7 +1531,7 @@ ${$p}
|
|
|
1531
1531
|
scope: global
|
|
1532
1532
|
actions: ["*"]
|
|
1533
1533
|
riskLevels: [read, write, destructive, admin]
|
|
1534
|
-
`,Ip=Ie.join(Oi,"default-rules.yml");be.writeFileSync(Ip,Ap,"utf-8"),console.log(` ${U("+")} ${b("config/rules/default-rules.yml")} written`);let tl=Ie.join(e,"data");be.existsSync(tl)||(be.mkdirSync(tl,{recursive:!0}),console.log(` ${U("+")} ${b("data/")} directory created`)),console.log(""),console.log(`${oi}${"=".repeat(52)}${A}`),console.log(`${oi}${J} Setup complete!${A}`),console.log(`${oi}${"=".repeat(52)}${A}`),console.log(""),console.log(` ${D("Bot name:")} ${r}`),console.log(` ${D("LLM default:")} ${a.name} (${f})`),c&&console.log(` ${D("API key:")} ${ke(c)}`);for(let[k,$]of Object.entries(I)){let N=k.charAt(0).toUpperCase()+k.slice(1);console.log(` ${D(`LLM ${N}:`)}${" ".repeat(Math.max(1,10-N.length))}${$.provider} (${$.model})`)}if(le.length>0?console.log(` ${D("Platforms:")} ${le.map(k=>k.label).join(", ")}`):console.log(` ${D("Platforms:")} none (configure later)`),ne){let k={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${Q})`};console.log(` ${D("Web search:")} ${k[ne]}`)}else console.log(` ${D("Web search:")} ${b("disabled")}`);if(X&&z.length>0){let k=z.map($=>$.provider==="microsoft"?`${$.name} (Microsoft 365)${$.msClientId?"":" \u2014 shared from Calendar"}`:`${$.name} (${$.imapHost})`);console.log(` ${D("Email:")} ${k.join(", ")}`)}else console.log(` ${D("Email:")} ${b("disabled")}`);if(Ye){let k={openai:"OpenAI Whisper",groq:"Groq Whisper"},$=cr?`, TTS: ${lr}`:"";console.log(` ${D("Voice:")} ${k[Ye]}${$}`)}else console.log(` ${D("Voice:")} ${b("disabled")}`);console.log(` ${D("Code Sandbox:")} ${di?U("enabled"):b("disabled")}`),console.log(` ${D("Web Chat UI:")} ${gi?U("enabled (/alfred/)"):b("disabled")}`),Hn&&console.log(` ${D("Proxmox:")} ${U(pr)}`),Wn&&console.log(` ${D("PBS:")} ${U(fr)} ${b(`(max age: ${yr}h)`)}`),wr&&console.log(` ${D("UniFi:")} ${U(
|
|
1534
|
+
`,Ip=Ie.join(Oi,"default-rules.yml");be.writeFileSync(Ip,Ap,"utf-8"),console.log(` ${U("+")} ${b("config/rules/default-rules.yml")} written`);let tl=Ie.join(e,"data");be.existsSync(tl)||(be.mkdirSync(tl,{recursive:!0}),console.log(` ${U("+")} ${b("data/")} directory created`)),console.log(""),console.log(`${oi}${"=".repeat(52)}${A}`),console.log(`${oi}${J} Setup complete!${A}`),console.log(`${oi}${"=".repeat(52)}${A}`),console.log(""),console.log(` ${D("Bot name:")} ${r}`),console.log(` ${D("LLM default:")} ${a.name} (${f})`),c&&console.log(` ${D("API key:")} ${ke(c)}`);for(let[k,$]of Object.entries(I)){let N=k.charAt(0).toUpperCase()+k.slice(1);console.log(` ${D(`LLM ${N}:`)}${" ".repeat(Math.max(1,10-N.length))}${$.provider} (${$.model})`)}if(le.length>0?console.log(` ${D("Platforms:")} ${le.map(k=>k.label).join(", ")}`):console.log(` ${D("Platforms:")} none (configure later)`),ne){let k={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${Q})`};console.log(` ${D("Web search:")} ${k[ne]}`)}else console.log(` ${D("Web search:")} ${b("disabled")}`);if(X&&z.length>0){let k=z.map($=>$.provider==="microsoft"?`${$.name} (Microsoft 365)${$.msClientId?"":" \u2014 shared from Calendar"}`:`${$.name} (${$.imapHost})`);console.log(` ${D("Email:")} ${k.join(", ")}`)}else console.log(` ${D("Email:")} ${b("disabled")}`);if(Ye){let k={openai:"OpenAI Whisper",groq:"Groq Whisper"},$=cr?`, TTS: ${lr}`:"";console.log(` ${D("Voice:")} ${k[Ye]}${$}`)}else console.log(` ${D("Voice:")} ${b("disabled")}`);console.log(` ${D("Code Sandbox:")} ${di?U("enabled"):b("disabled")}`),console.log(` ${D("Web Chat UI:")} ${gi?U("enabled (/alfred/)"):b("disabled")}`),Hn&&console.log(` ${D("Proxmox:")} ${U(pr)}`),Wn&&console.log(` ${D("PBS:")} ${U(fr)} ${b(`(max age: ${yr}h)`)}`),wr&&console.log(` ${D("UniFi:")} ${U(Zt)}`),Gn&&console.log(` ${D("Home Assist.:")} ${U(_r)}`),Xn&&console.log(` ${D("Contacts:")} ${U(Fe)}`),Kn&&console.log(` ${D("Docker:")} ${U(xt||Rt)}`),Vn&&console.log(` ${D("BMW CarData:")} ${U("enabled")}`),Yn&&console.log(` ${D("Routing:")} ${U("enabled")}`),Jn&&console.log(` ${D("Energy:")} ${U(Ct||"enabled")} ${b(`(${Nt} ct/kWh)`)}`),Re&&(console.log(` ${D("Owner ID:")} ${Re}`),console.log(` ${D("Shell access:")} ${Sr?U("enabled"):b("disabled")}`)),console.log(` ${D("Write scope:")} ${vr?"DMs + Groups":"DMs only"}`),console.log(` ${D("Rate limit:")} ${Qn}/hour per user`),console.log(""),console.log(`${ii}Next steps:${A}`),console.log(` ${D("alfred start")} Start Alfred`),console.log(` ${D("alfred status")} Check configuration`),console.log(` ${D("alfred --help")} Show all commands`),console.log(""),console.log(`${bt}Edit ${D(".env")}${bt} or ${D("config/default.yml")}${bt} for manual configuration.${A}`),console.log("")}finally{l.close()}}async function W(l,e,t){let s=(await l.question(`${J}${e}${A} ${b(`[${t}]`)}: ${F}`)).trim();return process.stdout.write(A),s||t}async function Le(l,e){for(;;){let t=(await l.question(`${J}${e}${A}: ${F}`)).trim();if(process.stdout.write(A),t)return t;console.log(` ${Um("!")} This field is required. Please enter a value.`)}}async function jn(l,e,t,s,r){for(;;){let n=(await l.question(`${F}${e}${A}`)).trim();if(!n)return r;let o=parseInt(n,10);if(!Number.isNaN(o)&&o>=t&&o<=s)return o;console.log(` ${Um("!")} Please enter a number between ${t} and ${s}.`)}}function Qg(){console.log(`
|
|
1535
1535
|
${Kg}${J} _ _ _____ ____ _____ ____
|
|
1536
1536
|
/ \\ | | | ___| _ \\| ____| _ \\
|
|
1537
1537
|
/ _ \\ | | | |_ | |_) | _| | | | |
|