@madh-io/alfred-ai 0.19.0-multi-ha.621 → 0.19.0-multi-ha.623

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/bundle/index.js +30 -19
  2. package/bundle/web-ui/404/index.html +1 -1
  3. package/bundle/web-ui/404.html +1 -1
  4. package/bundle/web-ui/_next/static/DoOtlailpAQI1HyuG88F3/_buildManifest.js +1 -0
  5. package/bundle/web-ui/_next/static/DoOtlailpAQI1HyuG88F3/_ssgManifest.js +1 -0
  6. package/bundle/web-ui/_next/static/chunks/719-b89569005b603f0e.js +1 -0
  7. package/bundle/web-ui/_next/static/chunks/719-d849d50a3f2943b7.js +1 -0
  8. package/bundle/web-ui/_next/static/chunks/app/background-tasks/page-06a7315f90f821da.js +1 -0
  9. package/bundle/web-ui/_next/static/chunks/app/dashboard/page-45e74e505c9c4c06.js +1 -0
  10. package/bundle/web-ui/_next/static/chunks/app/layout-a3854def15036175.js +1 -0
  11. package/bundle/web-ui/_next/static/css/c3ddc29040090487.css +1 -0
  12. package/bundle/web-ui/_next/static/css/d0e5e1bedf15f337.css +1 -0
  13. package/bundle/web-ui/_next/static/xjMSArs9oNoOlIuRR-296/_buildManifest.js +1 -0
  14. package/bundle/web-ui/_next/static/xjMSArs9oNoOlIuRR-296/_ssgManifest.js +1 -0
  15. package/bundle/web-ui/background-tasks/index.html +1 -0
  16. package/bundle/web-ui/background-tasks/index.txt +19 -0
  17. package/bundle/web-ui/chat/index.html +1 -1
  18. package/bundle/web-ui/chat/index.txt +6 -6
  19. package/bundle/web-ui/cluster/index.html +1 -1
  20. package/bundle/web-ui/cluster/index.txt +6 -6
  21. package/bundle/web-ui/cmdb/index.html +1 -1
  22. package/bundle/web-ui/cmdb/index.txt +6 -6
  23. package/bundle/web-ui/dashboard/index.html +1 -1
  24. package/bundle/web-ui/dashboard/index.txt +6 -6
  25. package/bundle/web-ui/docs/index.html +1 -1
  26. package/bundle/web-ui/docs/index.txt +6 -6
  27. package/bundle/web-ui/index.html +1 -1
  28. package/bundle/web-ui/index.txt +6 -6
  29. package/bundle/web-ui/itsm/index.html +1 -1
  30. package/bundle/web-ui/itsm/index.txt +6 -6
  31. package/bundle/web-ui/knowledge/index.html +1 -1
  32. package/bundle/web-ui/knowledge/index.txt +6 -6
  33. package/bundle/web-ui/logs/index.html +1 -1
  34. package/bundle/web-ui/logs/index.txt +6 -6
  35. package/bundle/web-ui/memories/index.html +1 -1
  36. package/bundle/web-ui/memories/index.txt +6 -6
  37. package/bundle/web-ui/project-agents/index.html +1 -1
  38. package/bundle/web-ui/project-agents/index.txt +6 -6
  39. package/bundle/web-ui/projects/index.html +1 -1
  40. package/bundle/web-ui/projects/index.txt +6 -6
  41. package/bundle/web-ui/runbooks/index.html +1 -1
  42. package/bundle/web-ui/runbooks/index.txt +6 -6
  43. package/bundle/web-ui/services/index.html +1 -1
  44. package/bundle/web-ui/services/index.txt +6 -6
  45. package/bundle/web-ui/settings/index.html +1 -1
  46. package/bundle/web-ui/settings/index.txt +6 -6
  47. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -2240,7 +2240,7 @@ CREATE INDEX IF NOT EXISTS idx_sla_events_type ON sla_events(event_type);
2240
2240
  completed_at = COALESCE(?, completed_at),
2241
2241
  checkpoint_at = COALESCE(?, checkpoint_at)
2242
2242
  WHERE id = ?
2243
- `,[t,s??null,i??null,r,a,o,e])}async getPending(e=10){return(await this.adapter.query("SELECT * FROM background_tasks WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[e])).map(s=>this.mapRow(s))}async claimPending(e=10){return this.adapter.transaction(async t=>{let s=await t.query("SELECT * FROM background_tasks WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[e]),i=new Date().toISOString();for(let n of s)await t.execute("UPDATE background_tasks SET status = 'running', started_at = ? WHERE id = ?",[i,n.id]);return s.map(n=>this.mapRow({...n,status:"running",started_at:i}))})}async claimTask(e){let t=new Date().toISOString();return(await this.adapter.execute("UPDATE background_tasks SET status = 'running', started_at = ? WHERE id = ? AND status = 'pending'",[t,e])).changes>0}async getById(e){let t=await this.adapter.queryOne("SELECT * FROM background_tasks WHERE id = ?",[e]);return t?this.mapRow(t):void 0}async getByUser(e){let t=new Date(Date.now()-864e5).toISOString();return(await this.adapter.query(`SELECT * FROM background_tasks
2243
+ `,[t,s??null,i??null,r,a,o,e])}async getPending(e=10){return(await this.adapter.query("SELECT * FROM background_tasks WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[e])).map(s=>this.mapRow(s))}async claimPending(e=10){return this.adapter.transaction(async t=>{let s=await t.query("SELECT * FROM background_tasks WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[e]),i=new Date().toISOString();for(let n of s)await t.execute("UPDATE background_tasks SET status = 'running', started_at = ? WHERE id = ?",[i,n.id]);return s.map(n=>this.mapRow({...n,status:"running",started_at:i}))})}async claimTask(e){let t=new Date().toISOString();return(await this.adapter.execute("UPDATE background_tasks SET status = 'running', started_at = ? WHERE id = ? AND status = 'pending'",[t,e])).changes>0}async getById(e){let t=await this.adapter.queryOne("SELECT * FROM background_tasks WHERE id = ?",[e]);return t?this.mapRow(t):void 0}async listAll(e){let t=e?.limit??200;return e?.status?(await this.adapter.query("SELECT * FROM background_tasks WHERE status = ? ORDER BY created_at DESC LIMIT ?",[e.status,t])).map(n=>this.mapRow(n)):(await this.adapter.query("SELECT * FROM background_tasks ORDER BY created_at DESC LIMIT ?",[t])).map(i=>this.mapRow(i))}async getByUser(e){let t=new Date(Date.now()-864e5).toISOString();return(await this.adapter.query(`SELECT * FROM background_tasks
2244
2244
  WHERE user_id = ?
2245
2245
  AND (status IN ('pending', 'running', 'checkpointed', 'resuming') OR completed_at > ?)
2246
2246
  ORDER BY created_at DESC`,[e,t])).map(i=>this.mapRow(i))}async cancel(e){let t=new Date().toISOString();return(await this.adapter.execute(`UPDATE background_tasks
@@ -2370,7 +2370,18 @@ CREATE INDEX IF NOT EXISTS idx_sla_events_type ON sla_events(event_type);
2370
2370
  SUM(cache_write_tokens) as cache_write_tokens,
2371
2371
  SUM(cost_usd) as cost_usd
2372
2372
  FROM llm_usage GROUP BY model
2373
- `)).map(t=>this.mapRow(t))}async cleanup(e=365){let t=new Date(Date.now()-e*864e5).toISOString().slice(0,10);return(await this.adapter.execute("DELETE FROM llm_usage WHERE date < ?",[t])).changes}buildSummary(e,t){let s=t.map(i=>this.mapRow(i));return{date:e,models:s,totalCalls:s.reduce((i,n)=>i+n.calls,0),totalInputTokens:s.reduce((i,n)=>i+n.inputTokens,0),totalOutputTokens:s.reduce((i,n)=>i+n.outputTokens,0),totalCostUsd:Math.round(s.reduce((i,n)=>i+n.costUsd,0)*1e6)/1e6}}mapRow(e){return{model:e.model,calls:e.calls,inputTokens:e.input_tokens,outputTokens:e.output_tokens,cacheReadTokens:e.cache_read_tokens,cacheWriteTokens:e.cache_write_tokens,costUsd:e.cost_usd}}}});var js,Cf=S(()=>{"use strict";js=class{static{f(this,"CalendarNotificationRepository")}adapter;constructor(e){this.adapter=e}async wasNotified(e,t){let s=new Date().toISOString();return!!await this.adapter.queryOne("SELECT 1 FROM calendar_notifications WHERE event_id = ? AND chat_id = ? AND event_start > ?",[e,t,s])}async markNotified(e,t,s,i){let n=new Date().toISOString();await this.adapter.execute(`
2373
+ `)).map(t=>this.mapRow(t))}async getRangeByMonth(e,t){let s=await this.adapter.query(`
2374
+ SELECT SUBSTR(date, 1, 7) AS month, model,
2375
+ SUM(calls) AS calls,
2376
+ SUM(input_tokens) AS input_tokens,
2377
+ SUM(output_tokens) AS output_tokens,
2378
+ SUM(cache_read_tokens) AS cache_read_tokens,
2379
+ SUM(cache_write_tokens) AS cache_write_tokens,
2380
+ SUM(cost_usd) AS cost_usd
2381
+ FROM llm_usage WHERE date >= ? AND date <= ?
2382
+ GROUP BY SUBSTR(date, 1, 7), model
2383
+ ORDER BY month, model
2384
+ `,[e,t]),i=new Map;for(let n of s){let r=n.month;i.has(r)||i.set(r,[]),i.get(r).push(n)}return[...i.entries()].map(([n,r])=>this.buildSummary(n,r))}async getEarliestDate(){return(await this.adapter.queryOne("SELECT MIN(date) AS min_date FROM llm_usage"))?.min_date??void 0}async cleanup(e=365){let t=new Date(Date.now()-e*864e5).toISOString().slice(0,10);return(await this.adapter.execute("DELETE FROM llm_usage WHERE date < ?",[t])).changes}buildSummary(e,t){let s=t.map(i=>this.mapRow(i));return{date:e,models:s,totalCalls:s.reduce((i,n)=>i+n.calls,0),totalInputTokens:s.reduce((i,n)=>i+n.inputTokens,0),totalOutputTokens:s.reduce((i,n)=>i+n.outputTokens,0),totalCostUsd:Math.round(s.reduce((i,n)=>i+n.costUsd,0)*1e6)/1e6}}mapRow(e){return{model:e.model,calls:e.calls,inputTokens:e.input_tokens,outputTokens:e.output_tokens,cacheReadTokens:e.cache_read_tokens,cacheWriteTokens:e.cache_write_tokens,costUsd:e.cost_usd}}}});var js,Cf=S(()=>{"use strict";js=class{static{f(this,"CalendarNotificationRepository")}adapter;constructor(e){this.adapter=e}async wasNotified(e,t){let s=new Date().toISOString();return!!await this.adapter.queryOne("SELECT 1 FROM calendar_notifications WHERE event_id = ? AND chat_id = ? AND event_start > ?",[e,t,s])}async markNotified(e,t,s,i){let n=new Date().toISOString();await this.adapter.execute(`
2374
2385
  INSERT INTO calendar_notifications (event_id, chat_id, platform, notified_at, event_start)
2375
2386
  VALUES (?, ?, ?, ?, ?)
2376
2387
  ON CONFLICT (event_id, chat_id) DO NOTHING
@@ -2603,7 +2614,7 @@ ${r}`:r;await this.db.execute("UPDATE cmdb_problems SET analysis_notes = ?, upda
2603
2614
  WHERE p.user_id = ?
2604
2615
  `,i=[e];return t?.projectId&&(s+=" AND oi.project_id = ?",i.push(t.projectId)),t?.status&&(s+=" AND oi.status = ?",i.push(t.status)),t?.priority&&(s+=" AND oi.priority = ?",i.push(t.priority)),s+=" ORDER BY oi.created_at DESC LIMIT ?",i.push(t?.limit??100),(await this.adapter.query(s,i)).map(cu)}async updateOpenItemStatus(e,t){let s=new Date().toISOString(),i=t==="done"||t==="cancelled"?s:null;return(await this.adapter.execute("UPDATE project_open_items SET status = ?, resolved_at = ? WHERE id = ?",[t,i,e])).changes>0}async addDecision(e,t){let s=on(),i=new Date().toISOString();return await this.adapter.execute(`INSERT INTO project_decisions (id, project_id, session_id, title, choice, rationale, alternatives_considered, created_at)
2605
2616
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[s,e,t.sessionId??null,t.title,t.choice,t.rationale??null,t.alternativesConsidered??null,i]),{id:s,projectId:e,sessionId:t.sessionId,title:t.title,choice:t.choice,rationale:t.rationale,alternativesConsidered:t.alternativesConsidered,createdAt:i}}async listDecisions(e,t=50){return(await this.adapter.query("SELECT * FROM project_decisions WHERE project_id = ? ORDER BY created_at DESC LIMIT ?",[e,t])).map(TS)}async recordHealth(e,t){let s=on(),i=new Date().toISOString();return await this.adapter.execute(`INSERT INTO project_health_log (id, project_id, probe, status, details, duration_ms, checked_at)
2606
- VALUES (?, ?, ?, ?, ?, ?, ?)`,[s,e,t.probe,t.status,t.details??null,t.durationMs??0,i]),{id:s,projectId:e,probe:t.probe,status:t.status,details:t.details,durationMs:t.durationMs??0,checkedAt:i}}async getLatestHealth(e,t){let s=await this.adapter.queryOne("SELECT * FROM project_health_log WHERE project_id = ? AND probe = ? ORDER BY checked_at DESC LIMIT 1",[e,t]);return s?{id:s.id,projectId:s.project_id,probe:s.probe,status:s.status,details:s.details??void 0,durationMs:Number(s.duration_ms??0),checkedAt:s.checked_at}:null}async listHealthLog(e,t=100){return(await this.adapter.query("SELECT * FROM project_health_log WHERE project_id = ? ORDER BY checked_at DESC LIMIT ?",[e,t])).map(i=>({id:i.id,projectId:i.project_id,probe:i.probe,status:i.status,details:i.details??void 0,durationMs:Number(i.duration_ms??0),checkedAt:i.checked_at}))}async getCurrentHealthSummary(e){let t={};for(let s of["git","build","deps","http"]){let i=await this.getLatestHealth(e,s);i&&(t[s]=i)}return t}}});var tt={};Ne(tt,{ActivityRepository:()=>Bs,AlfredUserRepository:()=>Yo,AuditRepository:()=>Fs,BackgroundTaskRepository:()=>Xi,BmwTelematicRepository:()=>sn,BrainstormingRepository:()=>rc,CalendarNotificationRepository:()=>js,CmdbRepository:()=>Hs,ConfirmationRepository:()=>Vi,ConversationRepository:()=>Mi,Database:()=>_s,DatabaseConnectionRepository:()=>Go,DocumentRepository:()=>Ki,EmbeddingRepository:()=>Bi,FeedbackRepository:()=>en,HostCapabilitiesRepository:()=>qo,ItsmRepository:()=>oi,KnowledgeGraphRepository:()=>rs,LinkTokenRepository:()=>Hi,LocalFileStore:()=>Lr,MIGRATIONS:()=>Ho,MealPlanRepository:()=>Qo,MemoryRepository:()=>Pi,Migrator:()=>ri,NoteRepository:()=>ji,PG_MIGRATIONS:()=>af,PG_SCHEMA:()=>$r,PgMigrator:()=>zo,PlanRepository:()=>ic,PostgresAsyncAdapter:()=>Rs,ProblemRepository:()=>lc,ProcessedMessageRepository:()=>nc,ProjectAgentInterjectionRepository:()=>sc,ProjectAgentSessionRepository:()=>tc,ProjectRepository:()=>pc,RecipeFavoriteRepository:()=>Zo,ReminderRepository:()=>Fi,RunbookRepository:()=>uc,S3FileStore:()=>Cr,SQLiteAsyncAdapter:()=>ai,ScheduledActionRepository:()=>Wi,ServiceUsageRepository:()=>nn,SharedResourceRepository:()=>Jo,SkillHealthRepository:()=>Zi,SkillStateRepository:()=>tn,SummaryRepository:()=>Yi,TodoRepository:()=>qi,TravelPlanRepository:()=>ec,UsageRepository:()=>Ji,UserRepository:()=>Ui,WatchRepository:()=>Gi,WorkflowRepository:()=>Qi,createDbAdapter:()=>Vm,createFileStore:()=>Vf});var Je=S(()=>{"use strict";Zm();ef();tf();sf();nf();Bo();Qd();su();rf();of();cf();lf();df();hf();pf();Sf();Af();Rf();If();$f();Nf();Lf();Cf();Df();xf();Mf();Uf();Ff();jf();Bf();Xf();zf();Wf();Kf();Gf();Yf();tu();Jf();Zf();Qf();eg();tg();sg();ng();ag();cg();ug();pg();mg();gg()});function $s(d){if(lu[d])return lu[d];let e=Object.entries(lu).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(d.startsWith(t))return s}var lu,ES,Wt,ci=S(()=>{"use strict";lu={"claude-opus-4-7":{maxInputTokens:1e6,maxOutputTokens:128e3},"claude-opus-4-6":{maxInputTokens:1e6,maxOutputTokens:128e3},"claude-sonnet-4-6":{maxInputTokens:1e6,maxOutputTokens:64e3},"claude-opus-4-5-20251101":{maxInputTokens:1e6,maxOutputTokens:64e3},"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-5-20250929":{maxInputTokens:1e6,maxOutputTokens:64e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:64e3},"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-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:1e6,maxOutputTokens:64e3},"gpt-5.5":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5.4-mini":{maxInputTokens:4e5,maxOutputTokens:128e3},"gpt-5.4-nano":{maxInputTokens:4e5,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"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:8192},"gpt-3.5-turbo":{maxInputTokens:16385,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gemini-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:256e3,maxOutputTokens:256e3},"mistral-medium-3-5":{maxInputTokens:256e3,maxOutputTokens:131072},"mistral-medium":{maxInputTokens:131072,maxOutputTokens:131072},"mistral-small":{maxInputTokens:256e3,maxOutputTokens:256e3},codestral:{maxInputTokens:256e3,maxOutputTokens:256e3},"magistral-medium":{maxInputTokens:4e4,maxOutputTokens:4e4},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},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:128e3},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:16384,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:64e3},"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}},ES={maxInputTokens:128e3,maxOutputTokens:8192};f($s,"lookupContextWindow");Wt=class{static{f(this,"LLMProvider")}config;contextWindow=ES;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import kS from"@anthropic-ai/sdk";var Mr,du=S(()=>{"use strict";ci();Mr=class extends Wt{static{f(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new kS({apiKey:this.config.apiKey,maxRetries:5});let e=$s(this.config.model);e&&(this.contextWindow=e)}supportsTemperature(){return!(this.config.model??"").toLowerCase().includes("opus-4-7")}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,i={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,...this.supportsTemperature()?{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(i);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,i=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,...this.supportsTemperature()?{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 i)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 r=await i.finalMessage();yield{type:"message_complete",response:this.mapResponse(r)}}}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(i=>{switch(i.type){case"text":return{type:"text",text:i.text};case"image":return{type:"image",source:{type:"base64",media_type:i.source.media_type,data:i.source.data}};case"tool_use":return{type:"tool_use",id:i.id,name:i.name,input:i.input};case"tool_result":return{type:"tool_result",tool_use_id:i.tool_use_id,content:i.content,is_error:i.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(i=>i!==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 i of e.content)i.type==="text"?t+=i.text:i.type==="tool_use"&&s.push({id:i.id,name:i.name,input:i.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 bS from"openai";var as,cn=S(()=>{"use strict";ci();as=class extends Wt{static{f(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new bS({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=$s(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,i=s?void 0:this.reasoningEffortParam(e.reasoningEffort),n={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},...i?{reasoning_effort:i}:{},...this.extraRequestParams(e)},r=await this.client.chat.completions.create(n);return this.mapResponse(r)}extraRequestParams(e){return{}}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,i=s?void 0:this.reasoningEffortParam(e.reasoningEffort),n={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},...i?{reasoning_effort:i}:{},...this.extraRequestParams(e),stream:!0},r=await this.client.chat.completions.create(n),a,o,c="",l="",u=[],h=null,p=0,m=0,y=0;for await(let g of r){let w=g.choices[0];if(!w)continue;let T=w.delta;if(T?.content&&(l+=T.content,yield{type:"text_delta",text:T.content}),T?.tool_calls)for(let _ of T.tool_calls)if(_.id){if(a){let k;try{k=JSON.parse(c||"{}")}catch{k={}}u.push({id:a,name:o,input:k})}a=_.id,o=_.function?.name,c=_.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:a,name:o}}}else _.function?.arguments&&(c+=_.function.arguments,yield{type:"tool_use_delta",toolCall:{input:_.function.arguments}});w.finish_reason&&(h=w.finish_reason),g.usage&&(p=g.usage.prompt_tokens,m=g.usage.completion_tokens,y=g.usage.prompt_tokens_details?.cached_tokens??0)}if(a){let g;try{g=JSON.parse(c||"{}")}catch{g={}}u.push({id:a,name:o,input:g})}yield{type:"message_complete",response:{content:l,model:this.config.model,toolCalls:u.length>0?u:void 0,usage:{inputTokens:p,outputTokens:m,cacheReadTokens:y},stopReason:this.mapStopReason(h)}}}isAvailable(){return!!this.config.apiKey}async embed(e){try{let t=this.config.model??"text-embedding-3-small",s=await this.client.embeddings.create({model:t,input:e}),i=s.data[0];return{embedding:i.embedding,model:t,dimensions:i.embedding.length,totalTokens:s.usage?.total_tokens??0}}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($|[.-][015]))/.test(this.config.model)}reasoningEffortParam(e){if(e&&this.isReasoningModel())return e}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 i of e){if(typeof i.content=="string"){s.push({role:i.role,content:i.content});continue}let n=[],r=[],a=[];for(let o of i.content)switch(o.type){case"text":n.push({type:"text",text:o.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${o.source.media_type};base64,${o.source.data}`}});break;case"tool_use":r.push({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.input)}});break;case"tool_result":a.push({tool_call_id:o.tool_use_id,content:o.content});break}if(i.role==="assistant"&&r.length>0){let o=n.map(c=>c.text).join("");s.push({role:"assistant",content:o||null,tool_calls:r})}else if(a.length>0)for(let o of a)s.push({role:"tool",tool_call_id:o.tool_call_id,content:o.content});else n.length>0&&(i.role==="user"?s.push({role:"user",content:n}):s.push({role:i.role,content:n.map(o=>o.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,i=s?.content??"",n=s?.tool_calls?.map(r=>({id:r.id,name:r.function.name,input:(()=>{try{return JSON.parse(r.function.arguments)}catch{return{}}})()}));return{content:i,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,cacheReadTokens:e.usage?.prompt_tokens_details?.cached_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 Ur,uu=S(()=>{"use strict";cn();Ur=class extends as{static{f(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Pr,hu=S(()=>{"use strict";ci();Pr=class extends Wt{static{f(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=$s(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??{},i=Object.keys(s).find(r=>r.includes("context_length")||r==="num_ctx"),n=i?Number(s[i]):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,i={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(i.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(i)});if(!n.ok){let a=await n.text();throw new Error(`Ollama API error (${n.status}): ${a}`)}let r=await n.json();return this.mapResponse(r)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,i={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(i.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(i)});if(!n.ok){let p=await n.text();throw new Error(`Ollama API error (${n.status}): ${p}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let r=n.body.getReader(),a=new TextDecoder,o="",c="",l=0,u=0,h=[];try{for(;;){let{done:p,value:m}=await r.read();if(p)break;o+=a.decode(m,{stream:!0});let y=o.split(`
2617
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,[s,e,t.probe,t.status,t.details??null,t.durationMs??0,i]),{id:s,projectId:e,probe:t.probe,status:t.status,details:t.details,durationMs:t.durationMs??0,checkedAt:i}}async getLatestHealth(e,t){let s=await this.adapter.queryOne("SELECT * FROM project_health_log WHERE project_id = ? AND probe = ? ORDER BY checked_at DESC LIMIT 1",[e,t]);return s?{id:s.id,projectId:s.project_id,probe:s.probe,status:s.status,details:s.details??void 0,durationMs:Number(s.duration_ms??0),checkedAt:s.checked_at}:null}async listHealthLog(e,t=100){return(await this.adapter.query("SELECT * FROM project_health_log WHERE project_id = ? ORDER BY checked_at DESC LIMIT ?",[e,t])).map(i=>({id:i.id,projectId:i.project_id,probe:i.probe,status:i.status,details:i.details??void 0,durationMs:Number(i.duration_ms??0),checkedAt:i.checked_at}))}async getCurrentHealthSummary(e){let t={};for(let s of["git","build","deps","http"]){let i=await this.getLatestHealth(e,s);i&&(t[s]=i)}return t}}});var Ze={};Ne(Ze,{ActivityRepository:()=>Bs,AlfredUserRepository:()=>Yo,AuditRepository:()=>Fs,BackgroundTaskRepository:()=>Xi,BmwTelematicRepository:()=>sn,BrainstormingRepository:()=>rc,CalendarNotificationRepository:()=>js,CmdbRepository:()=>Hs,ConfirmationRepository:()=>Vi,ConversationRepository:()=>Mi,Database:()=>_s,DatabaseConnectionRepository:()=>Go,DocumentRepository:()=>Ki,EmbeddingRepository:()=>Bi,FeedbackRepository:()=>en,HostCapabilitiesRepository:()=>qo,ItsmRepository:()=>oi,KnowledgeGraphRepository:()=>rs,LinkTokenRepository:()=>Hi,LocalFileStore:()=>Lr,MIGRATIONS:()=>Ho,MealPlanRepository:()=>Qo,MemoryRepository:()=>Pi,Migrator:()=>ri,NoteRepository:()=>ji,PG_MIGRATIONS:()=>af,PG_SCHEMA:()=>$r,PgMigrator:()=>zo,PlanRepository:()=>ic,PostgresAsyncAdapter:()=>Rs,ProblemRepository:()=>lc,ProcessedMessageRepository:()=>nc,ProjectAgentInterjectionRepository:()=>sc,ProjectAgentSessionRepository:()=>tc,ProjectRepository:()=>pc,RecipeFavoriteRepository:()=>Zo,ReminderRepository:()=>Fi,RunbookRepository:()=>uc,S3FileStore:()=>Cr,SQLiteAsyncAdapter:()=>ai,ScheduledActionRepository:()=>Wi,ServiceUsageRepository:()=>nn,SharedResourceRepository:()=>Jo,SkillHealthRepository:()=>Zi,SkillStateRepository:()=>tn,SummaryRepository:()=>Yi,TodoRepository:()=>qi,TravelPlanRepository:()=>ec,UsageRepository:()=>Ji,UserRepository:()=>Ui,WatchRepository:()=>Gi,WorkflowRepository:()=>Qi,createDbAdapter:()=>Vm,createFileStore:()=>Vf});var Je=S(()=>{"use strict";Zm();ef();tf();sf();nf();Bo();Qd();su();rf();of();cf();lf();df();hf();pf();Sf();Af();Rf();If();$f();Nf();Lf();Cf();Df();xf();Mf();Uf();Ff();jf();Bf();Xf();zf();Wf();Kf();Gf();Yf();tu();Jf();Zf();Qf();eg();tg();sg();ng();ag();cg();ug();pg();mg();gg()});function $s(d){if(lu[d])return lu[d];let e=Object.entries(lu).sort((t,s)=>s[0].length-t[0].length);for(let[t,s]of e)if(d.startsWith(t))return s}var lu,ES,Wt,ci=S(()=>{"use strict";lu={"claude-opus-4-7":{maxInputTokens:1e6,maxOutputTokens:128e3},"claude-opus-4-6":{maxInputTokens:1e6,maxOutputTokens:128e3},"claude-sonnet-4-6":{maxInputTokens:1e6,maxOutputTokens:64e3},"claude-opus-4-5-20251101":{maxInputTokens:1e6,maxOutputTokens:64e3},"claude-opus-4-20250514":{maxInputTokens:2e5,maxOutputTokens:32e3},"claude-sonnet-4-5-20250929":{maxInputTokens:1e6,maxOutputTokens:64e3},"claude-sonnet-4-20250514":{maxInputTokens:2e5,maxOutputTokens:16e3},"claude-haiku-4-5-20251001":{maxInputTokens:2e5,maxOutputTokens:64e3},"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-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:1e6,maxOutputTokens:64e3},"gpt-5.5":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5.4":{maxInputTokens:105e4,maxOutputTokens:128e3},"gpt-5.4-mini":{maxInputTokens:4e5,maxOutputTokens:128e3},"gpt-5.4-nano":{maxInputTokens:4e5,maxOutputTokens:128e3},"gpt-5":{maxInputTokens:4e5,maxOutputTokens:128e3},"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:8192},"gpt-3.5-turbo":{maxInputTokens:16385,maxOutputTokens:4096},o3:{maxInputTokens:2e5,maxOutputTokens:1e5},"o3-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},"o4-mini":{maxInputTokens:2e5,maxOutputTokens:1e5},o1:{maxInputTokens:2e5,maxOutputTokens:1e5},"o1-mini":{maxInputTokens:128e3,maxOutputTokens:65536},"gemini-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:256e3,maxOutputTokens:256e3},"mistral-medium-3-5":{maxInputTokens:256e3,maxOutputTokens:131072},"mistral-medium":{maxInputTokens:131072,maxOutputTokens:131072},"mistral-small":{maxInputTokens:256e3,maxOutputTokens:256e3},codestral:{maxInputTokens:256e3,maxOutputTokens:256e3},"magistral-medium":{maxInputTokens:4e4,maxOutputTokens:4e4},"magistral-small":{maxInputTokens:128e3,maxOutputTokens:128e3},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:128e3},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:16384,maxOutputTokens:4096},"deepseek-r1":{maxInputTokens:128e3,maxOutputTokens:64e3},"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}},ES={maxInputTokens:128e3,maxOutputTokens:8192};f($s,"lookupContextWindow");Wt=class{static{f(this,"LLMProvider")}config;contextWindow=ES;constructor(e){this.config=e}getContextWindow(){return this.contextWindow}async embed(e){}supportsEmbeddings(){return!1}}});import kS from"@anthropic-ai/sdk";var Mr,du=S(()=>{"use strict";ci();Mr=class extends Wt{static{f(this,"AnthropicProvider")}client;constructor(e){super(e)}async initialize(){this.client=new kS({apiKey:this.config.apiKey,maxRetries:5});let e=$s(this.config.model);e&&(this.contextWindow=e)}supportsTemperature(){return!(this.config.model??"").toLowerCase().includes("opus-4-7")}async complete(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,i={model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,...this.supportsTemperature()?{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(i);return this.mapResponse(n)}async*stream(e){let t=this.mapMessages(e.messages),s=e.tools?this.mapTools(e.tools):void 0,i=this.client.messages.stream({model:this.config.model,max_tokens:e.maxTokens??this.config.maxTokens??4096,...this.supportsTemperature()?{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 i)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 r=await i.finalMessage();yield{type:"message_complete",response:this.mapResponse(r)}}}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(i=>{switch(i.type){case"text":return{type:"text",text:i.text};case"image":return{type:"image",source:{type:"base64",media_type:i.source.media_type,data:i.source.data}};case"tool_use":return{type:"tool_use",id:i.id,name:i.name,input:i.input};case"tool_result":return{type:"tool_result",tool_use_id:i.tool_use_id,content:i.content,is_error:i.is_error};default:return{type:"text",text:"[Unsupported block type]"}}}).filter(i=>i!==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 i of e.content)i.type==="text"?t+=i.text:i.type==="tool_use"&&s.push({id:i.id,name:i.name,input:i.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 bS from"openai";var as,cn=S(()=>{"use strict";ci();as=class extends Wt{static{f(this,"OpenAIProvider")}client;constructor(e){super(e)}async initialize(){this.client=new bS({apiKey:this.config.apiKey,baseURL:this.config.baseUrl,maxRetries:5});let e=$s(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,i=s?void 0:this.reasoningEffortParam(e.reasoningEffort),n={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},...i?{reasoning_effort:i}:{},...this.extraRequestParams(e)},r=await this.client.chat.completions.create(n);return this.mapResponse(r)}extraRequestParams(e){return{}}async*stream(e){let t=this.mapMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,i=s?void 0:this.reasoningEffortParam(e.reasoningEffort),n={model:this.config.model,...this.tokenLimitParam(e.maxTokens),temperature:this.safeTemperature(e.temperature),messages:t,...s?{tools:s}:{},...i?{reasoning_effort:i}:{},...this.extraRequestParams(e),stream:!0},r=await this.client.chat.completions.create(n),a,o,c="",l="",u=[],h=null,p=0,m=0,y=0;for await(let g of r){let w=g.choices[0];if(!w)continue;let T=w.delta;if(T?.content&&(l+=T.content,yield{type:"text_delta",text:T.content}),T?.tool_calls)for(let _ of T.tool_calls)if(_.id){if(a){let k;try{k=JSON.parse(c||"{}")}catch{k={}}u.push({id:a,name:o,input:k})}a=_.id,o=_.function?.name,c=_.function?.arguments??"",yield{type:"tool_use_start",toolCall:{id:a,name:o}}}else _.function?.arguments&&(c+=_.function.arguments,yield{type:"tool_use_delta",toolCall:{input:_.function.arguments}});w.finish_reason&&(h=w.finish_reason),g.usage&&(p=g.usage.prompt_tokens,m=g.usage.completion_tokens,y=g.usage.prompt_tokens_details?.cached_tokens??0)}if(a){let g;try{g=JSON.parse(c||"{}")}catch{g={}}u.push({id:a,name:o,input:g})}yield{type:"message_complete",response:{content:l,model:this.config.model,toolCalls:u.length>0?u:void 0,usage:{inputTokens:p,outputTokens:m,cacheReadTokens:y},stopReason:this.mapStopReason(h)}}}isAvailable(){return!!this.config.apiKey}async embed(e){try{let t=this.config.model??"text-embedding-3-small",s=await this.client.embeddings.create({model:t,input:e}),i=s.data[0];return{embedding:i.embedding,model:t,dimensions:i.embedding.length,totalTokens:s.usage?.total_tokens??0}}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($|[.-][015]))/.test(this.config.model)}reasoningEffortParam(e){if(e&&this.isReasoningModel())return e}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 i of e){if(typeof i.content=="string"){s.push({role:i.role,content:i.content});continue}let n=[],r=[],a=[];for(let o of i.content)switch(o.type){case"text":n.push({type:"text",text:o.text});break;case"image":n.push({type:"image_url",image_url:{url:`data:${o.source.media_type};base64,${o.source.data}`}});break;case"tool_use":r.push({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.input)}});break;case"tool_result":a.push({tool_call_id:o.tool_use_id,content:o.content});break}if(i.role==="assistant"&&r.length>0){let o=n.map(c=>c.text).join("");s.push({role:"assistant",content:o||null,tool_calls:r})}else if(a.length>0)for(let o of a)s.push({role:"tool",tool_call_id:o.tool_call_id,content:o.content});else n.length>0&&(i.role==="user"?s.push({role:"user",content:n}):s.push({role:i.role,content:n.map(o=>o.text).join("")}))}return s}mapTools(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}mapResponse(e){let t=e.choices[0],s=t?.message,i=s?.content??"",n=s?.tool_calls?.map(r=>({id:r.id,name:r.function.name,input:(()=>{try{return JSON.parse(r.function.arguments)}catch{return{}}})()}));return{content:i,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,cacheReadTokens:e.usage?.prompt_tokens_details?.cached_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 Ur,uu=S(()=>{"use strict";cn();Ur=class extends as{static{f(this,"OpenRouterProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://openrouter.ai/api/v1"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!1}}});var Pr,hu=S(()=>{"use strict";ci();Pr=class extends Wt{static{f(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=$s(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??{},i=Object.keys(s).find(r=>r.includes("context_length")||r==="num_ctx"),n=i?Number(s[i]):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,i={model:this.config.model,messages:t,stream:!1,options:this.buildOptions(e)};s&&s.length>0&&(i.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(i)});if(!n.ok){let a=await n.text();throw new Error(`Ollama API error (${n.status}): ${a}`)}let r=await n.json();return this.mapResponse(r)}async*stream(e){let t=this.buildMessages(e.messages,e.system),s=e.tools?this.mapTools(e.tools):void 0,i={model:this.config.model,messages:t,stream:!0,options:this.buildOptions(e)};s&&s.length>0&&(i.tools=s);let n=await fetch(`${this.baseUrl}/api/chat`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify(i)});if(!n.ok){let p=await n.text();throw new Error(`Ollama API error (${n.status}): ${p}`)}if(!n.body)throw new Error("Ollama streaming response has no body");let r=n.body.getReader(),a=new TextDecoder,o="",c="",l=0,u=0,h=[];try{for(;;){let{done:p,value:m}=await r.read();if(p)break;o+=a.decode(m,{stream:!0});let y=o.split(`
2607
2618
  `);o=y.pop()??"";for(let g of y){let w=g.trim();if(!w)continue;let T;try{T=JSON.parse(w)}catch{continue}if(T.message?.content&&(c+=T.message.content,yield{type:"text_delta",text:T.message.content}),T.message?.tool_calls)for(let _ of T.message.tool_calls){let k={id:`ollama_tool_${h.length}`,name:_.function.name,input:_.function.arguments};h.push(k),yield{type:"tool_use_start",toolCall:{id:k.id,name:k.name}},yield{type:"tool_use_delta",toolCall:{input:k.input}}}T.done&&(l=T.prompt_eval_count??0,u=T.eval_count??0,yield{type:"message_complete",response:{content:c,model:this.config.model,toolCalls:h.length>0?h:void 0,usage:{inputTokens:l,outputTokens:u},stopReason:h.length>0?"tool_use":"end_turn"}})}}if(o.trim()){let p;try{p=JSON.parse(o.trim())}catch{return}if(p.message?.content&&(c+=p.message.content,yield{type:"text_delta",text:p.message.content}),p.message?.tool_calls)for(let m of p.message.tool_calls){let y={id:`ollama_tool_${h.length}`,name:m.function.name,input:m.function.arguments};h.push(y),yield{type:"tool_use_start",toolCall:{id:y.id,name:y.name}},yield{type:"tool_use_delta",toolCall:{input:y.input}}}p.done&&(l=p.prompt_eval_count??0,u=p.eval_count??0,yield{type:"message_complete",response:{content:c,toolCalls:h.length>0?h:void 0,usage:{inputTokens:l,outputTokens:u},stopReason:h.length>0?"tool_use":"end_turn"}})}}finally{r.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 i=s.embeddings[0];return{embedding:i,model:"nomic-embed-text",dimensions:i.length}}catch{return}}supportsEmbeddings(){return!0}buildOptions(e){let t={},s=e.temperature??this.config.temperature;s!==void 0&&(t.temperature=s);let i=e.maxTokens??this.config.maxTokens;return i!==void 0&&(t.num_predict=i),t}buildMessages(e,t){let s=[];t&&s.push({role:"system",content:t});for(let i of e)typeof i.content=="string"?s.push({role:i.role,content:i.content}):s.push(this.mapContentBlocks(i.role,i.content));return s}mapContentBlocks(e,t){let s=[],i=[];for(let r of t)switch(r.type){case"text":s.push(r.text);break;case"image":i.push(r.source.data);break;case"tool_use":s.push(`[Tool call: ${r.name}(${JSON.stringify(r.input)})]`);break;case"tool_result":s.push(`[Tool result for ${r.tool_use_id}]: ${r.content}`);break}let n={role:e,content:s.join(`
2608
2619
  `)};return i.length>0&&(n.images=i),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 Fr,pu=S(()=>{"use strict";cn();Fr=class extends as{static{f(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 SS}from"@google/genai";var jr,mu=S(()=>{"use strict";ci();jr=class extends Wt{static{f(this,"GoogleProvider")}client;rawContentCache=new Map;constructor(e){super(e)}async initialize(){this.client=new SS({apiKey:this.config.apiKey});let e=$s(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,i=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(i),this.mapResponse(i)}async*stream(e){let t=this.mapContents(e.messages),s=e.tools?this.mapTools(e.tools):void 0,i=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="",r=[],a=0,o=0,c=0,l;for await(let u of i){l=u;let h=u.text;if(h&&(n+=h,yield{type:"text_delta",text:h}),u.functionCalls)for(let p of u.functionCalls){let m={id:p.id??`google_tool_${r.length}`,name:p.name,input:p.args??{}};r.push(m),yield{type:"tool_use_start",toolCall:{id:m.id,name:m.name}}}u.usageMetadata&&(a=u.usageMetadata.promptTokenCount??0,o=u.usageMetadata.candidatesTokenCount??0,c=u.usageMetadata.cachedContentTokenCount??0)}l&&this.cacheRawContent(l),yield{type:"message_complete",response:{content:n,model:this.config.model,toolCalls:r.length>0?r:void 0,usage:{inputTokens:a,outputTokens:o,cacheReadTokens:c},stopReason:r.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 i=this.buildCacheKey(s);if(this.rawContentCache.set(i,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 i of e)if(!(i.role!=="assistant"||typeof i.content=="string"))for(let n of i.content)n.type==="tool_use"&&t.set(n.id,n.name);let s=[];for(let i of e){let n=i.role==="assistant"?"model":"user";if(typeof i.content=="string"){s.push({role:n,parts:[{text:i.content}]});continue}let r=[],a=[],o=[];for(let c of i.content)switch(c.type){case"text":a.push({text:c.text});break;case"image":a.push({inlineData:{mimeType:c.source.media_type,data:c.source.data}});break;case"tool_use":r.push({id:c.id,name:c.name,input:c.input});break;case"tool_result":{let l=t.get(c.tool_use_id)??c.tool_use_id,u;try{let h=JSON.parse(c.content);u=typeof h=="object"&&h!==null?h:{result:h}}catch{u={result:c.content}}o.push({functionResponse:{id:c.tool_use_id,name:l,response:u}});break}}if(i.role==="assistant"&&r.length>0){let c=this.buildCacheKeyFromBlocks(r),l=this.rawContentCache.get(c);if(l)this.rawContentCache.delete(c),this.rawContentCache.set(c,l),s.push(l);else{let u=[...a];for(let h=0;h<r.length;h++){let p=r[h];u.push({functionCall:{id:p.id,name:p.name,args:p.input},...h===0?{thoughtSignature:"skip_thought_signature_validator"}:{}})}s.push({role:"model",parts:u})}}else a.length>0&&s.push({role:n,parts:a});o.length>0&&s.push({role:"user",parts:o})}return this.sanitizeContents(s)}sanitizeContents(e){let t=new Set,s=[];for(let a of e)if(a.role==="model"){for(let o of a.parts??[])if(o.functionCall){let c=o.functionCall.id??o.functionCall.name??"";c&&t.add(c)}s.push(a)}else{let o=(a.parts??[]).filter(c=>{if(c.functionResponse){let l=c.functionResponse.id??c.functionResponse.name??"";return l?t.has(l):!1}return!0});o.length>0&&s.push({role:a.role,parts:o})}let i=new Set;for(let a of s)if(a.role!=="model"){for(let o of a.parts??[])if(o.functionResponse){let c=o.functionResponse.id??o.functionResponse.name??"";c&&i.add(c)}}let n=[];for(let a of s)if(a.role==="model"){let o=(a.parts??[]).filter(c=>{if(c.functionCall){let l=c.functionCall.id??c.functionCall.name??"";return l?i.has(l):!1}return!0});o.length>0&&n.push({role:a.role,parts:o})}else n.push(a);if(n.length<=1)return n;let r=[n[0]];for(let a=1;a<n.length;a++){let o=r[r.length-1],c=n[a];o.role===c.role?o.parts=[...o.parts??[],...c.parts??[]]:r.push(c)}return r}mapTools(e){return e.map(t=>({name:t.name,description:t.description,parameters:t.inputSchema}))}mapResponse(e){let t=e.text??"",i=e.functionCalls?.map((n,r)=>({id:n.id??`google_tool_${r}`,name:n.name,input:n.args??{}}));return{content:t,model:this.config.model,toolCalls:i&&i.length>0?i:void 0,usage:{inputTokens:e.usageMetadata?.promptTokenCount??0,outputTokens:e.usageMetadata?.candidatesTokenCount??0,cacheReadTokens:e.usageMetadata?.cachedContentTokenCount??0},stopReason:i&&i.length>0?"tool_use":"end_turn"}}}});import{createHash as vS}from"node:crypto";var Br,fu=S(()=>{"use strict";cn();Br=class extends as{static{f(this,"MistralProvider")}constructor(e){super({...e,baseUrl:e.baseUrl??"https://api.mistral.ai/v1/"})}isAvailable(){return!!this.config.apiKey}supportsEmbeddings(){return!0}supportsPromptCaching(){return/^mistral-medium-3-5/i.test(this.config.model)}computeCacheKey(e){let t=typeof e.system=="string"&&e.system.length>0,s=Array.isArray(e.tools)&&e.tools.length>0;if(!t&&!s)return;let i=`${e.system??""}
2609
2620
  ${JSON.stringify(e.tools??[])}`;return vS("sha256").update(i).digest("hex").slice(0,32)}extraRequestParams(e){if(!this.supportsPromptCaching())return{};let t=this.computeCacheKey(e);return t?{prompt_cache_key:t}:{}}}});function gu(d){switch(d.provider){case"anthropic":return new Mr(d);case"openai":return new as(d);case"openrouter":return new Ur(d);case"ollama":return new Pr(d);case"openwebui":return new Fr(d);case"google":return new jr(d);case"mistral":return new Br(d);default:throw new Error(`Unknown LLM provider: ${d.provider}`)}}var yu=S(()=>{"use strict";du();cn();uu();hu();pu();mu();fu();f(gu,"createLLMProvider")});function yg(d){let e=d.toLowerCase();for(let[t,s]of AS)if(e.startsWith(t.toLowerCase()))return s}function RS(d,e){return d.toLowerCase().startsWith("gpt-5.5")&&e>272e3?{input:2,output:1.5}:{input:1,output:1}}function mc(d,e){let t=yg(d);if(!t)return 0;let s=1e6,i=RS(d,e.inputTokens),n=0,r=e.cacheReadTokens??0,a=e.cacheCreationTokens??0,o=Math.max(0,e.inputTokens-r);return n+=o/s*t.input*i.input,n+=e.outputTokens/s*t.output*i.output,r>0&&t.cacheRead&&(n+=r/s*t.cacheRead*i.input),a>0&&t.cacheWrite&&(n+=a/s*t.cacheWrite*i.input),n}var AS,Hr,wu=S(()=>{"use strict";AS=[["gpt-5.5",{input:5,output:30,cacheRead:.5}],["gpt-5.4-nano",{input:.2,output:1.25,cacheRead:.02}],["gpt-5.4-mini",{input:.75,output:4.5,cacheRead:.075}],["gpt-5.4",{input:2.5,output:15,cacheRead:.25}],["gpt-5",{input:.625,output:5,cacheRead:.125}],["gpt-4.1-nano",{input:.05,output:.2,cacheRead:.025}],["gpt-4.1-mini",{input:.2,output:.8,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-7",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-opus-4-6",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-opus-4-5",{input:5,output:25,cacheRead:.5,cacheWrite:6.25}],["claude-opus-4-1",{input:15,output:75,cacheRead:1.5,cacheWrite:18.75}],["claude-opus-4",{input:15,output:75,cacheRead:1.5,cacheWrite:18.75}],["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-haiku-3-5",{input:.8,output:4,cacheRead:.08,cacheWrite:1}],["claude-3.5-sonnet",{input:3,output:15,cacheRead:.3,cacheWrite:3.75}],["claude-3-haiku",{input:.25,output:1.25,cacheRead:.03,cacheWrite:.3}],["gemini-3.1-pro",{input:2,output:12,cacheRead:.2}],["gemini-3.1-flash-lite",{input:.25,output:1.5,cacheRead:.025}],["gemini-3.1-flash",{input:.5,output:3,cacheRead:.05}],["gemini-3-pro",{input:2,output:12,cacheRead:.2}],["gemini-3-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}],["text-embedding-3-small",{input:.02,output:0}],["text-embedding-3-large",{input:.13,output:0}],["codestral",{input:.3,output:.9,cacheRead:.03}],["devstral-medium",{input:.4,output:2}],["devstral-small",{input:.1,output:.3}],["magistral-medium",{input:2,output:5}],["magistral-small",{input:.5,output:1.5}],["ministral-3b",{input:.1,output:.1}],["ministral-8b",{input:.15,output:.15}],["ministral-14b",{input:.2,output:.2}],["mistral-large",{input:.5,output:1.5,cacheRead:.05}],["mistral-medium-3-5",{input:1.5,output:7.5,cacheRead:.15}],["mistral-medium",{input:.4,output:2,cacheRead:.04}],["mistral-small",{input:.15,output:.6,cacheRead:.015}],["mistral-moderation",{input:.1,output:0}],["mistral-embed",{input:.1,output:0}],["pixtral-large",{input:2,output:6}],["pixtral-12b",{input:.15,output:.15}],["open-mixtral-8x22b",{input:2,output:6}],["open-mixtral-8x7b",{input:.7,output:.7}],["open-mistral-nemo",{input:.15,output:.15}],["open-mistral-7b",{input:.25,output:.25}]];f(yg,"getModelPricing");f(RS,"longPromptMultiplier");f(mc,"calculateCost");Hr=class{static{f(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=mc(e,t),i=t.cacheReadTokens??0,n=t.cacheCreationTokens??0;this.data.totalInputTokens+=t.inputTokens,this.data.totalOutputTokens+=t.outputTokens,this.data.totalCacheReadTokens+=i,this.data.totalCacheWriteTokens+=n,this.data.totalCostUsd+=s;let r=this.data.byModel[e];r||(r={calls:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,costUsd:0},this.data.byModel[e]=r),r.calls++,r.inputTokens+=t.inputTokens,r.outputTokens+=t.outputTokens,r.cacheReadTokens+=i,r.cacheWriteTokens+=n,r.costUsd+=s;try{this.persistFn?.(e,t.inputTokens,t.outputTokens,i,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 _u(d,e){return new fc(d,e)}var wg,IS,fc,_g=S(()=>{"use strict";ci();yu();wu();wg=["default","strong","fast","embeddings","local"],IS={fast:"low",default:"medium",strong:"high"},fc=class extends Wt{static{f(this,"ModelRouter")}providers=new Map;multiConfig;logger;costTracker=new Hr;constructor(e,t){super(e.default),this.multiConfig=e,this.logger=t}async initialize(){for(let e of wg){let t=this.multiConfig[e];if(t){let s=gu(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"}}sanitizeRequest(e){let t=f(s=>s&&s.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"\uFFFD"),"clean");return{...e,system:t(e.system),messages:e.messages.map(s=>({...s,content:typeof s.content=="string"?t(s.content)??"":s.content}))}}withTierEffort(e,t){if(e.reasoningEffort)return e;let s=IS[t];return s?{...e,reasoningEffort:s}:e}async complete(e){let t=this.sanitizeRequest(e),{provider:s,resolvedTier:i}=this.resolve(t.tier),n=this.multiConfig[i],r=this.withTierEffort(t,i);this.logger?.debug({requestedTier:t.tier??"default",resolvedTier:i,model:n?.model},"LLM routing request");try{return await this.executeComplete(s,i,r)}catch(a){if(!this.isRetryableError(a))throw a;return this.logger?.warn({err:a,tier:i},"Provider failed, attempting fallback"),this.completeWithFallback(r,i,a)}}async executeComplete(e,t,s){let i=this.multiConfig[t],n=await e.complete(s),r=n.model??i?.model??"unknown";n.model||(n.model=r);let a=this.costTracker.record(r,n.usage);return this.logger?.info({tier:t,model:r,costUsd:Math.round(a*1e6)/1e6,inputTokens:n.usage?.inputTokens,outputTokens:n.usage?.outputTokens,cacheReadTokens:n.usage?.cacheReadTokens,cacheWriteTokens:n.usage?.cacheCreationTokens},"LLM call completed"),n}isRetryableError(e){if(e instanceof Error){let s=e.message.toLowerCase();if(s.includes("econnrefused")||s.includes("enotfound")||s.includes("etimedout")||s.includes("econnreset")||s.includes("socket hang up")||s.includes("fetch failed")||s.includes("500")||s.includes("502")||s.includes("503")||s.includes("504")||s.includes("529")||s.includes("rate limit")||s.includes("overloaded")||s.includes("too many requests"))return!0}let t=e?.status??e?.statusCode;return typeof t=="number"&&(t>=500||t===429)}async completeWithFallback(e,t,s){let i=["default","strong","fast"].filter(n=>n!==t);for(let n of i){let r=this.providers.get(n);if(r)try{return this.logger?.info({tier:n},"Fallback to tier"),await this.executeComplete(r,n,e)}catch{continue}}throw s}async*stream(e){let{provider:t,resolvedTier:s}=this.resolve(e.tier),i=this.withTierEffort(e,s),n=!1;try{for await(let r of t.stream(i))n=!0,yield r}catch(r){if(n||!this.isRetryableError(r))throw r;this.logger?.warn({err:r,tier:s},"Stream provider failed before first chunk, attempting fallback");let a=["default","strong","fast"].filter(o=>o!==s);for(let o of a){let c=this.providers.get(o);if(c)try{this.logger?.info({tier:o},"Stream fallback to tier"),yield*c.stream(this.withTierEffort(e,o));return}catch{continue}}throw r}}async embed(e){let t=await(this.providers.get("embeddings")??this.resolve().provider).embed(e);return t?.totalTokens&&this.costTracker.record(t.model,{inputTokens:t.totalTokens,outputTokens:0}),t}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 wg){let s=this.providers.get(t);if(s){let i=this.multiConfig[t];e[t]={model:i?.model??"unknown",available:s.isAvailable()}}}return e}getCostSummary(){return this.costTracker.getSummary()}setPersist(e){this.costTracker.setPersist(e)}};f(_u,"createModelRouter")});function $S(d){let e=Date.now()-new Date(d).getTime();if(e<0)return d.slice(0,16).replace("T"," ");let t=Math.floor(e/1e3);if(t<120)return`${t}s ago`;let s=Math.floor(t/60);if(s<120)return`${s}m ago`;let i=Math.floor(s/60);return i<48?`${i}h ago`:`${Math.floor(i/24)}d ago`}function os(d){return Math.ceil(d.length/3.5)}function li(d){if(typeof d.content=="string")return os(d.content)+4;let e=4;for(let t of d.content)switch(t.type){case"text":e+=os(t.text);break;case"image":e+=1e3;break;case"tool_use":e+=os(t.name)+os(JSON.stringify(t.input));break;case"tool_result":e+=os(t.content);break}return e}function Tu(d,e){let t=e?.keepRecentPairs??3,s=e?.maxTrimmedLength??120,i=e?.minContentLength??300,n=new Map;for(let o of d)if(o.role==="assistant"&&Array.isArray(o.content))for(let c of o.content)c.type==="tool_use"&&n.set(c.id,c.name);let r=[];for(let o=0;o<d.length;o++){let c=d[o];c.role==="user"&&Array.isArray(c.content)&&c.content.some(l=>l.type==="tool_result")&&r.push(o)}let a=new Set(r.slice(-t));return d.map((o,c)=>{if(a.has(c)||o.role!=="user"||!Array.isArray(o.content))return o;let l=!1,u=o.content.map(h=>{if(h.type!=="tool_result")return h;let p=h.content;if(typeof p!="string"||p.length<i)return h;l=!0;let m=n.get(h.tool_use_id)||"unknown",y=p.split(`
@@ -5104,7 +5115,7 @@ ${s.lastBuildOutput.slice(-2e3)}`),i.length>0&&n.push(`USER-ANFORDERUNGEN:
5104
5115
  ${i.map(r=>`- ${r}`).join(`
5105
5116
  `)}`),n.push("ANWEISUNGEN:","- Implementiere nur diese Phase, nicht das ganze Projekt","- Erstelle alle n\xF6tigen Dateien und Verzeichnisse","- Wenn ein package.json existiert, nutze die vorhandene Struktur","- Wenn Build-Fehler im Output stehen, behebe sie zuerst","- Schreibe produktionsreifen Code"),n.join(`
5106
5117
 
5107
- `)}async updateSession(e,t,s){try{await this.sessionRepo.updateProgress(e,{currentPhase:t.projectPhase,currentIteration:t.projectIteration,totalFilesChanged:t.totalFilesChanged,lastBuildPassed:s,lastCommitSha:t.lastCommitSha})}catch(i){this.logger.warn({err:i,sessionId:e},"Project agent: session update failed")}}async sendProgress(e,t,s){this.lastProgressAt=Date.now();let i=this.adapters.get(e);if(i)try{await i.sendMessage(t,s)}catch{}}sendProgressThrottled(e,t,s){Date.now()-this.lastProgressAt<this.throttleMs||this.sendProgress(e,t,s).catch(()=>{})}}});var OT={};Ne(OT,{default:()=>lR});var lR,xT=S(()=>{lR={name:"@madh-io/alfred-ai",version:"0.19.0-multi-ha.621",description:"Alfred \u2014 Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",type:"module",bin:{alfred:"bundle/index.js"},files:["bundle"],scripts:{build:"tsc",bundle:"node ../../scripts/bundle.mjs",prepublishOnly:"npm run build && npm run bundle",clean:"rm -rf dist bundle *.tsbuildinfo"},keywords:["ai","assistant","chatbot","telegram","discord","whatsapp","matrix","signal","claude","openai","ollama"],license:"MIT",repository:{type:"git",url:"https://github.com/madh99/alfred-ai.git"},homepage:"https://github.com/madh99/alfred-ai#readme",bugs:{url:"https://github.com/madh99/alfred-ai/issues"},dependencies:{"@anthropic-ai/sdk":"^0.39.0","@google/genai":"^1.45.0","@modelcontextprotocol/sdk":"^1.12.1","better-sqlite3":"^11.8.0",botbuilder:"^4.23.0",ccxt:"^4.4.0","discord.js":"^14.18.0",docx:"^9.0.0",dotenv:"^16.4.0",exceljs:"^4.4.0",grammy:"^1.35.0",imapflow:"^1.2.10","js-yaml":"^4.1.0",mammoth:"^1.8.0",mqtt:"^5.0.0",nodemailer:"^8.0.1",openai:"^4.80.0","pdf-parse":"^1.1.1",pdfkit:"^0.16.0",pino:"^9.6.0","pino-pretty":"^13.0.0","pino-roll":"^4.0.0",puppeteer:"^24.0.0","puppeteer-core":"^24.0.0","rss-parser":"^3.13.0",sonos:"^1.14.0","youtube-transcript":"^1.3.0",zod:"^3.24.0"},optionalDependencies:{"@aws-sdk/client-s3":"^3.700.0","@influxdata/influxdb-client":"^1.35.0","@whiskeysockets/baileys":"6.7.21",googleapis:"^144.0.0","hafas-client":"^6.3.0",ioredis:"^5.4.0","matrix-bot-sdk":"^0.8.0",mongodb:"^6.12.0",mssql:"^11.0.0",mysql2:"^3.12.0",pg:"^8.13.0",tsdav:"^2.1.0"},devDependencies:{"@alfred/config":"workspace:*","@alfred/core":"workspace:*","@alfred/logger":"workspace:*","@alfred/security":"workspace:*","@alfred/storage":"workspace:*","@alfred/types":"workspace:*","@types/js-yaml":"^4.0.9"},publishConfig:{access:"public"},engines:{node:">=20"}}});var MT={};Ne(MT,{ClusterManager:()=>yo});var yo,zp=S(()=>{"use strict";yo=class{static{f(this,"ClusterManager")}config;logger;redis;heartbeatTimer;heartbeatMs;failoverMs;constructor(e,t){this.config=e,this.logger=t,this.heartbeatMs=e.heartbeatIntervalMs??1e4,this.failoverMs=e.failoverAfterMs??3e4}async connect(){try{let e;try{e=(await Function('return import("ioredis")')()).default}catch{throw new Error('Cluster mode requires the "ioredis" package. Install it: npm install ioredis')}this.redis=new e(this.config.redisUrl),this.logger.info({nodeId:this.config.nodeId,role:this.config.role},"Cluster manager connected to Redis")}catch(e){this.logger.error({err:e},"Failed to connect to Redis \u2014 cluster features disabled");return}this.heartbeatTimer=setInterval(()=>this.sendHeartbeat(),this.heartbeatMs),await this.sendHeartbeat()}async disconnect(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),await this.redis?.quit()}async sendHeartbeat(){try{let e=JSON.stringify({id:this.config.nodeId,role:this.config.role,timestamp:new Date().toISOString(),uptime:Math.floor(process.uptime())});await this.redis.set(`alfred:cluster:heartbeat:${this.config.nodeId}`,e,"EX",Math.ceil(this.failoverMs/1e3))}catch(e){this.logger.warn({err:e},"Heartbeat send failed")}}async getNodes(){if(!this.redis)return[];try{let e=await this.redis.keys("alfred:cluster:heartbeat:*"),t=[];for(let s of e){let i=await this.redis.get(s);if(i)try{let n=JSON.parse(i);t.push({...n,healthy:!0})}catch{}}return t}catch{return[]}}async acquireLock(e,t=3e5){if(!this.redis)return!0;try{return await this.redis.set(`alfred:lock:${e}`,this.config.nodeId,"NX","PX",t)==="OK"}catch{return!0}}async releaseLock(e){if(this.redis)try{await this.redis.get(`alfred:lock:${e}`)===this.config.nodeId&&await this.redis.del(`alfred:lock:${e}`)}catch{}}async publish(e,t){if(this.redis)try{await this.redis.publish(`alfred:${e}`,JSON.stringify({...t,nodeId:this.config.nodeId}))}catch(s){this.logger.warn({err:s,channel:e},"Cluster publish failed")}}async subscribe(e,t){if(this.redis)try{let s=this.redis.duplicate();await s.subscribe(`alfred:${e}`),s.on("message",(i,n)=>{try{let r=JSON.parse(n);r.nodeId!==this.config.nodeId&&t(r)}catch{}})}catch(s){this.logger.warn({err:s,channel:e},"Cluster subscribe failed")}}async routeMessage(e,t,s){await this.publish("messages",{type:"send_message",targetPlatform:e,chatId:t,text:s})}failoverCheckTimer;onFailoverCallback;startFailoverMonitoring(e){this.config.role==="secondary"&&(this.onFailoverCallback=e,this.failoverCheckTimer=setInterval(async()=>{try{let t=await this.getNodes(),s=new Set(t.map(i=>i.id));for(let i of this.config.nodes??[])i.id!==this.config.nodeId&&(s.has(i.id)||(this.logger.warn({deadNodeId:i.id},"Node heartbeat missing \u2014 failover triggered"),this.onFailoverCallback?.(i.id)))}catch(t){this.logger.debug({err:t},"Failover check error")}},this.failoverMs))}stopFailoverMonitoring(){this.failoverCheckTimer&&clearInterval(this.failoverCheckTimer)}async announceTakeover(e,t){await this.publish("events",{type:"failover",deadNodeId:e,takenOverBy:this.config.nodeId,adapters:t}),this.logger.info({deadNodeId:e,adapters:t},"Failover: adapters taken over")}async syncConfig(e,t){await this.publish("config-sync",{type:e,...t})}async onConfigSync(e){await this.subscribe("config-sync",t=>{let{type:s,...i}=t;e(s,i)})}get nodeId(){return this.config.nodeId}get role(){return this.config.role??"node"}get isConnected(){return!!this.redis}pgAdapter;pgHeartbeatTimer;startPgHeartbeat(e){this.pgAdapter=e,this.pgHeartbeatTimer=setInterval(()=>this.sendPgHeartbeat(),this.heartbeatMs),this.sendPgHeartbeat()}async sendPgHeartbeat(){if(this.pgAdapter)try{let e=new Date().toISOString();await this.pgAdapter.execute(`INSERT INTO node_heartbeats (node_id, host, last_seen_at, started_at, uptime_s)
5118
+ `)}async updateSession(e,t,s){try{await this.sessionRepo.updateProgress(e,{currentPhase:t.projectPhase,currentIteration:t.projectIteration,totalFilesChanged:t.totalFilesChanged,lastBuildPassed:s,lastCommitSha:t.lastCommitSha})}catch(i){this.logger.warn({err:i,sessionId:e},"Project agent: session update failed")}}async sendProgress(e,t,s){this.lastProgressAt=Date.now();let i=this.adapters.get(e);if(i)try{await i.sendMessage(t,s)}catch{}}sendProgressThrottled(e,t,s){Date.now()-this.lastProgressAt<this.throttleMs||this.sendProgress(e,t,s).catch(()=>{})}}});var OT={};Ne(OT,{default:()=>lR});var lR,xT=S(()=>{lR={name:"@madh-io/alfred-ai",version:"0.19.0-multi-ha.623",description:"Alfred \u2014 Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",type:"module",bin:{alfred:"bundle/index.js"},files:["bundle"],scripts:{build:"tsc",bundle:"node ../../scripts/bundle.mjs",prepublishOnly:"npm run build && npm run bundle",clean:"rm -rf dist bundle *.tsbuildinfo"},keywords:["ai","assistant","chatbot","telegram","discord","whatsapp","matrix","signal","claude","openai","ollama"],license:"MIT",repository:{type:"git",url:"https://github.com/madh99/alfred-ai.git"},homepage:"https://github.com/madh99/alfred-ai#readme",bugs:{url:"https://github.com/madh99/alfred-ai/issues"},dependencies:{"@anthropic-ai/sdk":"^0.39.0","@google/genai":"^1.45.0","@modelcontextprotocol/sdk":"^1.12.1","better-sqlite3":"^11.8.0",botbuilder:"^4.23.0",ccxt:"^4.4.0","discord.js":"^14.18.0",docx:"^9.0.0",dotenv:"^16.4.0",exceljs:"^4.4.0",grammy:"^1.35.0",imapflow:"^1.2.10","js-yaml":"^4.1.0",mammoth:"^1.8.0",mqtt:"^5.0.0",nodemailer:"^8.0.1",openai:"^4.80.0","pdf-parse":"^1.1.1",pdfkit:"^0.16.0",pino:"^9.6.0","pino-pretty":"^13.0.0","pino-roll":"^4.0.0",puppeteer:"^24.0.0","puppeteer-core":"^24.0.0","rss-parser":"^3.13.0",sonos:"^1.14.0","youtube-transcript":"^1.3.0",zod:"^3.24.0"},optionalDependencies:{"@aws-sdk/client-s3":"^3.700.0","@influxdata/influxdb-client":"^1.35.0","@whiskeysockets/baileys":"6.7.21",googleapis:"^144.0.0","hafas-client":"^6.3.0",ioredis:"^5.4.0","matrix-bot-sdk":"^0.8.0",mongodb:"^6.12.0",mssql:"^11.0.0",mysql2:"^3.12.0",pg:"^8.13.0",tsdav:"^2.1.0"},devDependencies:{"@alfred/config":"workspace:*","@alfred/core":"workspace:*","@alfred/logger":"workspace:*","@alfred/security":"workspace:*","@alfred/storage":"workspace:*","@alfred/types":"workspace:*","@types/js-yaml":"^4.0.9"},publishConfig:{access:"public"},engines:{node:">=20"}}});var MT={};Ne(MT,{ClusterManager:()=>yo});var yo,zp=S(()=>{"use strict";yo=class{static{f(this,"ClusterManager")}config;logger;redis;heartbeatTimer;heartbeatMs;failoverMs;constructor(e,t){this.config=e,this.logger=t,this.heartbeatMs=e.heartbeatIntervalMs??1e4,this.failoverMs=e.failoverAfterMs??3e4}async connect(){try{let e;try{e=(await Function('return import("ioredis")')()).default}catch{throw new Error('Cluster mode requires the "ioredis" package. Install it: npm install ioredis')}this.redis=new e(this.config.redisUrl),this.logger.info({nodeId:this.config.nodeId,role:this.config.role},"Cluster manager connected to Redis")}catch(e){this.logger.error({err:e},"Failed to connect to Redis \u2014 cluster features disabled");return}this.heartbeatTimer=setInterval(()=>this.sendHeartbeat(),this.heartbeatMs),await this.sendHeartbeat()}async disconnect(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),await this.redis?.quit()}async sendHeartbeat(){try{let e=JSON.stringify({id:this.config.nodeId,role:this.config.role,timestamp:new Date().toISOString(),uptime:Math.floor(process.uptime())});await this.redis.set(`alfred:cluster:heartbeat:${this.config.nodeId}`,e,"EX",Math.ceil(this.failoverMs/1e3))}catch(e){this.logger.warn({err:e},"Heartbeat send failed")}}async getNodes(){if(!this.redis)return[];try{let e=await this.redis.keys("alfred:cluster:heartbeat:*"),t=[];for(let s of e){let i=await this.redis.get(s);if(i)try{let n=JSON.parse(i);t.push({...n,healthy:!0})}catch{}}return t}catch{return[]}}async acquireLock(e,t=3e5){if(!this.redis)return!0;try{return await this.redis.set(`alfred:lock:${e}`,this.config.nodeId,"NX","PX",t)==="OK"}catch{return!0}}async releaseLock(e){if(this.redis)try{await this.redis.get(`alfred:lock:${e}`)===this.config.nodeId&&await this.redis.del(`alfred:lock:${e}`)}catch{}}async publish(e,t){if(this.redis)try{await this.redis.publish(`alfred:${e}`,JSON.stringify({...t,nodeId:this.config.nodeId}))}catch(s){this.logger.warn({err:s,channel:e},"Cluster publish failed")}}async subscribe(e,t){if(this.redis)try{let s=this.redis.duplicate();await s.subscribe(`alfred:${e}`),s.on("message",(i,n)=>{try{let r=JSON.parse(n);r.nodeId!==this.config.nodeId&&t(r)}catch{}})}catch(s){this.logger.warn({err:s,channel:e},"Cluster subscribe failed")}}async routeMessage(e,t,s){await this.publish("messages",{type:"send_message",targetPlatform:e,chatId:t,text:s})}failoverCheckTimer;onFailoverCallback;startFailoverMonitoring(e){this.config.role==="secondary"&&(this.onFailoverCallback=e,this.failoverCheckTimer=setInterval(async()=>{try{let t=await this.getNodes(),s=new Set(t.map(i=>i.id));for(let i of this.config.nodes??[])i.id!==this.config.nodeId&&(s.has(i.id)||(this.logger.warn({deadNodeId:i.id},"Node heartbeat missing \u2014 failover triggered"),this.onFailoverCallback?.(i.id)))}catch(t){this.logger.debug({err:t},"Failover check error")}},this.failoverMs))}stopFailoverMonitoring(){this.failoverCheckTimer&&clearInterval(this.failoverCheckTimer)}async announceTakeover(e,t){await this.publish("events",{type:"failover",deadNodeId:e,takenOverBy:this.config.nodeId,adapters:t}),this.logger.info({deadNodeId:e,adapters:t},"Failover: adapters taken over")}async syncConfig(e,t){await this.publish("config-sync",{type:e,...t})}async onConfigSync(e){await this.subscribe("config-sync",t=>{let{type:s,...i}=t;e(s,i)})}get nodeId(){return this.config.nodeId}get role(){return this.config.role??"node"}get isConnected(){return!!this.redis}pgAdapter;pgHeartbeatTimer;startPgHeartbeat(e){this.pgAdapter=e,this.pgHeartbeatTimer=setInterval(()=>this.sendPgHeartbeat(),this.heartbeatMs),this.sendPgHeartbeat()}async sendPgHeartbeat(){if(this.pgAdapter)try{let e=new Date().toISOString();await this.pgAdapter.execute(`INSERT INTO node_heartbeats (node_id, host, last_seen_at, started_at, uptime_s)
5108
5119
  VALUES (?, ?, ?, ?, ?)
5109
5120
  ON CONFLICT (node_id) DO UPDATE SET
5110
5121
  last_seen_at = excluded.last_seen_at,
@@ -5222,7 +5233,7 @@ Alfred Chat \u2014 type your message and press Enter. Use /quit or /exit to leav
5222
5233
  Goodbye!
5223
5234
  `),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 i=`cli-resp-${++this.messageCounter}`;return process.stdout.write(`
5224
5235
  Alfred: ${t}
5225
- `),this.prompt(),i}async editMessage(e,t,s,i){Jp.clearLine(process.stdout,0),Jp.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import tE from"node:http";import gR from"node:https";import Ze from"node:fs";import xt from"node:path";import yR from"node:os";import md from"node:crypto";var wR,sE,fd,iE=S(()=>{"use strict";ks();wR={".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"},sE=1048576,fd=class extends lt{static{f(this,"HttpAdapter")}platform="api";server=null;httpFallbackServer=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;dashboardFn;knowledgeGraphFn;knowledgeGraphDeleteEntityFn;knowledgeGraphDeleteRelationFn;knowledgeGraphUpdateEntityFn;knowledgeGraphUpdateRelationFn;memoriesListFn;memoriesDeleteFn;memoriesUpdateTypeFn;cmdbCallbacks;itsmCallbacks;docsCallbacks;webUiPath;tls;authCb;webhooks=new Map;oauthCallbacks=new Map;publicUrl;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,this.tls=s?.tls,this.publicUrl=s?.publicUrl,this.authCb=s?.authCallback,s?.webhooks)for(let i of s.webhooks)this.webhooks.set(i.name,i);if(s?.oauthCallbacks)for(let[i,n]of s.oauthCallbacks)this.oauthCallbacks.set(i,n)}addWebhook(e){this.webhooks.set(e.name,e)}registerOAuthCallback(e,t){this.oauthCallbacks.set(e,t)}setKnowledgeGraphCallbacks(e){this.knowledgeGraphFn=e.getGraph,this.knowledgeGraphDeleteEntityFn=e.deleteEntity,this.knowledgeGraphDeleteRelationFn=e.deleteRelation,this.knowledgeGraphUpdateEntityFn=e.updateEntity,this.knowledgeGraphUpdateRelationFn=e.updateRelation}setMemoryCallbacks(e){this.memoriesListFn=e.list,this.memoriesDeleteFn=e.delete,this.memoriesUpdateTypeFn=e.updateType}runbooksListFn;runbooksGetFn;runbooksUpdateFn;runbooksDeleteFn;setRunbookCallbacks(e){this.runbooksListFn=e.list,this.runbooksGetFn=e.get,this.runbooksUpdateFn=e.update,this.runbooksDeleteFn=e.delete}projectAgentsListFn;projectAgentsGetFn;projectAgentsStopFn;setProjectAgentCallbacks(e){this.projectAgentsListFn=e.list,this.projectAgentsGetFn=e.get,this.projectAgentsStopFn=e.stop}projectsCallbacks;setProjectsCallbacks(e){this.projectsCallbacks=e}setCmdbCallbacks(e){this.cmdbCallbacks=e}setItsmCallbacks(e){this.itsmCallbacks=e}setDocsCallbacks(e){this.docsCallbacks=e}logCallbacks;clusterCallbacks;setLogCallbacks(e){this.logCallbacks=e}setClusterCallbacks(e){this.clusterCallbacks=e}async connect(){this.status="connecting";let e=f((s,i)=>{this.handleRequest(s,i)},"handler"),t=await this.resolveTls();if(t){this.server=gR.createServer(t,e);let s=this.port+2,i=f((n,r)=>{n.url?.startsWith("/files/tts/")?this.handleRequest(n,r):(r.writeHead(403,{"Content-Type":"text/plain"}),r.end("Use HTTPS for API access"))},"httpHandler");this.httpFallbackServer=tE.createServer(i),this.httpFallbackServer.listen(s,this.host,()=>{console.log(`[HttpAdapter] HTTP fallback for Sonos TTS file serving on port ${s}`)})}else this.server=tE.createServer(e);await new Promise((s,i)=>{this.server.listen(this.port,this.host,()=>{s()}),this.server.once("error",i)}),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.httpFallbackServer&&(this.httpFallbackServer.close(),this.httpFallbackServer=null),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 i=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),i}async editMessage(e,t,s,i){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 i=this.streams.get(e);return i&&this.writeSseEvent(i,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,i){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:i}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let i=this.streams.get(e);return i&&this.writeSseEvent(i,"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))}async resolveTls(){if(!this.tls?.enabled)return null;if(this.tls.cert&&this.tls.key)try{return{cert:Ze.readFileSync(this.tls.cert),key:Ze.readFileSync(this.tls.key)}}catch(i){throw new Error(`TLS cert/key read failed: ${i instanceof Error?i.message:String(i)}`)}let e=xt.join(process.env.HOME??process.env.USERPROFILE??".",".alfred","tls"),t=xt.join(e,"cert.pem"),s=xt.join(e,"key.pem");if(Ze.existsSync(t)&&Ze.existsSync(s))return{cert:Ze.readFileSync(t),key:Ze.readFileSync(s)};try{let{execFileSync:i}=await import("node:child_process"),{generateKeyPairSync:n}=await import("node:crypto"),{privateKey:r}=n("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}});Ze.mkdirSync(e,{recursive:!0}),Ze.writeFileSync(s,r,{mode:384});let a=new Set(["IP:127.0.0.1","IP:0.0.0.0","DNS:localhost"]);if(this.host&&this.host!=="0.0.0.0"&&this.host!=="127.0.0.1"&&this.host!=="::"&&a.add(/^\d+\.\d+\.\d+\.\d+$/.test(this.host)?`IP:${this.host}`:`DNS:${this.host}`),this.publicUrl)try{let o=new URL(this.publicUrl).hostname;o&&o!=="localhost"&&a.add(/^\d+\.\d+\.\d+\.\d+$/.test(o)?`IP:${o}`:`DNS:${o}`)}catch{}return i("openssl",["req","-new","-x509","-key",s,"-out",t,"-days","365","-subj","/CN=Alfred AI/O=Alfred","-addext",`subjectAltName=${[...a].join(",")}`],{stdio:"pipe"}),{cert:Ze.readFileSync(t),key:Ze.readFileSync(s)}}catch(i){return console.warn(`[HttpAdapter] Self-signed TLS cert generation failed: ${i instanceof Error?i.message:String(i)}. Running without TLS.`),null}}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, PATCH, DELETE, 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).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/auth/required"&&e.method==="GET")t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({authRequired:!!(this.apiToken||this.authCb)}));else if(s.pathname==="/api/metrics"&&e.method==="GET")this.handleMetricsAuth(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/message"&&e.method==="POST")this.handleMessage(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/dashboard"&&e.method==="GET")this.handleDashboard(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/knowledge-graph"&&e.method==="GET")this.handleKnowledgeGraph(e,t).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/entity/")&&e.method==="DELETE")this.handleKgDeleteEntity(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/relation/")&&e.method==="DELETE")this.handleKgDeleteRelation(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/entity/")&&e.method==="PATCH")this.handleKgUpdateEntity(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/relation/")&&e.method==="PATCH")this.handleKgUpdateRelation(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/memories"&&e.method==="GET")this.handleMemoriesList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/memories/")&&e.method==="DELETE")this.handleMemoriesDelete(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/memories/")&&e.method==="PATCH")this.handleMemoriesUpdateType(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/runbooks"&&e.method==="GET")this.handleRunbooksList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/runbooks/")&&e.method==="GET")this.handleRunbooksGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/runbooks/")&&e.method==="PATCH")this.handleRunbooksUpdate(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/runbooks/")&&e.method==="DELETE")this.handleRunbooksDelete(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/project-agents"&&e.method==="GET")this.handleProjectAgentsList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/project-agents\/[^/]+$/)&&e.method==="GET")this.handleProjectAgentsGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/project-agents\/[^/]+\/stop$/)&&e.method==="POST")this.handleProjectAgentsStop(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/projects"&&e.method==="GET")this.handleProjectsList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/projects"&&e.method==="POST")this.handleProjectsCreate(e,t).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+$/)&&e.method==="GET")this.handleProjectsGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+$/)&&e.method==="PATCH")this.handleProjectsUpdate(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+$/)&&e.method==="DELETE")this.handleProjectsArchive(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+\/open-items$/)&&e.method==="POST")this.handleProjectsAddOpenItem(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/open-items\/[^/]+$/)&&e.method==="PATCH")this.handleProjectsUpdateOpenItem(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+\/health-log$/)&&e.method==="GET")this.handleProjectsHealthLog(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/logs/app"&&e.method==="GET")this.handleLogApp(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/logs/app/stream"&&e.method==="GET")this.handleLogStream(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/logs/audit"&&e.method==="GET")this.handleLogAudit(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/cluster/health"&&e.method==="GET")this.handleClusterHealth(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/cmdb/assets"&&e.method==="GET")this.handleCmdbRoute(e,t,async(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listAssets(n,r)});else if(s.pathname==="/api/cmdb/assets"&&e.method==="POST")this.handleCmdbBodyRoute(e,t,(i,n,r)=>i.createAsset(n,r));else if(s.pathname.startsWith("/api/cmdb/assets/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.getAsset(r,i))}else if(s.pathname.startsWith("/api/cmdb/assets/")&&e.method==="PATCH"){let i=s.pathname.split("/api/cmdb/assets/")[1];this.handleCmdbBodyRoute(e,t,(n,r,a)=>n.updateAsset(r,i,a))}else if(s.pathname.startsWith("/api/cmdb/assets/")&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.deleteAsset(r,i))}else if(s.pathname==="/api/cmdb/relations"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>i.listRelations(n));else if(s.pathname==="/api/cmdb/relations"&&e.method==="POST")this.handleCmdbBodyRoute(e,t,(i,n,r)=>i.createRelation(n,r));else if(s.pathname.startsWith("/api/cmdb/relations/")&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.deleteRelation(r,i))}else if(s.pathname==="/api/cmdb/discover"&&e.method==="POST")this.handleCmdbRoute(e,t,(i,n)=>i.discover(n));else if(s.pathname==="/api/cmdb/stats"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>i.getStats(n));else if(s.pathname.match(/^\/api\/services\/[^/]+\/failure-modes\/[^/]+$/)&&e.method==="DELETE"){let i=s.pathname.split("/"),n=i[3],r=decodeURIComponent(i[5]);this.handleItsmRoute(e,t,async(a,o)=>{let c=await a.getService(o,n);return c?(c.failureModes=(c.failureModes||[]).filter(l=>l.name!==r),a.updateService(o,n,{failure_modes:c.failureModes})):{error:"Service not found"}})}else if(s.pathname.match(/^\/api\/services\/[^/]+\/failure-modes$/)&&e.method==="POST"){let i=s.pathname.split("/")[3];this.handleItsmBodyRoute(e,t,async(n,r,a)=>{let o=await n.getService(r,i);if(!o)return{error:"Service not found"};let c=o.failureModes||[];return c.push(a),n.updateService(r,i,{failure_modes:c})})}else if(s.pathname.match(/^\/api\/services\/[^/]+\/impact$/)&&e.method==="GET"){let i=s.pathname.split("/")[3];this.handleItsmRoute(e,t,async(n,r)=>{let a=await n.getService(r,i);if(!a)return{error:"Service not found"};let o=a.dependencyMap?.downstream||[];return{service:a.name,impact:o,failureModes:a.failureModes||[]}})}else if(s.pathname.match(/^\/api\/services\/[^/]+\/generate-docs$/)&&e.method==="POST"){let i=s.pathname.split("/")[3];this.handleItsmRoute(e,t,(n,r)=>n.generateDocs(r,i))}else if(s.pathname==="/api/services"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listServices(n,r)});else if(s.pathname==="/api/services"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createService(n,r));else if(s.pathname.match(/^\/api\/services\/[^/]+$/)&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleItsmRoute(e,t,(n,r)=>n.getService(r,i))}else if(s.pathname.match(/^\/api\/services\/[^/]+$/)&&e.method==="PATCH"){let i=s.pathname.split("/").pop();this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateService(r,i,a))}else if(s.pathname.match(/^\/api\/services\/[^/]+$/)&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleItsmRoute(e,t,(n,r)=>n.deleteService(r,i))}else if(s.pathname==="/api/sla/compliance"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.checkSlaCompliance(n));else if(s.pathname==="/api/sla/breaches"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.getSlaBreaches(n,s.searchParams.get("period")??void 0));else if(s.pathname.match(/^\/api\/sla\/report\/(service|asset)\/[^/]+$/)&&e.method==="GET"){let i=s.pathname.split("/"),n=i[4],r=i[5];this.handleItsmRoute(e,t,(a,o)=>a.getSlaReport(o,n,r,s.searchParams.get("period")??void 0))}else if(s.pathname==="/api/sla/set"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.setSla(n,r.targetType,r.targetId,r.sla));else if(s.pathname==="/api/itsm/incidents"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listIncidents(n,r)});else if(s.pathname==="/api/itsm/incidents"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createIncident(n,r));else if(s.pathname.startsWith("/api/itsm/incidents/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleItsmRoute(e,t,(n,r)=>n.getIncident(r,i))}else if(s.pathname.startsWith("/api/itsm/incidents/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/incidents/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateIncident(r,i,a))}else if(s.pathname==="/api/itsm/changes"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listChanges(n,r)});else if(s.pathname==="/api/itsm/changes"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createChange(n,r));else if(s.pathname.startsWith("/api/itsm/changes/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/changes/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateChange(r,i,a))}else if(s.pathname==="/api/itsm/services"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listServices(n,r)});else if(s.pathname==="/api/itsm/services"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createService(n,r));else if(s.pathname.startsWith("/api/itsm/services/health-check")&&e.method==="POST")this.handleItsmRoute(e,t,(i,n)=>i.healthCheck(n));else if(s.pathname.startsWith("/api/itsm/services/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/services/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateService(r,i,a))}else if(s.pathname==="/api/itsm/dashboard"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.getDashboard(n));else if(s.pathname==="/api/itsm/problems/detect-patterns"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.detectPatterns(n,r));else if(s.pathname==="/api/itsm/problems/dashboard"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.getProblemDashboard(n));else if(s.pathname==="/api/itsm/problems"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listProblems(n,r)});else if(s.pathname==="/api/itsm/problems"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createProblem(n,r));else if(s.pathname.match(/^\/api\/itsm\/problems\/[^/]+\/link-incident$/)&&e.method==="POST"){let i=s.pathname.split("/api/itsm/problems/")[1].split("/link-incident")[0];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.linkIncidentToProblem(r,i,a.incident_id))}else if(s.pathname.match(/^\/api\/itsm\/problems\/[^/]+\/link-incident\/[^/]+$/)&&e.method==="DELETE"){let i=s.pathname.split("/"),n=i[4],r=i[6];this.handleItsmRoute(e,t,(a,o)=>a.unlinkIncidentFromProblem(o,n,r))}else if(s.pathname.match(/^\/api\/itsm\/problems\/[^/]+\/fix-change$/)&&e.method==="POST"){let i=s.pathname.split("/api/itsm/problems/")[1].split("/fix-change")[0];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.createFixChange(r,i,a))}else if(s.pathname.startsWith("/api/itsm/problems/")&&e.method==="GET"){let i=s.pathname.split("/api/itsm/problems/")[1];this.handleItsmRoute(e,t,(n,r)=>n.getProblem(r,i))}else if(s.pathname.startsWith("/api/itsm/problems/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/problems/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateProblem(r,i,a))}else if(s.pathname==="/api/docs/generate"&&e.method==="POST")this.handleDocsBodyRoute(e,t,(i,n,r)=>i.generate(n,r.type,r));else if(s.pathname==="/api/docs/export"&&e.method==="GET")this.handleDocsRoute(e,t,(i,n)=>i.exportData(n,s.searchParams.get("format")??void 0));else if(s.pathname==="/api/docs/list"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listDocuments(n,r)});else if(s.pathname==="/api/docs/tree"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>i.getDocumentTree(n));else if(s.pathname==="/api/docs/search"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>{let r=s.searchParams.get("q")??"",a=Object.fromEntries(s.searchParams.entries());return delete a.q,i.searchDocuments(n,r,a)});else if(s.pathname==="/api/docs"&&e.method==="POST")this.handleCmdbBodyRoute(e,t,(i,n,r)=>i.saveDocument(n,r));else if(s.pathname.match(/^\/api\/docs\/[^/]+\/versions$/)&&e.method==="GET"){let n=s.pathname.split("/")[3];this.handleCmdbRoute(e,t,async(r,a)=>{let o=await r.getDocument(a,n);return o?r.getDocumentVersions(a,o.linkedEntityType??"",o.linkedEntityId??"",o.docType):{error:"Document not found"}})}else if(s.pathname.startsWith("/api/docs/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.getDocument(r,i))}else if(s.pathname.startsWith("/api/docs/")&&e.method==="PATCH"){let i=s.pathname.split("/").pop();this.handleCmdbBodyRoute(e,t,(n,r,a)=>n.updateDocument(r,i,a))}else if(s.pathname.startsWith("/api/docs/")&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.deleteDocument(r,i))}else if(s.pathname==="/api/cmdb/documents"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listDocuments(n,r)});else if(s.pathname.startsWith("/api/cmdb/documents/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.getDocument(r,i))}else if(s.pathname==="/api/auth/login"&&e.method==="POST")this.handleAuthLogin(e,t);else if(s.pathname==="/api/auth/me"&&e.method==="GET")this.handleAuthMeProtected(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/oauth/callback"&&e.method==="GET")this.handleOAuthCallback(s,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let i=s.pathname.slice(13);this.handleWebhook(e,t,i)}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()):s.pathname.startsWith("/files/tts/")&&e.method==="GET"?this.serveTtsFile(s.pathname,t):(t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"})))}async checkAuth(e,t){if(!this.apiToken&&!this.authCb)return!0;let s=e.headers.authorization,i=s?.startsWith("Bearer ")?s.slice(7):null;if(this.apiToken&&i){let n=this.apiToken;if(i.length===n.length&&md.timingSafeEqual(Buffer.from(i),Buffer.from(n)))return!0}return this.authCb&&i&&await this.authCb.getUserByToken(i)?!0:(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1)}handleAuthLogin(e,t){if(!this.authCb){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Auth not configured"}));return}let s="";e.on("data",i=>{s+=i.toString()}),e.on("end",async()=>{try{let{code:i}=JSON.parse(s);if(!i){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing code"}));return}let n=await this.authCb.loginWithCode(i);n.success?(t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:!0,userId:n.userId,username:n.username,role:n.role,token:n.token}))):(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:!1,error:n.error??"Invalid code"})))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}))}})}async handleAuthMeProtected(e,t){if(await this.checkAuth(e,t))return this.handleAuthMe(e,t)}async handleMetricsAuth(e,t){if(await this.checkAuth(e,t))return this.handleMetrics(t)}async handleAuthMe(e,t){if(!this.authCb){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Auth not configured"}));return}let s=e.headers.authorization,i=s?.startsWith("Bearer ")?s.slice(7):null;if(!i){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"No token"}));return}let n=await this.authCb.getUserByToken(i);if(!n){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid token"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}async handleDashboard(e,t){if(await 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=await this.dashboardFn(),i=e.headers.authorization,n=i?.startsWith("Bearer ")?i.slice(7):null,r=n&&this.authCb?await this.authCb.getUserByToken(n):null;r&&r.role!=="admin"&&(delete s.userUsage,delete s.userSkillUsage),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 i=xt.resolve(this.webUiPath,"."+s);if(!i.startsWith(xt.resolve(this.webUiPath))){t.writeHead(403),t.end();return}let n=i;if(!Ze.existsSync(n))if(Ze.existsSync(n+".html"))n=n+".html";else if(Ze.existsSync(xt.join(n,"index.html")))n=xt.join(n,"index.html");else{t.writeHead(404,{"Content-Type":"text/html"}),t.end("Not found");return}try{if(Ze.statSync(n).isDirectory()){let u=xt.join(n,"index.html");if(Ze.existsSync(u))n=u;else{t.writeHead(404),t.end();return}}}catch{t.writeHead(404),t.end();return}let r=Ze.statSync(n),a=xt.extname(n).toLowerCase(),o=wR[a]??"application/octet-stream",c=a===".html"?"no-cache":"public, max-age=31536000, immutable";t.writeHead(200,{"Content-Type":o,"Content-Length":r.size,"Cache-Control":c}),Ze.createReadStream(n).pipe(t)}serveTtsFile(e,t){let s={".mp3":"audio/mpeg",".opus":"audio/ogg",".wav":"audio/wav",".flac":"audio/flac",".aac":"audio/aac",".ogg":"audio/ogg"},i=e.slice(11);if(!i||i.includes("/")||i.includes("\\")||i.includes("..")){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid filename"}));return}let n=xt.join(yR.tmpdir(),"alfred-tts"),r=xt.join(n,i);if(!xt.resolve(r).startsWith(xt.resolve(n))){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Forbidden"}));return}try{if(Ze.existsSync(n)){let l=Date.now();for(let u of Ze.readdirSync(n))try{let h=xt.join(n,u),p=Ze.statSync(h);l-p.mtimeMs>300*1e3&&Ze.unlinkSync(h)}catch{}}}catch{}if(!Ze.existsSync(r)){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"File not found"}));return}let a=Ze.statSync(r),o=xt.extname(i).toLowerCase(),c=s[o]??"audio/mpeg";t.writeHead(200,{"Content-Type":c,"Content-Length":a.size,"Cache-Control":"no-cache"}),Ze.createReadStream(r).pipe(t)}async handleKnowledgeGraph(e,t){if(await this.checkAuth(e,t)){if(!this.knowledgeGraphFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Knowledge graph not configured"}));return}try{let i=new URL(e.url,`http://${e.headers.host}`).searchParams.get("userId")??void 0,n=await this.knowledgeGraphFn(i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}catch{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Knowledge graph fetch failed"}))}}}async handleKgDeleteEntity(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphDeleteEntityFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.knowledgeGraphDeleteEntityFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleKgDeleteRelation(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphDeleteRelationFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.knowledgeGraphDeleteRelationFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleKgUpdateEntity(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphUpdateEntityFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r=JSON.parse(n),a=await this.knowledgeGraphUpdateEntityFn(i,r);t.writeHead(a?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:a}))}async handleKgUpdateRelation(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphUpdateRelationFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r=JSON.parse(n),a=await this.knowledgeGraphUpdateRelationFn(i,r);t.writeHead(a?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:a}))}async handleMemoriesList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.memoriesListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("type")??void 0,n=await this.memoriesListFn(i?{type:i}:void 0);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({memories:n}))}async handleMemoriesDelete(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.memoriesDeleteFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.memoriesDeleteFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleMemoriesUpdateType(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.memoriesUpdateTypeFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!r.type||typeof r.type!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"type required"}));return}let a=new Set(["correction","preference","fact","entity","general","pattern"]);if(!a.has(r.type)){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`invalid type, allowed: ${[...a].join(", ")}`}));return}let o=await this.memoriesUpdateTypeFn(i,r.type);t.writeHead(o?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:o}))}async handleRunbooksList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("status")??void 0,n=s.searchParams.get("source_type")??void 0,r=await this.runbooksListFn({status:i,sourceType:n});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({runbooks:r}))}async handleRunbooksGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksGetFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.runbooksGetFn(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({runbook:n}))}async handleRunbooksUpdate(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksUpdateFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let a=await this.runbooksUpdateFn(i,r);if(!a){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({runbook:a}))}async handleRunbooksDelete(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksDeleteFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.runbooksDeleteFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleProjectAgentsList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectAgentsListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("phase")??void 0,n=await this.projectAgentsListFn({phase:i});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({sessions:n}))}async handleProjectAgentsGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectAgentsGetFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.projectAgentsGetFn(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({session:n}))}async handleProjectAgentsStop(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectAgentsStopFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=await this.projectAgentsStopFn(n);t.writeHead(r?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:r}))}async handleProjectsList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("status")??void 0,n=await this.projectsCallbacks.list({status:i});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({projects:n}))}async handleProjectsGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.projectsCallbacks.get(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}async handleProjectsCreate(e,t){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let s=await this.readBody(e),i;try{i=JSON.parse(s)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!i.name){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"name required"}));return}let n=await this.projectsCallbacks.create(i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({project:n}))}async handleProjectsUpdate(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let a=await this.projectsCallbacks.update(i,r);if(!a){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({project:a}))}async handleProjectsArchive(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.projectsCallbacks.archive(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleProjectsAddOpenItem(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=await this.readBody(e),a;try{a=JSON.parse(r)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!a.title){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"title required"}));return}let o=await this.projectsCallbacks.addOpenItem(n,a);if(!o){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({item:o}))}async handleProjectsUpdateOpenItem(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!r.status){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"status required"}));return}let a=await this.projectsCallbacks.updateOpenItem(i,r.status);t.writeHead(a?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:a}))}async handleProjectsHealthLog(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=Number(s.searchParams.get("limit")??"100"),a=await this.projectsCallbacks.listHealthLog(n,r);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({entries:a}))}async resolveUserId(e){let t=e.headers.authorization?.startsWith("Bearer ")?e.headers.authorization.slice(7):null;if(this.authCb&&t){let s=await this.authCb.getUserByToken(t);if(s)return s.masterUserId??s.id??""}return""}handleCmdbRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.cmdbCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"CMDB not configured"}));return}let i=await this.resolveUserId(e),n=await s(this.cmdbCallbacks,i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))})().catch(i=>this.safeError(t,i))}handleCmdbBodyRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.cmdbCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"CMDB not configured"}));return}let i=await this.resolveUserId(e),n;try{n=JSON.parse(await this.readBody(e))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let r=await s(this.cmdbCallbacks,i,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))})().catch(i=>this.safeError(t,i))}handleItsmRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.itsmCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"ITSM not configured"}));return}let i=await this.resolveUserId(e),n=await s(this.itsmCallbacks,i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))})().catch(i=>this.safeError(t,i))}handleItsmBodyRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.itsmCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"ITSM not configured"}));return}let i=await this.resolveUserId(e),n;try{n=JSON.parse(await this.readBody(e))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let r=await s(this.itsmCallbacks,i,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))})().catch(i=>this.safeError(t,i))}handleDocsRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.docsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Docs not configured"}));return}let i=await this.resolveUserId(e),n=await s(this.docsCallbacks,i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))})().catch(i=>this.safeError(t,i))}handleDocsBodyRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.docsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Docs not configured"}));return}let i=await this.resolveUserId(e),n;try{n=JSON.parse(await this.readBody(e))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let r=await s(this.docsCallbacks,i,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))})().catch(i=>this.safeError(t,i))}readBody(e){return new Promise((t,s)=>{let i="";e.on("data",n=>i+=n),e.on("end",()=>t(i)),e.on("error",s)})}safeError(e,t){try{e.headersSent||e.writeHead(500,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"Internal server error"}))}catch{}}async handleHealth(e){let t=await this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",i=s==="ok"?200:503;e.writeHead(i,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}async handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(await this.metricsFn())):await this.handleHealth(e)}async handleMessage(e,t){if(!await this.checkAuth(e,t))return;let s="",i=0,n=!1;e.on("data",r=>{if(!n){if(i+=r.length,i>sE){n=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}s+=r.toString()}}),e.on("end",()=>{if(!n)try{let r=JSON.parse(s),a=r.text;if(!a||typeof a!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:'Missing or invalid "text" field'}));return}let o=r.chatId??`api-chat-${md.randomUUID()}`,c=r.userId??"api-user",l=this.streams.get(o);l&&(this.writeSseEvent(l,"done",{type:"done"}),l.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":this.corsOrigin,"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","X-Content-Type-Options":"nosniff"}),t.flushHeaders(),this.streams.set(o,t),t.on("close",()=>{this.streams.delete(o)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:o,chatType:"dm",userId:c,userName:c,displayName:"API User",text:a,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 i=this.webhooks.get(s);if(!i){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`Webhook "${s}" not found`}));return}let n="",r=0,a=!1;e.on("data",o=>{if(!a){if(r+=o.length,r>sE){a=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}n+=o.toString()}}),e.on("end",async()=>{if(a)return;let o=e.headers["x-webhook-signature"];if(!o){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing X-Webhook-Signature header"}));return}let c=md.createHmac("sha256",i.secret).update(n).digest(),l=Buffer.from(o,"hex");if(l.length!==c.length||!md.timingSafeEqual(l,c)){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid signature"}));return}try{let u=JSON.parse(n);await i.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"}))}})}async handleOAuthCallback(e,t){let s=e.searchParams.get("code"),i=e.searchParams.get("state"),n=e.searchParams.get("error");if(n){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Autorisierung abgelehnt</h2><p>${n}</p><p>Du kannst dieses Fenster schlie\xDFen.</p></body></html>`);return}if(!s||!i){t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end("<html><body><h2>Fehler</h2><p>Code oder State fehlt.</p></body></html>");return}let r;try{r=JSON.parse(Buffer.from(i,"base64url").toString())}catch{t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end("<html><body><h2>Fehler</h2><p>Ung\xFCltiger State-Parameter.</p></body></html>");return}let a=r.service,o=this.oauthCallbacks.get(a);if(!o){t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Fehler</h2><p>Kein OAuth-Handler f\xFCr "${a}" registriert.</p></body></html>`);return}try{let c=await o(s,r);c.success?(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end("<html><body><h2>Erfolgreich verbunden!</h2><p>Du kannst dieses Fenster schlie\xDFen und zu Alfred zur\xFCckkehren.</p></body></html>")):(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Fehler</h2><p>${c.error??"Unbekannter Fehler"}</p></body></html>`))}catch(c){t.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Fehler</h2><p>${c instanceof Error?c.message:"Interner Fehler"}</p></body></html>`)}}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
5236
+ `),this.prompt(),i}async editMessage(e,t,s,i){Jp.clearLine(process.stdout,0),Jp.cursorTo(process.stdout,0),process.stdout.write(`Alfred: ${s}`)}async deleteMessage(e,t){}prompt(){this.rl?.prompt()}}});import tE from"node:http";import gR from"node:https";import Qe from"node:fs";import xt from"node:path";import yR from"node:os";import md from"node:crypto";var wR,sE,fd,iE=S(()=>{"use strict";ks();wR={".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"},sE=1048576,fd=class extends lt{static{f(this,"HttpAdapter")}platform="api";server=null;httpFallbackServer=null;streams=new Map;messageCounter=0;port;host;apiToken;corsOrigin;healthCheckFn;metricsFn;dashboardFn;knowledgeGraphFn;knowledgeGraphDeleteEntityFn;knowledgeGraphDeleteRelationFn;knowledgeGraphUpdateEntityFn;knowledgeGraphUpdateRelationFn;memoriesListFn;memoriesDeleteFn;memoriesUpdateTypeFn;cmdbCallbacks;itsmCallbacks;docsCallbacks;webUiPath;tls;authCb;webhooks=new Map;oauthCallbacks=new Map;publicUrl;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,this.tls=s?.tls,this.publicUrl=s?.publicUrl,this.authCb=s?.authCallback,s?.webhooks)for(let i of s.webhooks)this.webhooks.set(i.name,i);if(s?.oauthCallbacks)for(let[i,n]of s.oauthCallbacks)this.oauthCallbacks.set(i,n)}addWebhook(e){this.webhooks.set(e.name,e)}registerOAuthCallback(e,t){this.oauthCallbacks.set(e,t)}setKnowledgeGraphCallbacks(e){this.knowledgeGraphFn=e.getGraph,this.knowledgeGraphDeleteEntityFn=e.deleteEntity,this.knowledgeGraphDeleteRelationFn=e.deleteRelation,this.knowledgeGraphUpdateEntityFn=e.updateEntity,this.knowledgeGraphUpdateRelationFn=e.updateRelation}setMemoryCallbacks(e){this.memoriesListFn=e.list,this.memoriesDeleteFn=e.delete,this.memoriesUpdateTypeFn=e.updateType}runbooksListFn;runbooksGetFn;runbooksUpdateFn;runbooksDeleteFn;setRunbookCallbacks(e){this.runbooksListFn=e.list,this.runbooksGetFn=e.get,this.runbooksUpdateFn=e.update,this.runbooksDeleteFn=e.delete}projectAgentsListFn;projectAgentsGetFn;projectAgentsStopFn;setProjectAgentCallbacks(e){this.projectAgentsListFn=e.list,this.projectAgentsGetFn=e.get,this.projectAgentsStopFn=e.stop}backgroundTasksListFn;backgroundTasksGetFn;backgroundTasksCancelFn;setBackgroundTaskCallbacks(e){this.backgroundTasksListFn=e.list,this.backgroundTasksGetFn=e.get,this.backgroundTasksCancelFn=e.cancel}projectsCallbacks;setProjectsCallbacks(e){this.projectsCallbacks=e}setCmdbCallbacks(e){this.cmdbCallbacks=e}setItsmCallbacks(e){this.itsmCallbacks=e}setDocsCallbacks(e){this.docsCallbacks=e}logCallbacks;clusterCallbacks;setLogCallbacks(e){this.logCallbacks=e}setClusterCallbacks(e){this.clusterCallbacks=e}async connect(){this.status="connecting";let e=f((s,i)=>{this.handleRequest(s,i)},"handler"),t=await this.resolveTls();if(t){this.server=gR.createServer(t,e);let s=this.port+2,i=f((n,r)=>{n.url?.startsWith("/files/tts/")?this.handleRequest(n,r):(r.writeHead(403,{"Content-Type":"text/plain"}),r.end("Use HTTPS for API access"))},"httpHandler");this.httpFallbackServer=tE.createServer(i),this.httpFallbackServer.listen(s,this.host,()=>{console.log(`[HttpAdapter] HTTP fallback for Sonos TTS file serving on port ${s}`)})}else this.server=tE.createServer(e);await new Promise((s,i)=>{this.server.listen(this.port,this.host,()=>{s()}),this.server.once("error",i)}),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.httpFallbackServer&&(this.httpFallbackServer.close(),this.httpFallbackServer=null),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 i=`api-resp-${++this.messageCounter}`,n=this.streams.get(e);return n&&this.writeSseEvent(n,"response",{type:"response",text:t}),i}async editMessage(e,t,s,i){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 i=this.streams.get(e);return i&&this.writeSseEvent(i,"attachment",{type:"attachment",attachmentType:"image",data:t.toString("base64"),caption:s}),`api-photo-${++this.messageCounter}`}async sendFile(e,t,s,i){let n=this.streams.get(e);return n&&this.writeSseEvent(n,"attachment",{type:"attachment",attachmentType:"file",data:t.toString("base64"),fileName:s,caption:i}),`api-file-${++this.messageCounter}`}async sendVoice(e,t,s){let i=this.streams.get(e);return i&&this.writeSseEvent(i,"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))}async resolveTls(){if(!this.tls?.enabled)return null;if(this.tls.cert&&this.tls.key)try{return{cert:Qe.readFileSync(this.tls.cert),key:Qe.readFileSync(this.tls.key)}}catch(i){throw new Error(`TLS cert/key read failed: ${i instanceof Error?i.message:String(i)}`)}let e=xt.join(process.env.HOME??process.env.USERPROFILE??".",".alfred","tls"),t=xt.join(e,"cert.pem"),s=xt.join(e,"key.pem");if(Qe.existsSync(t)&&Qe.existsSync(s))return{cert:Qe.readFileSync(t),key:Qe.readFileSync(s)};try{let{execFileSync:i}=await import("node:child_process"),{generateKeyPairSync:n}=await import("node:crypto"),{privateKey:r}=n("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}});Qe.mkdirSync(e,{recursive:!0}),Qe.writeFileSync(s,r,{mode:384});let a=new Set(["IP:127.0.0.1","IP:0.0.0.0","DNS:localhost"]);if(this.host&&this.host!=="0.0.0.0"&&this.host!=="127.0.0.1"&&this.host!=="::"&&a.add(/^\d+\.\d+\.\d+\.\d+$/.test(this.host)?`IP:${this.host}`:`DNS:${this.host}`),this.publicUrl)try{let o=new URL(this.publicUrl).hostname;o&&o!=="localhost"&&a.add(/^\d+\.\d+\.\d+\.\d+$/.test(o)?`IP:${o}`:`DNS:${o}`)}catch{}return i("openssl",["req","-new","-x509","-key",s,"-out",t,"-days","365","-subj","/CN=Alfred AI/O=Alfred","-addext",`subjectAltName=${[...a].join(",")}`],{stdio:"pipe"}),{cert:Qe.readFileSync(t),key:Qe.readFileSync(s)}}catch(i){return console.warn(`[HttpAdapter] Self-signed TLS cert generation failed: ${i instanceof Error?i.message:String(i)}. Running without TLS.`),null}}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, PATCH, DELETE, 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).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/auth/required"&&e.method==="GET")t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({authRequired:!!(this.apiToken||this.authCb)}));else if(s.pathname==="/api/metrics"&&e.method==="GET")this.handleMetricsAuth(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/message"&&e.method==="POST")this.handleMessage(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/dashboard"&&e.method==="GET")this.handleDashboard(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/knowledge-graph"&&e.method==="GET")this.handleKnowledgeGraph(e,t).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/entity/")&&e.method==="DELETE")this.handleKgDeleteEntity(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/relation/")&&e.method==="DELETE")this.handleKgDeleteRelation(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/entity/")&&e.method==="PATCH")this.handleKgUpdateEntity(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/knowledge-graph/relation/")&&e.method==="PATCH")this.handleKgUpdateRelation(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/memories"&&e.method==="GET")this.handleMemoriesList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/memories/")&&e.method==="DELETE")this.handleMemoriesDelete(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/memories/")&&e.method==="PATCH")this.handleMemoriesUpdateType(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/runbooks"&&e.method==="GET")this.handleRunbooksList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/runbooks/")&&e.method==="GET")this.handleRunbooksGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/runbooks/")&&e.method==="PATCH")this.handleRunbooksUpdate(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.startsWith("/api/runbooks/")&&e.method==="DELETE")this.handleRunbooksDelete(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/project-agents"&&e.method==="GET")this.handleProjectAgentsList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/project-agents\/[^/]+$/)&&e.method==="GET")this.handleProjectAgentsGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/project-agents\/[^/]+\/stop$/)&&e.method==="POST")this.handleProjectAgentsStop(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/background-tasks"&&e.method==="GET")this.handleBackgroundTasksList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/background-tasks\/[^/]+$/)&&e.method==="GET")this.handleBackgroundTasksGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/background-tasks\/[^/]+\/cancel$/)&&e.method==="POST")this.handleBackgroundTasksCancel(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/projects"&&e.method==="GET")this.handleProjectsList(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/projects"&&e.method==="POST")this.handleProjectsCreate(e,t).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+$/)&&e.method==="GET")this.handleProjectsGet(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+$/)&&e.method==="PATCH")this.handleProjectsUpdate(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+$/)&&e.method==="DELETE")this.handleProjectsArchive(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+\/open-items$/)&&e.method==="POST")this.handleProjectsAddOpenItem(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/open-items\/[^/]+$/)&&e.method==="PATCH")this.handleProjectsUpdateOpenItem(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname.match(/^\/api\/projects\/[^/]+\/health-log$/)&&e.method==="GET")this.handleProjectsHealthLog(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/logs/app"&&e.method==="GET")this.handleLogApp(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/logs/app/stream"&&e.method==="GET")this.handleLogStream(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/logs/audit"&&e.method==="GET")this.handleLogAudit(e,t,s).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/cluster/health"&&e.method==="GET")this.handleClusterHealth(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/cmdb/assets"&&e.method==="GET")this.handleCmdbRoute(e,t,async(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listAssets(n,r)});else if(s.pathname==="/api/cmdb/assets"&&e.method==="POST")this.handleCmdbBodyRoute(e,t,(i,n,r)=>i.createAsset(n,r));else if(s.pathname.startsWith("/api/cmdb/assets/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.getAsset(r,i))}else if(s.pathname.startsWith("/api/cmdb/assets/")&&e.method==="PATCH"){let i=s.pathname.split("/api/cmdb/assets/")[1];this.handleCmdbBodyRoute(e,t,(n,r,a)=>n.updateAsset(r,i,a))}else if(s.pathname.startsWith("/api/cmdb/assets/")&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.deleteAsset(r,i))}else if(s.pathname==="/api/cmdb/relations"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>i.listRelations(n));else if(s.pathname==="/api/cmdb/relations"&&e.method==="POST")this.handleCmdbBodyRoute(e,t,(i,n,r)=>i.createRelation(n,r));else if(s.pathname.startsWith("/api/cmdb/relations/")&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.deleteRelation(r,i))}else if(s.pathname==="/api/cmdb/discover"&&e.method==="POST")this.handleCmdbRoute(e,t,(i,n)=>i.discover(n));else if(s.pathname==="/api/cmdb/stats"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>i.getStats(n));else if(s.pathname.match(/^\/api\/services\/[^/]+\/failure-modes\/[^/]+$/)&&e.method==="DELETE"){let i=s.pathname.split("/"),n=i[3],r=decodeURIComponent(i[5]);this.handleItsmRoute(e,t,async(a,o)=>{let c=await a.getService(o,n);return c?(c.failureModes=(c.failureModes||[]).filter(l=>l.name!==r),a.updateService(o,n,{failure_modes:c.failureModes})):{error:"Service not found"}})}else if(s.pathname.match(/^\/api\/services\/[^/]+\/failure-modes$/)&&e.method==="POST"){let i=s.pathname.split("/")[3];this.handleItsmBodyRoute(e,t,async(n,r,a)=>{let o=await n.getService(r,i);if(!o)return{error:"Service not found"};let c=o.failureModes||[];return c.push(a),n.updateService(r,i,{failure_modes:c})})}else if(s.pathname.match(/^\/api\/services\/[^/]+\/impact$/)&&e.method==="GET"){let i=s.pathname.split("/")[3];this.handleItsmRoute(e,t,async(n,r)=>{let a=await n.getService(r,i);if(!a)return{error:"Service not found"};let o=a.dependencyMap?.downstream||[];return{service:a.name,impact:o,failureModes:a.failureModes||[]}})}else if(s.pathname.match(/^\/api\/services\/[^/]+\/generate-docs$/)&&e.method==="POST"){let i=s.pathname.split("/")[3];this.handleItsmRoute(e,t,(n,r)=>n.generateDocs(r,i))}else if(s.pathname==="/api/services"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listServices(n,r)});else if(s.pathname==="/api/services"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createService(n,r));else if(s.pathname.match(/^\/api\/services\/[^/]+$/)&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleItsmRoute(e,t,(n,r)=>n.getService(r,i))}else if(s.pathname.match(/^\/api\/services\/[^/]+$/)&&e.method==="PATCH"){let i=s.pathname.split("/").pop();this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateService(r,i,a))}else if(s.pathname.match(/^\/api\/services\/[^/]+$/)&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleItsmRoute(e,t,(n,r)=>n.deleteService(r,i))}else if(s.pathname==="/api/sla/compliance"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.checkSlaCompliance(n));else if(s.pathname==="/api/sla/breaches"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.getSlaBreaches(n,s.searchParams.get("period")??void 0));else if(s.pathname.match(/^\/api\/sla\/report\/(service|asset)\/[^/]+$/)&&e.method==="GET"){let i=s.pathname.split("/"),n=i[4],r=i[5];this.handleItsmRoute(e,t,(a,o)=>a.getSlaReport(o,n,r,s.searchParams.get("period")??void 0))}else if(s.pathname==="/api/sla/set"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.setSla(n,r.targetType,r.targetId,r.sla));else if(s.pathname==="/api/itsm/incidents"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listIncidents(n,r)});else if(s.pathname==="/api/itsm/incidents"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createIncident(n,r));else if(s.pathname.startsWith("/api/itsm/incidents/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleItsmRoute(e,t,(n,r)=>n.getIncident(r,i))}else if(s.pathname.startsWith("/api/itsm/incidents/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/incidents/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateIncident(r,i,a))}else if(s.pathname==="/api/itsm/changes"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listChanges(n,r)});else if(s.pathname==="/api/itsm/changes"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createChange(n,r));else if(s.pathname.startsWith("/api/itsm/changes/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/changes/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateChange(r,i,a))}else if(s.pathname==="/api/itsm/services"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listServices(n,r)});else if(s.pathname==="/api/itsm/services"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createService(n,r));else if(s.pathname.startsWith("/api/itsm/services/health-check")&&e.method==="POST")this.handleItsmRoute(e,t,(i,n)=>i.healthCheck(n));else if(s.pathname.startsWith("/api/itsm/services/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/services/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateService(r,i,a))}else if(s.pathname==="/api/itsm/dashboard"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.getDashboard(n));else if(s.pathname==="/api/itsm/problems/detect-patterns"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.detectPatterns(n,r));else if(s.pathname==="/api/itsm/problems/dashboard"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>i.getProblemDashboard(n));else if(s.pathname==="/api/itsm/problems"&&e.method==="GET")this.handleItsmRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listProblems(n,r)});else if(s.pathname==="/api/itsm/problems"&&e.method==="POST")this.handleItsmBodyRoute(e,t,(i,n,r)=>i.createProblem(n,r));else if(s.pathname.match(/^\/api\/itsm\/problems\/[^/]+\/link-incident$/)&&e.method==="POST"){let i=s.pathname.split("/api/itsm/problems/")[1].split("/link-incident")[0];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.linkIncidentToProblem(r,i,a.incident_id))}else if(s.pathname.match(/^\/api\/itsm\/problems\/[^/]+\/link-incident\/[^/]+$/)&&e.method==="DELETE"){let i=s.pathname.split("/"),n=i[4],r=i[6];this.handleItsmRoute(e,t,(a,o)=>a.unlinkIncidentFromProblem(o,n,r))}else if(s.pathname.match(/^\/api\/itsm\/problems\/[^/]+\/fix-change$/)&&e.method==="POST"){let i=s.pathname.split("/api/itsm/problems/")[1].split("/fix-change")[0];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.createFixChange(r,i,a))}else if(s.pathname.startsWith("/api/itsm/problems/")&&e.method==="GET"){let i=s.pathname.split("/api/itsm/problems/")[1];this.handleItsmRoute(e,t,(n,r)=>n.getProblem(r,i))}else if(s.pathname.startsWith("/api/itsm/problems/")&&e.method==="PATCH"){let i=s.pathname.split("/api/itsm/problems/")[1];this.handleItsmBodyRoute(e,t,(n,r,a)=>n.updateProblem(r,i,a))}else if(s.pathname==="/api/docs/generate"&&e.method==="POST")this.handleDocsBodyRoute(e,t,(i,n,r)=>i.generate(n,r.type,r));else if(s.pathname==="/api/docs/export"&&e.method==="GET")this.handleDocsRoute(e,t,(i,n)=>i.exportData(n,s.searchParams.get("format")??void 0));else if(s.pathname==="/api/docs/list"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listDocuments(n,r)});else if(s.pathname==="/api/docs/tree"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>i.getDocumentTree(n));else if(s.pathname==="/api/docs/search"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>{let r=s.searchParams.get("q")??"",a=Object.fromEntries(s.searchParams.entries());return delete a.q,i.searchDocuments(n,r,a)});else if(s.pathname==="/api/docs"&&e.method==="POST")this.handleCmdbBodyRoute(e,t,(i,n,r)=>i.saveDocument(n,r));else if(s.pathname.match(/^\/api\/docs\/[^/]+\/versions$/)&&e.method==="GET"){let n=s.pathname.split("/")[3];this.handleCmdbRoute(e,t,async(r,a)=>{let o=await r.getDocument(a,n);return o?r.getDocumentVersions(a,o.linkedEntityType??"",o.linkedEntityId??"",o.docType):{error:"Document not found"}})}else if(s.pathname.startsWith("/api/docs/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.getDocument(r,i))}else if(s.pathname.startsWith("/api/docs/")&&e.method==="PATCH"){let i=s.pathname.split("/").pop();this.handleCmdbBodyRoute(e,t,(n,r,a)=>n.updateDocument(r,i,a))}else if(s.pathname.startsWith("/api/docs/")&&e.method==="DELETE"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.deleteDocument(r,i))}else if(s.pathname==="/api/cmdb/documents"&&e.method==="GET")this.handleCmdbRoute(e,t,(i,n)=>{let r=Object.fromEntries(s.searchParams.entries());return i.listDocuments(n,r)});else if(s.pathname.startsWith("/api/cmdb/documents/")&&e.method==="GET"){let i=s.pathname.split("/").pop();this.handleCmdbRoute(e,t,(n,r)=>n.getDocument(r,i))}else if(s.pathname==="/api/auth/login"&&e.method==="POST")this.handleAuthLogin(e,t);else if(s.pathname==="/api/auth/me"&&e.method==="GET")this.handleAuthMeProtected(e,t).catch(i=>this.safeError(t,i));else if(s.pathname==="/api/oauth/callback"&&e.method==="GET")this.handleOAuthCallback(s,t);else if(s.pathname.startsWith("/api/webhook/")&&e.method==="POST"){let i=s.pathname.slice(13);this.handleWebhook(e,t,i)}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()):s.pathname.startsWith("/files/tts/")&&e.method==="GET"?this.serveTtsFile(s.pathname,t):(t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"})))}async checkAuth(e,t){if(!this.apiToken&&!this.authCb)return!0;let s=e.headers.authorization,i=s?.startsWith("Bearer ")?s.slice(7):null;if(this.apiToken&&i){let n=this.apiToken;if(i.length===n.length&&md.timingSafeEqual(Buffer.from(i),Buffer.from(n)))return!0}return this.authCb&&i&&await this.authCb.getUserByToken(i)?!0:(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Unauthorized"})),!1)}handleAuthLogin(e,t){if(!this.authCb){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Auth not configured"}));return}let s="";e.on("data",i=>{s+=i.toString()}),e.on("end",async()=>{try{let{code:i}=JSON.parse(s);if(!i){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing code"}));return}let n=await this.authCb.loginWithCode(i);n.success?(t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:!0,userId:n.userId,username:n.username,role:n.role,token:n.token}))):(t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:!1,error:n.error??"Invalid code"})))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}))}})}async handleAuthMeProtected(e,t){if(await this.checkAuth(e,t))return this.handleAuthMe(e,t)}async handleMetricsAuth(e,t){if(await this.checkAuth(e,t))return this.handleMetrics(t)}async handleAuthMe(e,t){if(!this.authCb){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Auth not configured"}));return}let s=e.headers.authorization,i=s?.startsWith("Bearer ")?s.slice(7):null;if(!i){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"No token"}));return}let n=await this.authCb.getUserByToken(i);if(!n){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid token"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}async handleDashboard(e,t){if(await 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 i=new URL(e.url??"",`http://${e.headers.host??"localhost"}`).searchParams.get("range")??void 0,r=i&&["today","week","month","year","all"].includes(i)?i:void 0,a=await this.dashboardFn(r?{range:r}:void 0),o=e.headers.authorization,c=o?.startsWith("Bearer ")?o.slice(7):null,l=c&&this.authCb?await this.authCb.getUserByToken(c):null;l&&l.role!=="admin"&&(delete a.userUsage,delete a.userSkillUsage),t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(a))}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 i=xt.resolve(this.webUiPath,"."+s);if(!i.startsWith(xt.resolve(this.webUiPath))){t.writeHead(403),t.end();return}let n=i;if(!Qe.existsSync(n))if(Qe.existsSync(n+".html"))n=n+".html";else if(Qe.existsSync(xt.join(n,"index.html")))n=xt.join(n,"index.html");else{t.writeHead(404,{"Content-Type":"text/html"}),t.end("Not found");return}try{if(Qe.statSync(n).isDirectory()){let u=xt.join(n,"index.html");if(Qe.existsSync(u))n=u;else{t.writeHead(404),t.end();return}}}catch{t.writeHead(404),t.end();return}let r=Qe.statSync(n),a=xt.extname(n).toLowerCase(),o=wR[a]??"application/octet-stream",c=a===".html"?"no-cache":"public, max-age=31536000, immutable";t.writeHead(200,{"Content-Type":o,"Content-Length":r.size,"Cache-Control":c}),Qe.createReadStream(n).pipe(t)}serveTtsFile(e,t){let s={".mp3":"audio/mpeg",".opus":"audio/ogg",".wav":"audio/wav",".flac":"audio/flac",".aac":"audio/aac",".ogg":"audio/ogg"},i=e.slice(11);if(!i||i.includes("/")||i.includes("\\")||i.includes("..")){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid filename"}));return}let n=xt.join(yR.tmpdir(),"alfred-tts"),r=xt.join(n,i);if(!xt.resolve(r).startsWith(xt.resolve(n))){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Forbidden"}));return}try{if(Qe.existsSync(n)){let l=Date.now();for(let u of Qe.readdirSync(n))try{let h=xt.join(n,u),p=Qe.statSync(h);l-p.mtimeMs>300*1e3&&Qe.unlinkSync(h)}catch{}}}catch{}if(!Qe.existsSync(r)){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"File not found"}));return}let a=Qe.statSync(r),o=xt.extname(i).toLowerCase(),c=s[o]??"audio/mpeg";t.writeHead(200,{"Content-Type":c,"Content-Length":a.size,"Cache-Control":"no-cache"}),Qe.createReadStream(r).pipe(t)}async handleKnowledgeGraph(e,t){if(await this.checkAuth(e,t)){if(!this.knowledgeGraphFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Knowledge graph not configured"}));return}try{let i=new URL(e.url,`http://${e.headers.host}`).searchParams.get("userId")??void 0,n=await this.knowledgeGraphFn(i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}catch{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Knowledge graph fetch failed"}))}}}async handleKgDeleteEntity(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphDeleteEntityFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.knowledgeGraphDeleteEntityFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleKgDeleteRelation(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphDeleteRelationFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.knowledgeGraphDeleteRelationFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleKgUpdateEntity(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphUpdateEntityFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r=JSON.parse(n),a=await this.knowledgeGraphUpdateEntityFn(i,r);t.writeHead(a?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:a}))}async handleKgUpdateRelation(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.knowledgeGraphUpdateRelationFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r=JSON.parse(n),a=await this.knowledgeGraphUpdateRelationFn(i,r);t.writeHead(a?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:a}))}async handleMemoriesList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.memoriesListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("type")??void 0,n=await this.memoriesListFn(i?{type:i}:void 0);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({memories:n}))}async handleMemoriesDelete(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.memoriesDeleteFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.memoriesDeleteFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleMemoriesUpdateType(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.memoriesUpdateTypeFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!r.type||typeof r.type!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"type required"}));return}let a=new Set(["correction","preference","fact","entity","general","pattern"]);if(!a.has(r.type)){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`invalid type, allowed: ${[...a].join(", ")}`}));return}let o=await this.memoriesUpdateTypeFn(i,r.type);t.writeHead(o?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:o}))}async handleRunbooksList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("status")??void 0,n=s.searchParams.get("source_type")??void 0,r=await this.runbooksListFn({status:i,sourceType:n});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({runbooks:r}))}async handleRunbooksGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksGetFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.runbooksGetFn(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({runbook:n}))}async handleRunbooksUpdate(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksUpdateFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let a=await this.runbooksUpdateFn(i,r);if(!a){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({runbook:a}))}async handleRunbooksDelete(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.runbooksDeleteFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.runbooksDeleteFn(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleProjectAgentsList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectAgentsListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("phase")??void 0,n=await this.projectAgentsListFn({phase:i});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({sessions:n}))}async handleProjectAgentsGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectAgentsGetFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.projectAgentsGetFn(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({session:n}))}async handleProjectAgentsStop(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectAgentsStopFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=await this.projectAgentsStopFn(n);t.writeHead(r?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:r}))}async handleBackgroundTasksList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.backgroundTasksListFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("status")??void 0,n=await this.backgroundTasksListFn({status:i});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({tasks:n}))}async handleBackgroundTasksGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.backgroundTasksGetFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.backgroundTasksGetFn(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({task:n}))}async handleBackgroundTasksCancel(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.backgroundTasksCancelFn){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=await this.backgroundTasksCancelFn(n);t.writeHead(r?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:r}))}async handleProjectsList(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.searchParams.get("status")??void 0,n=await this.projectsCallbacks.list({status:i});t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({projects:n}))}async handleProjectsGet(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.projectsCallbacks.get(i);if(!n){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}async handleProjectsCreate(e,t){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let s=await this.readBody(e),i;try{i=JSON.parse(s)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!i.name){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"name required"}));return}let n=await this.projectsCallbacks.create(i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({project:n}))}async handleProjectsUpdate(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let a=await this.projectsCallbacks.update(i,r);if(!a){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({project:a}))}async handleProjectsArchive(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.projectsCallbacks.archive(i);t.writeHead(n?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:n}))}async handleProjectsAddOpenItem(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=await this.readBody(e),a;try{a=JSON.parse(r)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!a.title){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"title required"}));return}let o=await this.projectsCallbacks.addOpenItem(n,a);if(!o){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not found"}));return}t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({item:o}))}async handleProjectsUpdateOpenItem(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/").pop(),n=await this.readBody(e),r;try{r=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}if(!r.status){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"status required"}));return}let a=await this.projectsCallbacks.updateOpenItem(i,r.status);t.writeHead(a?200:404,{"Content-Type":"application/json"}),t.end(JSON.stringify({success:a}))}async handleProjectsHealthLog(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.projectsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Not configured"}));return}let i=s.pathname.split("/"),n=i[i.length-2],r=Number(s.searchParams.get("limit")??"100"),a=await this.projectsCallbacks.listHealthLog(n,r);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({entries:a}))}async resolveUserId(e){let t=e.headers.authorization?.startsWith("Bearer ")?e.headers.authorization.slice(7):null;if(this.authCb&&t){let s=await this.authCb.getUserByToken(t);if(s)return s.masterUserId??s.id??""}return""}handleCmdbRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.cmdbCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"CMDB not configured"}));return}let i=await this.resolveUserId(e),n=await s(this.cmdbCallbacks,i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))})().catch(i=>this.safeError(t,i))}handleCmdbBodyRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.cmdbCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"CMDB not configured"}));return}let i=await this.resolveUserId(e),n;try{n=JSON.parse(await this.readBody(e))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let r=await s(this.cmdbCallbacks,i,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))})().catch(i=>this.safeError(t,i))}handleItsmRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.itsmCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"ITSM not configured"}));return}let i=await this.resolveUserId(e),n=await s(this.itsmCallbacks,i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))})().catch(i=>this.safeError(t,i))}handleItsmBodyRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.itsmCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"ITSM not configured"}));return}let i=await this.resolveUserId(e),n;try{n=JSON.parse(await this.readBody(e))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let r=await s(this.itsmCallbacks,i,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))})().catch(i=>this.safeError(t,i))}handleDocsRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.docsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Docs not configured"}));return}let i=await this.resolveUserId(e),n=await s(this.docsCallbacks,i);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))})().catch(i=>this.safeError(t,i))}handleDocsBodyRoute(e,t,s){(async()=>{if(!await this.checkAuth(e,t))return;if(!this.docsCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Docs not configured"}));return}let i=await this.resolveUserId(e),n;try{n=JSON.parse(await this.readBody(e))}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}let r=await s(this.docsCallbacks,i,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))})().catch(i=>this.safeError(t,i))}readBody(e){return new Promise((t,s)=>{let i="";e.on("data",n=>i+=n),e.on("end",()=>t(i)),e.on("error",s)})}safeError(e,t){try{e.headersSent||e.writeHead(500,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"Internal server error"}))}catch{}}async handleHealth(e){let t=await this.healthCheckFn?.()??{},s=t.db!==!1?"ok":"degraded",i=s==="ok"?200:503;e.writeHead(i,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:s,...t,timestamp:new Date().toISOString()}))}async handleMetrics(e){this.metricsFn?(e.writeHead(200,{"Content-Type":"text/plain; version=0.0.4; charset=utf-8"}),e.end(await this.metricsFn())):await this.handleHealth(e)}async handleMessage(e,t){if(!await this.checkAuth(e,t))return;let s="",i=0,n=!1;e.on("data",r=>{if(!n){if(i+=r.length,i>sE){n=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}s+=r.toString()}}),e.on("end",()=>{if(!n)try{let r=JSON.parse(s),a=r.text;if(!a||typeof a!="string"){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:'Missing or invalid "text" field'}));return}let o=r.chatId??`api-chat-${md.randomUUID()}`,c=r.userId??"api-user",l=this.streams.get(o);l&&(this.writeSseEvent(l,"done",{type:"done"}),l.end()),t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":this.corsOrigin,"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","X-Content-Type-Options":"nosniff"}),t.flushHeaders(),this.streams.set(o,t),t.on("close",()=>{this.streams.delete(o)}),this.messageCounter++;let u={id:`api-${this.messageCounter}`,platform:"api",chatId:o,chatType:"dm",userId:c,userName:c,displayName:"API User",text:a,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 i=this.webhooks.get(s);if(!i){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:`Webhook "${s}" not found`}));return}let n="",r=0,a=!1;e.on("data",o=>{if(!a){if(r+=o.length,r>sE){a=!0,t.writeHead(413,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Payload too large"})),e.destroy();return}n+=o.toString()}}),e.on("end",async()=>{if(a)return;let o=e.headers["x-webhook-signature"];if(!o){t.writeHead(401,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Missing X-Webhook-Signature header"}));return}let c=md.createHmac("sha256",i.secret).update(n).digest(),l=Buffer.from(o,"hex");if(l.length!==c.length||!md.timingSafeEqual(l,c)){t.writeHead(403,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid signature"}));return}try{let u=JSON.parse(n);await i.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"}))}})}async handleOAuthCallback(e,t){let s=e.searchParams.get("code"),i=e.searchParams.get("state"),n=e.searchParams.get("error");if(n){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Autorisierung abgelehnt</h2><p>${n}</p><p>Du kannst dieses Fenster schlie\xDFen.</p></body></html>`);return}if(!s||!i){t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end("<html><body><h2>Fehler</h2><p>Code oder State fehlt.</p></body></html>");return}let r;try{r=JSON.parse(Buffer.from(i,"base64url").toString())}catch{t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end("<html><body><h2>Fehler</h2><p>Ung\xFCltiger State-Parameter.</p></body></html>");return}let a=r.service,o=this.oauthCallbacks.get(a);if(!o){t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Fehler</h2><p>Kein OAuth-Handler f\xFCr "${a}" registriert.</p></body></html>`);return}try{let c=await o(s,r);c.success?(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end("<html><body><h2>Erfolgreich verbunden!</h2><p>Du kannst dieses Fenster schlie\xDFen und zu Alfred zur\xFCckkehren.</p></body></html>")):(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Fehler</h2><p>${c.error??"Unbekannter Fehler"}</p></body></html>`))}catch(c){t.writeHead(500,{"Content-Type":"text/html; charset=utf-8"}),t.end(`<html><body><h2>Fehler</h2><p>${c instanceof Error?c.message:"Interner Fehler"}</p></body></html>`)}}writeSseEvent(e,t,s){e.writableEnded||e.write(`event: ${t}
5226
5237
  data: ${JSON.stringify(s)}
5227
5238
 
5228
5239
  `)}async handleLogApp(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.logCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Log viewer not configured"}));return}let i=Math.min(parseInt(s.searchParams.get("lines")??"200",10)||200,5e3),n=s.searchParams.get("level")??void 0,r=s.searchParams.get("filter")??void 0,a=s.searchParams.has("file")?parseInt(s.searchParams.get("file"),10)||0:void 0,o=await this.logCallbacks.readAppLog(i,n,r,a);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(o))}async handleLogStream(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.logCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Log streaming not configured"}));return}let i=s.searchParams.get("level")??void 0,n=s.searchParams.get("filter")??void 0;t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":this.corsOrigin,"X-Content-Type-Options":"nosniff"}),t.flushHeaders();let r=this.logCallbacks.streamAppLog(t,i,n);t.on("close",r)}async handleLogAudit(e,t,s){if(!await this.checkAuth(e,t))return;if(!this.logCallbacks){t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Log viewer not configured"}));return}let i=Math.min(parseInt(s.searchParams.get("lines")??"100",10)||100,2e3),n=s.searchParams.has("file")?parseInt(s.searchParams.get("file"),10)||0:void 0,r=await this.logCallbacks.readAuditLog(i,void 0,void 0,n);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))}async handleClusterHealth(e,t){if(!await this.checkAuth(e,t))return;if(!this.clusterCallbacks){t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({clusterEnabled:!1,thisNodeId:"single",nodes:[],claims:[],recentReasoningSlots:[],operations:{}}));return}let s=await this.clusterCallbacks.getHealth();t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}}});var Os={};Ne(Os,{CLIAdapter:()=>pd,DiscordAdapter:()=>cd,HttpAdapter:()=>fd,MSTeamsAdapter:()=>hd,MatrixAdapter:()=>ld,MessagingAdapter:()=>lt,SignalAdapter:()=>ud,TelegramAdapter:()=>ad,WhatsAppAdapter:()=>dd});var xs=S(()=>{"use strict";ks();qT();GT();VT();YT();JT();QT();eE();iE()});var nE={};Ne(nE,{AdapterClaimManager:()=>Zp});var Zp,rE=S(()=>{"use strict";Zp=class{static{f(this,"AdapterClaimManager")}adapter;nodeId;logger;renewTimer;checkTimer;claimedPlatforms=new Set;claimTtlMs;onClaimAcquired;constructor(e,t,s,i=6e4){this.adapter=e,this.nodeId=t,this.logger=s,this.claimTtlMs=i}onAcquired(e){this.onClaimAcquired=e}async tryClaim(e){if(this.adapter.type==="sqlite")return this.claimedPlatforms.add(e),!0;let t=new Date().toISOString(),s=new Date(Date.now()+this.claimTtlMs).toISOString();return(await this.adapter.execute(`INSERT INTO adapter_claims (platform, node_id, claimed_at, expires_at)
@@ -5281,7 +5292,7 @@ Confidence-Skala:
5281
5292
  - 0.5-0.7: m\xF6glicherweise hilfreich, aber L\xF6sung nicht eindeutig
5282
5293
  - < 0.5: keine konkrete Erkenntnis/L\xF6sung erkennbar \u2192 is_runbook_candidate: false
5283
5294
 
5284
- Wenn is_runbook_candidate false ist, alle anderen Felder d\xFCrfen leer sein.`,c={};try{let g=(await this.llm.complete({messages:[{role:"user",content:o}],maxTokens:1500,temperature:.2,tier:"default"})).content.trim().match(/\{[\s\S]*\}/);g&&(c=JSON.parse(g[0]))}catch(m){this.logger.debug({err:m,conversationId:e},"Runbook-reflector LLM call failed"),await this.markProcessed(t,i);return}let l=typeof c.confidence=="number"?c.confidence:0,u=c.is_runbook_candidate===!0,h=!!c.title&&Array.isArray(c.steps)&&c.steps.length>=2;if(!u||!h||l<d.DRAFT_THRESHOLD){await this.markProcessed(t,i);return}if(await this.runbookRepo.findBySource(t,"chat_session",e)){await this.markProcessed(t,i);return}try{let m=new Set((c.tags??[]).map(g=>g.toLowerCase())),y=aE(c.title??"");if(y.size>=2||m.size>=2){let w=(await this.runbookRepo.list(t,{limit:200})).find(T=>{if([...m].filter($=>T.tags.map(C=>C.toLowerCase()).includes($)).length>=3)return!0;let k=aE(T.title);if(y.size===0||k.size===0)return!1;let b=[...y].filter($=>k.has($)).length,v=Math.min(y.size,k.size);return v>0&&b/v>=.6});if(w){this.logger.info({conversationId:e,newTitle:c.title?.slice(0,60),existingId:w.id.slice(0,8),existingTitle:w.title.slice(0,60)},"Runbook-reflector R2: similar runbook already exists \u2014 skipping"),await this.markProcessed(t,i);return}}}catch(m){this.logger.debug({err:m},"Runbook-reflector R2: similarity-dedup failed (non-critical, falling through)")}if(l>=d.CONFIRM_THRESHOLD)await this.confirmationQueue.enqueue({chatId:this.ownerChatId,platform:this.ownerPlatform,source:"reasoning",sourceId:`runbook-from-chat-${e.slice(0,8)}`,description:`Runbook aus Chat-Session erstellen (Confidence ${(l*100).toFixed(0)}%): "${c.title?.slice(0,80)}"?`,skillName:"runbook",skillParams:{action:"create",title:c.title,symptom:c.symptom??"",cause:c.cause??"",steps:c.steps,verification:c.verification??"",rollback:c.rollback??"",source_type:"chat_session",source_id:e,status:"draft",tags:[...c.tags??[],"auto-extracted","high-confidence"]},timeoutMinutes:1440}),this.logger.info({conversationId:e,title:c.title,confidence:l},"Chat-session runbook enqueued for confirmation");else try{await this.runbookRepo.create(t,{title:c.title,symptom:c.symptom,cause:c.cause,steps:c.steps,verification:c.verification,rollback:c.rollback,sourceType:"chat_session",sourceId:e,confidence:l,status:"draft",tags:[...c.tags??[],"auto-extracted","low-confidence"]}),this.logger.info({conversationId:e,title:c.title,confidence:l},"Chat-session runbook auto-saved as draft")}catch(m){this.logger.debug({err:m},"Auto-draft runbook creation failed")}await this.markProcessed(t,i)}async markProcessed(e,t){try{await this.memoryRepo.saveWithMetadata(e,t,new Date().toISOString(),"system","general",1,"auto");let s=new Date(Date.now()+d.MARKER_TTL_MS).toISOString();await this.memoryRepo.setExpiry(e,t,s)}catch{}}}});var lE={};Ne(lE,{SkillFailureReflector:()=>em});var em,dE=S(()=>{"use strict";em=class{static{f(this,"SkillFailureReflector")}activityRepo;logger;windowMinutes;minConsecutiveFails;maxWorkaroundSteps;constructor(e,t,s){this.activityRepo=e,this.logger=t,this.windowMinutes=s?.windowMinutes??30,this.minConsecutiveFails=s?.minConsecutiveFails??2,this.maxWorkaroundSteps=s?.maxWorkaroundSteps??10}async detect(e){let t=this.windowMinutes*60*1e3,s=new Date(Date.now()-t).toISOString(),i;try{i=(await this.activityRepo.query({eventType:"skill_exec",userId:e,since:s,limit:200})).map(o=>({id:o.id,skillName:o.action??"",success:o.outcome==="success",error:o.errorMessage,input:o.details,createdAt:o.timestamp}))}catch{return[]}if(i.length===0)return[];i.sort((a,o)=>a.createdAt.localeCompare(o.createdAt));let n=[],r=0;for(;r<i.length;){let a=i[r];if(a.success){r++;continue}let o=this.classifyError(a.error??""),c=1,l=r+1;for(;l<i.length&&!i[l].success&&i[l].skillName===a.skillName&&this.classifyError(i[l].error??"")===o;)c++,l++;if(c<this.minConsecutiveFails){r=l;continue}let u=Math.min(i.length,l+8),h=[],p=i.slice(r,l).map(y=>y.id),m=!1;for(let y=l;y<u;y++){let g=i[y];if(g.skillName==="shell"||g.skillName==="code_agent"||g.skillName==="deploy"){let w=typeof g.input?.command=="string"?g.input.command:JSON.stringify(g.input).slice(0,200);if(h.push(w),p.push(g.id),g.success&&(m=!0),h.length>=this.maxWorkaroundSteps)break}}if(h.length>0&&m){let y=this.extractScope(a.input);n.push({failedSkill:a.skillName,errorClass:o,scope:y,workaroundSteps:h,finalSuccess:m,detectedAt:new Date().toISOString(),participatingActivityIds:p}),this.logger.info({failedSkill:a.skillName,errorClass:o,scope:y,workaroundSteps:h.length},"SkillFailureReflector: workaround pattern detected")}r=u>l?u:l}return n}classifyError(e){let t=e.toLowerCase();return/command not found/.test(t)?"COMMAND_NOT_FOUND":/eacces|permission denied/.test(t)?"EACCES":/enoent|no such file/.test(t)?"ENOENT":/etimedout|timeout/.test(t)?"TIMEOUT":/ehostunreach|enetunreach|econnrefused/.test(t)?"NETWORK":/auth|unauthorized|forbidden/.test(t)?"AUTH_FAIL":/not found|404/.test(t)?"NOT_FOUND":"OTHER"}extractScope(e){if(e){if(typeof e.host=="string")return`host=${e.host}`;if(typeof e.target_host=="string")return`host=${e.target_host}`;if(typeof e.cwd=="string")return`cwd=${e.cwd}`}}}});import hr from"node:fs";import TR from"node:os";import Lt from"node:path";import ER from"js-yaml";function kR(d){let e=new Date(Date.UTC(d.getFullYear(),d.getMonth(),d.getDate()));e.setUTCDate(e.getUTCDate()+4-(e.getUTCDay()||7));let t=new Date(Date.UTC(e.getUTCFullYear(),0,1));return Math.ceil(((e.getTime()-t.getTime())/864e5+1)/7)}var Ii,uE=S(()=>{"use strict";jo();Je();ws();Eu();zr();fe();Uh();Bh();Hh();Xh();zh();Wh();Kh();qh();Gh();Vh();Yh();Jh();Zh();H_();ep();rp();ap();op();lp();W_();dp();Gl();Vl();pp();mp();fp();gp();yp();Tp();Ep();kp();bp();Sp();vp();Ip();La();xp();Mp();f(kR,"getISOWeek");Ii=class{static{f(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;triggerManager;confirmationQueue;adapters=new Map;formatter=new Pa;userRepo;skillRegistry;skillSandbox;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;reflectionEngine;chatSessionRunbookReflector;usageRepo;serviceUsageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;runbookRepo;projectRepo;projectManager;projectHealthMonitor;projectSkillRef;projectAgentRunnerRef;delegateSkillRef;codeAgentSkillRef;watchRepo;scheduledActionRepo;skillHealthRepo;clusterManager;adapterClaimManager;webAuthCallback;reminderRepo;spotifySkill;bmwSkill;bmwTelematicRepo;memorySkillRef;kgServiceRef;sonosSkill;skillHealthTracker;healthCheckTimer;memoryConsolidatorTimer;patternAnalyzerTimer;temporalAnalyzerTimer;insightExpiryTimer;clusterMonitorTimer;cmdbDiscoveryTimer;cmdbHealthCheckTimer;insightTracker;ownerMasterUserId;userServiceResolverRef;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=xi("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=await _s.create({backend:this.config.storage.backend??"sqlite",path:this.config.storage.path,connectionString:this.config.storage.connectionString});let e=this.database.getAdapter(),t=new Mi(e),s=new Ui(e);this.userRepo=s;let i=new Fs(e);this.auditRepo=i;let n=new Pi(e);this.memoryRepo=n;let r=new tn(e),a=new Fi(e);this.reminderRepo=a;let o=new ji(e),c=new Bi(e),l=new Hi(e),u=new Xi(e),h=new Wi(e);this.scheduledActionRepo=h;let p=new Bs(e);this.activityRepo=p;let m=new io(p,this.logger.child({component:"activity"})),y=new Zi(e);this.skillHealthRepo=y;let g=new no(y,this.logger.child({component:"skill-health"}),m);this.skillHealthTracker=g,this.logger.info("Storage initialized");let w=new dn,T=this.loadSecurityRules();w.loadRules(T);let _;try{let{AuditLogger:N}=await Promise.resolve().then(()=>(jo(),Gm)),M=this.config.logger.auditLogPath??"./data/logs/audit.log";_=new N(M),this.logger.info({path:M},"File-based audit logger initialized")}catch(N){this.logger.warn({err:N},"File-based audit logger init failed \u2014 DB-audit still active")}let k=new un(w,i,this.logger.child({component:"security"}),_);this.logger.info({ruleCount:T.length},"Security engine initialized");let b=_u(this.config.llm,this.logger.child({component:"llm"}));await b.initialize(),this.llmProvider=b;let v=new Ji(e);this.usageRepo=v,b.setPersist((N,M,X,q,J,le)=>{v.record(N,M,X,q,J,le).catch(()=>{})});let $=new nn(e);this.serviceUsageRepo=$;let C=new Fa(b,c,this.logger.child({component:"embeddings"})),L=this.config.llm.embeddings?.model??this.config.llm.default?.model??"unknown";if(b.supportsEmbeddings())try{await C.validateModelConsistency(L)>0&&setTimeout(async()=>{try{let M=await s.listAll(),X=0;for(let q of M){let J=await n.listAll(q.id);for(let le of J)await C.embedAndStore(q.id,`${le.key}: ${le.value}`,"memory",le.id),X++}this.logger.info({count:X,model:L},"Re-embedded all memories with new model")}catch(M){this.logger.error({err:M},"Background re-embedding failed")}},5e3)}catch(N){this.logger.error({err:N},"Embedding model consistency check failed")}let x=this.config.activeLearning?.enabled!==!1,O,P;x&&(O=new Va({llm:b,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:C,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),P=new Ya(n,this.logger.child({component:"memory-retriever"}),C),this.logger.info("Active learning & memory retriever initialized"));let Z=new Yi(e);this.summaryRepo=Z;let oe=new eo(b,Z,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let H=this.skillSandbox=new gn(this.logger.child({component:"sandbox"})),A=this.skillRegistry=new fn;A.register(new yn),A.register(new wn),A.register(new _n(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),A.register(new Tn(a));let Se=new En(o);A.register(Se);let we=new qi(e),Pe=new Bn(we);A.register(Pe),A.register(new kn),A.register(new bn);let yt=new Sn(n,C);A.register(yt),this.memorySkillRef=yt;let Rt=new vn(b,A,H,k);A.register(Rt),this.delegateSkillRef=Rt;{let{ChatHistorySkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(t))}{let{BrainstormingSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{BrainstormingRepository:M}=await Promise.resolve().then(()=>(Je(),tt)),X=new M(e),q=new N(X);q.setKgContextFn(async(J,le)=>{if(!this.kgServiceRef)return"";let Ee=this.ownerMasterUserId??J,Me=await new rs(e).getFullGraph(Ee),Le=le.toLowerCase(),Ge=Me.entities.filter(_e=>_e.name.toLowerCase().includes(Le)||_e.normalizedName.includes(Le)||_e.attributes?.value&&String(_e.attributes.value).toLowerCase().includes(Le)),Ue=new Set(Ge.map(_e=>_e.id)),Fe=Me.relations.filter(_e=>Ue.has(_e.sourceEntityId)||Ue.has(_e.targetEntityId)),me=new Set;for(let _e of Fe)me.add(_e.sourceEntityId),me.add(_e.targetEntityId);let Y=Me.entities.filter(_e=>Ue.has(_e.id)||me.has(_e.id)),Te=Y.slice(0,20).map(_e=>{let pt=Object.entries(_e.attributes??{}).filter(([St])=>!["skillName","type","memoryKey","memoryConfidence"].includes(St)).map(([St,G])=>`${St}=${String(G).slice(0,60)}`).join(", ");return`- [${_e.entityType}] ${_e.name}${pt?` (${pt})`:""}`}),se=Fe.slice(0,15).map(_e=>{let pt=Y.find(G=>G.id===_e.sourceEntityId)?.name??"?",St=Y.find(G=>G.id===_e.targetEntityId)?.name??"?";return`- ${pt} \u2192 ${_e.relationType} \u2192 ${St}`}),Be="";try{Be=(await n.search(Ee,le)).slice(0,5).map(pt=>`- [memory] ${pt.key}: ${pt.value.slice(0,100)}`).join(`
5295
+ Wenn is_runbook_candidate false ist, alle anderen Felder d\xFCrfen leer sein.`,c={};try{let g=(await this.llm.complete({messages:[{role:"user",content:o}],maxTokens:1500,temperature:.2,tier:"default"})).content.trim().match(/\{[\s\S]*\}/);g&&(c=JSON.parse(g[0]))}catch(m){this.logger.debug({err:m,conversationId:e},"Runbook-reflector LLM call failed"),await this.markProcessed(t,i);return}let l=typeof c.confidence=="number"?c.confidence:0,u=c.is_runbook_candidate===!0,h=!!c.title&&Array.isArray(c.steps)&&c.steps.length>=2;if(!u||!h||l<d.DRAFT_THRESHOLD){await this.markProcessed(t,i);return}if(await this.runbookRepo.findBySource(t,"chat_session",e)){await this.markProcessed(t,i);return}try{let m=new Set((c.tags??[]).map(g=>g.toLowerCase())),y=aE(c.title??"");if(y.size>=2||m.size>=2){let w=(await this.runbookRepo.list(t,{limit:200})).find(T=>{if([...m].filter($=>T.tags.map(C=>C.toLowerCase()).includes($)).length>=3)return!0;let k=aE(T.title);if(y.size===0||k.size===0)return!1;let b=[...y].filter($=>k.has($)).length,v=Math.min(y.size,k.size);return v>0&&b/v>=.6});if(w){this.logger.info({conversationId:e,newTitle:c.title?.slice(0,60),existingId:w.id.slice(0,8),existingTitle:w.title.slice(0,60)},"Runbook-reflector R2: similar runbook already exists \u2014 skipping"),await this.markProcessed(t,i);return}}}catch(m){this.logger.debug({err:m},"Runbook-reflector R2: similarity-dedup failed (non-critical, falling through)")}if(l>=d.CONFIRM_THRESHOLD)await this.confirmationQueue.enqueue({chatId:this.ownerChatId,platform:this.ownerPlatform,source:"reasoning",sourceId:`runbook-from-chat-${e.slice(0,8)}`,description:`Runbook aus Chat-Session erstellen (Confidence ${(l*100).toFixed(0)}%): "${c.title?.slice(0,80)}"?`,skillName:"runbook",skillParams:{action:"create",title:c.title,symptom:c.symptom??"",cause:c.cause??"",steps:c.steps,verification:c.verification??"",rollback:c.rollback??"",source_type:"chat_session",source_id:e,status:"draft",tags:[...c.tags??[],"auto-extracted","high-confidence"]},timeoutMinutes:1440}),this.logger.info({conversationId:e,title:c.title,confidence:l},"Chat-session runbook enqueued for confirmation");else try{await this.runbookRepo.create(t,{title:c.title,symptom:c.symptom,cause:c.cause,steps:c.steps,verification:c.verification,rollback:c.rollback,sourceType:"chat_session",sourceId:e,confidence:l,status:"draft",tags:[...c.tags??[],"auto-extracted","low-confidence"]}),this.logger.info({conversationId:e,title:c.title,confidence:l},"Chat-session runbook auto-saved as draft")}catch(m){this.logger.debug({err:m},"Auto-draft runbook creation failed")}await this.markProcessed(t,i)}async markProcessed(e,t){try{await this.memoryRepo.saveWithMetadata(e,t,new Date().toISOString(),"system","general",1,"auto");let s=new Date(Date.now()+d.MARKER_TTL_MS).toISOString();await this.memoryRepo.setExpiry(e,t,s)}catch{}}}});var lE={};Ne(lE,{SkillFailureReflector:()=>em});var em,dE=S(()=>{"use strict";em=class{static{f(this,"SkillFailureReflector")}activityRepo;logger;windowMinutes;minConsecutiveFails;maxWorkaroundSteps;constructor(e,t,s){this.activityRepo=e,this.logger=t,this.windowMinutes=s?.windowMinutes??30,this.minConsecutiveFails=s?.minConsecutiveFails??2,this.maxWorkaroundSteps=s?.maxWorkaroundSteps??10}async detect(e){let t=this.windowMinutes*60*1e3,s=new Date(Date.now()-t).toISOString(),i;try{i=(await this.activityRepo.query({eventType:"skill_exec",userId:e,since:s,limit:200})).map(o=>({id:o.id,skillName:o.action??"",success:o.outcome==="success",error:o.errorMessage,input:o.details,createdAt:o.timestamp}))}catch{return[]}if(i.length===0)return[];i.sort((a,o)=>a.createdAt.localeCompare(o.createdAt));let n=[],r=0;for(;r<i.length;){let a=i[r];if(a.success){r++;continue}let o=this.classifyError(a.error??""),c=1,l=r+1;for(;l<i.length&&!i[l].success&&i[l].skillName===a.skillName&&this.classifyError(i[l].error??"")===o;)c++,l++;if(c<this.minConsecutiveFails){r=l;continue}let u=Math.min(i.length,l+8),h=[],p=i.slice(r,l).map(y=>y.id),m=!1;for(let y=l;y<u;y++){let g=i[y];if(g.skillName==="shell"||g.skillName==="code_agent"||g.skillName==="deploy"){let w=typeof g.input?.command=="string"?g.input.command:JSON.stringify(g.input).slice(0,200);if(h.push(w),p.push(g.id),g.success&&(m=!0),h.length>=this.maxWorkaroundSteps)break}}if(h.length>0&&m){let y=this.extractScope(a.input);n.push({failedSkill:a.skillName,errorClass:o,scope:y,workaroundSteps:h,finalSuccess:m,detectedAt:new Date().toISOString(),participatingActivityIds:p}),this.logger.info({failedSkill:a.skillName,errorClass:o,scope:y,workaroundSteps:h.length},"SkillFailureReflector: workaround pattern detected")}r=u>l?u:l}return n}classifyError(e){let t=e.toLowerCase();return/command not found/.test(t)?"COMMAND_NOT_FOUND":/eacces|permission denied/.test(t)?"EACCES":/enoent|no such file/.test(t)?"ENOENT":/etimedout|timeout/.test(t)?"TIMEOUT":/ehostunreach|enetunreach|econnrefused/.test(t)?"NETWORK":/auth|unauthorized|forbidden/.test(t)?"AUTH_FAIL":/not found|404/.test(t)?"NOT_FOUND":"OTHER"}extractScope(e){if(e){if(typeof e.host=="string")return`host=${e.host}`;if(typeof e.target_host=="string")return`host=${e.target_host}`;if(typeof e.cwd=="string")return`cwd=${e.cwd}`}}}});import hr from"node:fs";import TR from"node:os";import Lt from"node:path";import ER from"js-yaml";function kR(d){let e=new Date(Date.UTC(d.getFullYear(),d.getMonth(),d.getDate()));e.setUTCDate(e.getUTCDate()+4-(e.getUTCDay()||7));let t=new Date(Date.UTC(e.getUTCFullYear(),0,1));return Math.ceil(((e.getTime()-t.getTime())/864e5+1)/7)}var Ii,uE=S(()=>{"use strict";jo();Je();ws();Eu();zr();fe();Uh();Bh();Hh();Xh();zh();Wh();Kh();qh();Gh();Vh();Yh();Jh();Zh();H_();ep();rp();ap();op();lp();W_();dp();Gl();Vl();pp();mp();fp();gp();yp();Tp();Ep();kp();bp();Sp();vp();Ip();La();xp();Mp();f(kR,"getISOWeek");Ii=class{static{f(this,"Alfred")}config;logger;database;pipeline;llmProvider;reminderScheduler;backgroundTaskRunner;proactiveScheduler;watchEngine;triggerManager;confirmationQueue;adapters=new Map;formatter=new Pa;userRepo;skillRegistry;skillSandbox;mcpManager;calendarSkill;calendarWatcher;todoWatcher;reasoningEngine;reflectionEngine;chatSessionRunbookReflector;usageRepo;serviceUsageRepo;auditRepo;summaryRepo;activityRepo;memoryRepo;runbookRepo;projectRepo;projectManager;projectHealthMonitor;projectSkillRef;projectAgentRunnerRef;delegateSkillRef;codeAgentSkillRef;watchRepo;scheduledActionRepo;skillHealthRepo;clusterManager;adapterClaimManager;webAuthCallback;reminderRepo;spotifySkill;bmwSkill;bmwTelematicRepo;memorySkillRef;kgServiceRef;sonosSkill;skillHealthTracker;healthCheckTimer;memoryConsolidatorTimer;patternAnalyzerTimer;temporalAnalyzerTimer;insightExpiryTimer;clusterMonitorTimer;cmdbDiscoveryTimer;cmdbHealthCheckTimer;insightTracker;ownerMasterUserId;userServiceResolverRef;startedAt=new Date().toISOString();constructor(e){this.config=e,this.logger=xi("alfred",e.logger.level)}async initialize(){this.logger.info("Initializing Alfred..."),this.database=await _s.create({backend:this.config.storage.backend??"sqlite",path:this.config.storage.path,connectionString:this.config.storage.connectionString});let e=this.database.getAdapter(),t=new Mi(e),s=new Ui(e);this.userRepo=s;let i=new Fs(e);this.auditRepo=i;let n=new Pi(e);this.memoryRepo=n;let r=new tn(e),a=new Fi(e);this.reminderRepo=a;let o=new ji(e),c=new Bi(e),l=new Hi(e),u=new Xi(e),h=new Wi(e);this.scheduledActionRepo=h;let p=new Bs(e);this.activityRepo=p;let m=new io(p,this.logger.child({component:"activity"})),y=new Zi(e);this.skillHealthRepo=y;let g=new no(y,this.logger.child({component:"skill-health"}),m);this.skillHealthTracker=g,this.logger.info("Storage initialized");let w=new dn,T=this.loadSecurityRules();w.loadRules(T);let _;try{let{AuditLogger:N}=await Promise.resolve().then(()=>(jo(),Gm)),M=this.config.logger.auditLogPath??"./data/logs/audit.log";_=new N(M),this.logger.info({path:M},"File-based audit logger initialized")}catch(N){this.logger.warn({err:N},"File-based audit logger init failed \u2014 DB-audit still active")}let k=new un(w,i,this.logger.child({component:"security"}),_);this.logger.info({ruleCount:T.length},"Security engine initialized");let b=_u(this.config.llm,this.logger.child({component:"llm"}));await b.initialize(),this.llmProvider=b;let v=new Ji(e);this.usageRepo=v,b.setPersist((N,M,X,q,J,le)=>{v.record(N,M,X,q,J,le).catch(()=>{})});let $=new nn(e);this.serviceUsageRepo=$;let C=new Fa(b,c,this.logger.child({component:"embeddings"})),L=this.config.llm.embeddings?.model??this.config.llm.default?.model??"unknown";if(b.supportsEmbeddings())try{await C.validateModelConsistency(L)>0&&setTimeout(async()=>{try{let M=await s.listAll(),X=0;for(let q of M){let J=await n.listAll(q.id);for(let le of J)await C.embedAndStore(q.id,`${le.key}: ${le.value}`,"memory",le.id),X++}this.logger.info({count:X,model:L},"Re-embedded all memories with new model")}catch(M){this.logger.error({err:M},"Background re-embedding failed")}},5e3)}catch(N){this.logger.error({err:N},"Embedding model consistency check failed")}let x=this.config.activeLearning?.enabled!==!1,O,P;x&&(O=new Va({llm:b,memoryRepo:n,logger:this.logger.child({component:"active-learning"}),embeddingService:C,minMessageLength:this.config.activeLearning?.minMessageLength,minConfidence:this.config.activeLearning?.minConfidence,maxExtractionsPerMinute:this.config.activeLearning?.maxExtractionsPerMinute}),P=new Ya(n,this.logger.child({component:"memory-retriever"}),C),this.logger.info("Active learning & memory retriever initialized"));let Z=new Yi(e);this.summaryRepo=Z;let oe=new eo(b,Z,this.logger.child({component:"summarizer"}));this.logger.info("Conversation summarizer initialized");let H=this.skillSandbox=new gn(this.logger.child({component:"sandbox"})),A=this.skillRegistry=new fn;A.register(new yn),A.register(new wn),A.register(new _n(this.config.search?{provider:this.config.search.provider,apiKey:this.config.search.apiKey,baseUrl:this.config.search.baseUrl}:void 0)),A.register(new Tn(a));let Se=new En(o);A.register(Se);let we=new qi(e),Pe=new Bn(we);A.register(Pe),A.register(new kn),A.register(new bn);let yt=new Sn(n,C);A.register(yt),this.memorySkillRef=yt;let Rt=new vn(b,A,H,k);A.register(Rt),this.delegateSkillRef=Rt;{let{ChatHistorySkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(t))}{let{BrainstormingSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{BrainstormingRepository:M}=await Promise.resolve().then(()=>(Je(),Ze)),X=new M(e),q=new N(X);q.setKgContextFn(async(J,le)=>{if(!this.kgServiceRef)return"";let Ee=this.ownerMasterUserId??J,Me=await new rs(e).getFullGraph(Ee),Le=le.toLowerCase(),Ge=Me.entities.filter(_e=>_e.name.toLowerCase().includes(Le)||_e.normalizedName.includes(Le)||_e.attributes?.value&&String(_e.attributes.value).toLowerCase().includes(Le)),Ue=new Set(Ge.map(_e=>_e.id)),Fe=Me.relations.filter(_e=>Ue.has(_e.sourceEntityId)||Ue.has(_e.targetEntityId)),me=new Set;for(let _e of Fe)me.add(_e.sourceEntityId),me.add(_e.targetEntityId);let Y=Me.entities.filter(_e=>Ue.has(_e.id)||me.has(_e.id)),Te=Y.slice(0,20).map(_e=>{let pt=Object.entries(_e.attributes??{}).filter(([St])=>!["skillName","type","memoryKey","memoryConfidence"].includes(St)).map(([St,G])=>`${St}=${String(G).slice(0,60)}`).join(", ");return`- [${_e.entityType}] ${_e.name}${pt?` (${pt})`:""}`}),se=Fe.slice(0,15).map(_e=>{let pt=Y.find(G=>G.id===_e.sourceEntityId)?.name??"?",St=Y.find(G=>G.id===_e.targetEntityId)?.name??"?";return`- ${pt} \u2192 ${_e.relationType} \u2192 ${St}`}),Be="";try{Be=(await n.search(Ee,le)).slice(0,5).map(pt=>`- [memory] ${pt.key}: ${pt.value.slice(0,100)}`).join(`
5285
5296
  `)}catch{}return`Entities:
5286
5297
  ${Te.join(`
5287
5298
  `)}
@@ -5291,26 +5302,26 @@ ${se.join(`
5291
5302
  `)}${Be?`
5292
5303
 
5293
5304
  Memories:
5294
- ${Be}`:""}`}),q.setLlmCallFn(async(J,le)=>(await b.complete({messages:[{role:"user",content:J}],tier:le,maxTokens:2e3})).content),A.register(q),this.logger.info("Brainstorming skill registered")}if(this.config.email?.accounts?.length){let N=new Map;for(let X of this.config.email.accounts)try{X.provider==="microsoft"&&!X.microsoft?.clientId&&this.config.calendar?.microsoft&&(X.microsoft={...this.config.calendar.microsoft});let q=await An(X);N.set(X.name,q),this.logger.info({account:X.name,provider:X.provider??"imap-smtp"},"Email account initialized")}catch(q){this.logger.warn({err:q,account:X.name},"Email account initialization failed, skipping")}let M=N.size>0?new Ws(N):new Ws;M.setLLM(b),A.register(M)}else{let N=new Ws;N.setLLM(b),A.register(N)}A.register(new Rn),A.register(new In);let Us=new qn;Us.setReloadCallback(N=>this.reloadService(N)),Us.setHealthAdapter(g),A.register(Us),A.register(new Nn),A.register(new Ln),A.register(new Cn),A.register(new Dn(s));let ms=new xn(s,l,this.adapters,(N,M)=>t.findByPlatformAndUser(N,M));A.register(ms);let Kt=new Mn(u,A);A.register(Kt),A.register(new Un(h,A));let nt=new Ki(e),Ie=new ja(nt,C,this.logger.child({component:"documents"})),dt=this.detectMistralApiKey();if(dt){let{OcrService:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(dt);M.setUsageCallback((X,q)=>{$.record("ocr",X,q).catch(()=>{})}),Ie.setOcrService(M),this.logger.info("Mistral OCR enabled for document processing")}let Ni=new Pn(nt,Ie,C);A.register(Ni);let qt,kt;if(this.config.calendar)try{kt=await On(this.config.calendar),qt=new ui(kt),A.register(qt),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(N){this.logger.warn({err:N},"Calendar initialization failed, continuing without calendar")}this.calendarSkill=qt;let st=[...this.adapters.keys()][0]??"telegram";if(kt&&this.config.calendar?.vorlauf?.enabled){let N=new js(e),M=this.config.security?.ownerUserId;M&&(this.calendarWatcher=new to(kt,N,this.adapters,M,st,this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),m))}{let N=this.config.security?.ownerUserId;if(N){let M=new js(e);this.todoWatcher=new so(we,M,this.adapters,N,st,{minutesBefore:30},this.logger.child({component:"todo-watcher"}),m,N)}}if(this.config.mcp?.servers?.length){let{MCPManager:N}=await Promise.resolve().then(()=>(fe(),ye));this.mcpManager=new N(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let M of this.mcpManager.getSkills())A.register(M);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},b);A.register(M),this.codeAgentSkillRef=M,this.logger.info({agents:this.config.codeAgents.agents.map(X=>X.name)},"Code agent skill enabled")}if(this.config.projects?.enabled!==!1){let{ProjectRepository:N}=await Promise.resolve().then(()=>(Je(),tt)),{ProjectManager:M}=await Promise.resolve().then(()=>(dT(),lT)),{SessionSummarizer:X}=await Promise.resolve().then(()=>(hT(),uT)),q=new N(e),J=new X(b,this.config.projects?.summarizerLlmTier??"strong"),le=new M(q,J,this.logger.child({component:"project-manager"}),this.config.projects?.autoBindByCwd??!0);this.projectRepo=q,this.projectManager=le,(async()=>{try{let Y=this.ownerMasterUserId??this.config.security?.ownerUserId;if(!Y)return;if(this.memoryRepo){let se="project_names_rebuilt_v616";if((await this.memoryRepo.search(Y,se).catch(()=>[])).some(_e=>_e.key===se))return}let Te=await le.rebuildLongProjectNames(Y);this.logger.info({...Te},"v616 NA1: project names rebuild complete"),this.memoryRepo&&await this.memoryRepo.saveWithMetadata(Y,"project_names_rebuilt_v616",`Rebuild: ${Te.renamed} renamed, ${Te.skipped} skipped`,"general","feedback",1,"auto").catch(()=>{})}catch(Y){this.logger.debug({err:Y},"v616 NA1 startup rebuild failed (non-critical)")}})().catch(()=>{});let{ProjectSkill:Ee}=await Promise.resolve().then(()=>(fe(),ye)),Me=new Ee(q);Me.setIncidentCascade(async(Y,Te)=>{try{let se=A.get("itsm");if(!se)return!1;let Be=this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(!Be)return!1;let _e={userId:Be,masterUserId:Be,chatId:this.config.security?.ownerUserId??"",platform:"api"};return await se.execute({action:Te==="closed"?"close_incident":"update_incident",incident_id:Y,status:Te},_e),!0}catch{return!1}}),A.register(Me),this.projectSkillRef=Me;let{isSubstantialSession:Le}=await Promise.resolve().then(()=>(mT(),pT)),{WorkflowExtractor:Ge}=await Promise.resolve().then(()=>(gT(),fT)),Ue={toolCallsThreshold:this.config.projects?.orphanDelegateThresholdToolCalls,minutesThreshold:this.config.projects?.orphanDelegateThresholdMinutes},Fe=new Ge(b,this.config.projects?.summarizerLlmTier??"strong"),me=f(async Y=>{if(this.confirmationQueue)try{let Te=new Set(A.getAll().map(_e=>_e.metadata.name)),se=await Fe.analyze({goal:Y.goal,toolCalls:Y.toolCalls,availableSkills:Te});if(!se.reusable||!se.steps||!se.suggestedName)return;let Be=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:Be,source:"reasoning",sourceId:`workflow-from-session-${Y.sourceId.slice(0,16)}`,description:`Workflow '${se.suggestedName}' (${se.steps.length} Schritte) aus der Session erkannt \u2014 als wiederverwendbar speichern?
5305
+ ${Be}`:""}`}),q.setLlmCallFn(async(J,le)=>(await b.complete({messages:[{role:"user",content:J}],tier:le,maxTokens:2e3})).content),A.register(q),this.logger.info("Brainstorming skill registered")}if(this.config.email?.accounts?.length){let N=new Map;for(let X of this.config.email.accounts)try{X.provider==="microsoft"&&!X.microsoft?.clientId&&this.config.calendar?.microsoft&&(X.microsoft={...this.config.calendar.microsoft});let q=await An(X);N.set(X.name,q),this.logger.info({account:X.name,provider:X.provider??"imap-smtp"},"Email account initialized")}catch(q){this.logger.warn({err:q,account:X.name},"Email account initialization failed, skipping")}let M=N.size>0?new Ws(N):new Ws;M.setLLM(b),A.register(M)}else{let N=new Ws;N.setLLM(b),A.register(N)}A.register(new Rn),A.register(new In);let Us=new qn;Us.setReloadCallback(N=>this.reloadService(N)),Us.setHealthAdapter(g),A.register(Us),A.register(new Nn),A.register(new Ln),A.register(new Cn),A.register(new Dn(s));let ms=new xn(s,l,this.adapters,(N,M)=>t.findByPlatformAndUser(N,M));A.register(ms);let Kt=new Mn(u,A);A.register(Kt),A.register(new Un(h,A));let nt=new Ki(e),Ie=new ja(nt,C,this.logger.child({component:"documents"})),dt=this.detectMistralApiKey();if(dt){let{OcrService:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(dt);M.setUsageCallback((X,q)=>{$.record("ocr",X,q).catch(()=>{})}),Ie.setOcrService(M),this.logger.info("Mistral OCR enabled for document processing")}let Ni=new Pn(nt,Ie,C);A.register(Ni);let qt,kt;if(this.config.calendar)try{kt=await On(this.config.calendar),qt=new ui(kt),A.register(qt),this.logger.info({provider:this.config.calendar.provider},"Calendar initialized")}catch(N){this.logger.warn({err:N},"Calendar initialization failed, continuing without calendar")}this.calendarSkill=qt;let st=[...this.adapters.keys()][0]??"telegram";if(kt&&this.config.calendar?.vorlauf?.enabled){let N=new js(e),M=this.config.security?.ownerUserId;M&&(this.calendarWatcher=new to(kt,N,this.adapters,M,st,this.config.calendar.vorlauf,this.logger.child({component:"calendar-watcher"}),m))}{let N=this.config.security?.ownerUserId;if(N){let M=new js(e);this.todoWatcher=new so(we,M,this.adapters,N,st,{minutesBefore:30},this.logger.child({component:"todo-watcher"}),m,N)}}if(this.config.mcp?.servers?.length){let{MCPManager:N}=await Promise.resolve().then(()=>(fe(),ye));this.mcpManager=new N(this.logger.child({component:"mcp"})),await this.mcpManager.initialize(this.config.mcp);for(let M of this.mcpManager.getSkills())A.register(M);this.logger.info({mcpSkills:this.mcpManager.getSkills().length},"MCP skills registered")}if(this.config.codeSandbox?.enabled){let{CodeExecutionSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N({allowedLanguages:this.config.codeSandbox.allowedLanguages,maxTimeoutMs:this.config.codeSandbox.maxTimeoutMs})),this.logger.info("Code sandbox enabled")}if(this.config.codeAgents?.enabled){let{CodeAgentSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N({agents:this.config.codeAgents.agents,forge:this.config.codeAgents.forge},b);A.register(M),this.codeAgentSkillRef=M,this.logger.info({agents:this.config.codeAgents.agents.map(X=>X.name)},"Code agent skill enabled")}if(this.config.projects?.enabled!==!1){let{ProjectRepository:N}=await Promise.resolve().then(()=>(Je(),Ze)),{ProjectManager:M}=await Promise.resolve().then(()=>(dT(),lT)),{SessionSummarizer:X}=await Promise.resolve().then(()=>(hT(),uT)),q=new N(e),J=new X(b,this.config.projects?.summarizerLlmTier??"strong"),le=new M(q,J,this.logger.child({component:"project-manager"}),this.config.projects?.autoBindByCwd??!0);this.projectRepo=q,this.projectManager=le,(async()=>{try{let Y=this.ownerMasterUserId??this.config.security?.ownerUserId;if(!Y)return;if(this.memoryRepo){let se="project_names_rebuilt_v616";if((await this.memoryRepo.search(Y,se).catch(()=>[])).some(_e=>_e.key===se))return}let Te=await le.rebuildLongProjectNames(Y);this.logger.info({...Te},"v616 NA1: project names rebuild complete"),this.memoryRepo&&await this.memoryRepo.saveWithMetadata(Y,"project_names_rebuilt_v616",`Rebuild: ${Te.renamed} renamed, ${Te.skipped} skipped`,"general","feedback",1,"auto").catch(()=>{})}catch(Y){this.logger.debug({err:Y},"v616 NA1 startup rebuild failed (non-critical)")}})().catch(()=>{});let{ProjectSkill:Ee}=await Promise.resolve().then(()=>(fe(),ye)),Me=new Ee(q);Me.setIncidentCascade(async(Y,Te)=>{try{let se=A.get("itsm");if(!se)return!1;let Be=this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(!Be)return!1;let _e={userId:Be,masterUserId:Be,chatId:this.config.security?.ownerUserId??"",platform:"api"};return await se.execute({action:Te==="closed"?"close_incident":"update_incident",incident_id:Y,status:Te},_e),!0}catch{return!1}}),A.register(Me),this.projectSkillRef=Me;let{isSubstantialSession:Le}=await Promise.resolve().then(()=>(mT(),pT)),{WorkflowExtractor:Ge}=await Promise.resolve().then(()=>(gT(),fT)),Ue={toolCallsThreshold:this.config.projects?.orphanDelegateThresholdToolCalls,minutesThreshold:this.config.projects?.orphanDelegateThresholdMinutes},Fe=new Ge(b,this.config.projects?.summarizerLlmTier??"strong"),me=f(async Y=>{if(this.confirmationQueue)try{let Te=new Set(A.getAll().map(_e=>_e.metadata.name)),se=await Fe.analyze({goal:Y.goal,toolCalls:Y.toolCalls,availableSkills:Te});if(!se.reusable||!se.steps||!se.suggestedName)return;let Be=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:Be,source:"reasoning",sourceId:`workflow-from-session-${Y.sourceId.slice(0,16)}`,description:`Workflow '${se.suggestedName}' (${se.steps.length} Schritte) aus der Session erkannt \u2014 als wiederverwendbar speichern?
5295
5306
 
5296
- ${se.suggestedDescription??""}`,skillName:"workflow",skillParams:{action:"create",name:se.suggestedName,description:se.suggestedDescription,steps:se.steps,triggerType:"manual",autoExtracted:!0,sourceSessionId:Y.sourceId},timeoutMinutes:1440}),this.logger.info({name:se.suggestedName,steps:se.steps.length,sourceId:Y.sourceId},"Workflow extraction enqueued")}catch(Te){this.logger.debug({err:Te},"WorkflowExtractor failed (non-critical)")}},"proposeWorkflowFromSession");if(this.delegateSkillRef&&this.delegateSkillRef.setSessionCompletionCallback(async Y=>{if(!Le({toolCalls:Y.toolCalls,filesChanged:Y.filesChanged,durationMs:Y.durationMs},Ue))return;let Te=Y.context.masterUserId??this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(!Te)return;let se=`delegate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;try{await le.finishOrphanSession({userId:Te,sessionType:"delegate",sourceId:se,goal:Y.task,success:Y.success,transcript:Y.finalResponse,totalFilesChanged:Y.filesChanged})}catch(Be){this.logger.debug({err:Be},"delegate completion \u2192 project-manager failed")}if(Y.success&&Y.toolNames.length>0)try{let Be=Y.toolNames.map(_e=>({name:_e,input:{},success:!0}));await me({userId:Te,goal:Y.task,toolCalls:Be,sourceId:se})}catch(Be){this.logger.debug({err:Be},"delegate workflow-extraction failed")}}),this.codeAgentSkillRef&&this.codeAgentSkillRef.setSessionCompletionCallback(async Y=>{if(!Le({toolCalls:Y.toolCalls,filesChanged:Y.filesChanged,durationMs:Y.durationMs},Ue))return;let Te=Y.context.masterUserId??this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(Te){try{Y.cwd?await le.finishSession({userId:Te,sessionType:"code_agent",sourceId:`code-agent-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,goal:Y.agentOrTask,cwd:Y.cwd,success:Y.success,transcript:Y.finalOutput,files:Y.modifiedFiles,totalFilesChanged:Y.filesChanged}):await le.finishOrphanSession({userId:Te,sessionType:"code_agent",sourceId:`code-agent-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,goal:Y.agentOrTask,success:Y.success,transcript:Y.finalOutput,files:Y.modifiedFiles,totalFilesChanged:Y.filesChanged})}catch(se){this.logger.debug({err:se},"code-agent completion \u2192 project-manager failed")}if(Y.success&&(Y.toolCalls??0)>0)try{let se=[{name:"code_agent",input:{task:Y.agentOrTask,cwd:Y.cwd},success:Y.success}];await me({userId:Te,goal:Y.agentOrTask,toolCalls:se,sourceId:`code-agent-wf-${Date.now()}-${Math.random().toString(36).slice(2,8)}`})}catch(se){this.logger.debug({err:se},"code-agent workflow-extraction failed")}}}),this.config.projects?.healthCheckEnabled!==!1){let{HealthMonitor:Y}=await Promise.resolve().then(()=>(NT(),$T)),Te=new Y(q,()=>this.ownerMasterUserId??this.config.security?.ownerUserId,this.logger.child({component:"project-health-monitor"}),{intervalHours:this.config.projects?.healthCheckIntervalHours,probeTimeoutMs:this.config.projects?.healthProbeTimeoutMs},()=>this.adapterClaimManager);Te.onStatusChange(async se=>{if(!this.confirmationQueue||!(this.ownerMasterUserId??this.config.security?.ownerUserId??""))return;let _e=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",pt=se.probe==="build"?`Build von Projekt "${se.project.name}" ist kaputt (${se.from} \u2192 ${se.to}). Code-Agent zur Reparatur starten?`:se.probe==="deps"?`Dependencies von "${se.project.name}" sind veraltet. Updates pr\xFCfen?`:se.probe==="http"?`Deploy-URL von "${se.project.name}" antwortet nicht mehr (${se.from} \u2192 ${se.to}). Pr\xFCfen?`:`Health-Probe "${se.probe}" f\xFCr "${se.project.name}" hat sich verschlechtert (${se.from} \u2192 ${se.to}).`;try{await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:_e,source:"reasoning",sourceId:`project-health-${se.project.id}-${se.probe}-${Date.now()}`,description:pt,skillName:"project",skillParams:{action:"get",project_id:se.project.id},timeoutMinutes:1440})}catch(St){this.logger.debug({err:St},"project-health confirmation enqueue failed")}}),Te.start(),this.projectHealthMonitor=Te,this.logger.info({intervalHours:this.config.projects?.healthCheckIntervalHours??6},"Project HealthMonitor started")}this.logger.info("Projects skill + manager enabled (T4 delegate + code-agent hooks active)")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:N,setInterjectionRepo:M}=await Promise.resolve().then(()=>(fe(),ye)),{ProjectAgentSessionRepository:X,ProjectAgentInterjectionRepository:q}=await Promise.resolve().then(()=>(Je(),tt)),J=new X(e);M(new q(e));let le=new N({...this.config.projectAgents,agents:this.config.codeAgents.agents},b,J),{ProjectAgentRunner:Ee}=await Promise.resolve().then(()=>(Xp(),DT)),Me=new Ee(new Map(this.config.codeAgents.agents.map(Le=>[Le.name,Le])),b,J,this.adapters,this.logger.child({component:"project-agent"}),this.config.codeAgents.forge);le.setRunner(Me),this.projectAgentRunnerRef=Me,this.projectRepo&&le.setProjectLookup(this.projectRepo,this.ownerMasterUserId??this.config.security?.ownerUserId),Me.setCompletionCallback(async(Le,Ge,Ue,Fe)=>{if(this.memoryRepo&&Ge.cwd)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"",Y=(Ge.cwd??"").replace(/\/+$/,"").split("/").filter(Boolean).pop();if(me&&Y){let Te=`project_workspace_${Y.replace(/[^a-zA-Z0-9_-]/g,"_")}`,se=await this.database?.getAdapter().queryOne("SELECT last_commit_sha, last_build_passed FROM project_agent_sessions WHERE task_id = ?",[Le]).catch(()=>null),Be=[`Dev-Workspace f\xFCr Projekt "${Y}": ${Ge.cwd} (lokal auf Alfred-Node)`,`last_run=${new Date().toISOString().slice(0,16).replace("T"," ")}`,`phases=${Ue.projectIteration}`,`files_changed=${Ue.totalFilesChanged}`,`build_passed=${Fe?"yes":"no"}`];se?.last_commit_sha&&Be.push(`last_commit=${se.last_commit_sha.slice(0,8)}`),Be.push("HINWEIS: Das ist der LOKALE Workspace zum Entwickeln, NICHT der Deploy-Target-Pfad"),await this.memoryRepo.saveWithMetadata(me,Te,Be.join(", "),"workspace","fact",.95,"auto")}}catch(me){this.logger.debug({err:me},"project-agent workspace-memory auto-save failed")}if(this.projectManager)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"";me&&await this.projectManager.finishSession({userId:me,sessionType:"project_agent",sourceId:Le,goal:Ge.goal,cwd:Ge.cwd,milestones:Ue.milestonesReached,totalFilesChanged:Ue.totalFilesChanged,success:Fe})}catch(me){this.logger.debug({err:me},"project-manager finishSession failed")}if(Fe){if(Ue.milestonesReached.length>=3&&this.runbookRepo&&this.confirmationQueue)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(me){if(!await this.runbookRepo.findBySource(me,"project_agent",Le)){let Te=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",se=`Projekt: ${Ge.goal.slice(0,100)}`;try{let _e=(await b.complete({messages:[{role:"user",content:`Fasse das folgende Projekt-Ziel in einem klaren, pr\xE4gnanten Titel zusammen (max 60 Zeichen, ohne Quotes, ohne "Projekt:" Prefix, ohne "Starte einen ..." Boilerplate). Antworte NUR mit dem Titel.
5307
+ ${se.suggestedDescription??""}`,skillName:"workflow",skillParams:{action:"create",name:se.suggestedName,description:se.suggestedDescription,steps:se.steps,triggerType:"manual",autoExtracted:!0,sourceSessionId:Y.sourceId},timeoutMinutes:1440}),this.logger.info({name:se.suggestedName,steps:se.steps.length,sourceId:Y.sourceId},"Workflow extraction enqueued")}catch(Te){this.logger.debug({err:Te},"WorkflowExtractor failed (non-critical)")}},"proposeWorkflowFromSession");if(this.delegateSkillRef&&this.delegateSkillRef.setSessionCompletionCallback(async Y=>{if(!Le({toolCalls:Y.toolCalls,filesChanged:Y.filesChanged,durationMs:Y.durationMs},Ue))return;let Te=Y.context.masterUserId??this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(!Te)return;let se=`delegate-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;try{await le.finishOrphanSession({userId:Te,sessionType:"delegate",sourceId:se,goal:Y.task,success:Y.success,transcript:Y.finalResponse,totalFilesChanged:Y.filesChanged})}catch(Be){this.logger.debug({err:Be},"delegate completion \u2192 project-manager failed")}if(Y.success&&Y.toolNames.length>0)try{let Be=Y.toolNames.map(_e=>({name:_e,input:{},success:!0}));await me({userId:Te,goal:Y.task,toolCalls:Be,sourceId:se})}catch(Be){this.logger.debug({err:Be},"delegate workflow-extraction failed")}}),this.codeAgentSkillRef&&this.codeAgentSkillRef.setSessionCompletionCallback(async Y=>{if(!Le({toolCalls:Y.toolCalls,filesChanged:Y.filesChanged,durationMs:Y.durationMs},Ue))return;let Te=Y.context.masterUserId??this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(Te){try{Y.cwd?await le.finishSession({userId:Te,sessionType:"code_agent",sourceId:`code-agent-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,goal:Y.agentOrTask,cwd:Y.cwd,success:Y.success,transcript:Y.finalOutput,files:Y.modifiedFiles,totalFilesChanged:Y.filesChanged}):await le.finishOrphanSession({userId:Te,sessionType:"code_agent",sourceId:`code-agent-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,goal:Y.agentOrTask,success:Y.success,transcript:Y.finalOutput,files:Y.modifiedFiles,totalFilesChanged:Y.filesChanged})}catch(se){this.logger.debug({err:se},"code-agent completion \u2192 project-manager failed")}if(Y.success&&(Y.toolCalls??0)>0)try{let se=[{name:"code_agent",input:{task:Y.agentOrTask,cwd:Y.cwd},success:Y.success}];await me({userId:Te,goal:Y.agentOrTask,toolCalls:se,sourceId:`code-agent-wf-${Date.now()}-${Math.random().toString(36).slice(2,8)}`})}catch(se){this.logger.debug({err:se},"code-agent workflow-extraction failed")}}}),this.config.projects?.healthCheckEnabled!==!1){let{HealthMonitor:Y}=await Promise.resolve().then(()=>(NT(),$T)),Te=new Y(q,()=>this.ownerMasterUserId??this.config.security?.ownerUserId,this.logger.child({component:"project-health-monitor"}),{intervalHours:this.config.projects?.healthCheckIntervalHours,probeTimeoutMs:this.config.projects?.healthProbeTimeoutMs},()=>this.adapterClaimManager);Te.onStatusChange(async se=>{if(!this.confirmationQueue||!(this.ownerMasterUserId??this.config.security?.ownerUserId??""))return;let _e=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",pt=se.probe==="build"?`Build von Projekt "${se.project.name}" ist kaputt (${se.from} \u2192 ${se.to}). Code-Agent zur Reparatur starten?`:se.probe==="deps"?`Dependencies von "${se.project.name}" sind veraltet. Updates pr\xFCfen?`:se.probe==="http"?`Deploy-URL von "${se.project.name}" antwortet nicht mehr (${se.from} \u2192 ${se.to}). Pr\xFCfen?`:`Health-Probe "${se.probe}" f\xFCr "${se.project.name}" hat sich verschlechtert (${se.from} \u2192 ${se.to}).`;try{await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:_e,source:"reasoning",sourceId:`project-health-${se.project.id}-${se.probe}-${Date.now()}`,description:pt,skillName:"project",skillParams:{action:"get",project_id:se.project.id},timeoutMinutes:1440})}catch(St){this.logger.debug({err:St},"project-health confirmation enqueue failed")}}),Te.start(),this.projectHealthMonitor=Te,this.logger.info({intervalHours:this.config.projects?.healthCheckIntervalHours??6},"Project HealthMonitor started")}this.logger.info("Projects skill + manager enabled (T4 delegate + code-agent hooks active)")}if(this.config.projectAgents?.enabled&&this.config.codeAgents?.agents){let{ProjectAgentSkill:N,setInterjectionRepo:M}=await Promise.resolve().then(()=>(fe(),ye)),{ProjectAgentSessionRepository:X,ProjectAgentInterjectionRepository:q}=await Promise.resolve().then(()=>(Je(),Ze)),J=new X(e);M(new q(e));let le=new N({...this.config.projectAgents,agents:this.config.codeAgents.agents},b,J),{ProjectAgentRunner:Ee}=await Promise.resolve().then(()=>(Xp(),DT)),Me=new Ee(new Map(this.config.codeAgents.agents.map(Le=>[Le.name,Le])),b,J,this.adapters,this.logger.child({component:"project-agent"}),this.config.codeAgents.forge);le.setRunner(Me),this.projectAgentRunnerRef=Me,this.projectRepo&&le.setProjectLookup(this.projectRepo,this.ownerMasterUserId??this.config.security?.ownerUserId),Me.setCompletionCallback(async(Le,Ge,Ue,Fe)=>{if(this.memoryRepo&&Ge.cwd)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"",Y=(Ge.cwd??"").replace(/\/+$/,"").split("/").filter(Boolean).pop();if(me&&Y){let Te=`project_workspace_${Y.replace(/[^a-zA-Z0-9_-]/g,"_")}`,se=await this.database?.getAdapter().queryOne("SELECT last_commit_sha, last_build_passed FROM project_agent_sessions WHERE task_id = ?",[Le]).catch(()=>null),Be=[`Dev-Workspace f\xFCr Projekt "${Y}": ${Ge.cwd} (lokal auf Alfred-Node)`,`last_run=${new Date().toISOString().slice(0,16).replace("T"," ")}`,`phases=${Ue.projectIteration}`,`files_changed=${Ue.totalFilesChanged}`,`build_passed=${Fe?"yes":"no"}`];se?.last_commit_sha&&Be.push(`last_commit=${se.last_commit_sha.slice(0,8)}`),Be.push("HINWEIS: Das ist der LOKALE Workspace zum Entwickeln, NICHT der Deploy-Target-Pfad"),await this.memoryRepo.saveWithMetadata(me,Te,Be.join(", "),"workspace","fact",.95,"auto")}}catch(me){this.logger.debug({err:me},"project-agent workspace-memory auto-save failed")}if(this.projectManager)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"";me&&await this.projectManager.finishSession({userId:me,sessionType:"project_agent",sourceId:Le,goal:Ge.goal,cwd:Ge.cwd,milestones:Ue.milestonesReached,totalFilesChanged:Ue.totalFilesChanged,success:Fe})}catch(me){this.logger.debug({err:me},"project-manager finishSession failed")}if(Fe){if(Ue.milestonesReached.length>=3&&this.runbookRepo&&this.confirmationQueue)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(me){if(!await this.runbookRepo.findBySource(me,"project_agent",Le)){let Te=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",se=`Projekt: ${Ge.goal.slice(0,100)}`;try{let _e=(await b.complete({messages:[{role:"user",content:`Fasse das folgende Projekt-Ziel in einem klaren, pr\xE4gnanten Titel zusammen (max 60 Zeichen, ohne Quotes, ohne "Projekt:" Prefix, ohne "Starte einen ..." Boilerplate). Antworte NUR mit dem Titel.
5297
5308
 
5298
5309
  Ziel:
5299
- ${Ge.goal.slice(0,600)}`}],tier:"fast",maxTokens:30,temperature:.1})).content.trim().replace(/^["'"„""]|["'"„""]$/g,"").slice(0,60);_e.length>=8&&(se=_e)}catch{}await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:Te,source:"reasoning",sourceId:`runbook-from-project-${Le.slice(0,8)}`,description:`Runbook aus Project-Agent-Session erstellen: "${se}"?`,skillName:"runbook",skillParams:{action:"create",title:se,symptom:`Initialer Goal: ${Ge.goal}`,steps:Ue.milestonesReached,source_type:"project_agent",source_id:Le,status:"draft",tags:["project-agent","auto"]},timeoutMinutes:1440}),this.logger.info({sessionId:Le,milestones:Ue.milestonesReached.length,title:se},"Project-agent runbook suggestion enqueued")}}}catch(me){this.logger.debug({err:me},"Runbook suggestion (project-agent) failed")}if(Fe&&this.memoryRepo&&this.confirmationQueue)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(!me)return;let Y=(Ge.cwd??"").replace(/\/+$/,"").split("/").filter(Boolean).pop();if(!Y)return;let Be=(await this.memoryRepo.search(me,`deploy_${Y}_`)).filter(he=>he.category==="deployment"&&he.key.startsWith(`deploy_${Y}_`)).sort((he,Re)=>Re.updatedAt.localeCompare(he.updatedAt))[0];if(!Be)return;let _e=Be.value,pt=_e.match(/→\s*([\w.-]+)\s*\(/),St=_e.match(/user=([^,)]+)/),G=_e.match(/port=(\d+)/),V=_e.match(/pm=([^,)]+)/),K=_e.match(/runtime=([^,)]+)/);if(!pt)return;let U=pt[1],re=St?.[1]??"root",Ae=G?Number(G[1]):void 0,xe=V?.[1],ne=K?.[1],ve=`auto-deploy-from-project-${Le.slice(0,8)}`,Ye=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",Qe={action:"deploy",host:U,user:re,project:Y};Ae!==void 0&&(Qe.app_port=Ae),xe&&(Qe.process_manager=xe),ne&&(Qe.runtime=ne),await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:Ye,source:"reasoning",sourceId:ve,description:`Project Agent fertig \u2014 auch nach \`${U}\`${Ae?`:${Ae}`:""} (user \`${re}\`${xe?`, pm ${xe}`:""}) deployen wie letztes Mal?`,skillName:"deploy",skillParams:Qe,timeoutMinutes:60}),this.logger.info({sessionId:Le,host:U,projectName:Y,port:Ae},"Project-agent auto-deploy suggestion enqueued")}catch(me){this.logger.debug({err:me},"Auto-deploy suggestion (project-agent) failed")}}}),A.register(le),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(this.config.proxmox),X=this.config.infra?.sshKeyPath??`${process.env.HOME??"/root"}/.ssh/id_ed25519`;M.setSshKeyPath(X),M.setSshUser(this.config.infra?.sshUser??"root"),M.setPostProvisionCallback(async(q,J,le,Ee,Me)=>{let{execFile:Le}=await import("node:child_process"),{promisify:Ge}=await import("node:util"),Ue=Ge(Le),Fe=[],me=f(async se=>{let{stdout:Be}=await Ue("ssh",["-i",X,"-o","StrictHostKeyChecking=no","-o","UserKnownHostsFile=/dev/null","-o","ConnectTimeout=10",`${J}@${q}`,se],{maxBuffer:5242880,timeout:3e5});return Be.trim()},"runSsh");Fe.push("\u23F3 Warte auf SSH + Cloud-Init...");let Y=!1,Te=Date.now();for(await new Promise(se=>setTimeout(se,2e4));Date.now()-Te<18e4;){try{await me("echo ok"),Y=!0;break}catch{}await new Promise(se=>setTimeout(se,15e3))}if(!Y)return Fe.push(`\u274C SSH nicht erreichbar nach ${Math.round((Date.now()-Te)/1e3)}s`),Fe;Fe.push(`\u2705 SSH erreichbar nach ${Math.round((Date.now()-Te)/1e3)}s`);try{if(le==="docker"){if(await me("curl -fsSL https://get.docker.com | sudo sh && sudo usermod -aG docker $USER"),Ee?await me("sudo dnf install -y docker-compose-plugin").catch(()=>{}):await me("sudo apt-get install -y docker-compose-plugin || sudo apt-get install -y docker-compose").catch(()=>{}),Fe.push("\u{1F433} Docker + Docker Compose installiert"),Me?.dockerBridgeIp)try{await me(`echo '{"bip":"${Me.dockerBridgeIp}"}' | sudo tee /etc/docker/daemon.json && sudo systemctl restart docker`),Fe.push(`\u{1F310} Docker Bridge: ${Me.dockerBridgeIp}`)}catch{Fe.push("\u26A0\uFE0F Docker Bridge IP Konfiguration fehlgeschlagen")}}else le==="node"?(Ee?await me("curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash - && sudo dnf install -y nodejs && sudo npm install -g pm2"):await me("curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs && sudo npm install -g pm2 && sudo pm2 startup systemd -u $USER --hp /home/$USER"),Fe.push("\u{1F4E6} Node.js + pm2 installiert")):le==="python"&&(Ee?await me("sudo dnf install -y python3 python3-pip"):await me("sudo apt-get update && sudo apt-get install -y python3 python3-pip python3-venv"),Fe.push("\u{1F40D} Python installiert"))}catch(se){Fe.push(`\u26A0\uFE0F Runtime-Installation: ${se.message?.slice(0,100)}`)}try{Ee?await me("sudo dnf install -y qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent"):await me("sudo apt-get install -y qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent"),Fe.push("\u{1F4E1} qemu-guest-agent installiert")}catch{Fe.push("\u26A0\uFE0F qemu-guest-agent Installation fehlgeschlagen")}try{await me("id -nG | grep -q docker || sudo usermod -aG docker $USER 2>/dev/null")}catch{}return Fe}),A.register(M),this.logger.info({baseUrl:this.config.proxmox.baseUrl,sshKeyPath:X},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:N,createContactsProvider:M}=await Promise.resolve().then(()=>(fe(),ye)),X=await M(this.config.contacts);A.register(new N(X)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(N){this.logger.warn({err:N},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:N}=await Promise.resolve().then(()=>(fe(),ye));this.bmwSkill=new N(this.config.bmw),A.register(this.bmwSkill),this.logger.info("BMW CarData skill enabled")}if(this.config.goeCharger?.host){let{GoeChargerSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.goeCharger,this.config.energy)),this.logger.info({host:this.config.goeCharger.host},"go-e Charger skill registered")}if(this.config.routing){let{RoutingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.todo){let{OneDriveSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.todo)),this.logger.info("OneDrive skill registered")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N({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:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{CryptoPriceSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N),this.logger.info("Crypto price skill registered")}{let{BitpandaSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.bitpanda)),this.logger.info({hasApiKey:!!this.config.bitpanda?.apiKey},"Bitpanda skill registered")}if(this.config.trading?.exchanges&&Object.keys(this.config.trading.exchanges).length>0){let{TradingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.trading)),this.logger.info({exchanges:Object.keys(this.config.trading.exchanges)},"Trading skill registered")}{let{RecipeSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{RecipeFavoriteRepository:M,MealPlanRepository:X,AlfredUserRepository:q}=await Promise.resolve().then(()=>(Je(),tt)),J=new M(e),le=new X(e),Ee=new q(e);A.register(new N(this.config.recipe,{favorites:J,mealPlans:le,userRepo:Ee})),this.logger.info({hasSpoonacular:!!this.config.recipe?.spoonacular?.apiKey,hasEdamam:!!this.config.recipe?.edamam?.appId},"Recipe skill registered")}if(this.config.spotify?.clientId){let{SpotifySkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=this.config.api?.publicUrl??`http://${this.config.api?.host??"localhost"}:${this.config.api?.port??3420}`;this.spotifySkill=new N(this.config.spotify,M),A.register(this.spotifySkill),this.logger.info("Spotify skill registered")}{let{SonosSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=this.config.api?.publicUrl??`http://${this.config.api?.host??"localhost"}:${this.config.api?.port??3420}`;this.sonosSkill=new N(this.config.sonos,M,n,r),A.register(this.sonosSkill),this.logger.info({hasCloud:!!this.config.sonos?.cloud},"Sonos skill registered")}if(this.config.travel?.booking?.rapidApiKey){let{TravelSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{TravelPlanRepository:M}=await Promise.resolve().then(()=>(Je(),tt)),X=new M(e);A.register(new N(this.config.travel,{plans:X})),this.logger.info({hasFlights:!0,hasHotels:!0},"Travel skill registered")}if(this.config.mqtt?.brokerUrl){let{MqttSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.mqtt)),this.logger.info({broker:this.config.mqtt.brokerUrl},"MQTT skill registered")}if(this.config.cloudflare?.apiToken){let{CloudflareDnsSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.cloudflare)),this.logger.info("Cloudflare DNS skill registered")}if(this.config.nginxProxyManager?.baseUrl){let{NginxProxyManagerSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.nginxProxyManager)),this.logger.info({baseUrl:this.config.nginxProxyManager.baseUrl},"Nginx Proxy Manager skill registered")}if(this.config.pfsense?.baseUrl){let{PfSenseSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.pfsense)),this.logger.info({baseUrl:this.config.pfsense.baseUrl,auth:this.config.pfsense.authMethod??"apikey"},"pfSense Firewall skill registered")}{let{DeploySkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(this.config.infra),X={};if(A.has("proxmox")&&(X.proxmox=q=>H.execute(A.get("proxmox"),q,{})),A.has("cloudflare_dns")&&(X.cloudflare=q=>H.execute(A.get("cloudflare_dns"),q,{})),A.has("nginx_proxy_manager")&&(X.npm=q=>H.execute(A.get("nginx_proxy_manager"),q,{})),A.has("pfsense")&&(X.firewall=q=>H.execute(A.get("pfsense"),q,{})),A.has("unifi")&&(X.unifi=q=>H.execute(A.get("unifi"),q,{})),M.setOrchestrationCallbacks(X),this.config.codeAgents?.forge&&M.setForgeConfig(this.config.codeAgents.forge),this.database){let{HostCapabilitiesRepository:q}=await Promise.resolve().then(()=>(Je(),tt));M.setHostCapabilitiesRepo(new q(this.database.getAdapter()))}if(this.memoryRepo){let q=this.config.security?.ownerUserId,J;try{if(q&&this.userRepo){let le=await this.userRepo.findOrCreate("telegram",q);J=le.masterUserId??le.id}}catch{}M.setMemoryRepo(this.memoryRepo,J??q)}if(A.register(M),this.logger.info("Deploy skill registered (with orchestration)"),this.config.mikrotik?.enabled){let{MikroTikSkill:q}=await Promise.resolve().then(()=>(fe(),ye)),J=new q(this.config.mikrotik);A.register(J),this.logger.info("MikroTik skill registered")}if(this.config.cmdb?.enabled!==!1&&(this.config.proxmox||this.config.unifi||this.config.docker||this.config.cloudflare||this.config.nginxProxyManager||this.config.pfsense||this.config.homeassistant||this.config.mikrotik)){let q=new Hs(e),J=new oi(e);J.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;let{ProblemRepository:le,RunbookRepository:Ee}=await Promise.resolve().then(()=>(Je(),tt)),Me=new le(e),Le=new Ee(e);this.runbookRepo=Le;let{CmdbSkill:Ge,ItsmSkill:Ue,InfraDocsSkill:Fe,RunbookSkill:me}=await Promise.resolve().then(()=>(fe(),ye)),Y=new Ge(q,this.config.cmdb?.staleThresholdDays??7),Te=new Ue(J,q,Me),se=new Fe(q,J),Be=new me(Le);Te.setLlmCallback(async(G,V)=>{if(!this.llmProvider)throw new Error("LLM nicht verf\xFCgbar");return(await this.llmProvider.complete({messages:[{role:"user",content:G}],tier:V??"default",maxTokens:3e3})).content}),Te.setProjectItemCascade(async G=>{if(this.projectRepo)try{let V=await this.projectRepo.findOpenItemsByLinkedIncident(G);for(let K of V)await this.projectRepo.updateOpenItemStatus(K.id,"done")}catch(V){this.logger.debug({err:V,incidentId:G},"ITSM\u2192project cascade failed (non-critical)")}}),se.setLlmCallback(async(G,V)=>{if(!this.llmProvider)throw new Error("LLM nicht verf\xFCgbar");return(await this.llmProvider.complete({messages:[{role:"user",content:G}],tier:V??"default",maxTokens:3e3})).content}),A.has("shell")&&se.setSshCallback(async(G,V,K)=>{let U=A.get("shell"),re=K??this.config.infra?.sshUser,Ae=`ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${re?re+"@":""}${G} '${V.replace(/'/g,"'\\''")}'`,xe=await H.execute(U,{command:Ae},{userId:"",platform:"api",chatId:"",conversationId:""});return xe.success?xe.data?.stdout??xe.display??"":""});let _e=f((G,V)=>{A.has(G)&&Y.registerDiscoverySource(G,V)},"wrapSkillAsSource");if(_e("proxmox",async()=>{let G=[],V=[],K=A.get("proxmox"),U=new Map,re;try{try{let ne=await H.execute(K,{action:"cluster_status"},{});if(ne.success&&Array.isArray(ne.data)){let ve=ne.data.find(Ye=>Ye.type==="cluster");ve&&(re=`cluster:${ve.name}`,G.push({name:ve.name,assetType:"cluster",sourceSkill:"proxmox",sourceId:re,status:ve.quorate?"active":"degraded",attributes:{nodes:ve.nodes,version:ve.version,quorate:ve.quorate}}));for(let Ye of ne.data)Ye.type==="node"&&Ye.name&&Ye.ip&&U.set(Ye.name,Ye.ip)}}catch{}let Ae=await H.execute(K,{action:"list_nodes"},{});if(Ae.success&&Array.isArray(Ae.data))for(let ne of Ae.data)G.push({name:ne.node,assetType:"server",sourceSkill:"proxmox",sourceId:`node:${ne.node}`,ipAddress:U.get(ne.node),status:ne.status==="online"?"active":"inactive",attributes:{cpu:ne.cpu,maxcpu:ne.maxcpu,mem:ne.mem,maxmem:ne.maxmem,uptime:ne.uptime}}),re&&V.push({sourceKey:`proxmox:node:${ne.node}`,targetKey:`proxmox:${re}`,relationType:"part_of"});try{let ne=await H.execute(K,{action:"list_storage",node:""},{});if(ne.success&&Array.isArray(ne.data))for(let ve of ne.data)ve.enabled===!1||ve.enabled===0||(G.push({name:ve.storage,assetType:"storage",sourceSkill:"proxmox",sourceId:`storage:${ve.storage}`,status:ve.active?"active":"inactive",attributes:{storageType:ve.type,content:ve.content,used:ve.used,total:ve.total}}),re&&V.push({sourceKey:`proxmox:${re}`,targetKey:`proxmox:storage:${ve.storage}`,relationType:"connects_to"}))}catch{}let xe=await H.execute(K,{action:"list_vms"},{});if(xe.success&&Array.isArray(xe.data))for(let ne of xe.data){let ve=ne.type==="lxc"?"lxc":"vm",Ye,Qe;try{let he=ve==="lxc"?`/nodes/${ne.node}/lxc/${ne.vmid}/config`:`/nodes/${ne.node}/qemu/${ne.vmid}/config`,Re=await H.execute(A.get("proxmox"),{action:"api_raw",path:he},{}),ke=Re.success?Re.data:null;if(ke){let ze=String(ke.net0??""),et=ze.match(/ip=([0-9.]+)/);et&&(Ye=et[1]);let $t=ze.match(/(?:virtio|hwaddr)=([0-9A-Fa-f:]+)/);$t&&(Qe=$t[1].toLowerCase())}}catch{}if(!Ye&&ve==="vm"&&ne.status==="running")try{let he=await H.execute(A.get("proxmox"),{action:"api_raw",path:`/nodes/${ne.node}/qemu/${ne.vmid}/agent/network-get-interfaces`},{});if(he.success&&he.data){let Re=he.data.result??he.data;if(Array.isArray(Re))for(let ke of Re){let ze=ke["ip-addresses"]??[];for(let et of ze)if(et["ip-address-type"]==="ipv4"&&!String(et["ip-address"]).startsWith("127.")){Ye=et["ip-address"];break}if(Ye)break}}}catch{}G.push({name:ne.name||`${ve}-${ne.vmid}`,assetType:ve,sourceSkill:"proxmox",sourceId:`${ne.node}:${ne.vmid}`,identifier:`vmid:${ne.vmid}`,ipAddress:Ye,status:ne.status==="running"?"active":"inactive",attributes:{vmid:ne.vmid,node:ne.node,cpus:ne.cpus,maxmem:ne.maxmem,maxdisk:ne.maxdisk,mac:Qe}}),V.push({sourceKey:`proxmox:${ne.node}:${ne.vmid}`,targetKey:`proxmox:node:${ne.node}`,relationType:"hosted_on"})}}catch{}return{assets:G,relations:V}}),_e("docker",async()=>{let G=[],V=[],K=this.config.docker?.host?.replace(/^https?:\/\//,"").replace(/:\d+$/,"");try{let U=await H.execute(A.get("docker"),{action:"containers"},{});if(U.success&&Array.isArray(U.data))for(let re of U.data){let Ae=(re.Names?.[0]??re.Id??"").replace(/^\//,""),xe=(re.Id??"").slice(0,12);G.push({name:Ae,assetType:"container",sourceSkill:"docker",sourceId:xe,status:re.State==="running"?"active":"inactive",ipAddress:K,attributes:{image:re.Image,status:re.Status,ports:re.Ports,host_ip:K}}),K&&V.push({sourceKey:`docker:${xe}`,targetKey:`ip:${K}`,relationType:"runs_on"})}}catch{}return{assets:G,relations:V}}),_e("unifi",async()=>{let G=[];try{let V=await H.execute(A.get("unifi"),{action:"list_devices"},{});if(V.success&&Array.isArray(V.data))for(let U of V.data)G.push({name:U.name||U.mac,assetType:"network_device",sourceSkill:"unifi",sourceId:`device:${U.mac??U._id}`,ipAddress:U.ip,status:U.state===1?"active":"inactive",attributes:{mac:U.mac,model:U.model,type:U.type,version:U.version}});let K=await H.execute(A.get("unifi"),{action:"list_networks"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.name||U._id,assetType:"network",sourceSkill:"unifi",sourceId:`net:${U._id}`,attributes:{vlan:U.vlan_enabled?U.vlan:void 0,subnet:U.ip_subnet}})}catch{}return{assets:G,relations:[]}}),_e("cloudflare_dns",async()=>{let G=[];try{let V=await H.execute(A.get("cloudflare_dns"),{action:"list_zones"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data){let U=await H.execute(A.get("cloudflare_dns"),{action:"list_records",domain:K.name},{});if(U.success&&Array.isArray(U.data))for(let re of U.data)G.push({name:`${re.name} (${re.type})`,assetType:"dns_record",sourceSkill:"cloudflare_dns",sourceId:`${K.id}:${re.id}`,fqdn:re.name,attributes:{type:re.type,content:re.content,proxied:re.proxied,ttl:re.ttl,zone:K.name}})}}catch{}return{assets:G,relations:[]}}),_e("nginx_proxy_manager",async()=>{let G=[];try{let V=await H.execute(A.get("nginx_proxy_manager"),{action:"list_hosts"},{});if(V.success&&Array.isArray(V.data))for(let U of V.data)G.push({name:U.domain_names?.[0]??`host-${U.id}`,assetType:"proxy_host",sourceSkill:"nginx_proxy_manager",sourceId:`host:${U.id}`,attributes:{domain_names:U.domain_names,forward_host:U.forward_host,forward_port:U.forward_port,forward_scheme:U.forward_scheme,ssl_forced:U.ssl_forced}});let K=await H.execute(A.get("nginx_proxy_manager"),{action:"list_certificates"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.nice_name||U.domain_names?.[0]||`cert-${U.id}`,assetType:"certificate",sourceSkill:"nginx_proxy_manager",sourceId:`cert:${U.id}`,attributes:{domain_names:U.domain_names,expires_on:U.expires_on,provider:U.provider}})}catch{}return{assets:G,relations:[]}}),_e("pfsense",async()=>{let G=[],V=A.get("pfsense");try{let K=await H.execute(V,{action:"list_rules"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.descr||`rule-${U.id}`,assetType:"firewall_rule",sourceSkill:"pfsense",sourceId:`rule:${U.id}`,attributes:{type:U.type,interface:U.interface,protocol:U.protocol,source:U.source,destination:U.destination,destination_address:U.destination?.address}})}catch{}try{let K=await H.execute(V,{action:"list_interfaces"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data){let re=U.descr||U.name||U.if||"unknown",Ae=U.ipaddr&&U.ipaddr!=="dhcp"?U.ipaddr:void 0,xe=U.subnet?`${Ae??""}/${U.subnet}`:void 0;G.push({name:re,assetType:"network",sourceSkill:"pfsense",sourceId:`if:${U.if??re}`,ipAddress:Ae,attributes:{interface:U.if,subnet:xe,vlan:U.tag,enable:U.enable,gateway:U.gateway}})}}catch{}try{let K=await H.execute(V,{action:"list_vlans"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.descr||`VLAN ${U.tag}`,assetType:"network",sourceSkill:"pfsense",sourceId:`vlan:${U.tag}`,attributes:{vlan_tag:U.tag,parent_if:U.parentif??U.if?.split(".")[0],vlanif:U.vlanif??U.if}})}catch{}try{let K=await H.execute(V,{action:"list_gateways"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.name||`gw-${U.interface}`,assetType:"network",sourceSkill:"pfsense",sourceId:`gw:${U.name??U.interface}`,ipAddress:U.gateway,attributes:{interface:U.interface,monitor:U.monitor,status:U.status,default:U.defaultgw}})}catch{}return{assets:G,relations:[]}}),_e("homeassistant",async()=>{let G=[];try{let V=await H.execute(A.get("homeassistant"),{action:"states"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data){let U=K.entity_id;if(!U)continue;let re=U.split(".")[0];if(!["automation","switch","light","sensor","binary_sensor","climate","cover","fan","media_player","camera"].includes(re))continue;let Ae=re==="automation"?"automation":"iot_device";G.push({name:K.attributes?.friendly_name||U,assetType:Ae,sourceSkill:"homeassistant",sourceId:U,status:K.state==="unavailable"?"inactive":"active",attributes:{entity_id:U,domain:re,state:K.state}})}}catch{}return{assets:G,relations:[]}}),_e("mikrotik",async()=>{let G=[],V=[],K=A.get("mikrotik"),U=K.getRouters?.()??[];for(let re of U){let Ae={name:re.name,cfg:re};try{let xe=await K.api(Ae,"GET","/system/resource"),ve=(await K.api(Ae,"GET","/system/identity"))?.name??re.name,Ye={name:ve,assetType:"network_device",sourceSkill:"mikrotik",sourceId:`router:${re.name}`,ipAddress:re.host,status:"active",attributes:{version:xe.version,architecture:xe["architecture-name"],board:xe["board-name"],cpu_count:xe["cpu-count"],total_memory:xe["total-memory"],uptime:xe.uptime}};G.push(Ye);let Qe=await K.api(Ae,"GET","/interface");for(let ke of Qe)ke.type==="bridge"||ke.type==="loopback"||(G.push({name:`${ve}/${ke.name}`,assetType:"network",sourceSkill:"mikrotik",sourceId:`if:${re.name}:${ke.name}`,attributes:{type:ke.type,mac:ke["mac-address"],running:ke.running,mtu:ke["actual-mtu"]}}),V.push({sourceEntityName:`${ve}/${ke.name}`,targetEntityName:ve,relationType:"part_of"}));let he=await K.api(Ae,"GET","/ip/firewall/filter");for(let ke of he.slice(0,50)){let ze=ke.comment||`${ke.chain}-${ke.action}-${ke[".id"]}`;G.push({name:`${ve}/fw/${ze}`,assetType:"firewall_rule",sourceSkill:"mikrotik",sourceId:`fw:${re.name}:${ke[".id"]}`,attributes:{chain:ke.chain,action:ke.action,src:ke["src-address"],dst:ke["dst-address"],protocol:ke.protocol,port:ke["dst-port"],disabled:ke.disabled}})}let Re=await K.api(Ae,"GET","/ip/dhcp-server/lease");for(let ke of Re){if(ke.status!=="bound")continue;let ze=ke["host-name"]||ke["mac-address"]||ke.address;G.push({name:ze,assetType:"network_device",sourceSkill:"mikrotik",sourceId:`dhcp:${re.name}:${ke["mac-address"]??ke.address}`,ipAddress:ke.address,attributes:{mac:ke["mac-address"],hostname:ke["host-name"],server:ke.server,dynamic:ke.dynamic}})}}catch{}}return{assets:G,relations:V}}),M.setCmdbCallback?.(async G=>{try{let V=this.config.security?.ownerUserId??"",K=await this.userRepo?.findOrCreate("telegram",V),U=K?.masterUserId??K?.id??V;G.host&&await q.upsertAsset(U,{name:G.project??"deployed-app",assetType:"application",sourceSkill:"deploy",sourceId:`deploy:${G.host}:${G.project}`,ipAddress:G.host,status:"active",attributes:G}),await q.logChange(U,null,"created","deploy",void 0,void 0,void 0,`Full deploy: ${G.project??"app"} auf ${G.host??"?"}`,"deploy_skill")}catch{}}),M.setPostDeployCallback?.(async(G,V)=>{try{let K=this.ownerMasterUserId||this.config.security?.ownerUserId||"",U=A.get("cmdb");U&&(await H.execute(U,{action:"discover_source",source:"proxmox"},{userId:K,masterUserId:K}),this.logger.info({host:G,project:V},"Post-deploy: CMDB Proxmox discovery completed"));let re=(await q.listAssets(K,{search:G}))?.[0];if(re){let Ae=A.get("infra_docs");Ae&&(await H.execute(Ae,{action:"generate_system_doc",asset_id:re.id,deep_scan:!0},{userId:K,masterUserId:K}),this.logger.info({host:G,project:V,assetId:re.id},"Post-deploy: Deep Scan completed"));let xe=A.get("itsm");if(xe){let ne=`Service "${V}" deployed auf ${re.name} (${G}). Host-Asset: ${re.name}, IP: ${G}. Automatisch erstellt nach full_deploy.`;await H.execute(xe,{action:"create_service_from_description",description:ne},{userId:K,masterUserId:K}),this.logger.info({host:G,project:V},"Post-deploy: Service auto-created")}}else this.logger.warn({host:G,project:V},"Post-deploy: Host asset not found in CMDB \u2014 skipping Deep Scan + Service")}catch(K){this.logger.warn({err:K,host:G,project:V},"Post-deploy callback failed")}}),this.config.cmdb?.autoIncidentFromMonitor!==!1&&A.has("monitor")){let G=A.get("monitor"),V=G.execute.bind(G);G.execute=async(K,U)=>{let re=await V(K,U);if(re.success){let Ae=this.ownerMasterUserId||U.masterUserId||U.userId,xe=Array.isArray(re.data)?re.data:[];if(xe.length>0){let ne=new Map,ve=[],Ye=await q.listAssets(Ae),Qe=new Map;for(let he of Ye)he.name&&Qe.set(he.name.toLowerCase(),he.id),he.hostname&&Qe.set(he.hostname.toLowerCase(),he.id);for(let he of xe)try{let Re=new Set(["device","connected","state","status","failed","error","warning","health","check","entities","unavailable","subsystem","battery","settings","offline","online"]),ke=he.message.split(/[\s"()]+/).filter(Nt=>Nt.length>=4&&!Re.has(Nt.toLowerCase())).map(Nt=>Nt.toLowerCase()),ze=he.message.toLowerCase().includes("offline")||he.message.toLowerCase().includes("critical")?"critical":he.message.toLowerCase().includes("high")||he.message.toLowerCase().includes("cpu")?"high":"medium",et=he.message.toLowerCase(),$t=new Set;for(let[Nt,mr]of Qe)Nt.length>=3&&new RegExp(`\\b${Nt.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}\\b`).test(et)&&$t.add(mr);let jt=[...$t],Vt=await J.findOpenIncidentForAsset(Ae,he.source,ke);if(Vt){await J.appendSymptoms(Ae,Vt.id,he.message),ne.has(he.source)||ne.set(he.source,Vt.id);continue}let Bt=ne.get(he.source);if(!Bt){let Nt=await J.findRecentIncidentForSource(Ae,he.source,4);Nt&&(Bt=Nt.id)}let ts=await J.createIncident(Ae,{title:`${he.source}: ${he.message.slice(0,100)}`,severity:ze,symptoms:he.message,detectedBy:"monitor",relatedIncidentId:Bt,affectedAssetIds:jt});ne.has(he.source)||ne.set(he.source,ts.id),ve.push(ts.id)}catch(Re){this.logger.warn({err:Re.message,source:he.source},"Auto-incident creation failed")}if(ve.length>0&&this.confirmationQueue)try{let he=await Me.detectPatterns(Ae,{windowDays:14,minIncidents:3});for(let Re of he.slice(0,3)){if(Re.existingProblemId||!Re.incidentIds.some(jt=>ve.includes(jt)))continue;let ze=`Wiederkehrende Incidents: ${Re.keywordCluster.slice(0,4).join(", ")||"unbenannt"} (${Re.incidentCount}\xD7 in ${Math.ceil((Date.now()-new Date(Re.firstSeen).getTime())/864e5)}d)`,et=`Pattern erkannt: ${Re.incidentCount} \xE4hnliche Incidents [${Re.keywordCluster.slice(0,5).join(", ")}]. Problem-Ticket erstellen f\xFCr Root-Cause-Analyse?`,$t=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:$t,source:"reasoning",sourceId:`itsm-pattern-${Re.patternKey}`,description:et,skillName:"itsm",skillParams:{action:"create_problem",title:ze,priority:Re.incidentCount>=5?"high":"medium",linked_incident_ids:Re.incidentIds,symptoms:Re.keywordCluster.join(", ")},timeoutMinutes:1440}),this.logger.info({pattern:Re.patternKey,incidentCount:Re.incidentCount},"ITSM pattern-detection: problem-creation suggested")}}catch(he){this.logger.warn({err:he.message},"Pattern-detection failed")}try{let he=A.get("itsm");he&&await H.execute(he,{action:"health_check"},{userId:Ae,masterUserId:Ae})}catch{}}try{let ne=K.checks??[],ve=[];this.config.proxmox&&ve.push("proxmox"),this.config.unifi&&ve.push("unifi"),this.config.homeassistant&&ve.push("homeassistant"),this.config.proxmoxBackup&&ve.push("proxmox_backup");let Ye=ne.length>0?ne:ve,Qe=new Set;for(let Re of xe)Re.message.startsWith("Health check failed")&&Qe.add(Re.source);let he=Ye.filter(Re=>!Qe.has(Re));if(he.length>0){let ke=await J.findRecoveryCandidates(Ae,60),ze=0;for(let et of ke){let $t=et.title.toLowerCase(),jt=he.find(Bt=>$t.startsWith(`${Bt}:`));if(!jt)continue;let Vt=Math.floor((Date.now()-new Date(et.updatedAt).getTime())/6e4);try{await J.updateIncident(Ae,et.id,{status:"resolved",resolution:`\u{1F504} Auto-resolved: Monitor-Bedingung f\xFCr "${jt}" ist seit ${Vt}min nicht mehr aufgetreten. Finaler Close liegt beim User.`}),ze++,this.logger.info({incidentId:et.id,source:jt,ageMinutes:Vt},"ITSM auto-recovery: incident resolved")}catch(Bt){this.logger.warn({err:Bt.message,incidentId:et.id},"ITSM auto-recovery: update failed")}}ze>0&&this.logger.info({resolvedCount:ze,cleanSources:he},`ITSM auto-recovery: ${ze} incident(s) resolved`)}}catch(ne){this.logger.warn({err:ne.message},"ITSM auto-recovery scan failed")}}return re}}Y.setIpResolverCallback(async()=>{let G=[];if(A.has("pfsense"))try{let V=await H.execute(A.get("pfsense"),{action:"list_arp"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data)K.mac&&K.ip&&G.push({mac:String(K.mac),ip:String(K.ip),hostname:K.hostname,source:"pfsense_arp"})}catch{}if(A.has("pfsense"))try{let V=await H.execute(A.get("pfsense"),{action:"list_dhcp_leases"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data)K.mac&&K.ip&&G.push({mac:String(K.mac),ip:String(K.ip),hostname:K.hostname,source:"pfsense_dhcp"})}catch{}if(A.has("unifi"))try{let V=await H.execute(A.get("unifi"),{action:"list_clients"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data)K.mac&&K.ip&&G.push({mac:String(K.mac),ip:String(K.ip),hostname:K.hostname??K.name,source:"unifi"})}catch{}return G}),this.config.cmdb?.kgSync!==!1&&Y.setKgSyncCallback(async G=>{if(!this.kgServiceRef)return;let V=await q.listAssets(G),U=(await q.getAllRelations(G)).map(re=>{let Ae=V.find(ne=>ne.id===re.sourceAssetId),xe=V.find(ne=>ne.id===re.targetAssetId);return{sourceEntityName:Ae?.name??"",targetEntityName:xe?.name??"",relationType:re.relationType}}).filter(re=>re.sourceEntityName&&re.targetEntityName);await this.kgServiceRef.syncFromCmdb(G,V,U)});{let G=Te.execute.bind(Te);Te.execute=async(V,K)=>{let U=await G(V,K);try{let re=V.action==="update_incident"||V.action==="close_incident",Ae=V.status??"",xe=re&&(Ae==="resolved"||Ae==="closed"),ne=V.root_cause??"",ve=V.resolution??"",Ye=/workaround|temporary|tempor[äa]r|kurzfristig|notfall|manuell.*neustart/i.test(ve);if(U.success&&xe&&ne.length>=20&&ve.length>=20&&!Ye&&this.confirmationQueue){let Qe=U.data??{},he=Qe.title??"(unbenannt)",Re=Qe.id??"",ke=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:ke,source:"reasoning",sourceId:`itsm-fix-change-${Re.slice(0,8)}`,description:`Permanenten Fix als Change-Request anlegen f\xFCr: ${he.slice(0,80)}?`,skillName:"itsm",skillParams:{action:"create_change_request",title:`Fix: ${he.slice(0,100)}`,type:"normal",risk_level:"medium",description:`Root Cause: ${ne}
5310
+ ${Ge.goal.slice(0,600)}`}],tier:"fast",maxTokens:30,temperature:.1})).content.trim().replace(/^["'"„""]|["'"„""]$/g,"").slice(0,60);_e.length>=8&&(se=_e)}catch{}await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:Te,source:"reasoning",sourceId:`runbook-from-project-${Le.slice(0,8)}`,description:`Runbook aus Project-Agent-Session erstellen: "${se}"?`,skillName:"runbook",skillParams:{action:"create",title:se,symptom:`Initialer Goal: ${Ge.goal}`,steps:Ue.milestonesReached,source_type:"project_agent",source_id:Le,status:"draft",tags:["project-agent","auto"]},timeoutMinutes:1440}),this.logger.info({sessionId:Le,milestones:Ue.milestonesReached.length,title:se},"Project-agent runbook suggestion enqueued")}}}catch(me){this.logger.debug({err:me},"Runbook suggestion (project-agent) failed")}if(Fe&&this.memoryRepo&&this.confirmationQueue)try{let me=this.ownerMasterUserId??this.config.security?.ownerUserId??"";if(!me)return;let Y=(Ge.cwd??"").replace(/\/+$/,"").split("/").filter(Boolean).pop();if(!Y)return;let Be=(await this.memoryRepo.search(me,`deploy_${Y}_`)).filter(he=>he.category==="deployment"&&he.key.startsWith(`deploy_${Y}_`)).sort((he,Re)=>Re.updatedAt.localeCompare(he.updatedAt))[0];if(!Be)return;let _e=Be.value,pt=_e.match(/→\s*([\w.-]+)\s*\(/),St=_e.match(/user=([^,)]+)/),G=_e.match(/port=(\d+)/),V=_e.match(/pm=([^,)]+)/),K=_e.match(/runtime=([^,)]+)/);if(!pt)return;let U=pt[1],re=St?.[1]??"root",Ae=G?Number(G[1]):void 0,xe=V?.[1],ne=K?.[1],ve=`auto-deploy-from-project-${Le.slice(0,8)}`,Ye=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",et={action:"deploy",host:U,user:re,project:Y};Ae!==void 0&&(et.app_port=Ae),xe&&(et.process_manager=xe),ne&&(et.runtime=ne),await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:Ye,source:"reasoning",sourceId:ve,description:`Project Agent fertig \u2014 auch nach \`${U}\`${Ae?`:${Ae}`:""} (user \`${re}\`${xe?`, pm ${xe}`:""}) deployen wie letztes Mal?`,skillName:"deploy",skillParams:et,timeoutMinutes:60}),this.logger.info({sessionId:Le,host:U,projectName:Y,port:Ae},"Project-agent auto-deploy suggestion enqueued")}catch(me){this.logger.debug({err:me},"Auto-deploy suggestion (project-agent) failed")}}}),A.register(le),this.logger.info("Project agent skill enabled")}if(this.config.proxmox){let{ProxmoxSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(this.config.proxmox),X=this.config.infra?.sshKeyPath??`${process.env.HOME??"/root"}/.ssh/id_ed25519`;M.setSshKeyPath(X),M.setSshUser(this.config.infra?.sshUser??"root"),M.setPostProvisionCallback(async(q,J,le,Ee,Me)=>{let{execFile:Le}=await import("node:child_process"),{promisify:Ge}=await import("node:util"),Ue=Ge(Le),Fe=[],me=f(async se=>{let{stdout:Be}=await Ue("ssh",["-i",X,"-o","StrictHostKeyChecking=no","-o","UserKnownHostsFile=/dev/null","-o","ConnectTimeout=10",`${J}@${q}`,se],{maxBuffer:5242880,timeout:3e5});return Be.trim()},"runSsh");Fe.push("\u23F3 Warte auf SSH + Cloud-Init...");let Y=!1,Te=Date.now();for(await new Promise(se=>setTimeout(se,2e4));Date.now()-Te<18e4;){try{await me("echo ok"),Y=!0;break}catch{}await new Promise(se=>setTimeout(se,15e3))}if(!Y)return Fe.push(`\u274C SSH nicht erreichbar nach ${Math.round((Date.now()-Te)/1e3)}s`),Fe;Fe.push(`\u2705 SSH erreichbar nach ${Math.round((Date.now()-Te)/1e3)}s`);try{if(le==="docker"){if(await me("curl -fsSL https://get.docker.com | sudo sh && sudo usermod -aG docker $USER"),Ee?await me("sudo dnf install -y docker-compose-plugin").catch(()=>{}):await me("sudo apt-get install -y docker-compose-plugin || sudo apt-get install -y docker-compose").catch(()=>{}),Fe.push("\u{1F433} Docker + Docker Compose installiert"),Me?.dockerBridgeIp)try{await me(`echo '{"bip":"${Me.dockerBridgeIp}"}' | sudo tee /etc/docker/daemon.json && sudo systemctl restart docker`),Fe.push(`\u{1F310} Docker Bridge: ${Me.dockerBridgeIp}`)}catch{Fe.push("\u26A0\uFE0F Docker Bridge IP Konfiguration fehlgeschlagen")}}else le==="node"?(Ee?await me("curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash - && sudo dnf install -y nodejs && sudo npm install -g pm2"):await me("curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs && sudo npm install -g pm2 && sudo pm2 startup systemd -u $USER --hp /home/$USER"),Fe.push("\u{1F4E6} Node.js + pm2 installiert")):le==="python"&&(Ee?await me("sudo dnf install -y python3 python3-pip"):await me("sudo apt-get update && sudo apt-get install -y python3 python3-pip python3-venv"),Fe.push("\u{1F40D} Python installiert"))}catch(se){Fe.push(`\u26A0\uFE0F Runtime-Installation: ${se.message?.slice(0,100)}`)}try{Ee?await me("sudo dnf install -y qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent"):await me("sudo apt-get install -y qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent"),Fe.push("\u{1F4E1} qemu-guest-agent installiert")}catch{Fe.push("\u26A0\uFE0F qemu-guest-agent Installation fehlgeschlagen")}try{await me("id -nG | grep -q docker || sudo usermod -aG docker $USER 2>/dev/null")}catch{}return Fe}),A.register(M),this.logger.info({baseUrl:this.config.proxmox.baseUrl,sshKeyPath:X},"Proxmox skill enabled")}if(this.config.unifi){let{UniFiSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.unifi)),this.logger.info({baseUrl:this.config.unifi.baseUrl},"UniFi skill enabled")}if(this.config.homeassistant){let{HomeAssistantSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.homeassistant)),this.logger.info({baseUrl:this.config.homeassistant.baseUrl},"Home Assistant skill enabled")}if(this.config.contacts)try{let{ContactsSkill:N,createContactsProvider:M}=await Promise.resolve().then(()=>(fe(),ye)),X=await M(this.config.contacts);A.register(new N(X)),this.logger.info({provider:this.config.contacts.provider},"Contacts skill enabled")}catch(N){this.logger.warn({err:N},"Contacts initialization failed, continuing without contacts")}if(this.config.docker){let{DockerSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.docker)),this.logger.info("Docker skill enabled")}if(this.config.bmw){let{BMWSkill:N}=await Promise.resolve().then(()=>(fe(),ye));this.bmwSkill=new N(this.config.bmw),A.register(this.bmwSkill),this.logger.info("BMW CarData skill enabled")}if(this.config.goeCharger?.host){let{GoeChargerSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.goeCharger,this.config.energy)),this.logger.info({host:this.config.goeCharger.host},"go-e Charger skill registered")}if(this.config.routing){let{RoutingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.routing)),this.logger.info("Routing skill enabled")}if(this.config.todo){let{MicrosoftTodoSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.todo)),this.logger.info("Microsoft To Do skill enabled")}if(this.config.todo){let{OneDriveSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.todo)),this.logger.info("OneDrive skill registered")}if(this.config.proxmox||this.config.unifi||this.config.homeassistant||this.config.proxmoxBackup){let{MonitorSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N({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:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.energy)),this.logger.info({grid:this.config.energy?.gridName},"Energy price skill registered")}{let{CryptoPriceSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N),this.logger.info("Crypto price skill registered")}{let{BitpandaSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.bitpanda)),this.logger.info({hasApiKey:!!this.config.bitpanda?.apiKey},"Bitpanda skill registered")}if(this.config.trading?.exchanges&&Object.keys(this.config.trading.exchanges).length>0){let{TradingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.trading)),this.logger.info({exchanges:Object.keys(this.config.trading.exchanges)},"Trading skill registered")}{let{RecipeSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{RecipeFavoriteRepository:M,MealPlanRepository:X,AlfredUserRepository:q}=await Promise.resolve().then(()=>(Je(),Ze)),J=new M(e),le=new X(e),Ee=new q(e);A.register(new N(this.config.recipe,{favorites:J,mealPlans:le,userRepo:Ee})),this.logger.info({hasSpoonacular:!!this.config.recipe?.spoonacular?.apiKey,hasEdamam:!!this.config.recipe?.edamam?.appId},"Recipe skill registered")}if(this.config.spotify?.clientId){let{SpotifySkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=this.config.api?.publicUrl??`http://${this.config.api?.host??"localhost"}:${this.config.api?.port??3420}`;this.spotifySkill=new N(this.config.spotify,M),A.register(this.spotifySkill),this.logger.info("Spotify skill registered")}{let{SonosSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=this.config.api?.publicUrl??`http://${this.config.api?.host??"localhost"}:${this.config.api?.port??3420}`;this.sonosSkill=new N(this.config.sonos,M,n,r),A.register(this.sonosSkill),this.logger.info({hasCloud:!!this.config.sonos?.cloud},"Sonos skill registered")}if(this.config.travel?.booking?.rapidApiKey){let{TravelSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{TravelPlanRepository:M}=await Promise.resolve().then(()=>(Je(),Ze)),X=new M(e);A.register(new N(this.config.travel,{plans:X})),this.logger.info({hasFlights:!0,hasHotels:!0},"Travel skill registered")}if(this.config.mqtt?.brokerUrl){let{MqttSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.mqtt)),this.logger.info({broker:this.config.mqtt.brokerUrl},"MQTT skill registered")}if(this.config.cloudflare?.apiToken){let{CloudflareDnsSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.cloudflare)),this.logger.info("Cloudflare DNS skill registered")}if(this.config.nginxProxyManager?.baseUrl){let{NginxProxyManagerSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.nginxProxyManager)),this.logger.info({baseUrl:this.config.nginxProxyManager.baseUrl},"Nginx Proxy Manager skill registered")}if(this.config.pfsense?.baseUrl){let{PfSenseSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.pfsense)),this.logger.info({baseUrl:this.config.pfsense.baseUrl,auth:this.config.pfsense.authMethod??"apikey"},"pfSense Firewall skill registered")}{let{DeploySkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(this.config.infra),X={};if(A.has("proxmox")&&(X.proxmox=q=>H.execute(A.get("proxmox"),q,{})),A.has("cloudflare_dns")&&(X.cloudflare=q=>H.execute(A.get("cloudflare_dns"),q,{})),A.has("nginx_proxy_manager")&&(X.npm=q=>H.execute(A.get("nginx_proxy_manager"),q,{})),A.has("pfsense")&&(X.firewall=q=>H.execute(A.get("pfsense"),q,{})),A.has("unifi")&&(X.unifi=q=>H.execute(A.get("unifi"),q,{})),M.setOrchestrationCallbacks(X),this.config.codeAgents?.forge&&M.setForgeConfig(this.config.codeAgents.forge),this.database){let{HostCapabilitiesRepository:q}=await Promise.resolve().then(()=>(Je(),Ze));M.setHostCapabilitiesRepo(new q(this.database.getAdapter()))}if(this.memoryRepo){let q=this.config.security?.ownerUserId,J;try{if(q&&this.userRepo){let le=await this.userRepo.findOrCreate("telegram",q);J=le.masterUserId??le.id}}catch{}M.setMemoryRepo(this.memoryRepo,J??q)}if(A.register(M),this.logger.info("Deploy skill registered (with orchestration)"),this.config.mikrotik?.enabled){let{MikroTikSkill:q}=await Promise.resolve().then(()=>(fe(),ye)),J=new q(this.config.mikrotik);A.register(J),this.logger.info("MikroTik skill registered")}if(this.config.cmdb?.enabled!==!1&&(this.config.proxmox||this.config.unifi||this.config.docker||this.config.cloudflare||this.config.nginxProxyManager||this.config.pfsense||this.config.homeassistant||this.config.mikrotik)){let q=new Hs(e),J=new oi(e);J.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;let{ProblemRepository:le,RunbookRepository:Ee}=await Promise.resolve().then(()=>(Je(),Ze)),Me=new le(e),Le=new Ee(e);this.runbookRepo=Le;let{CmdbSkill:Ge,ItsmSkill:Ue,InfraDocsSkill:Fe,RunbookSkill:me}=await Promise.resolve().then(()=>(fe(),ye)),Y=new Ge(q,this.config.cmdb?.staleThresholdDays??7),Te=new Ue(J,q,Me),se=new Fe(q,J),Be=new me(Le);Te.setLlmCallback(async(G,V)=>{if(!this.llmProvider)throw new Error("LLM nicht verf\xFCgbar");return(await this.llmProvider.complete({messages:[{role:"user",content:G}],tier:V??"default",maxTokens:3e3})).content}),Te.setProjectItemCascade(async G=>{if(this.projectRepo)try{let V=await this.projectRepo.findOpenItemsByLinkedIncident(G);for(let K of V)await this.projectRepo.updateOpenItemStatus(K.id,"done")}catch(V){this.logger.debug({err:V,incidentId:G},"ITSM\u2192project cascade failed (non-critical)")}}),se.setLlmCallback(async(G,V)=>{if(!this.llmProvider)throw new Error("LLM nicht verf\xFCgbar");return(await this.llmProvider.complete({messages:[{role:"user",content:G}],tier:V??"default",maxTokens:3e3})).content}),A.has("shell")&&se.setSshCallback(async(G,V,K)=>{let U=A.get("shell"),re=K??this.config.infra?.sshUser,Ae=`ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${re?re+"@":""}${G} '${V.replace(/'/g,"'\\''")}'`,xe=await H.execute(U,{command:Ae},{userId:"",platform:"api",chatId:"",conversationId:""});return xe.success?xe.data?.stdout??xe.display??"":""});let _e=f((G,V)=>{A.has(G)&&Y.registerDiscoverySource(G,V)},"wrapSkillAsSource");if(_e("proxmox",async()=>{let G=[],V=[],K=A.get("proxmox"),U=new Map,re;try{try{let ne=await H.execute(K,{action:"cluster_status"},{});if(ne.success&&Array.isArray(ne.data)){let ve=ne.data.find(Ye=>Ye.type==="cluster");ve&&(re=`cluster:${ve.name}`,G.push({name:ve.name,assetType:"cluster",sourceSkill:"proxmox",sourceId:re,status:ve.quorate?"active":"degraded",attributes:{nodes:ve.nodes,version:ve.version,quorate:ve.quorate}}));for(let Ye of ne.data)Ye.type==="node"&&Ye.name&&Ye.ip&&U.set(Ye.name,Ye.ip)}}catch{}let Ae=await H.execute(K,{action:"list_nodes"},{});if(Ae.success&&Array.isArray(Ae.data))for(let ne of Ae.data)G.push({name:ne.node,assetType:"server",sourceSkill:"proxmox",sourceId:`node:${ne.node}`,ipAddress:U.get(ne.node),status:ne.status==="online"?"active":"inactive",attributes:{cpu:ne.cpu,maxcpu:ne.maxcpu,mem:ne.mem,maxmem:ne.maxmem,uptime:ne.uptime}}),re&&V.push({sourceKey:`proxmox:node:${ne.node}`,targetKey:`proxmox:${re}`,relationType:"part_of"});try{let ne=await H.execute(K,{action:"list_storage",node:""},{});if(ne.success&&Array.isArray(ne.data))for(let ve of ne.data)ve.enabled===!1||ve.enabled===0||(G.push({name:ve.storage,assetType:"storage",sourceSkill:"proxmox",sourceId:`storage:${ve.storage}`,status:ve.active?"active":"inactive",attributes:{storageType:ve.type,content:ve.content,used:ve.used,total:ve.total}}),re&&V.push({sourceKey:`proxmox:${re}`,targetKey:`proxmox:storage:${ve.storage}`,relationType:"connects_to"}))}catch{}let xe=await H.execute(K,{action:"list_vms"},{});if(xe.success&&Array.isArray(xe.data))for(let ne of xe.data){let ve=ne.type==="lxc"?"lxc":"vm",Ye,et;try{let he=ve==="lxc"?`/nodes/${ne.node}/lxc/${ne.vmid}/config`:`/nodes/${ne.node}/qemu/${ne.vmid}/config`,Re=await H.execute(A.get("proxmox"),{action:"api_raw",path:he},{}),ke=Re.success?Re.data:null;if(ke){let ze=String(ke.net0??""),tt=ze.match(/ip=([0-9.]+)/);tt&&(Ye=tt[1]);let $t=ze.match(/(?:virtio|hwaddr)=([0-9A-Fa-f:]+)/);$t&&(et=$t[1].toLowerCase())}}catch{}if(!Ye&&ve==="vm"&&ne.status==="running")try{let he=await H.execute(A.get("proxmox"),{action:"api_raw",path:`/nodes/${ne.node}/qemu/${ne.vmid}/agent/network-get-interfaces`},{});if(he.success&&he.data){let Re=he.data.result??he.data;if(Array.isArray(Re))for(let ke of Re){let ze=ke["ip-addresses"]??[];for(let tt of ze)if(tt["ip-address-type"]==="ipv4"&&!String(tt["ip-address"]).startsWith("127.")){Ye=tt["ip-address"];break}if(Ye)break}}}catch{}G.push({name:ne.name||`${ve}-${ne.vmid}`,assetType:ve,sourceSkill:"proxmox",sourceId:`${ne.node}:${ne.vmid}`,identifier:`vmid:${ne.vmid}`,ipAddress:Ye,status:ne.status==="running"?"active":"inactive",attributes:{vmid:ne.vmid,node:ne.node,cpus:ne.cpus,maxmem:ne.maxmem,maxdisk:ne.maxdisk,mac:et}}),V.push({sourceKey:`proxmox:${ne.node}:${ne.vmid}`,targetKey:`proxmox:node:${ne.node}`,relationType:"hosted_on"})}}catch{}return{assets:G,relations:V}}),_e("docker",async()=>{let G=[],V=[],K=this.config.docker?.host?.replace(/^https?:\/\//,"").replace(/:\d+$/,"");try{let U=await H.execute(A.get("docker"),{action:"containers"},{});if(U.success&&Array.isArray(U.data))for(let re of U.data){let Ae=(re.Names?.[0]??re.Id??"").replace(/^\//,""),xe=(re.Id??"").slice(0,12);G.push({name:Ae,assetType:"container",sourceSkill:"docker",sourceId:xe,status:re.State==="running"?"active":"inactive",ipAddress:K,attributes:{image:re.Image,status:re.Status,ports:re.Ports,host_ip:K}}),K&&V.push({sourceKey:`docker:${xe}`,targetKey:`ip:${K}`,relationType:"runs_on"})}}catch{}return{assets:G,relations:V}}),_e("unifi",async()=>{let G=[];try{let V=await H.execute(A.get("unifi"),{action:"list_devices"},{});if(V.success&&Array.isArray(V.data))for(let U of V.data)G.push({name:U.name||U.mac,assetType:"network_device",sourceSkill:"unifi",sourceId:`device:${U.mac??U._id}`,ipAddress:U.ip,status:U.state===1?"active":"inactive",attributes:{mac:U.mac,model:U.model,type:U.type,version:U.version}});let K=await H.execute(A.get("unifi"),{action:"list_networks"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.name||U._id,assetType:"network",sourceSkill:"unifi",sourceId:`net:${U._id}`,attributes:{vlan:U.vlan_enabled?U.vlan:void 0,subnet:U.ip_subnet}})}catch{}return{assets:G,relations:[]}}),_e("cloudflare_dns",async()=>{let G=[];try{let V=await H.execute(A.get("cloudflare_dns"),{action:"list_zones"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data){let U=await H.execute(A.get("cloudflare_dns"),{action:"list_records",domain:K.name},{});if(U.success&&Array.isArray(U.data))for(let re of U.data)G.push({name:`${re.name} (${re.type})`,assetType:"dns_record",sourceSkill:"cloudflare_dns",sourceId:`${K.id}:${re.id}`,fqdn:re.name,attributes:{type:re.type,content:re.content,proxied:re.proxied,ttl:re.ttl,zone:K.name}})}}catch{}return{assets:G,relations:[]}}),_e("nginx_proxy_manager",async()=>{let G=[];try{let V=await H.execute(A.get("nginx_proxy_manager"),{action:"list_hosts"},{});if(V.success&&Array.isArray(V.data))for(let U of V.data)G.push({name:U.domain_names?.[0]??`host-${U.id}`,assetType:"proxy_host",sourceSkill:"nginx_proxy_manager",sourceId:`host:${U.id}`,attributes:{domain_names:U.domain_names,forward_host:U.forward_host,forward_port:U.forward_port,forward_scheme:U.forward_scheme,ssl_forced:U.ssl_forced}});let K=await H.execute(A.get("nginx_proxy_manager"),{action:"list_certificates"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.nice_name||U.domain_names?.[0]||`cert-${U.id}`,assetType:"certificate",sourceSkill:"nginx_proxy_manager",sourceId:`cert:${U.id}`,attributes:{domain_names:U.domain_names,expires_on:U.expires_on,provider:U.provider}})}catch{}return{assets:G,relations:[]}}),_e("pfsense",async()=>{let G=[],V=A.get("pfsense");try{let K=await H.execute(V,{action:"list_rules"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.descr||`rule-${U.id}`,assetType:"firewall_rule",sourceSkill:"pfsense",sourceId:`rule:${U.id}`,attributes:{type:U.type,interface:U.interface,protocol:U.protocol,source:U.source,destination:U.destination,destination_address:U.destination?.address}})}catch{}try{let K=await H.execute(V,{action:"list_interfaces"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data){let re=U.descr||U.name||U.if||"unknown",Ae=U.ipaddr&&U.ipaddr!=="dhcp"?U.ipaddr:void 0,xe=U.subnet?`${Ae??""}/${U.subnet}`:void 0;G.push({name:re,assetType:"network",sourceSkill:"pfsense",sourceId:`if:${U.if??re}`,ipAddress:Ae,attributes:{interface:U.if,subnet:xe,vlan:U.tag,enable:U.enable,gateway:U.gateway}})}}catch{}try{let K=await H.execute(V,{action:"list_vlans"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.descr||`VLAN ${U.tag}`,assetType:"network",sourceSkill:"pfsense",sourceId:`vlan:${U.tag}`,attributes:{vlan_tag:U.tag,parent_if:U.parentif??U.if?.split(".")[0],vlanif:U.vlanif??U.if}})}catch{}try{let K=await H.execute(V,{action:"list_gateways"},{});if(K.success&&Array.isArray(K.data))for(let U of K.data)G.push({name:U.name||`gw-${U.interface}`,assetType:"network",sourceSkill:"pfsense",sourceId:`gw:${U.name??U.interface}`,ipAddress:U.gateway,attributes:{interface:U.interface,monitor:U.monitor,status:U.status,default:U.defaultgw}})}catch{}return{assets:G,relations:[]}}),_e("homeassistant",async()=>{let G=[];try{let V=await H.execute(A.get("homeassistant"),{action:"states"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data){let U=K.entity_id;if(!U)continue;let re=U.split(".")[0];if(!["automation","switch","light","sensor","binary_sensor","climate","cover","fan","media_player","camera"].includes(re))continue;let Ae=re==="automation"?"automation":"iot_device";G.push({name:K.attributes?.friendly_name||U,assetType:Ae,sourceSkill:"homeassistant",sourceId:U,status:K.state==="unavailable"?"inactive":"active",attributes:{entity_id:U,domain:re,state:K.state}})}}catch{}return{assets:G,relations:[]}}),_e("mikrotik",async()=>{let G=[],V=[],K=A.get("mikrotik"),U=K.getRouters?.()??[];for(let re of U){let Ae={name:re.name,cfg:re};try{let xe=await K.api(Ae,"GET","/system/resource"),ve=(await K.api(Ae,"GET","/system/identity"))?.name??re.name,Ye={name:ve,assetType:"network_device",sourceSkill:"mikrotik",sourceId:`router:${re.name}`,ipAddress:re.host,status:"active",attributes:{version:xe.version,architecture:xe["architecture-name"],board:xe["board-name"],cpu_count:xe["cpu-count"],total_memory:xe["total-memory"],uptime:xe.uptime}};G.push(Ye);let et=await K.api(Ae,"GET","/interface");for(let ke of et)ke.type==="bridge"||ke.type==="loopback"||(G.push({name:`${ve}/${ke.name}`,assetType:"network",sourceSkill:"mikrotik",sourceId:`if:${re.name}:${ke.name}`,attributes:{type:ke.type,mac:ke["mac-address"],running:ke.running,mtu:ke["actual-mtu"]}}),V.push({sourceEntityName:`${ve}/${ke.name}`,targetEntityName:ve,relationType:"part_of"}));let he=await K.api(Ae,"GET","/ip/firewall/filter");for(let ke of he.slice(0,50)){let ze=ke.comment||`${ke.chain}-${ke.action}-${ke[".id"]}`;G.push({name:`${ve}/fw/${ze}`,assetType:"firewall_rule",sourceSkill:"mikrotik",sourceId:`fw:${re.name}:${ke[".id"]}`,attributes:{chain:ke.chain,action:ke.action,src:ke["src-address"],dst:ke["dst-address"],protocol:ke.protocol,port:ke["dst-port"],disabled:ke.disabled}})}let Re=await K.api(Ae,"GET","/ip/dhcp-server/lease");for(let ke of Re){if(ke.status!=="bound")continue;let ze=ke["host-name"]||ke["mac-address"]||ke.address;G.push({name:ze,assetType:"network_device",sourceSkill:"mikrotik",sourceId:`dhcp:${re.name}:${ke["mac-address"]??ke.address}`,ipAddress:ke.address,attributes:{mac:ke["mac-address"],hostname:ke["host-name"],server:ke.server,dynamic:ke.dynamic}})}}catch{}}return{assets:G,relations:V}}),M.setCmdbCallback?.(async G=>{try{let V=this.config.security?.ownerUserId??"",K=await this.userRepo?.findOrCreate("telegram",V),U=K?.masterUserId??K?.id??V;G.host&&await q.upsertAsset(U,{name:G.project??"deployed-app",assetType:"application",sourceSkill:"deploy",sourceId:`deploy:${G.host}:${G.project}`,ipAddress:G.host,status:"active",attributes:G}),await q.logChange(U,null,"created","deploy",void 0,void 0,void 0,`Full deploy: ${G.project??"app"} auf ${G.host??"?"}`,"deploy_skill")}catch{}}),M.setPostDeployCallback?.(async(G,V)=>{try{let K=this.ownerMasterUserId||this.config.security?.ownerUserId||"",U=A.get("cmdb");U&&(await H.execute(U,{action:"discover_source",source:"proxmox"},{userId:K,masterUserId:K}),this.logger.info({host:G,project:V},"Post-deploy: CMDB Proxmox discovery completed"));let re=(await q.listAssets(K,{search:G}))?.[0];if(re){let Ae=A.get("infra_docs");Ae&&(await H.execute(Ae,{action:"generate_system_doc",asset_id:re.id,deep_scan:!0},{userId:K,masterUserId:K}),this.logger.info({host:G,project:V,assetId:re.id},"Post-deploy: Deep Scan completed"));let xe=A.get("itsm");if(xe){let ne=`Service "${V}" deployed auf ${re.name} (${G}). Host-Asset: ${re.name}, IP: ${G}. Automatisch erstellt nach full_deploy.`;await H.execute(xe,{action:"create_service_from_description",description:ne},{userId:K,masterUserId:K}),this.logger.info({host:G,project:V},"Post-deploy: Service auto-created")}}else this.logger.warn({host:G,project:V},"Post-deploy: Host asset not found in CMDB \u2014 skipping Deep Scan + Service")}catch(K){this.logger.warn({err:K,host:G,project:V},"Post-deploy callback failed")}}),this.config.cmdb?.autoIncidentFromMonitor!==!1&&A.has("monitor")){let G=A.get("monitor"),V=G.execute.bind(G);G.execute=async(K,U)=>{let re=await V(K,U);if(re.success){let Ae=this.ownerMasterUserId||U.masterUserId||U.userId,xe=Array.isArray(re.data)?re.data:[];if(xe.length>0){let ne=new Map,ve=[],Ye=await q.listAssets(Ae),et=new Map;for(let he of Ye)he.name&&et.set(he.name.toLowerCase(),he.id),he.hostname&&et.set(he.hostname.toLowerCase(),he.id);for(let he of xe)try{let Re=new Set(["device","connected","state","status","failed","error","warning","health","check","entities","unavailable","subsystem","battery","settings","offline","online"]),ke=he.message.split(/[\s"()]+/).filter(Nt=>Nt.length>=4&&!Re.has(Nt.toLowerCase())).map(Nt=>Nt.toLowerCase()),ze=he.message.toLowerCase().includes("offline")||he.message.toLowerCase().includes("critical")?"critical":he.message.toLowerCase().includes("high")||he.message.toLowerCase().includes("cpu")?"high":"medium",tt=he.message.toLowerCase(),$t=new Set;for(let[Nt,mr]of et)Nt.length>=3&&new RegExp(`\\b${Nt.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")}\\b`).test(tt)&&$t.add(mr);let jt=[...$t],Vt=await J.findOpenIncidentForAsset(Ae,he.source,ke);if(Vt){await J.appendSymptoms(Ae,Vt.id,he.message),ne.has(he.source)||ne.set(he.source,Vt.id);continue}let Bt=ne.get(he.source);if(!Bt){let Nt=await J.findRecentIncidentForSource(Ae,he.source,4);Nt&&(Bt=Nt.id)}let ts=await J.createIncident(Ae,{title:`${he.source}: ${he.message.slice(0,100)}`,severity:ze,symptoms:he.message,detectedBy:"monitor",relatedIncidentId:Bt,affectedAssetIds:jt});ne.has(he.source)||ne.set(he.source,ts.id),ve.push(ts.id)}catch(Re){this.logger.warn({err:Re.message,source:he.source},"Auto-incident creation failed")}if(ve.length>0&&this.confirmationQueue)try{let he=await Me.detectPatterns(Ae,{windowDays:14,minIncidents:3});for(let Re of he.slice(0,3)){if(Re.existingProblemId||!Re.incidentIds.some(jt=>ve.includes(jt)))continue;let ze=`Wiederkehrende Incidents: ${Re.keywordCluster.slice(0,4).join(", ")||"unbenannt"} (${Re.incidentCount}\xD7 in ${Math.ceil((Date.now()-new Date(Re.firstSeen).getTime())/864e5)}d)`,tt=`Pattern erkannt: ${Re.incidentCount} \xE4hnliche Incidents [${Re.keywordCluster.slice(0,5).join(", ")}]. Problem-Ticket erstellen f\xFCr Root-Cause-Analyse?`,$t=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:$t,source:"reasoning",sourceId:`itsm-pattern-${Re.patternKey}`,description:tt,skillName:"itsm",skillParams:{action:"create_problem",title:ze,priority:Re.incidentCount>=5?"high":"medium",linked_incident_ids:Re.incidentIds,symptoms:Re.keywordCluster.join(", ")},timeoutMinutes:1440}),this.logger.info({pattern:Re.patternKey,incidentCount:Re.incidentCount},"ITSM pattern-detection: problem-creation suggested")}}catch(he){this.logger.warn({err:he.message},"Pattern-detection failed")}try{let he=A.get("itsm");he&&await H.execute(he,{action:"health_check"},{userId:Ae,masterUserId:Ae})}catch{}}try{let ne=K.checks??[],ve=[];this.config.proxmox&&ve.push("proxmox"),this.config.unifi&&ve.push("unifi"),this.config.homeassistant&&ve.push("homeassistant"),this.config.proxmoxBackup&&ve.push("proxmox_backup");let Ye=ne.length>0?ne:ve,et=new Set;for(let Re of xe)Re.message.startsWith("Health check failed")&&et.add(Re.source);let he=Ye.filter(Re=>!et.has(Re));if(he.length>0){let ke=await J.findRecoveryCandidates(Ae,60),ze=0;for(let tt of ke){let $t=tt.title.toLowerCase(),jt=he.find(Bt=>$t.startsWith(`${Bt}:`));if(!jt)continue;let Vt=Math.floor((Date.now()-new Date(tt.updatedAt).getTime())/6e4);try{await J.updateIncident(Ae,tt.id,{status:"resolved",resolution:`\u{1F504} Auto-resolved: Monitor-Bedingung f\xFCr "${jt}" ist seit ${Vt}min nicht mehr aufgetreten. Finaler Close liegt beim User.`}),ze++,this.logger.info({incidentId:tt.id,source:jt,ageMinutes:Vt},"ITSM auto-recovery: incident resolved")}catch(Bt){this.logger.warn({err:Bt.message,incidentId:tt.id},"ITSM auto-recovery: update failed")}}ze>0&&this.logger.info({resolvedCount:ze,cleanSources:he},`ITSM auto-recovery: ${ze} incident(s) resolved`)}}catch(ne){this.logger.warn({err:ne.message},"ITSM auto-recovery scan failed")}}return re}}Y.setIpResolverCallback(async()=>{let G=[];if(A.has("pfsense"))try{let V=await H.execute(A.get("pfsense"),{action:"list_arp"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data)K.mac&&K.ip&&G.push({mac:String(K.mac),ip:String(K.ip),hostname:K.hostname,source:"pfsense_arp"})}catch{}if(A.has("pfsense"))try{let V=await H.execute(A.get("pfsense"),{action:"list_dhcp_leases"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data)K.mac&&K.ip&&G.push({mac:String(K.mac),ip:String(K.ip),hostname:K.hostname,source:"pfsense_dhcp"})}catch{}if(A.has("unifi"))try{let V=await H.execute(A.get("unifi"),{action:"list_clients"},{});if(V.success&&Array.isArray(V.data))for(let K of V.data)K.mac&&K.ip&&G.push({mac:String(K.mac),ip:String(K.ip),hostname:K.hostname??K.name,source:"unifi"})}catch{}return G}),this.config.cmdb?.kgSync!==!1&&Y.setKgSyncCallback(async G=>{if(!this.kgServiceRef)return;let V=await q.listAssets(G),U=(await q.getAllRelations(G)).map(re=>{let Ae=V.find(ne=>ne.id===re.sourceAssetId),xe=V.find(ne=>ne.id===re.targetAssetId);return{sourceEntityName:Ae?.name??"",targetEntityName:xe?.name??"",relationType:re.relationType}}).filter(re=>re.sourceEntityName&&re.targetEntityName);await this.kgServiceRef.syncFromCmdb(G,V,U)});{let G=Te.execute.bind(Te);Te.execute=async(V,K)=>{let U=await G(V,K);try{let re=V.action==="update_incident"||V.action==="close_incident",Ae=V.status??"",xe=re&&(Ae==="resolved"||Ae==="closed"),ne=V.root_cause??"",ve=V.resolution??"",Ye=/workaround|temporary|tempor[äa]r|kurzfristig|notfall|manuell.*neustart/i.test(ve);if(U.success&&xe&&ne.length>=20&&ve.length>=20&&!Ye&&this.confirmationQueue){let et=U.data??{},he=et.title??"(unbenannt)",Re=et.id??"",ke=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:ke,source:"reasoning",sourceId:`itsm-fix-change-${Re.slice(0,8)}`,description:`Permanenten Fix als Change-Request anlegen f\xFCr: ${he.slice(0,80)}?`,skillName:"itsm",skillParams:{action:"create_change_request",title:`Fix: ${he.slice(0,100)}`,type:"normal",risk_level:"medium",description:`Root Cause: ${ne}
5300
5311
 
5301
5312
  L\xF6sung im Incident: ${ve}
5302
5313
 
5303
- Urspr\xFCnglicher Incident: ${Re}`,related_incident_id:Re},timeoutMinutes:1440}),this.logger.info({incidentId:Re,title:he.slice(0,60)},"ITSM auto-change suggestion enqueued");try{let ze=K?.masterUserId??K?.userId??this.ownerMasterUserId??"";if(!ze)throw new Error("no user for runbook lookup");await Le.findBySource(ze,"itsm_incident",Re)||(await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:ke,source:"reasoning",sourceId:`runbook-from-incident-${Re.slice(0,8)}`,description:`Runbook aus Incident-L\xF6sung erstellen: "${he.slice(0,80)}"?`,skillName:"runbook",skillParams:{action:"create",title:he.slice(0,120),symptom:V.symptoms??he,cause:ne,steps:ve.split(/\n+/).filter($t=>$t.trim().length>0),source_type:"itsm_incident",source_id:Re,status:"draft"},timeoutMinutes:1440}),this.logger.info({incidentId:Re},"ITSM auto-runbook suggestion enqueued"))}catch(ze){this.logger.debug({err:ze.message},"Auto-runbook suggestion failed")}}}catch(re){this.logger.debug({err:re.message},"ITSM auto-change-suggestion hook failed")}return U}}A.register(Y),A.register(Te),A.register(se),A.register(Be);let pt=this.config.cmdb?.autoDiscoveryIntervalHours??24;if(pt>0){let G=pt*36e5;setTimeout(()=>{let V=this.ownerMasterUserId||this.config.security?.ownerUserId||"";V&&Y.execute({action:"discover"},{userId:V,masterUserId:V}).catch(()=>{}),this.cmdbDiscoveryTimer=setInterval(()=>{V&&Y.execute({action:"discover"},{userId:V,masterUserId:V}).catch(()=>{})},G)},12e4),this.logger.info({intervalHours:pt},"CMDB auto-discovery scheduled")}let St=this.config.cmdb?.healthCheckIntervalMinutes??60;if(St>0){let G=St*6e4;setTimeout(()=>{let V=this.ownerMasterUserId||this.config.security?.ownerUserId||"",K=f(()=>{V&&Te.execute({action:"health_check"},{userId:V,masterUserId:V}).catch(()=>{})},"runHealthCheck");K(),this.cmdbHealthCheckTimer=setInterval(K,G)},18e4)}this.logger.info("CMDB + ITSM + InfraDocs skills registered")}}{let{MarketplaceSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{ShoppingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N),this.logger.info("Shopping skill registered")}{let{BriefingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(A,this.config,n)),this.logger.info("Briefing skill registered")}A.register(new Yn(r)),this.logger.info("Feed reader skill registered");let Qt=new Jn(A);A.register(Qt);{let{OnboardingSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N;if(n){let X=this.ownerMasterUserId||"";M.setMemoryCallback(async(q,J,le,Ee)=>{await n.saveWithMetadata(X,q,J,Ee,le,1,"manual")})}A.register(M)}{let{AlfredUserRepository:N}=await Promise.resolve().then(()=>(Je(),tt)),{UserManagementSkill:M}=await Promise.resolve().then(()=>(fe(),ye)),X=new N(e);if(this.config.security?.ownerUserId){let Ue=this.config.security.ownerUserId,Y=(await X.getAll()).filter(se=>se.role==="admin")[0];Y||(Y=await X.create({username:"admin",role:"admin",displayName:"Admin"}),await X.clearInviteCode(Y.id),this.logger.info({userId:Ue},"Auto-created admin user from ownerUserId"));let Te=["telegram","discord","matrix","signal","api"];for(let se of Te)if(!await X.getUserByPlatform(se,Ue))try{await X.linkPlatform(Y.id,se,Ue)}catch{}try{let se=await s.findOrCreate("telegram",this.config.security.ownerUserId);this.ownerMasterUserId=se.masterUserId??se.id}catch{this.ownerMasterUserId=Y.id}}let q=(()=>{let Ue=this.config.email?.accounts?.[0]?.microsoft??this.config.email?.microsoft??this.config.calendar?.microsoft??this.config.contacts?.microsoft??this.config.todo;if(Ue?.clientId&&Ue?.clientSecret)return{clientId:Ue.clientId,clientSecret:Ue.clientSecret,tenantId:Ue.tenantId}})(),J={};this.config.calendar?.microsoft&&(J.calendar={provider:"microsoft",microsoft:this.config.calendar.microsoft}),this.config.contacts?.microsoft&&(J.contacts={provider:"microsoft",microsoft:this.config.contacts.microsoft});let le=this.config.email?.accounts?.[0]?.microsoft??this.config.email?.microsoft;le&&(J.email={provider:"microsoft",microsoft:le}),this.config.todo?.clientId&&(J.todo={...this.config.todo}),A.register(new M(X,q,Object.keys(J).length>0?J:void 0)),this.logger.info("User management skill registered"),ms.setAlfredUserLookup(X);let{SharingSkill:Ee}=await Promise.resolve().then(()=>(fe(),ye)),{SharedResourceRepository:Me}=await Promise.resolve().then(()=>(Je(),tt)),Le=new Me(e);A.register(new Ee(Le,X)),Ni.sharedResourceRepo=Le,Se.sharedResourceRepo=Le,Pe.sharedResourceRepo=Le,this.logger.info("Sharing skill registered");let Ge=l;this.webAuthCallback={loginWithCode:f(async Ue=>{let Fe=`web-pending-${Date.now()}`,me=await X.consumeInviteCode(Ue,"api",Fe);if(!me)return{success:!1,error:"Ung\xFCltiger oder abgelaufener Code"};let Y=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,Te=new Date(Date.now()+720*60*6e4).toISOString();return await Ge.createSession(Y,me.id,"web-session",Te),{success:!0,userId:me.id,username:me.username,role:me.role,token:Y}},"loginWithCode"),getUserByToken:f(async Ue=>{let Fe=await Ge.findByToken(Ue);if(!Fe||new Date(Fe.expiresAt)<new Date)return null;let me=await X.getById(Fe.userId);return me?{userId:me.id,username:me.username,role:me.role}:null},"getUserByToken")}}if(this.config.database?.enabled){let{DatabaseSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{DatabaseConnectionRepository:M}=await Promise.resolve().then(()=>(Je(),tt)),X=new M(e),q=new N(this.config.database,X);if(this.config.database.connections)for(let J of this.config.database.connections)await X.getByName(J.name)||await X.create({name:J.name,type:J.type,host:J.host,port:J.port,databaseName:J.database,username:J.username,authConfig:J.password?{password:J.password}:void 0,options:{readOnly:J.options?.readOnly??!0,rowLimit:J.options?.rowLimit,timeoutMs:J.options?.timeoutMs}});A.register(q),this.logger.info("Database skill registered")}if(this.config.backup?.enabled){let{SystemBackupSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=await Promise.resolve().then(()=>(xT(),OT)).catch(()=>({default:{version:"unknown"}})),X=new N(this.config.backup,e,this.config.cluster?.nodeId??"single",M.default.version??"unknown",this.config.fileStore);A.register(X),this.logger.info("System Backup skill registered")}if(this.config.commvault?.enabled){let{CommvaultSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(this.config.commvault);if(this.config.cmdb?.autoIncidentFromMonitor){let X=A.get("itsm");X&&M.setItsmCallback(async q=>X.execute(q,{alfredUserId:this.ownerMasterUserId}))}A.register(M),this.logger.info("Commvault skill registered")}if(this.config.mikrotik?.enabled&&this.config.cmdb?.autoIncidentFromMonitor){let N=A.get("mikrotik"),M=A.get("itsm");N&&M&&N.setItsmCallback(async X=>M.execute(X,{alfredUserId:this.ownerMasterUserId}))}if(this.config.youtube?.apiKey){let{YouTubeSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:A.getAll().map(N=>N.metadata.name)},"Skills registered"),this.config.speech&&(this.config.speech.sttProvider==="mistral"&&!this.config.speech.sttApiKey&&dt&&(this.config.speech.sttApiKey=dt),this.config.speech.ttsProvider==="mistral"&&!this.config.speech.ttsApiKey&&dt&&(this.config.speech.ttsApiKey=dt));let fs;if(this.config.speech?.apiKey){fs=new Oa(this.config.speech,this.logger.child({component:"speech"})),fs.setUsageCallback((M,X)=>{$.record("stt",M,X).catch(()=>{})});let N=this.config.speech.sttProvider??this.config.speech.provider;this.logger.info({provider:N},"Speech-to-text initialized")}if(this.config.speech?.ttsEnabled){let N=new xa(this.config.speech,this.logger.child({component:"tts"}));N.setSkillState(r),N.setUsageCallback((X,q)=>{$.record("tts",X,q).catch(()=>{})}),A.register(new Fn(N));let M=this.config.speech.ttsProvider??"openai";this.logger.info({provider:M},"Text-to-speech skill registered")}{let N=this.config.speech,M=N?.ttsProvider==="mistral"&&N.voiceManagement!==!1,X=N?.ttsApiKey??dt;if(M&&X&&n){let q,J="localhost",le=TR.networkInterfaces();for(let Le of Object.values(le))if(Le){for(let Ge of Le)if(Ge.family==="IPv4"&&!Ge.internal){J=Ge.address;break}if(J!=="localhost")break}let Ee=this.config.api?.port??3420,Me=this.config.api?.tls?.enabled?Ee+2:Ee;q=`http://${J}:${Me}`,A.register(new er(X,"https://api.mistral.ai/v1","voxtral-mini-tts-2603",n,A,q,r)),this.logger.info({announceBaseUrl:q},"Voice management skill registered")}}let Gt=this.detectImageGenProvider();if(Gt){let N=new Ma(Gt,this.logger.child({component:"image-gen"}));A.register(new jn(N)),this.logger.info({provider:Gt.provider},"Image generation skill registered")}try{let N=new Ua(this.logger.child({component:"transit"}));A.register(new Wn(N)),this.logger.info("Public transit skill registered")}catch(N){this.logger.warn({err:N},"Failed to register transit skill")}let gs;if(this.config.fileStore){let{createFileStore:N}=await Promise.resolve().then(()=>(Je(),tt));gs=N(this.config.fileStore),this.logger.info({backend:this.config.fileStore.backend},"File store initialized")}gs&&this.projectAgentRunnerRef&&(this.projectAgentRunnerRef.setFileStore(gs),this.logger.info("Project-agent runner connected to file-store for asset-bridge"));let es=new Na(t),Li=Lt.resolve(Lt.dirname(this.config.storage.path),"inbox");if(this.pipeline=new Ca({llm:b,conversationManager:es,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:A,skillSandbox:H,securityManager:k,memoryRepo:n,speechTranscriber:fs,inboxPath:Li,fileStore:gs,processedMessageRepo:this.config.cluster?.enabled?new(await Promise.resolve().then(()=>(Je(),tt))).ProcessedMessageRepository(e):void 0,nodeId:this.config.cluster?.nodeId??"single",embeddingService:C,activeLearning:O,memoryRetriever:P,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:Ie,conversationSummarizer:oe,personality:this.config.personality}),this.config.cluster?.enabled){if(e.type!=="postgres")throw new Error('HA Cluster erfordert storage.backend: "postgres". SQLite ist nicht f\xFCr Multi-Node geeignet.');if(!this.config.cluster.nodeId)throw new Error("HA Cluster erfordert cluster.nodeId. Jeder Node braucht eine eindeutige ID.");(!this.config.fileStore||this.config.fileStore.backend==="local")&&this.logger.warn('HA Cluster ohne S3/NFS FileStore \u2014 Datei-Uploads sind nur auf dem empfangenden Node sichtbar. Empfohlen: fileStore.backend: "s3" oder "nfs"');let{ClusterManager:N}=await Promise.resolve().then(()=>(zp(),MT));this.clusterManager=new N(this.config.cluster,this.logger.child({component:"cluster"})),await this.clusterManager.connect(),this.clusterManager.isConnected||this.logger.warn("Redis nicht erreichbar \u2014 Cross-Node Pub/Sub und Echtzeit-Heartbeat deaktiviert. PG-Heartbeat als Fallback aktiv.");let{PgMigrator:M,PG_MIGRATIONS:X}=await Promise.resolve().then(()=>(Je(),tt));await new M(e).migrate(X),this.clusterManager.startPgHeartbeat(e),this.logger.info({nodeId:this.config.cluster.nodeId},"Cluster manager initialized (Active-Active)")}this.reminderScheduler=new Da(a,async(N,M,X)=>{let q=this.adapters.get(N);q?await q.sendMessage(M,X):this.logger.warn({platform:N,chatId:M},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:f(N=>s.getMasterUserId(N),"getMasterUserId"),getLinkedUsers:f(N=>s.getLinkedUsers(N),"getLinkedUsers"),findConversation:f((N,M)=>t.findByPlatformAndUser(N,M),"findConversation")},this.config.cluster?.nodeId??"single"),this.backgroundTaskRunner=new Ba(A,H,u,this.adapters,s,this.logger.child({component:"background-tasks"}),m,g);let ut=new Ha(A,H,u,this.adapters,s,this.logger.child({component:"persistent-agents"}),m);this.backgroundTaskRunner.setPersistentRunner(ut),Kt.setPersistentRunner(ut),this.proactiveScheduler=new Xa(h,A,H,b,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,es,m,this.config.cluster?.nodeId??"single");let ys=new Gi(e);this.watchRepo=ys,A.register(new Gn(ys,A));let bt=new Vi(e);this.confirmationQueue=new Ka(bt,A,H,this.adapters,this.logger.child({component:"confirmation-queue"}),m);let It=new en(e),Q=new nr(It,n,this.logger.child({component:"feedback"}));Q.setLLM(b),b.supportsEmbeddings()&&Q.setEmbeddingService(b),setTimeout(()=>{let N=this.ownerMasterUserId??this.config.security?.ownerUserId;N&&Q.migrateCorrectionMemories(N).then(M=>this.logger.info({...M},"Feedback: correction-migration completed")).catch(M=>this.logger.debug({err:M},"Feedback: correction-migration failed (non-critical)"))},3e4),this.confirmationQueue.setFeedbackService(Q),O&&O.setFeedbackService(Q),this.watchEngine=new zl(ys,A,H,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,m,g,b,this.config.cluster?.nodeId??"single");let ie=new Qi(e),ce=new Vn(ie,A);ce.setRunConfirmationCallback(async({chain:N,context:M})=>{if(!this.confirmationQueue)throw new Error("ConfirmationQueue not available");let X=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":M.platform??"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:X,source:"reasoning",sourceId:`workflow-run-${N.id.slice(0,8)}-${Date.now()}`,description:`Workflow '${N.name}' (${N.steps.length} Schritte) ausf\xFChren?`+(N.description?`
5314
+ Urspr\xFCnglicher Incident: ${Re}`,related_incident_id:Re},timeoutMinutes:1440}),this.logger.info({incidentId:Re,title:he.slice(0,60)},"ITSM auto-change suggestion enqueued");try{let ze=K?.masterUserId??K?.userId??this.ownerMasterUserId??"";if(!ze)throw new Error("no user for runbook lookup");await Le.findBySource(ze,"itsm_incident",Re)||(await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:ke,source:"reasoning",sourceId:`runbook-from-incident-${Re.slice(0,8)}`,description:`Runbook aus Incident-L\xF6sung erstellen: "${he.slice(0,80)}"?`,skillName:"runbook",skillParams:{action:"create",title:he.slice(0,120),symptom:V.symptoms??he,cause:ne,steps:ve.split(/\n+/).filter($t=>$t.trim().length>0),source_type:"itsm_incident",source_id:Re,status:"draft"},timeoutMinutes:1440}),this.logger.info({incidentId:Re},"ITSM auto-runbook suggestion enqueued"))}catch(ze){this.logger.debug({err:ze.message},"Auto-runbook suggestion failed")}}}catch(re){this.logger.debug({err:re.message},"ITSM auto-change-suggestion hook failed")}return U}}A.register(Y),A.register(Te),A.register(se),A.register(Be);let pt=this.config.cmdb?.autoDiscoveryIntervalHours??24;if(pt>0){let G=pt*36e5;setTimeout(()=>{let V=this.ownerMasterUserId||this.config.security?.ownerUserId||"";V&&Y.execute({action:"discover"},{userId:V,masterUserId:V}).catch(()=>{}),this.cmdbDiscoveryTimer=setInterval(()=>{V&&Y.execute({action:"discover"},{userId:V,masterUserId:V}).catch(()=>{})},G)},12e4),this.logger.info({intervalHours:pt},"CMDB auto-discovery scheduled")}let St=this.config.cmdb?.healthCheckIntervalMinutes??60;if(St>0){let G=St*6e4;setTimeout(()=>{let V=this.ownerMasterUserId||this.config.security?.ownerUserId||"",K=f(()=>{V&&Te.execute({action:"health_check"},{userId:V,masterUserId:V}).catch(()=>{})},"runHealthCheck");K(),this.cmdbHealthCheckTimer=setInterval(K,G)},18e4)}this.logger.info("CMDB + ITSM + InfraDocs skills registered")}}{let{MarketplaceSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.marketplace)),this.logger.info("Marketplace skill registered")}{let{ShoppingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N),this.logger.info("Shopping skill registered")}{let{BriefingSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(A,this.config,n)),this.logger.info("Briefing skill registered")}A.register(new Yn(r)),this.logger.info("Feed reader skill registered");let Qt=new Jn(A);A.register(Qt);{let{OnboardingSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N;if(n){let X=this.ownerMasterUserId||"";M.setMemoryCallback(async(q,J,le,Ee)=>{await n.saveWithMetadata(X,q,J,Ee,le,1,"manual")})}A.register(M)}{let{AlfredUserRepository:N}=await Promise.resolve().then(()=>(Je(),Ze)),{UserManagementSkill:M}=await Promise.resolve().then(()=>(fe(),ye)),X=new N(e);if(this.config.security?.ownerUserId){let Ue=this.config.security.ownerUserId,Y=(await X.getAll()).filter(se=>se.role==="admin")[0];Y||(Y=await X.create({username:"admin",role:"admin",displayName:"Admin"}),await X.clearInviteCode(Y.id),this.logger.info({userId:Ue},"Auto-created admin user from ownerUserId"));let Te=["telegram","discord","matrix","signal","api"];for(let se of Te)if(!await X.getUserByPlatform(se,Ue))try{await X.linkPlatform(Y.id,se,Ue)}catch{}try{let se=await s.findOrCreate("telegram",this.config.security.ownerUserId);this.ownerMasterUserId=se.masterUserId??se.id}catch{this.ownerMasterUserId=Y.id}}let q=(()=>{let Ue=this.config.email?.accounts?.[0]?.microsoft??this.config.email?.microsoft??this.config.calendar?.microsoft??this.config.contacts?.microsoft??this.config.todo;if(Ue?.clientId&&Ue?.clientSecret)return{clientId:Ue.clientId,clientSecret:Ue.clientSecret,tenantId:Ue.tenantId}})(),J={};this.config.calendar?.microsoft&&(J.calendar={provider:"microsoft",microsoft:this.config.calendar.microsoft}),this.config.contacts?.microsoft&&(J.contacts={provider:"microsoft",microsoft:this.config.contacts.microsoft});let le=this.config.email?.accounts?.[0]?.microsoft??this.config.email?.microsoft;le&&(J.email={provider:"microsoft",microsoft:le}),this.config.todo?.clientId&&(J.todo={...this.config.todo}),A.register(new M(X,q,Object.keys(J).length>0?J:void 0)),this.logger.info("User management skill registered"),ms.setAlfredUserLookup(X);let{SharingSkill:Ee}=await Promise.resolve().then(()=>(fe(),ye)),{SharedResourceRepository:Me}=await Promise.resolve().then(()=>(Je(),Ze)),Le=new Me(e);A.register(new Ee(Le,X)),Ni.sharedResourceRepo=Le,Se.sharedResourceRepo=Le,Pe.sharedResourceRepo=Le,this.logger.info("Sharing skill registered");let Ge=l;this.webAuthCallback={loginWithCode:f(async Ue=>{let Fe=`web-pending-${Date.now()}`,me=await X.consumeInviteCode(Ue,"api",Fe);if(!me)return{success:!1,error:"Ung\xFCltiger oder abgelaufener Code"};let Y=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,Te=new Date(Date.now()+720*60*6e4).toISOString();return await Ge.createSession(Y,me.id,"web-session",Te),{success:!0,userId:me.id,username:me.username,role:me.role,token:Y}},"loginWithCode"),getUserByToken:f(async Ue=>{let Fe=await Ge.findByToken(Ue);if(!Fe||new Date(Fe.expiresAt)<new Date)return null;let me=await X.getById(Fe.userId);return me?{userId:me.id,username:me.username,role:me.role}:null},"getUserByToken")}}if(this.config.database?.enabled){let{DatabaseSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),{DatabaseConnectionRepository:M}=await Promise.resolve().then(()=>(Je(),Ze)),X=new M(e),q=new N(this.config.database,X);if(this.config.database.connections)for(let J of this.config.database.connections)await X.getByName(J.name)||await X.create({name:J.name,type:J.type,host:J.host,port:J.port,databaseName:J.database,username:J.username,authConfig:J.password?{password:J.password}:void 0,options:{readOnly:J.options?.readOnly??!0,rowLimit:J.options?.rowLimit,timeoutMs:J.options?.timeoutMs}});A.register(q),this.logger.info("Database skill registered")}if(this.config.backup?.enabled){let{SystemBackupSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=await Promise.resolve().then(()=>(xT(),OT)).catch(()=>({default:{version:"unknown"}})),X=new N(this.config.backup,e,this.config.cluster?.nodeId??"single",M.default.version??"unknown",this.config.fileStore);A.register(X),this.logger.info("System Backup skill registered")}if(this.config.commvault?.enabled){let{CommvaultSkill:N}=await Promise.resolve().then(()=>(fe(),ye)),M=new N(this.config.commvault);if(this.config.cmdb?.autoIncidentFromMonitor){let X=A.get("itsm");X&&M.setItsmCallback(async q=>X.execute(q,{alfredUserId:this.ownerMasterUserId}))}A.register(M),this.logger.info("Commvault skill registered")}if(this.config.mikrotik?.enabled&&this.config.cmdb?.autoIncidentFromMonitor){let N=A.get("mikrotik"),M=A.get("itsm");N&&M&&N.setItsmCallback(async X=>M.execute(X,{alfredUserId:this.ownerMasterUserId}))}if(this.config.youtube?.apiKey){let{YouTubeSkill:N}=await Promise.resolve().then(()=>(fe(),ye));A.register(new N(this.config.youtube)),this.logger.info("YouTube skill registered")}this.logger.info({skills:A.getAll().map(N=>N.metadata.name)},"Skills registered"),this.config.speech&&(this.config.speech.sttProvider==="mistral"&&!this.config.speech.sttApiKey&&dt&&(this.config.speech.sttApiKey=dt),this.config.speech.ttsProvider==="mistral"&&!this.config.speech.ttsApiKey&&dt&&(this.config.speech.ttsApiKey=dt));let fs;if(this.config.speech?.apiKey){fs=new Oa(this.config.speech,this.logger.child({component:"speech"})),fs.setUsageCallback((M,X)=>{$.record("stt",M,X).catch(()=>{})});let N=this.config.speech.sttProvider??this.config.speech.provider;this.logger.info({provider:N},"Speech-to-text initialized")}if(this.config.speech?.ttsEnabled){let N=new xa(this.config.speech,this.logger.child({component:"tts"}));N.setSkillState(r),N.setUsageCallback((X,q)=>{$.record("tts",X,q).catch(()=>{})}),A.register(new Fn(N));let M=this.config.speech.ttsProvider??"openai";this.logger.info({provider:M},"Text-to-speech skill registered")}{let N=this.config.speech,M=N?.ttsProvider==="mistral"&&N.voiceManagement!==!1,X=N?.ttsApiKey??dt;if(M&&X&&n){let q,J="localhost",le=TR.networkInterfaces();for(let Le of Object.values(le))if(Le){for(let Ge of Le)if(Ge.family==="IPv4"&&!Ge.internal){J=Ge.address;break}if(J!=="localhost")break}let Ee=this.config.api?.port??3420,Me=this.config.api?.tls?.enabled?Ee+2:Ee;q=`http://${J}:${Me}`,A.register(new er(X,"https://api.mistral.ai/v1","voxtral-mini-tts-2603",n,A,q,r)),this.logger.info({announceBaseUrl:q},"Voice management skill registered")}}let Gt=this.detectImageGenProvider();if(Gt){let N=new Ma(Gt,this.logger.child({component:"image-gen"}));A.register(new jn(N)),this.logger.info({provider:Gt.provider},"Image generation skill registered")}try{let N=new Ua(this.logger.child({component:"transit"}));A.register(new Wn(N)),this.logger.info("Public transit skill registered")}catch(N){this.logger.warn({err:N},"Failed to register transit skill")}let gs;if(this.config.fileStore){let{createFileStore:N}=await Promise.resolve().then(()=>(Je(),Ze));gs=N(this.config.fileStore),this.logger.info({backend:this.config.fileStore.backend},"File store initialized")}gs&&this.projectAgentRunnerRef&&(this.projectAgentRunnerRef.setFileStore(gs),this.logger.info("Project-agent runner connected to file-store for asset-bridge"));let es=new Na(t),Li=Lt.resolve(Lt.dirname(this.config.storage.path),"inbox");if(this.pipeline=new Ca({llm:b,conversationManager:es,users:s,logger:this.logger.child({component:"pipeline"}),skillRegistry:A,skillSandbox:H,securityManager:k,memoryRepo:n,speechTranscriber:fs,inboxPath:Li,fileStore:gs,processedMessageRepo:this.config.cluster?.enabled?new(await Promise.resolve().then(()=>(Je(),Ze))).ProcessedMessageRepository(e):void 0,nodeId:this.config.cluster?.nodeId??"single",embeddingService:C,activeLearning:O,memoryRetriever:P,maxHistoryMessages:this.config.conversation?.maxHistoryMessages??100,documentProcessor:Ie,conversationSummarizer:oe,personality:this.config.personality}),this.config.cluster?.enabled){if(e.type!=="postgres")throw new Error('HA Cluster erfordert storage.backend: "postgres". SQLite ist nicht f\xFCr Multi-Node geeignet.');if(!this.config.cluster.nodeId)throw new Error("HA Cluster erfordert cluster.nodeId. Jeder Node braucht eine eindeutige ID.");(!this.config.fileStore||this.config.fileStore.backend==="local")&&this.logger.warn('HA Cluster ohne S3/NFS FileStore \u2014 Datei-Uploads sind nur auf dem empfangenden Node sichtbar. Empfohlen: fileStore.backend: "s3" oder "nfs"');let{ClusterManager:N}=await Promise.resolve().then(()=>(zp(),MT));this.clusterManager=new N(this.config.cluster,this.logger.child({component:"cluster"})),await this.clusterManager.connect(),this.clusterManager.isConnected||this.logger.warn("Redis nicht erreichbar \u2014 Cross-Node Pub/Sub und Echtzeit-Heartbeat deaktiviert. PG-Heartbeat als Fallback aktiv.");let{PgMigrator:M,PG_MIGRATIONS:X}=await Promise.resolve().then(()=>(Je(),Ze));await new M(e).migrate(X),this.clusterManager.startPgHeartbeat(e),this.logger.info({nodeId:this.config.cluster.nodeId},"Cluster manager initialized (Active-Active)")}this.reminderScheduler=new Da(a,async(N,M,X)=>{let q=this.adapters.get(N);q?await q.sendMessage(M,X):this.logger.warn({platform:N,chatId:M},"No adapter for reminder platform")},this.logger.child({component:"reminders"}),15e3,{getMasterUserId:f(N=>s.getMasterUserId(N),"getMasterUserId"),getLinkedUsers:f(N=>s.getLinkedUsers(N),"getLinkedUsers"),findConversation:f((N,M)=>t.findByPlatformAndUser(N,M),"findConversation")},this.config.cluster?.nodeId??"single"),this.backgroundTaskRunner=new Ba(A,H,u,this.adapters,s,this.logger.child({component:"background-tasks"}),m,g);let ut=new Ha(A,H,u,this.adapters,s,this.logger.child({component:"persistent-agents"}),m);this.backgroundTaskRunner.setPersistentRunner(ut),Kt.setPersistentRunner(ut),this.proactiveScheduler=new Xa(h,A,H,b,this.adapters,s,this.logger.child({component:"proactive-scheduler"}),this.pipeline,this.formatter,es,m,this.config.cluster?.nodeId??"single");let ys=new Gi(e);this.watchRepo=ys,A.register(new Gn(ys,A));let bt=new Vi(e);this.confirmationQueue=new Ka(bt,A,H,this.adapters,this.logger.child({component:"confirmation-queue"}),m);let It=new en(e),Q=new nr(It,n,this.logger.child({component:"feedback"}));Q.setLLM(b),b.supportsEmbeddings()&&Q.setEmbeddingService(b),setTimeout(()=>{let N=this.ownerMasterUserId??this.config.security?.ownerUserId;N&&Q.migrateCorrectionMemories(N).then(M=>this.logger.info({...M},"Feedback: correction-migration completed")).catch(M=>this.logger.debug({err:M},"Feedback: correction-migration failed (non-critical)"))},3e4),this.confirmationQueue.setFeedbackService(Q),O&&O.setFeedbackService(Q),this.watchEngine=new zl(ys,A,H,this.adapters,s,this.logger.child({component:"watch-engine"}),this.confirmationQueue,m,g,b,this.config.cluster?.nodeId??"single");let ie=new Qi(e),ce=new Vn(ie,A);ce.setRunConfirmationCallback(async({chain:N,context:M})=>{if(!this.confirmationQueue)throw new Error("ConfirmationQueue not available");let X=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":M.platform??"api";await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:X,source:"reasoning",sourceId:`workflow-run-${N.id.slice(0,8)}-${Date.now()}`,description:`Workflow '${N.name}' (${N.steps.length} Schritte) ausf\xFChren?`+(N.description?`
5304
5315
 
5305
- ${N.description}`:""),skillName:"workflow",skillParams:{action:"run",workflow_id:N.id,confirmed:!0},timeoutMinutes:60})}),A.register(ce);let ue=new ao("./data/scripts",this.logger.child({component:"script-executor"})),$e=new oo(e,this.logger.child({component:"db-query-executor"})),pe=new ro(ie,A,H,this.logger.child({component:"workflow-runner"}),m,g,ue,$e);ce.setRunner(pe);let wt=new co(b,A,this.logger.child({component:"prompt-parser"}));ce.setPromptParser(wt);{let N=new uo(A,H),M=new lo(ie,N,async(X,q)=>{let J=await ie.getById(X);if(!J)return;let{context:le}=await(await Promise.resolve().then(()=>(ps(),C_))).buildSkillContext(s,{userId:this.config.security?.ownerUserId??"",platform:"api",chatId:""});return pe.run(J,le,q)},this.logger.child({component:"trigger-manager"}));M.start(),this.triggerManager=M}let ht,Ke;{let N=this.config.security?.ownerUserId;if(N&&this.config.reasoning?.enabled!==!1){ht=new Ds(n,this.logger.child({component:"insight-tracker"}),r),this.insightTracker=ht;let M=new js(e);Ke=new rr(new rs(e),this.logger.child({component:"knowledge-graph"}),n,A,H,s,N,st);let X=this.config.reasoning?.llmLinking;if(X?.enabled){let J=X.provider??"mistral",le=this.config.mistralApiKey;if(!le)for(let Ee of["fast","default","strong"]){let Me=this.config.llm[Ee];if(Me?.provider===J&&Me.apiKey){le=Me.apiKey;break}}if(le){let{LLMEntityLinker:Ee}=await Promise.resolve().then(()=>(PT(),UT)),Me=J==="openai"?"https://api.openai.com/v1":J==="anthropic"?"https://api.anthropic.com/v1":"https://api.mistral.ai/v1",Le=new Ee(new rs(e),X,this.logger.child({component:"llm-entity-linker"}),le,Me);Le.setUsageCallback((Ge,Ue,Fe,me)=>{v.record(Ue,Fe,me,0,0,0).catch(()=>{})}),Le.setDocumentRepo(nt),Ke.setLLMLinker(Le),this.logger.info({provider:J,model:X.model??"mistral-small-latest"},"LLM entity linker enabled")}}let q;try{q=(await s.getProfile?.(this.ownerMasterUserId||N))?.timezone}catch{}this.reasoningEngine=new mo(kt,we,ys,n,p,y,M,A,H,b,this.adapters,s,N,st,this.config.reasoning,this.logger.child({component:"reasoning-engine"}),m,this.config.briefing?.location,It,this.confirmationQueue,this.config.cluster?.nodeId??"single",e,ht,void 0,Ke,ie,this.bmwTelematicRepo,o,this.reminderRepo,nt,q,t,this.runbookRepo,this.projectRepo)}}if(this.reasoningEngine){let{PlanRepository:N}=await Promise.resolve().then(()=>(Je(),tt)),{PlanningAgent:M}=await Promise.resolve().then(()=>(jT(),FT)),X=new N(e),q=new M(X,b,{execute:f(async(J,le,Ee)=>{let Me=A.get(J);return Me?H.execute(Me,le,{userId:Ee,masterUserId:Ee}):{success:!1,error:`Skill "${J}" not found`}},"execute")},this.logger.child({component:"planning-agent"}));this.reasoningEngine.setPlanningAgent(q),this.reasoningEngine.collector?.setPlanningAgent&&this.reasoningEngine.collector.setPlanningAgent(q)}Ke&&(this.pipeline.setKnowledgeGraphService(Ke),this.kgServiceRef=Ke,this.memorySkillRef&&this.memorySkillRef.setKgAnalyzeCallback(async N=>{let M=this.ownerMasterUserId??N,X=new rs(this.database.getAdapter());try{await Ke.syncMemoryEntities(M)}catch{}try{await Ke.buildCrossExtractorRelations(M)}catch{}try{await Ke.buildFamilyInference(M)}catch{}try{await Ke.buildGenericEntityLinks(M)}catch{}let q=Ke.getLLMLinker(),J={relations:0,newEntities:0,corrections:0};if(q)try{J=await q.run(M)}catch{}try{await Ke.maintenance(M)}catch(Ee){this.logger.warn({err:Ee.message},"KG maintenance in kg_analyze failed")}let le=await X.getFullGraph(M);return{entities:le.entities.length,relations:le.relations.length,newEntities:J.newEntities,corrections:J.corrections}}));{let N=this.watchEngine.onWatchTriggered;this.watchEngine.onWatchTriggered=(M,X,q,J)=>{N?.(M,X,q,J),this.triggerManager&&this.triggerManager.onWatchTriggered(M,X).catch(()=>{}),J!=="feed_reader"&&this.reasoningEngine&&this.reasoningEngine.triggerOnEvent("watch_alert",`Watch "${M}" ausgel\xF6st: ${X}`,q).catch(le=>this.logger.warn({err:le},"Event-triggered reasoning failed"))}}if(this.reasoningEngine&&this.calendarWatcher&&(this.calendarWatcher.onEventNotified=N=>{this.reasoningEngine.triggerOnEvent("calendar_upcoming",`Termin in K\xFCrze: ${N.title}${N.location?` (${N.location})`:""}`,{eventId:N.id,title:N.title,location:N.location,start:N.start.toISOString()}).catch(M=>this.logger.warn({err:M},"Calendar-triggered reasoning failed"))}),this.reasoningEngine&&this.todoWatcher&&(this.todoWatcher.onTodoNotified=(N,M,X)=>{this.reasoningEngine.triggerOnEvent(`todo_${X}`,`Todo ${X==="overdue"?"\xFCberf\xE4llig":"bald f\xE4llig"}: ${M}`,{todoId:N,title:M,kind:X}).catch(q=>this.logger.warn({err:q},"Todo-triggered reasoning failed"))}),this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(m),this.pipeline.setSkillHealthTracker(g),this.skillHealthRepo&&this.pipeline.setSkillHealthRepo(this.skillHealthRepo),ht&&this.pipeline.setInsightTracker(ht),this.reasoningEngine&&this.pipeline.setReasoningEngine(this.reasoningEngine),this.runbookRepo&&this.pipeline.setRunbookRepo(this.runbookRepo),this.config.projectAgents?.enabled&&this.config.codeAgents?.agents)try{let{ProjectAgentSessionRepository:N}=await Promise.resolve().then(()=>(Je(),tt));this.pipeline.setProjectAgentSessionRepo(new N(e))}catch(N){this.logger.debug({err:N},"Could not wire project-agent-session repo into pipeline (non-critical)")}if(this.config.security?.moderation?.enabled){let N=this.config.security.moderation,M=N.provider??"mistral",X=M==="mistral"?"https://api.mistral.ai/v1":"https://api.openai.com/v1",q=N.model??(M==="mistral"?"mistral-moderation-latest":"omni-moderation-latest"),J;if(M==="mistral"&&this.config.mistralApiKey&&(J=this.config.mistralApiKey),!J)for(let le of["default","strong","fast"]){let Ee=this.config.llm[le];if(Ee?.provider===M&&Ee.apiKey){J=Ee.apiKey;break}}if(J||(J=this.config.llm.default?.apiKey),J){let{ModerationService:le}=await Promise.resolve().then(()=>(zr(),Ig)),Ee=new le(J,X,q,this.logger.child({component:"moderation"}));Ee.setUsageCallback((Me,Le)=>{this.serviceUsageRepo?.record("moderation",Me,Le).catch(()=>{})}),this.pipeline.setModerationService(Ee),this.logger.info({provider:M,model:q},"Moderation service enabled")}else this.logger.warn("Moderation enabled but no API key found \u2014 skipping")}{let{AlfredUserRepository:N,UsageRepository:M}=await Promise.resolve().then(()=>(Je(),tt)),{ROLE_SKILL_ACCESS:X}=await Promise.resolve().then(()=>(fe(),ye)),q=new N(e),{UserServiceResolver:J}=await Promise.resolve().then(()=>(qp(),BT)),le=new J(q);if(this.userServiceResolverRef=le,this.pipeline.setAlfredUserRepo(q,X,this.usageRepo,le),Qt.roleAccess=X,this.spotifySkill&&"setServiceResolver"in this.spotifySkill&&this.spotifySkill.setServiceResolver(le),this.bmwSkill&&"setServiceResolver"in this.bmwSkill){this.bmwSkill.setServiceResolver(le,this.ownerMasterUserId);let Ee=new sn(e);this.bmwSkill.setTelematicRepo(Ee),this.bmwTelematicRepo=Ee}}if(this.clusterManager&&(await this.clusterManager.subscribe("messages",N=>{let{targetPlatform:M,chatId:X,text:q}=N,J=this.adapters.get(M);J&&J.sendMessage(X,q).catch(le=>{this.logger.warn({err:le,targetPlatform:M,chatId:X},"Cross-node message delivery failed")})}),this.config.cluster)){let{ClusterDiscovery:N}=await Promise.resolve().then(()=>(Gp(),zT));new N(this.logger.child({component:"cluster-discovery"})).startBroadcasting({nodeId:this.config.cluster.nodeId,host:"0.0.0.0",port:this.config.api?.port??3420,role:this.config.cluster?.role??"node"})}await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(xs(),Os));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(()=>(xs(),Os));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(()=>(xs(),Os));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(()=>(xs(),Os));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(()=>(xs(),Os));this.adapters.set("signal",new t(e.signal.apiUrl,e.signal.phoneNumber)),this.logger.info("Signal adapter registered")}if(e.msteams?.enabled&&e.msteams.appId){let{MSTeamsAdapter:t}=await Promise.resolve().then(()=>(xs(),Os)),s=new t(e.msteams),i=this.database.getAdapter(),n="msteams",r="conv_ref:",a="_system";s.setDbCallback({async saveConversationRef(o,c){let l=`msteams-ref-${o.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,60)}`,u=new Date().toISOString();await i.execute(`INSERT INTO skill_state (id, user_id, skill, key, value, updated_at)
5316
+ ${N.description}`:""),skillName:"workflow",skillParams:{action:"run",workflow_id:N.id,confirmed:!0},timeoutMinutes:60})}),A.register(ce);let ue=new ao("./data/scripts",this.logger.child({component:"script-executor"})),$e=new oo(e,this.logger.child({component:"db-query-executor"})),pe=new ro(ie,A,H,this.logger.child({component:"workflow-runner"}),m,g,ue,$e);ce.setRunner(pe);let wt=new co(b,A,this.logger.child({component:"prompt-parser"}));ce.setPromptParser(wt);{let N=new uo(A,H),M=new lo(ie,N,async(X,q)=>{let J=await ie.getById(X);if(!J)return;let{context:le}=await(await Promise.resolve().then(()=>(ps(),C_))).buildSkillContext(s,{userId:this.config.security?.ownerUserId??"",platform:"api",chatId:""});return pe.run(J,le,q)},this.logger.child({component:"trigger-manager"}));M.start(),this.triggerManager=M}let ht,Ke;{let N=this.config.security?.ownerUserId;if(N&&this.config.reasoning?.enabled!==!1){ht=new Ds(n,this.logger.child({component:"insight-tracker"}),r),this.insightTracker=ht;let M=new js(e);Ke=new rr(new rs(e),this.logger.child({component:"knowledge-graph"}),n,A,H,s,N,st);let X=this.config.reasoning?.llmLinking;if(X?.enabled){let J=X.provider??"mistral",le=this.config.mistralApiKey;if(!le)for(let Ee of["fast","default","strong"]){let Me=this.config.llm[Ee];if(Me?.provider===J&&Me.apiKey){le=Me.apiKey;break}}if(le){let{LLMEntityLinker:Ee}=await Promise.resolve().then(()=>(PT(),UT)),Me=J==="openai"?"https://api.openai.com/v1":J==="anthropic"?"https://api.anthropic.com/v1":"https://api.mistral.ai/v1",Le=new Ee(new rs(e),X,this.logger.child({component:"llm-entity-linker"}),le,Me);Le.setUsageCallback((Ge,Ue,Fe,me)=>{v.record(Ue,Fe,me,0,0,0).catch(()=>{})}),Le.setDocumentRepo(nt),Ke.setLLMLinker(Le),this.logger.info({provider:J,model:X.model??"mistral-small-latest"},"LLM entity linker enabled")}}let q;try{q=(await s.getProfile?.(this.ownerMasterUserId||N))?.timezone}catch{}this.reasoningEngine=new mo(kt,we,ys,n,p,y,M,A,H,b,this.adapters,s,N,st,this.config.reasoning,this.logger.child({component:"reasoning-engine"}),m,this.config.briefing?.location,It,this.confirmationQueue,this.config.cluster?.nodeId??"single",e,ht,void 0,Ke,ie,this.bmwTelematicRepo,o,this.reminderRepo,nt,q,t,this.runbookRepo,this.projectRepo)}}if(this.reasoningEngine){let{PlanRepository:N}=await Promise.resolve().then(()=>(Je(),Ze)),{PlanningAgent:M}=await Promise.resolve().then(()=>(jT(),FT)),X=new N(e),q=new M(X,b,{execute:f(async(J,le,Ee)=>{let Me=A.get(J);return Me?H.execute(Me,le,{userId:Ee,masterUserId:Ee}):{success:!1,error:`Skill "${J}" not found`}},"execute")},this.logger.child({component:"planning-agent"}));this.reasoningEngine.setPlanningAgent(q),this.reasoningEngine.collector?.setPlanningAgent&&this.reasoningEngine.collector.setPlanningAgent(q)}Ke&&(this.pipeline.setKnowledgeGraphService(Ke),this.kgServiceRef=Ke,this.memorySkillRef&&this.memorySkillRef.setKgAnalyzeCallback(async N=>{let M=this.ownerMasterUserId??N,X=new rs(this.database.getAdapter());try{await Ke.syncMemoryEntities(M)}catch{}try{await Ke.buildCrossExtractorRelations(M)}catch{}try{await Ke.buildFamilyInference(M)}catch{}try{await Ke.buildGenericEntityLinks(M)}catch{}let q=Ke.getLLMLinker(),J={relations:0,newEntities:0,corrections:0};if(q)try{J=await q.run(M)}catch{}try{await Ke.maintenance(M)}catch(Ee){this.logger.warn({err:Ee.message},"KG maintenance in kg_analyze failed")}let le=await X.getFullGraph(M);return{entities:le.entities.length,relations:le.relations.length,newEntities:J.newEntities,corrections:J.corrections}}));{let N=this.watchEngine.onWatchTriggered;this.watchEngine.onWatchTriggered=(M,X,q,J)=>{N?.(M,X,q,J),this.triggerManager&&this.triggerManager.onWatchTriggered(M,X).catch(()=>{}),J!=="feed_reader"&&this.reasoningEngine&&this.reasoningEngine.triggerOnEvent("watch_alert",`Watch "${M}" ausgel\xF6st: ${X}`,q).catch(le=>this.logger.warn({err:le},"Event-triggered reasoning failed"))}}if(this.reasoningEngine&&this.calendarWatcher&&(this.calendarWatcher.onEventNotified=N=>{this.reasoningEngine.triggerOnEvent("calendar_upcoming",`Termin in K\xFCrze: ${N.title}${N.location?` (${N.location})`:""}`,{eventId:N.id,title:N.title,location:N.location,start:N.start.toISOString()}).catch(M=>this.logger.warn({err:M},"Calendar-triggered reasoning failed"))}),this.reasoningEngine&&this.todoWatcher&&(this.todoWatcher.onTodoNotified=(N,M,X)=>{this.reasoningEngine.triggerOnEvent(`todo_${X}`,`Todo ${X==="overdue"?"\xFCberf\xE4llig":"bald f\xE4llig"}: ${M}`,{todoId:N,title:M,kind:X}).catch(q=>this.logger.warn({err:q},"Todo-triggered reasoning failed"))}),this.pipeline.setConfirmationQueue(this.confirmationQueue),this.pipeline.setActivityLogger(m),this.pipeline.setSkillHealthTracker(g),this.skillHealthRepo&&this.pipeline.setSkillHealthRepo(this.skillHealthRepo),ht&&this.pipeline.setInsightTracker(ht),this.reasoningEngine&&this.pipeline.setReasoningEngine(this.reasoningEngine),this.runbookRepo&&this.pipeline.setRunbookRepo(this.runbookRepo),this.config.projectAgents?.enabled&&this.config.codeAgents?.agents)try{let{ProjectAgentSessionRepository:N}=await Promise.resolve().then(()=>(Je(),Ze));this.pipeline.setProjectAgentSessionRepo(new N(e))}catch(N){this.logger.debug({err:N},"Could not wire project-agent-session repo into pipeline (non-critical)")}if(this.config.security?.moderation?.enabled){let N=this.config.security.moderation,M=N.provider??"mistral",X=M==="mistral"?"https://api.mistral.ai/v1":"https://api.openai.com/v1",q=N.model??(M==="mistral"?"mistral-moderation-latest":"omni-moderation-latest"),J;if(M==="mistral"&&this.config.mistralApiKey&&(J=this.config.mistralApiKey),!J)for(let le of["default","strong","fast"]){let Ee=this.config.llm[le];if(Ee?.provider===M&&Ee.apiKey){J=Ee.apiKey;break}}if(J||(J=this.config.llm.default?.apiKey),J){let{ModerationService:le}=await Promise.resolve().then(()=>(zr(),Ig)),Ee=new le(J,X,q,this.logger.child({component:"moderation"}));Ee.setUsageCallback((Me,Le)=>{this.serviceUsageRepo?.record("moderation",Me,Le).catch(()=>{})}),this.pipeline.setModerationService(Ee),this.logger.info({provider:M,model:q},"Moderation service enabled")}else this.logger.warn("Moderation enabled but no API key found \u2014 skipping")}{let{AlfredUserRepository:N,UsageRepository:M}=await Promise.resolve().then(()=>(Je(),Ze)),{ROLE_SKILL_ACCESS:X}=await Promise.resolve().then(()=>(fe(),ye)),q=new N(e),{UserServiceResolver:J}=await Promise.resolve().then(()=>(qp(),BT)),le=new J(q);if(this.userServiceResolverRef=le,this.pipeline.setAlfredUserRepo(q,X,this.usageRepo,le),Qt.roleAccess=X,this.spotifySkill&&"setServiceResolver"in this.spotifySkill&&this.spotifySkill.setServiceResolver(le),this.bmwSkill&&"setServiceResolver"in this.bmwSkill){this.bmwSkill.setServiceResolver(le,this.ownerMasterUserId);let Ee=new sn(e);this.bmwSkill.setTelematicRepo(Ee),this.bmwTelematicRepo=Ee}}if(this.clusterManager&&(await this.clusterManager.subscribe("messages",N=>{let{targetPlatform:M,chatId:X,text:q}=N,J=this.adapters.get(M);J&&J.sendMessage(X,q).catch(le=>{this.logger.warn({err:le,targetPlatform:M,chatId:X},"Cross-node message delivery failed")})}),this.config.cluster)){let{ClusterDiscovery:N}=await Promise.resolve().then(()=>(Gp(),zT));new N(this.logger.child({component:"cluster-discovery"})).startBroadcasting({nodeId:this.config.cluster.nodeId,host:"0.0.0.0",port:this.config.api?.port??3420,role:this.config.cluster?.role??"node"})}await this.initializeAdapters(),this.logger.info("Alfred initialized")}async initializeAdapters(){let{config:e}=this;if(e.telegram.enabled&&e.telegram.token){let{TelegramAdapter:t}=await Promise.resolve().then(()=>(xs(),Os));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(()=>(xs(),Os));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(()=>(xs(),Os));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(()=>(xs(),Os));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(()=>(xs(),Os));this.adapters.set("signal",new t(e.signal.apiUrl,e.signal.phoneNumber)),this.logger.info("Signal adapter registered")}if(e.msteams?.enabled&&e.msteams.appId){let{MSTeamsAdapter:t}=await Promise.resolve().then(()=>(xs(),Os)),s=new t(e.msteams),i=this.database.getAdapter(),n="msteams",r="conv_ref:",a="_system";s.setDbCallback({async saveConversationRef(o,c){let l=`msteams-ref-${o.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,60)}`,u=new Date().toISOString();await i.execute(`INSERT INTO skill_state (id, user_id, skill, key, value, updated_at)
5306
5317
  VALUES (?, ?, ?, ?, ?, ?)
5307
- ON CONFLICT (user_id, skill, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,[l,a,n,`${r}${o}`,JSON.stringify(c),u])},async loadAllConversationRefs(){let o=await i.query("SELECT key, value FROM skill_state WHERE user_id = ? AND skill = ? AND key LIKE ?",[a,n,`${r}%`]),c=new Map;for(let l of o){let u=l.key.slice(r.length);try{c.set(u,JSON.parse(l.value))}catch{}}return c}}),this.adapters.set("msteams",s),this.logger.info({port:e.msteams.webhookPort??3978},"MS Teams adapter registered (cluster-aware ConversationRef persistence)")}if(e.api?.enabled!==!1){let{HttpAdapter:t}=await Promise.resolve().then(()=>(xs(),Os)),s=e.api?.port??3420,i=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,i,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,publicUrl:e.api?.publicUrl,tls:e.api?.tls,authCallback:this.webAuthCallback,healthCheck:f(async()=>{let n;try{let r=this.config.storage.path,a=hr.statSync(r);n={path:r,sizeBytes:a.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([r,a])=>[r,a.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:await this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:await this.watchRepo?.countEnabled()??0,schedulersActive:await this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:f(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:f(async()=>{let n=new Date().toISOString().slice(0,10),r=new Date(Date.now()-10080*6e4).toISOString().slice(0,10);return{watches:await this.watchRepo?.getEnabled()??[],scheduled:await this.scheduledActionRepo?.getAll()??[],skillHealth:await this.skillHealthRepo?.getAll()??[],reminders:await this.reminderRepo?.getAllPending()??[],usage:{today:await this.usageRepo?.getDaily(n)??null,week:await this.usageRepo?.getRange(r,n)??[],total:await this.usageRepo?.getTotal()??[]},uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters.entries()].map(([a,o])=>[a,o.getStatus()])),llmProviders:this.llmProvider.getProviderStatuses(),services:this.getConfiguredServices(),serviceUsage:{today:await this.serviceUsageRepo?.getDaily(n)??[],week:await this.serviceUsageRepo?.getRange(r,n)??[],total:await this.serviceUsageRepo?.getTotal()??[]},userUsage:await this.usageRepo?.getByUser(r,n)??[],userSkillUsage:await this.activityRepo?.skillUsageByUser(r)??[]}},"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:i,webUi:e.api?.webUi!==!1},"HTTP API adapter registered")}}async start(){if(this.logger.info("Starting Alfred..."),this.config.cluster?.enabled&&this.database.getAdapter().type==="postgres"){let{AdapterClaimManager:t}=await Promise.resolve().then(()=>(rE(),nE));this.adapterClaimManager=new t(this.database.getAdapter(),this.config.cluster.nodeId,this.logger.child({component:"adapter-claims"}));for(let[s,i]of this.adapters){if(s==="api"){this.setupAdapterHandlers(s,i);try{await i.connect(),this.logger.info({platform:s},"Adapter connected (always-on)")}catch(r){this.logger.error({platform:s,err:r},"Adapter connection failed")}continue}if(this.adapterClaimManager.registerPlatform(s),await this.adapterClaimManager.tryClaim(s)){this.setupAdapterHandlers(s,i);try{await i.connect(),this.logger.info({platform:s},"Adapter connected (claimed)")}catch(r){this.logger.error({platform:s,err:r},"Adapter connection failed")}}else this.logger.info({platform:s},"Adapter claimed by another node, skipping")}this.adapterClaimManager.onAcquired(async s=>{if(s==="bmw-streaming"){this.bmwSkill&&(this.logger.info("BMW MQTT streaming acquired from dead node, starting..."),this.bmwSkill.startStreaming().then(()=>this.logger.info("BMW MQTT streaming started (failover)")).catch(n=>this.logger.warn({err:n},"BMW MQTT streaming failover failed")));return}let i=this.adapters.get(s);if(i&&i.getStatus()==="disconnected"){this.setupAdapterHandlers(s,i);try{await i.connect(),this.logger.info({platform:s},"Adapter connected (failover)")}catch(n){this.logger.error({platform:s,err:n},"Failover adapter connection failed")}}}),this.adapterClaimManager.start()}else for(let[t,s]of this.adapters){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected")}catch(i){this.logger.error({platform:t,err:i},"Adapter connection failed \u2014 skipping")}}if(this.adapterClaimManager&&this.projectHealthMonitor&&this.adapterClaimManager.registerPlatform("project-health-monitor"),this.bmwSkill&&this.config.bmw?.streaming?.enabled&&(this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("bmw-streaming"),!this.adapterClaimManager||await this.adapterClaimManager.tryClaim("bmw-streaming")?(this.logger.info({username:this.config.bmw.streaming.username,topic:this.config.bmw.streaming.topic},"Starting BMW MQTT streaming..."),this.bmwSkill.startStreaming().then(()=>this.logger.info("BMW MQTT streaming started")).catch(s=>this.logger.warn({err:s},"BMW MQTT streaming failed to start"))):this.logger.info("BMW MQTT streaming claimed by another node, skipping")),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.backup?.enabled&&this.config.backup?.storage!=="none"){this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("system-backup");let t=this.skillRegistry.get("system_backup");if(t){let s=-1;setInterval(async()=>{let i=new Date;if(i.getMinutes()===s)return;let n=this.config.backup?.schedule??"0 3 * * *",[r,a]=n.split(" "),o=r==="*"||(r.includes("/")?i.getMinutes()%parseInt(r.split("/")[1])===0:r.split(",").some(l=>parseInt(l)===i.getMinutes())),c=a==="*"||(a.includes("/")?i.getHours()%parseInt(a.split("/")[1])===0:a.split(",").some(l=>parseInt(l)===i.getHours()));if(!(!o||!c)&&(s=i.getMinutes(),!(this.adapterClaimManager&&!await this.adapterClaimManager.tryClaim("system-backup"))))try{await t.createBackup({},"scheduled"),this.logger.info("Scheduled system backup completed")}catch(l){this.logger.warn({err:l},"Scheduled system backup failed")}},6e4),this.logger.info({schedule:this.config.backup.schedule??"0 3 * * *"},"System backup scheduler started")}}if(this.config.commvault?.enabled&&(this.config.commvault.polling_interval??30)>0){this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("commvault-monitor");let t=this.skillRegistry.get("commvault");if(t?.pollAndReport){let s=(this.config.commvault.polling_interval??30)*6e4;setInterval(async()=>{if(!(this.adapterClaimManager&&!await this.adapterClaimManager.tryClaim("commvault-monitor")))try{let i=await t.pollAndReport();(i.failed>0||i.storageWarnings.length>0||i.slaViolations.length>0)&&this.logger.info({...i},"Commvault monitoring alert")}catch(i){this.logger.debug({err:i},"Commvault monitoring poll failed")}},s),this.logger.info({interval:`${this.config.commvault.polling_interval??30}min`},"Commvault monitoring started")}}if(this.config.mikrotik?.enabled&&(this.config.mikrotik.polling_interval??5)>0){this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("mikrotik-monitor");let t=this.skillRegistry.get("mikrotik");if(t?.pollAndReport){let s=(this.config.mikrotik.polling_interval??5)*6e4;setInterval(async()=>{if(!(this.adapterClaimManager&&!await this.adapterClaimManager.tryClaim("mikrotik-monitor")))try{let i=await t.pollAndReport();(i.downInterfaces.length>0||i.cpuWarnings.length>0)&&this.logger.info({...i},"MikroTik monitoring alert")}catch(i){this.logger.debug({err:i},"MikroTik monitoring poll failed")}},s),this.logger.info({interval:`${this.config.mikrotik.polling_interval??5}min`},"MikroTik monitoring started")}}if(this.config.webhooks?.length&&this.watchEngine){let t=this.adapters.get("api");if(t&&"addWebhook"in t){let s=t;for(let i of this.config.webhooks)s.addWebhook({name:i.name,secret:i.secret,callback:f(async n=>{if(i.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(i.watchId),i.chatId&&i.platform){let r=this.adapters.get(i.platform);if(r){let a=`\u{1F514} Webhook "${i.name}" triggered`+(n.action?`: ${n.action}`:"");await r.sendMessage(i.chatId,a)}}},"callback")}),this.logger.info({name:i.name,watchId:i.watchId},"Webhook registered")}}{let t=this.adapters.get("api");t&&"registerOAuthCallback"in t&&(this.spotifySkill&&(t.registerOAuthCallback("spotify",(s,i)=>this.spotifySkill.handleOAuthCallback(s,i)),this.logger.info("Spotify OAuth callback registered")),this.sonosSkill&&this.config.sonos?.cloud?.clientId&&(t.registerOAuthCallback("sonos",(s,i)=>this.sonosSkill.handleOAuthCallback(s,i)),this.logger.info("Sonos Cloud OAuth callback registered")))}{let t=this.adapters.get("api"),s=this.database.getAdapter();if(t&&"setKnowledgeGraphCallbacks"in t){let i=new rs(s);t.setKnowledgeGraphCallbacks({getGraph:f(async n=>{let r=n??this.config.security?.ownerUserId??"";try{let a=await this.userRepo.findOrCreate("telegram",r),o=a.masterUserId??a.id;return i.getFullGraph(o)}catch{return i.getFullGraph(r)}},"getGraph"),deleteEntity:f(async n=>(await s.execute("DELETE FROM kg_entities WHERE id = ?",[n])).changes>0,"deleteEntity"),deleteRelation:f(async n=>(await s.execute("DELETE FROM kg_relations WHERE id = ?",[n])).changes>0,"deleteRelation"),updateEntity:f(async(n,r)=>{let a=[],o=[];if(r.name!==void 0&&(a.push("name = ?"),o.push(r.name),a.push("normalized_name = ?"),o.push(String(r.name).trim().toLowerCase())),r.entityType!==void 0&&(a.push("entity_type = ?"),o.push(r.entityType)),r.attributes!==void 0&&(a.push("attributes = ?"),o.push(JSON.stringify(r.attributes))),a.length===0)return!1;a.push("last_seen_at = ?"),o.push(new Date().toISOString()),o.push(n);try{return(await s.execute(`UPDATE kg_entities SET ${a.join(", ")} WHERE id = ?`,o)).changes>0}catch{return!1}},"updateEntity"),updateRelation:f(async(n,r)=>{let a=[],o=[];if(r.relationType!==void 0&&(a.push("relation_type = ?"),o.push(r.relationType)),r.strength!==void 0&&(a.push("strength = ?"),o.push(r.strength)),r.context!==void 0&&(a.push("context = ?"),o.push(r.context)),a.length===0)return!1;a.push("last_seen_at = ?"),o.push(new Date().toISOString()),o.push(n);try{return(await s.execute(`UPDATE kg_relations SET ${a.join(", ")} WHERE id = ?`,o)).changes>0}catch{return!1}},"updateRelation")}),this.logger.info("Knowledge Graph API registered")}if(t&&this.memoryRepo&&"setMemoryCallbacks"in t){let i=this.memoryRepo,n=s;t.setMemoryCallbacks({list:f(async r=>{try{let a=this.config.security?.ownerUserId??"",o=await this.userRepo.findOrCreate("telegram",a),c=o.masterUserId??o.id;return r?.type?await i.getByType(c,r.type,200):await i.getAllForUser(c)}catch(a){return this.logger.warn({err:a},"Memories API list failed"),[]}},"list"),delete:f(async r=>(await n.execute("DELETE FROM memories WHERE id = ?",[r])).changes>0,"delete"),updateType:f(async(r,a)=>await i.updateType(r,a),"updateType")}),this.logger.info("Memories API registered")}if(t&&this.runbookRepo&&"setRunbookCallbacks"in t){let i=this.runbookRepo,n=f(async()=>{let r=this.config.security?.ownerUserId??"";try{let a=await this.userRepo.findOrCreate("telegram",r);return a.masterUserId??a.id}catch{return r}},"resolveOwner");t.setRunbookCallbacks({list:f(async r=>{try{let a=await n();return await i.list(a,r)}catch(a){return this.logger.warn({err:a},"Runbook API list failed"),[]}},"list"),get:f(async r=>{try{let a=await n();return await i.getById(a,r)}catch{return null}},"get"),update:f(async(r,a)=>{try{let o=await n();return await i.update(o,r,a)}catch(o){return this.logger.warn({err:o},"Runbook API update failed"),null}},"update"),delete:f(async r=>{try{let a=await n();return await i.delete(a,r)}catch{return!1}},"delete")}),this.logger.info("Runbook API registered")}if(t&&this.database&&"setProjectAgentCallbacks"in t){let{ProjectAgentSessionRepository:i}=await Promise.resolve().then(()=>(Je(),tt)),n=new i(this.database.getAdapter()),{pushInterjection:r}=await Promise.resolve().then(()=>(fe(),ye));t.setProjectAgentCallbacks({list:f(async a=>{try{return await n.listAll({phase:a?.phase,limit:200})}catch(o){return this.logger.warn({err:o},"Project-Agent API list failed"),[]}},"list"),get:f(async a=>{try{return await n.getByTaskId(a)}catch{return null}},"get"),stop:f(async a=>{try{let o=await n.getByTaskId(a);return o?(o.currentPhase==="done"||o.currentPhase==="failed"||await r(a,"__STOP__"),!0):!1}catch(o){return this.logger.warn({err:o,taskId:a},"Project-Agent API stop failed"),!1}},"stop")}),this.logger.info("Project-Agent API registered")}if(t&&this.projectRepo&&"setProjectsCallbacks"in t){let i=this.projectRepo,n=f(async()=>{let r=this.config.security?.ownerUserId??"";try{let a=await this.userRepo.findOrCreate("telegram",r);return a.masterUserId??a.id}catch{return r}},"resolveOwnerProj");t.setProjectsCallbacks({list:f(async r=>{try{let a=await n();return await i.list(a,r)}catch(a){return this.logger.warn({err:a},"Projects API list failed"),[]}},"list"),get:f(async r=>{try{let a=await n(),o=await i.getById(a,r);if(!o)return null;let[c,l,u,h]=await Promise.all([i.listSessions(o.id,50),i.listOpenItems(a,{projectId:o.id,limit:200}),i.listDecisions(o.id,50),i.getCurrentHealthSummary(o.id)]);return{project:o,sessions:c,openItems:l,decisions:u,health:h}}catch(a){return this.logger.warn({err:a},"Projects API get failed"),null}},"get"),create:f(async r=>{try{let a=await n();return await i.create(a,r)}catch(a){return this.logger.warn({err:a},"Projects API create failed"),null}},"create"),update:f(async(r,a)=>{try{let o=await n();return await i.update(o,r,a)}catch(o){return this.logger.warn({err:o},"Projects API update failed"),null}},"update"),archive:f(async r=>{try{let a=await n();return!!await i.update(a,r,{status:"archived"})}catch{return!1}},"archive"),addOpenItem:f(async(r,a)=>{try{let o=await n(),c=await i.getById(o,r);return c?await i.addOpenItem(c.id,a):null}catch(o){return this.logger.warn({err:o},"Projects API addOpenItem failed"),null}},"addOpenItem"),updateOpenItem:f(async(r,a)=>{try{return await i.updateOpenItemStatus(r,a)}catch{return!1}},"updateOpenItem"),listHealthLog:f(async(r,a)=>{try{let o=await n(),c=await i.getById(o,r);return c?await i.listHealthLog(c.id,a):[]}catch{return[]}},"listHealthLog")}),this.logger.info("Projects API registered")}}if(this.config.cmdb?.enabled!==!1&&(this.config.proxmox||this.config.unifi||this.config.docker||this.config.cloudflare||this.config.nginxProxyManager||this.config.pfsense||this.config.homeassistant)){let t=this.adapters.get("api"),s=this.database.getAdapter();if(t&&"setCmdbCallbacks"in t){let i=new Hs(s),n=new oi(s);n.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;let{ProblemRepository:r}=await Promise.resolve().then(()=>(Je(),tt)),a=new r(s),o=f(async c=>{if(!c&&this.config.security?.ownerUserId&&this.userRepo)try{let l=await this.userRepo.findOrCreate("telegram",this.config.security.ownerUserId);return l.masterUserId??l.id??this.config.security.ownerUserId}catch{return this.config.security.ownerUserId}return c||this.ownerMasterUserId||this.config.security?.ownerUserId||""},"resolveUser");t.setCmdbCallbacks({listAssets:f(async(c,l)=>i.listAssets(await o(c),l),"listAssets"),getAsset:f(async(c,l)=>{let u=await o(c),h=await i.getAssetById(u,l),p=h?await i.getRelationsForAsset(u,l):[],m=h?await i.getChangesForAsset(u,l,20):[];return{asset:h,relations:p,changes:m}},"getAsset"),createAsset:f(async(c,l)=>i.upsertAsset(await o(c),l),"createAsset"),updateAsset:f(async(c,l,u)=>i.updateAsset(await o(c),l,u),"updateAsset"),deleteAsset:f(async(c,l)=>i.decommissionAsset(await o(c),l),"deleteAsset"),listRelations:f(async c=>i.getAllRelations(await o(c)),"listRelations"),createRelation:f(async(c,l)=>i.upsertRelation(await o(c),l.source_asset_id,l.target_asset_id,l.relation_type),"createRelation"),deleteRelation:f(async(c,l)=>i.removeRelation(await o(c),l),"deleteRelation"),discover:f(async c=>{let l=this.skillRegistry?.get("cmdb");return l?l.execute({action:"discover"},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"CMDB skill not registered"}},"discover"),getStats:f(async c=>i.getStats(await o(c)),"getStats"),getChanges:f(async(c,l)=>i.getChangesForAsset(await o(c),l),"getChanges"),listDocuments:f(async(c,l)=>i.listDocuments(await o(c),l),"listDocuments"),getDocument:f(async(c,l)=>i.getDocumentById(await o(c),l),"getDocument"),getDocumentTree:f(async c=>i.getDocumentTree(await o(c)),"getDocumentTree"),saveDocument:f(async(c,l)=>i.saveDocument(await o(c),l),"saveDocument"),updateDocument:f(async(c,l,u)=>i.updateDocument(await o(c),l,u),"updateDocument"),deleteDocument:f(async(c,l)=>i.deleteDocument(await o(c),l),"deleteDocument"),getDocumentVersions:f(async(c,l,u,h)=>i.getDocumentVersions(await o(c),l,u,h),"getDocumentVersions"),searchDocuments:f(async(c,l,u)=>i.searchDocuments(await o(c),l,u),"searchDocuments")}),t.setItsmCallbacks({listIncidents:f(async(c,l)=>n.listIncidents(await o(c),l),"listIncidents"),getIncident:f(async(c,l)=>n.getIncidentById(await o(c),l),"getIncident"),createIncident:f(async(c,l)=>n.createIncident(await o(c),l),"createIncident"),updateIncident:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return n.updateIncident(await o(c),l,h)},"updateIncident"),listChanges:f(async(c,l)=>n.listChangeRequests(await o(c),l),"listChanges"),createChange:f(async(c,l)=>n.createChangeRequest(await o(c),l),"createChange"),updateChange:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return n.updateChangeRequest(await o(c),l,h)},"updateChange"),listServices:f(async(c,l)=>n.listServices(await o(c),l),"listServices"),createService:f(async(c,l)=>{let u=await o(c),h=await n.createService(u,l),p={};return l.components&&(p.components=l.components),l.failureModes&&(p.failureModes=l.failureModes),l.sla&&(p.sla=l.sla),Object.keys(p).length>0?n.updateService(u,h.id,p)??h:h},"createService"),updateService:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return n.updateService(await o(c),l,h)},"updateService"),healthCheck:f(async c=>{let l=this.skillRegistry?.get("itsm");return l?l.execute({action:"health_check"},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"ITSM skill not registered"}},"healthCheck"),getDashboard:f(async c=>n.getDashboard(await o(c)),"getDashboard"),getService:f(async(c,l)=>n.getServiceById(await o(c),l),"getService"),deleteService:f(async(c,l)=>n.deleteService(await o(c),l),"deleteService"),getServicesForAsset:f(async(c,l)=>n.getServicesForAsset(await o(c),l),"getServicesForAsset"),generateDocs:f(async(c,l)=>{let u=this.skillRegistry?.get("infra_docs");return u?u.execute({action:"generate_service_doc",service_id:l},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"InfraDocs not available"}},"generateDocs"),listProblems:f(async(c,l)=>a.listProblems(await o(c),l),"listProblems"),getProblem:f(async(c,l)=>a.getProblemById(await o(c),l),"getProblem"),createProblem:f(async(c,l)=>a.createProblem(await o(c),l),"createProblem"),updateProblem:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return a.updateProblem(await o(c),l,h)},"updateProblem"),linkIncidentToProblem:f(async(c,l,u)=>a.linkIncident(await o(c),l,u),"linkIncidentToProblem"),unlinkIncidentFromProblem:f(async(c,l,u)=>a.unlinkIncident(await o(c),l,u),"unlinkIncidentFromProblem"),createFixChange:f(async(c,l,u)=>{let h=await n.createChangeRequest(await o(c),{...u,linkedProblemId:l});return await a.linkChangeRequest(await o(c),l,h.id),{problem:await a.getProblemById(await o(c),l),changeRequest:h}},"createFixChange"),detectPatterns:f(async(c,l)=>a.detectPatterns(await o(c),l),"detectPatterns"),getProblemDashboard:f(async c=>a.getDashboard(await o(c)),"getProblemDashboard"),setSla:f(async(c,l,u,h)=>{let p=await o(c);return l==="service"?n.updateService(p,u,{sla:h}):i.updateAsset(p,u,{sla:h})},"setSla"),getSlaReport:f(async(c,l,u,h)=>{let p=await o(c),m=this.skillRegistry?.get("itsm");return m?m.execute({action:"get_sla_report",sla_target_type:l,sla_target_id:u,sla_period:h},{userId:p,masterUserId:p}):{success:!1,error:"ITSM skill not registered"}},"getSlaReport"),checkSlaCompliance:f(async c=>{let l=await o(c),u=this.skillRegistry?.get("itsm");return u?u.execute({action:"check_sla_compliance"},{userId:l,masterUserId:l}):{success:!1,error:"ITSM skill not registered"}},"checkSlaCompliance"),getSlaBreaches:f(async(c,l)=>{let u=await o(c);return n.getSlaBreaches(u,l?new Date(l).toISOString():void 0)},"getSlaBreaches")}),t.setDocsCallbacks({generate:f(async(c,l,u)=>{let h=this.skillRegistry?.get("infra_docs");return h?h.execute({action:l,...u},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"InfraDocs skill not registered"}},"generate"),exportData:f(async(c,l)=>{let u=this.skillRegistry?.get("infra_docs");return u?u.execute({action:"export",format:l},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"InfraDocs skill not registered"}},"exportData")}),this.logger.info("CMDB/ITSM/Docs API registered")}}let e=this.adapters.get("api");if(e&&"setLogCallbacks"in e){let t=this.config.logger.file?.path??process.env.ALFRED_LOG_FILE_PATH??"./data/logs/alfred.log",s=this.config.logger.auditLogPath??"./data/logs/audit.log",i=await import("node:fs"),n=await import("node:readline"),r={10:"trace",20:"debug",30:"info",40:"warn",50:"error",60:"fatal"},a={trace:10,debug:20,info:30,warn:40,error:50,fatal:60},o=f(l=>{let u=[],h=Lt.dirname(l),p=Lt.basename(l),m=Lt.extname(p),y=m?p.slice(0,-m.length):p;try{for(let g of i.readdirSync(h)){let w=g===p||g.startsWith(p+"."),T=m!==""&&y!==p&&g.startsWith(y+".")&&g.endsWith(m);if(w||T){let _=Lt.join(h,g);try{let k=i.statSync(_);k.isFile()&&u.push({name:g,path:_,size:k.size,modified:new Date(k.mtimeMs).toISOString(),mtime:k.mtimeMs})}catch{}}}}catch{}return u.sort((g,w)=>w.mtime-g.mtime),u.map(({mtime:g,...w})=>w)},"listLogFiles"),c=f(async(l,u,h,p,m)=>{let y=o(l);if(y.length===0)return{lines:[],total:0,file:l,files:[]};let g=Math.min(m??0,y.length-1),w=y[g].path,k=i.readFileSync(w,"utf-8").split(`
5318
+ ON CONFLICT (user_id, skill, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,[l,a,n,`${r}${o}`,JSON.stringify(c),u])},async loadAllConversationRefs(){let o=await i.query("SELECT key, value FROM skill_state WHERE user_id = ? AND skill = ? AND key LIKE ?",[a,n,`${r}%`]),c=new Map;for(let l of o){let u=l.key.slice(r.length);try{c.set(u,JSON.parse(l.value))}catch{}}return c}}),this.adapters.set("msteams",s),this.logger.info({port:e.msteams.webhookPort??3978},"MS Teams adapter registered (cluster-aware ConversationRef persistence)")}if(e.api?.enabled!==!1){let{HttpAdapter:t}=await Promise.resolve().then(()=>(xs(),Os)),s=e.api?.port??3420,i=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,i,{apiToken:e.api?.token,corsOrigin:e.api?.corsOrigin,publicUrl:e.api?.publicUrl,tls:e.api?.tls,authCallback:this.webAuthCallback,healthCheck:f(async()=>{let n;try{let r=this.config.storage.path,a=hr.statSync(r);n={path:r,sizeBytes:a.size}}catch{}return{db:!!this.database,uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters].map(([r,a])=>[r,a.getStatus()])),metrics:this.pipeline.getMetrics(),costs:this.llmProvider.getCostSummary(),todayUsage:await this.usageRepo?.getDaily(new Date().toISOString().slice(0,10)),watchesActive:await this.watchRepo?.countEnabled()??0,schedulersActive:await this.scheduledActionRepo?.countEnabled()??0,llmProviders:this.llmProvider.getProviderStatuses(),diskUsage:n}},"healthCheck"),metricsCallback:f(()=>this.buildPrometheusMetrics(),"metricsCallback"),dashboardCallback:f(async n=>{let r=new Date().toISOString().slice(0,10),a=n?.range??"week",o,c=!1;a==="today"?o=r:a==="week"?o=new Date(Date.now()-8640*6e4).toISOString().slice(0,10):a==="month"?o=new Date(Date.now()-696*60*6e4).toISOString().slice(0,10):a==="year"?(o=new Date(Date.now()-364*24*60*6e4).toISOString().slice(0,10),c=!0):(o=await this.usageRepo?.getEarliestDate()??r,c=!0);let l=c?await this.usageRepo?.getRangeByMonth(o,r)??[]:await this.usageRepo?.getRange(o,r)??[],u=await this.serviceUsageRepo?.getRange(o,r)??[];return{range:a,startDate:o,endDate:r,bucketGranularity:c?"month":"day",watches:await this.watchRepo?.getEnabled()??[],scheduled:await this.scheduledActionRepo?.getAll()??[],skillHealth:await this.skillHealthRepo?.getAll()??[],reminders:await this.reminderRepo?.getAllPending()??[],usage:{today:await this.usageRepo?.getDaily(r)??null,buckets:l,week:a==="week"?l:[],total:await this.usageRepo?.getTotal()??[]},uptime:Math.floor(process.uptime()),startedAt:this.startedAt,adapters:Object.fromEntries([...this.adapters.entries()].map(([h,p])=>[h,p.getStatus()])),llmProviders:this.llmProvider.getProviderStatuses(),services:this.getConfiguredServices(),serviceUsage:{today:await this.serviceUsageRepo?.getDaily(r)??[],range:u,week:a==="week"?u:await this.serviceUsageRepo?.getRange(new Date(Date.now()-8640*6e4).toISOString().slice(0,10),r)??[],total:await this.serviceUsageRepo?.getTotal()??[]},userUsage:await this.usageRepo?.getByUser(o,r)??[],userSkillUsage:await this.activityRepo?.skillUsageByUser(o)??[]}},"dashboardCallback"),webUiPath:e.api?.webUi!==!1?this.resolveWebUiPath():void 0})),this.logger.info({port:s,host:i,webUi:e.api?.webUi!==!1},"HTTP API adapter registered")}}async start(){if(this.logger.info("Starting Alfred..."),this.config.cluster?.enabled&&this.database.getAdapter().type==="postgres"){let{AdapterClaimManager:t}=await Promise.resolve().then(()=>(rE(),nE));this.adapterClaimManager=new t(this.database.getAdapter(),this.config.cluster.nodeId,this.logger.child({component:"adapter-claims"}));for(let[s,i]of this.adapters){if(s==="api"){this.setupAdapterHandlers(s,i);try{await i.connect(),this.logger.info({platform:s},"Adapter connected (always-on)")}catch(r){this.logger.error({platform:s,err:r},"Adapter connection failed")}continue}if(this.adapterClaimManager.registerPlatform(s),await this.adapterClaimManager.tryClaim(s)){this.setupAdapterHandlers(s,i);try{await i.connect(),this.logger.info({platform:s},"Adapter connected (claimed)")}catch(r){this.logger.error({platform:s,err:r},"Adapter connection failed")}}else this.logger.info({platform:s},"Adapter claimed by another node, skipping")}this.adapterClaimManager.onAcquired(async s=>{if(s==="bmw-streaming"){this.bmwSkill&&(this.logger.info("BMW MQTT streaming acquired from dead node, starting..."),this.bmwSkill.startStreaming().then(()=>this.logger.info("BMW MQTT streaming started (failover)")).catch(n=>this.logger.warn({err:n},"BMW MQTT streaming failover failed")));return}let i=this.adapters.get(s);if(i&&i.getStatus()==="disconnected"){this.setupAdapterHandlers(s,i);try{await i.connect(),this.logger.info({platform:s},"Adapter connected (failover)")}catch(n){this.logger.error({platform:s,err:n},"Failover adapter connection failed")}}}),this.adapterClaimManager.start()}else for(let[t,s]of this.adapters){this.setupAdapterHandlers(t,s);try{await s.connect(),this.logger.info({platform:t},"Adapter connected")}catch(i){this.logger.error({platform:t,err:i},"Adapter connection failed \u2014 skipping")}}if(this.adapterClaimManager&&this.projectHealthMonitor&&this.adapterClaimManager.registerPlatform("project-health-monitor"),this.bmwSkill&&this.config.bmw?.streaming?.enabled&&(this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("bmw-streaming"),!this.adapterClaimManager||await this.adapterClaimManager.tryClaim("bmw-streaming")?(this.logger.info({username:this.config.bmw.streaming.username,topic:this.config.bmw.streaming.topic},"Starting BMW MQTT streaming..."),this.bmwSkill.startStreaming().then(()=>this.logger.info("BMW MQTT streaming started")).catch(s=>this.logger.warn({err:s},"BMW MQTT streaming failed to start"))):this.logger.info("BMW MQTT streaming claimed by another node, skipping")),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.backup?.enabled&&this.config.backup?.storage!=="none"){this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("system-backup");let t=this.skillRegistry.get("system_backup");if(t){let s=-1;setInterval(async()=>{let i=new Date;if(i.getMinutes()===s)return;let n=this.config.backup?.schedule??"0 3 * * *",[r,a]=n.split(" "),o=r==="*"||(r.includes("/")?i.getMinutes()%parseInt(r.split("/")[1])===0:r.split(",").some(l=>parseInt(l)===i.getMinutes())),c=a==="*"||(a.includes("/")?i.getHours()%parseInt(a.split("/")[1])===0:a.split(",").some(l=>parseInt(l)===i.getHours()));if(!(!o||!c)&&(s=i.getMinutes(),!(this.adapterClaimManager&&!await this.adapterClaimManager.tryClaim("system-backup"))))try{await t.createBackup({},"scheduled"),this.logger.info("Scheduled system backup completed")}catch(l){this.logger.warn({err:l},"Scheduled system backup failed")}},6e4),this.logger.info({schedule:this.config.backup.schedule??"0 3 * * *"},"System backup scheduler started")}}if(this.config.commvault?.enabled&&(this.config.commvault.polling_interval??30)>0){this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("commvault-monitor");let t=this.skillRegistry.get("commvault");if(t?.pollAndReport){let s=(this.config.commvault.polling_interval??30)*6e4;setInterval(async()=>{if(!(this.adapterClaimManager&&!await this.adapterClaimManager.tryClaim("commvault-monitor")))try{let i=await t.pollAndReport();(i.failed>0||i.storageWarnings.length>0||i.slaViolations.length>0)&&this.logger.info({...i},"Commvault monitoring alert")}catch(i){this.logger.debug({err:i},"Commvault monitoring poll failed")}},s),this.logger.info({interval:`${this.config.commvault.polling_interval??30}min`},"Commvault monitoring started")}}if(this.config.mikrotik?.enabled&&(this.config.mikrotik.polling_interval??5)>0){this.adapterClaimManager&&this.adapterClaimManager.registerPlatform("mikrotik-monitor");let t=this.skillRegistry.get("mikrotik");if(t?.pollAndReport){let s=(this.config.mikrotik.polling_interval??5)*6e4;setInterval(async()=>{if(!(this.adapterClaimManager&&!await this.adapterClaimManager.tryClaim("mikrotik-monitor")))try{let i=await t.pollAndReport();(i.downInterfaces.length>0||i.cpuWarnings.length>0)&&this.logger.info({...i},"MikroTik monitoring alert")}catch(i){this.logger.debug({err:i},"MikroTik monitoring poll failed")}},s),this.logger.info({interval:`${this.config.mikrotik.polling_interval??5}min`},"MikroTik monitoring started")}}if(this.config.webhooks?.length&&this.watchEngine){let t=this.adapters.get("api");if(t&&"addWebhook"in t){let s=t;for(let i of this.config.webhooks)s.addWebhook({name:i.name,secret:i.secret,callback:f(async n=>{if(i.watchId&&this.watchEngine&&await this.watchEngine.triggerWatch(i.watchId),i.chatId&&i.platform){let r=this.adapters.get(i.platform);if(r){let a=`\u{1F514} Webhook "${i.name}" triggered`+(n.action?`: ${n.action}`:"");await r.sendMessage(i.chatId,a)}}},"callback")}),this.logger.info({name:i.name,watchId:i.watchId},"Webhook registered")}}{let t=this.adapters.get("api");t&&"registerOAuthCallback"in t&&(this.spotifySkill&&(t.registerOAuthCallback("spotify",(s,i)=>this.spotifySkill.handleOAuthCallback(s,i)),this.logger.info("Spotify OAuth callback registered")),this.sonosSkill&&this.config.sonos?.cloud?.clientId&&(t.registerOAuthCallback("sonos",(s,i)=>this.sonosSkill.handleOAuthCallback(s,i)),this.logger.info("Sonos Cloud OAuth callback registered")))}{let t=this.adapters.get("api"),s=this.database.getAdapter();if(t&&"setKnowledgeGraphCallbacks"in t){let i=new rs(s);t.setKnowledgeGraphCallbacks({getGraph:f(async n=>{let r=n??this.config.security?.ownerUserId??"";try{let a=await this.userRepo.findOrCreate("telegram",r),o=a.masterUserId??a.id;return i.getFullGraph(o)}catch{return i.getFullGraph(r)}},"getGraph"),deleteEntity:f(async n=>(await s.execute("DELETE FROM kg_entities WHERE id = ?",[n])).changes>0,"deleteEntity"),deleteRelation:f(async n=>(await s.execute("DELETE FROM kg_relations WHERE id = ?",[n])).changes>0,"deleteRelation"),updateEntity:f(async(n,r)=>{let a=[],o=[];if(r.name!==void 0&&(a.push("name = ?"),o.push(r.name),a.push("normalized_name = ?"),o.push(String(r.name).trim().toLowerCase())),r.entityType!==void 0&&(a.push("entity_type = ?"),o.push(r.entityType)),r.attributes!==void 0&&(a.push("attributes = ?"),o.push(JSON.stringify(r.attributes))),a.length===0)return!1;a.push("last_seen_at = ?"),o.push(new Date().toISOString()),o.push(n);try{return(await s.execute(`UPDATE kg_entities SET ${a.join(", ")} WHERE id = ?`,o)).changes>0}catch{return!1}},"updateEntity"),updateRelation:f(async(n,r)=>{let a=[],o=[];if(r.relationType!==void 0&&(a.push("relation_type = ?"),o.push(r.relationType)),r.strength!==void 0&&(a.push("strength = ?"),o.push(r.strength)),r.context!==void 0&&(a.push("context = ?"),o.push(r.context)),a.length===0)return!1;a.push("last_seen_at = ?"),o.push(new Date().toISOString()),o.push(n);try{return(await s.execute(`UPDATE kg_relations SET ${a.join(", ")} WHERE id = ?`,o)).changes>0}catch{return!1}},"updateRelation")}),this.logger.info("Knowledge Graph API registered")}if(t&&this.memoryRepo&&"setMemoryCallbacks"in t){let i=this.memoryRepo,n=s;t.setMemoryCallbacks({list:f(async r=>{try{let a=this.config.security?.ownerUserId??"",o=await this.userRepo.findOrCreate("telegram",a),c=o.masterUserId??o.id;return r?.type?await i.getByType(c,r.type,200):await i.getAllForUser(c)}catch(a){return this.logger.warn({err:a},"Memories API list failed"),[]}},"list"),delete:f(async r=>(await n.execute("DELETE FROM memories WHERE id = ?",[r])).changes>0,"delete"),updateType:f(async(r,a)=>await i.updateType(r,a),"updateType")}),this.logger.info("Memories API registered")}if(t&&this.runbookRepo&&"setRunbookCallbacks"in t){let i=this.runbookRepo,n=f(async()=>{let r=this.config.security?.ownerUserId??"";try{let a=await this.userRepo.findOrCreate("telegram",r);return a.masterUserId??a.id}catch{return r}},"resolveOwner");t.setRunbookCallbacks({list:f(async r=>{try{let a=await n();return await i.list(a,r)}catch(a){return this.logger.warn({err:a},"Runbook API list failed"),[]}},"list"),get:f(async r=>{try{let a=await n();return await i.getById(a,r)}catch{return null}},"get"),update:f(async(r,a)=>{try{let o=await n();return await i.update(o,r,a)}catch(o){return this.logger.warn({err:o},"Runbook API update failed"),null}},"update"),delete:f(async r=>{try{let a=await n();return await i.delete(a,r)}catch{return!1}},"delete")}),this.logger.info("Runbook API registered")}if(t&&this.database&&"setProjectAgentCallbacks"in t){let{ProjectAgentSessionRepository:i}=await Promise.resolve().then(()=>(Je(),Ze)),n=new i(this.database.getAdapter()),{pushInterjection:r}=await Promise.resolve().then(()=>(fe(),ye));t.setProjectAgentCallbacks({list:f(async a=>{try{return await n.listAll({phase:a?.phase,limit:200})}catch(o){return this.logger.warn({err:o},"Project-Agent API list failed"),[]}},"list"),get:f(async a=>{try{return await n.getByTaskId(a)}catch{return null}},"get"),stop:f(async a=>{try{let o=await n.getByTaskId(a);return o?(o.currentPhase==="done"||o.currentPhase==="failed"||await r(a,"__STOP__"),!0):!1}catch(o){return this.logger.warn({err:o,taskId:a},"Project-Agent API stop failed"),!1}},"stop")}),this.logger.info("Project-Agent API registered")}if(t&&this.database&&"setBackgroundTaskCallbacks"in t){let{BackgroundTaskRepository:i}=await Promise.resolve().then(()=>(Je(),Ze)),n=new i(this.database.getAdapter());t.setBackgroundTaskCallbacks({list:f(async r=>{try{return await n.listAll({status:r?.status,limit:200})}catch(a){return this.logger.warn({err:a},"Background-Tasks API list failed"),[]}},"list"),get:f(async r=>{try{return await n.getById(r)??null}catch{return null}},"get"),cancel:f(async r=>{try{return await n.cancel(r)}catch(a){return this.logger.warn({err:a,id:r},"Background-Tasks API cancel failed"),!1}},"cancel")}),this.logger.info("Background-Tasks API registered")}if(t&&this.projectRepo&&"setProjectsCallbacks"in t){let i=this.projectRepo,n=f(async()=>{let r=this.config.security?.ownerUserId??"";try{let a=await this.userRepo.findOrCreate("telegram",r);return a.masterUserId??a.id}catch{return r}},"resolveOwnerProj");t.setProjectsCallbacks({list:f(async r=>{try{let a=await n();return await i.list(a,r)}catch(a){return this.logger.warn({err:a},"Projects API list failed"),[]}},"list"),get:f(async r=>{try{let a=await n(),o=await i.getById(a,r);if(!o)return null;let[c,l,u,h]=await Promise.all([i.listSessions(o.id,50),i.listOpenItems(a,{projectId:o.id,limit:200}),i.listDecisions(o.id,50),i.getCurrentHealthSummary(o.id)]);return{project:o,sessions:c,openItems:l,decisions:u,health:h}}catch(a){return this.logger.warn({err:a},"Projects API get failed"),null}},"get"),create:f(async r=>{try{let a=await n();return await i.create(a,r)}catch(a){return this.logger.warn({err:a},"Projects API create failed"),null}},"create"),update:f(async(r,a)=>{try{let o=await n();return await i.update(o,r,a)}catch(o){return this.logger.warn({err:o},"Projects API update failed"),null}},"update"),archive:f(async r=>{try{let a=await n();return!!await i.update(a,r,{status:"archived"})}catch{return!1}},"archive"),addOpenItem:f(async(r,a)=>{try{let o=await n(),c=await i.getById(o,r);return c?await i.addOpenItem(c.id,a):null}catch(o){return this.logger.warn({err:o},"Projects API addOpenItem failed"),null}},"addOpenItem"),updateOpenItem:f(async(r,a)=>{try{return await i.updateOpenItemStatus(r,a)}catch{return!1}},"updateOpenItem"),listHealthLog:f(async(r,a)=>{try{let o=await n(),c=await i.getById(o,r);return c?await i.listHealthLog(c.id,a):[]}catch{return[]}},"listHealthLog")}),this.logger.info("Projects API registered")}}if(this.config.cmdb?.enabled!==!1&&(this.config.proxmox||this.config.unifi||this.config.docker||this.config.cloudflare||this.config.nginxProxyManager||this.config.pfsense||this.config.homeassistant)){let t=this.adapters.get("api"),s=this.database.getAdapter();if(t&&"setCmdbCallbacks"in t){let i=new Hs(s),n=new oi(s);n.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;let{ProblemRepository:r}=await Promise.resolve().then(()=>(Je(),Ze)),a=new r(s),o=f(async c=>{if(!c&&this.config.security?.ownerUserId&&this.userRepo)try{let l=await this.userRepo.findOrCreate("telegram",this.config.security.ownerUserId);return l.masterUserId??l.id??this.config.security.ownerUserId}catch{return this.config.security.ownerUserId}return c||this.ownerMasterUserId||this.config.security?.ownerUserId||""},"resolveUser");t.setCmdbCallbacks({listAssets:f(async(c,l)=>i.listAssets(await o(c),l),"listAssets"),getAsset:f(async(c,l)=>{let u=await o(c),h=await i.getAssetById(u,l),p=h?await i.getRelationsForAsset(u,l):[],m=h?await i.getChangesForAsset(u,l,20):[];return{asset:h,relations:p,changes:m}},"getAsset"),createAsset:f(async(c,l)=>i.upsertAsset(await o(c),l),"createAsset"),updateAsset:f(async(c,l,u)=>i.updateAsset(await o(c),l,u),"updateAsset"),deleteAsset:f(async(c,l)=>i.decommissionAsset(await o(c),l),"deleteAsset"),listRelations:f(async c=>i.getAllRelations(await o(c)),"listRelations"),createRelation:f(async(c,l)=>i.upsertRelation(await o(c),l.source_asset_id,l.target_asset_id,l.relation_type),"createRelation"),deleteRelation:f(async(c,l)=>i.removeRelation(await o(c),l),"deleteRelation"),discover:f(async c=>{let l=this.skillRegistry?.get("cmdb");return l?l.execute({action:"discover"},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"CMDB skill not registered"}},"discover"),getStats:f(async c=>i.getStats(await o(c)),"getStats"),getChanges:f(async(c,l)=>i.getChangesForAsset(await o(c),l),"getChanges"),listDocuments:f(async(c,l)=>i.listDocuments(await o(c),l),"listDocuments"),getDocument:f(async(c,l)=>i.getDocumentById(await o(c),l),"getDocument"),getDocumentTree:f(async c=>i.getDocumentTree(await o(c)),"getDocumentTree"),saveDocument:f(async(c,l)=>i.saveDocument(await o(c),l),"saveDocument"),updateDocument:f(async(c,l,u)=>i.updateDocument(await o(c),l,u),"updateDocument"),deleteDocument:f(async(c,l)=>i.deleteDocument(await o(c),l),"deleteDocument"),getDocumentVersions:f(async(c,l,u,h)=>i.getDocumentVersions(await o(c),l,u,h),"getDocumentVersions"),searchDocuments:f(async(c,l,u)=>i.searchDocuments(await o(c),l,u),"searchDocuments")}),t.setItsmCallbacks({listIncidents:f(async(c,l)=>n.listIncidents(await o(c),l),"listIncidents"),getIncident:f(async(c,l)=>n.getIncidentById(await o(c),l),"getIncident"),createIncident:f(async(c,l)=>n.createIncident(await o(c),l),"createIncident"),updateIncident:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return n.updateIncident(await o(c),l,h)},"updateIncident"),listChanges:f(async(c,l)=>n.listChangeRequests(await o(c),l),"listChanges"),createChange:f(async(c,l)=>n.createChangeRequest(await o(c),l),"createChange"),updateChange:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return n.updateChangeRequest(await o(c),l,h)},"updateChange"),listServices:f(async(c,l)=>n.listServices(await o(c),l),"listServices"),createService:f(async(c,l)=>{let u=await o(c),h=await n.createService(u,l),p={};return l.components&&(p.components=l.components),l.failureModes&&(p.failureModes=l.failureModes),l.sla&&(p.sla=l.sla),Object.keys(p).length>0?n.updateService(u,h.id,p)??h:h},"createService"),updateService:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return n.updateService(await o(c),l,h)},"updateService"),healthCheck:f(async c=>{let l=this.skillRegistry?.get("itsm");return l?l.execute({action:"health_check"},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"ITSM skill not registered"}},"healthCheck"),getDashboard:f(async c=>n.getDashboard(await o(c)),"getDashboard"),getService:f(async(c,l)=>n.getServiceById(await o(c),l),"getService"),deleteService:f(async(c,l)=>n.deleteService(await o(c),l),"deleteService"),getServicesForAsset:f(async(c,l)=>n.getServicesForAsset(await o(c),l),"getServicesForAsset"),generateDocs:f(async(c,l)=>{let u=this.skillRegistry?.get("infra_docs");return u?u.execute({action:"generate_service_doc",service_id:l},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"InfraDocs not available"}},"generateDocs"),listProblems:f(async(c,l)=>a.listProblems(await o(c),l),"listProblems"),getProblem:f(async(c,l)=>a.getProblemById(await o(c),l),"getProblem"),createProblem:f(async(c,l)=>a.createProblem(await o(c),l),"createProblem"),updateProblem:f(async(c,l,u)=>{let h={};for(let[p,m]of Object.entries(u))h[p.replace(/_([a-z])/g,(y,g)=>g.toUpperCase())]=m;return a.updateProblem(await o(c),l,h)},"updateProblem"),linkIncidentToProblem:f(async(c,l,u)=>a.linkIncident(await o(c),l,u),"linkIncidentToProblem"),unlinkIncidentFromProblem:f(async(c,l,u)=>a.unlinkIncident(await o(c),l,u),"unlinkIncidentFromProblem"),createFixChange:f(async(c,l,u)=>{let h=await n.createChangeRequest(await o(c),{...u,linkedProblemId:l});return await a.linkChangeRequest(await o(c),l,h.id),{problem:await a.getProblemById(await o(c),l),changeRequest:h}},"createFixChange"),detectPatterns:f(async(c,l)=>a.detectPatterns(await o(c),l),"detectPatterns"),getProblemDashboard:f(async c=>a.getDashboard(await o(c)),"getProblemDashboard"),setSla:f(async(c,l,u,h)=>{let p=await o(c);return l==="service"?n.updateService(p,u,{sla:h}):i.updateAsset(p,u,{sla:h})},"setSla"),getSlaReport:f(async(c,l,u,h)=>{let p=await o(c),m=this.skillRegistry?.get("itsm");return m?m.execute({action:"get_sla_report",sla_target_type:l,sla_target_id:u,sla_period:h},{userId:p,masterUserId:p}):{success:!1,error:"ITSM skill not registered"}},"getSlaReport"),checkSlaCompliance:f(async c=>{let l=await o(c),u=this.skillRegistry?.get("itsm");return u?u.execute({action:"check_sla_compliance"},{userId:l,masterUserId:l}):{success:!1,error:"ITSM skill not registered"}},"checkSlaCompliance"),getSlaBreaches:f(async(c,l)=>{let u=await o(c);return n.getSlaBreaches(u,l?new Date(l).toISOString():void 0)},"getSlaBreaches")}),t.setDocsCallbacks({generate:f(async(c,l,u)=>{let h=this.skillRegistry?.get("infra_docs");return h?h.execute({action:l,...u},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"InfraDocs skill not registered"}},"generate"),exportData:f(async(c,l)=>{let u=this.skillRegistry?.get("infra_docs");return u?u.execute({action:"export",format:l},{userId:await o(c),masterUserId:await o(c)}):{success:!1,error:"InfraDocs skill not registered"}},"exportData")}),this.logger.info("CMDB/ITSM/Docs API registered")}}let e=this.adapters.get("api");if(e&&"setLogCallbacks"in e){let t=this.config.logger.file?.path??process.env.ALFRED_LOG_FILE_PATH??"./data/logs/alfred.log",s=this.config.logger.auditLogPath??"./data/logs/audit.log",i=await import("node:fs"),n=await import("node:readline"),r={10:"trace",20:"debug",30:"info",40:"warn",50:"error",60:"fatal"},a={trace:10,debug:20,info:30,warn:40,error:50,fatal:60},o=f(l=>{let u=[],h=Lt.dirname(l),p=Lt.basename(l),m=Lt.extname(p),y=m?p.slice(0,-m.length):p;try{for(let g of i.readdirSync(h)){let w=g===p||g.startsWith(p+"."),T=m!==""&&y!==p&&g.startsWith(y+".")&&g.endsWith(m);if(w||T){let _=Lt.join(h,g);try{let k=i.statSync(_);k.isFile()&&u.push({name:g,path:_,size:k.size,modified:new Date(k.mtimeMs).toISOString(),mtime:k.mtimeMs})}catch{}}}}catch{}return u.sort((g,w)=>w.mtime-g.mtime),u.map(({mtime:g,...w})=>w)},"listLogFiles"),c=f(async(l,u,h,p,m)=>{let y=o(l);if(y.length===0)return{lines:[],total:0,file:l,files:[]};let g=Math.min(m??0,y.length-1),w=y[g].path,k=i.readFileSync(w,"utf-8").split(`
5308
5319
  `).filter(Boolean).map($=>{try{return JSON.parse($)}catch{return null}}).filter(Boolean);if(h){let $=a[h]??30;k=k.filter(C=>C.level>=$)}if(p){let $=p.toLowerCase();k=k.filter(C=>{let L=(C.msg??"").toLowerCase(),x=(C.component??"").toLowerCase();return L.includes($)||x.includes($)||JSON.stringify(C).toLowerCase().includes($)})}let b=k.length;return{lines:k.slice(-u),total:b,file:w,files:y}},"readLogFile");e.setLogCallbacks({readAppLog:f((l,u,h,p)=>c(t,l,u,h,p),"readAppLog"),readAuditLog:f((l,u,h,p)=>c(s,l,void 0,void 0,p),"readAuditLog"),streamAppLog:f((l,u,h)=>{let p=o(t),m=p.length>0?p[0].path:t,y=u?a[u]??30:0,g=h?.toLowerCase(),w=0;try{w=i.statSync(m).size}catch{}let T=i.watch(m,()=>{try{let _=i.statSync(m);if(_.size<=w){w=_.size;return}let k=i.createReadStream(m,{start:w,encoding:"utf-8"}),b="";k.on("data",v=>{b+=String(v)}),k.on("end",()=>{for(let v of b.split(`
5309
5320
  `).filter(Boolean))try{let $=JSON.parse(v);if(y&&$.level<y||g&&!JSON.stringify($).toLowerCase().includes(g))continue;l.writableEnded||l.write(`data: ${JSON.stringify($)}
5310
5321
 
5311
- `)}catch{}w=_.size})}catch{}});return()=>{T.close()}},"streamAppLog")})}if(e&&"setClusterCallbacks"in e){let t=this.database?.getAdapter(),s=this.config.cluster?.nodeId??"single",i=this.config.cluster?.enabled===!0,n=this.config.reasoning?.schedule??"hourly",r=this.startedAt;e.setClusterCallbacks({getHealth:f(async()=>{let a=[],o=[],c=[];if(t){try{let l=await t.query("SELECT * FROM node_heartbeats ORDER BY last_seen_at DESC",[]),u=Date.now();for(let h of l)a.push({nodeId:h.node_id,host:h.host??"",lastSeenAt:h.last_seen_at,startedAt:h.started_at,uptimeS:h.uptime_s??0,adapters:JSON.parse(h.adapters??"[]"),version:h.version??"",alive:u-new Date(h.last_seen_at).getTime()<6e4})}catch{}try{let l=await t.query("SELECT * FROM adapter_claims ORDER BY platform",[]),u=new Date().toISOString();for(let h of l)o.push({platform:h.platform,nodeId:h.node_id,claimedAt:h.claimed_at,expiresAt:h.expires_at,active:h.expires_at>u})}catch{}try{let l=await t.query("SELECT * FROM reasoning_slots ORDER BY claimed_at DESC LIMIT 20",[]);for(let u of l)c.push({slotKey:u.slot_key,nodeId:u.node_id,claimedAt:u.claimed_at})}catch{}}if(!i&&a.length===0){let l=Math.floor((Date.now()-new Date(r).getTime())/1e3),u=[...this.adapters?.keys()??[]];a.push({nodeId:s,host:Wd("os").hostname(),lastSeenAt:new Date().toISOString(),startedAt:r,uptimeS:l,adapters:u,version:"",alive:!0})}return{clusterEnabled:i,thisNodeId:s,nodes:a,claims:o,recentReasoningSlots:c,operations:{reasoning:{schedule:n},backup:this.config.backup?.schedule?{schedule:this.config.backup.schedule}:void 0}}},"getHealth")})}try{let t={audit:await this.auditRepo?.cleanup(90)??0,summaries:await this.summaryRepo?.cleanup(180)??0,activity:await this.activityRepo?.cleanup(90)??0,usage:await this.usageRepo?.cleanup(365)??0,expiredMemories:await this.memoryRepo?.cleanupExpired()??0,processedMessages:this.config.cluster?.enabled?await new(await Promise.resolve().then(()=>(Je(),tt))).ProcessedMessageRepository(this.database.getAdapter()).cleanup():0};(t.audit||t.summaries||t.activity||t.usage)&&this.logger.info(t,"Startup DB cleanup completed")}catch(t){this.logger.warn({err:t},"Startup DB cleanup failed")}if(this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.config.activeLearning?.enabled!==!1&&this.memoryRepo){let t=new Ja(this.llmProvider,this.memoryRepo,this.logger.child({component:"memory-consolidator"}));if(this.database){let{EmbeddingRepository:n}=await Promise.resolve().then(()=>(Je(),tt)),r=new n(this.database.getAdapter());t.setEmbeddingRepo(r)}let s=this.userRepo;try{let n=Intl.DateTimeFormat().resolvedOptions().timeZone,r=await s.listAll();for(let a of r){let o=await t.migrateLegacyMemoriesV582(a.id,n);(o.resolved>0||o.relevantUntilSet>0||o.refsSet>0||o.resolvedExpirySet>0)&&this.logger.info({userId:a.id,...o},"Legacy memory migration v582 applied")}}catch(n){this.logger.warn({err:n},"Legacy memory migration v582 startup hook failed")}let i="";if(this.memoryConsolidatorTimer=setInterval(async()=>{let n=new Date,r=n.toISOString().slice(0,10);if(!(n.getHours()!==3||i===r)){i=r;try{let a=await s.listAll();for(let o of a){let c=await t.consolidate(o.id);(c.deleted>0||c.merged>0)&&this.logger.info({userId:o.id,...c},"Memory consolidation completed")}}catch(a){this.logger.warn({err:a},"Memory consolidation failed")}}},60*6e4),this.activityRepo){let n=new Kl(this.llmProvider,this.memoryRepo,this.activityRepo,this.logger.child({component:"pattern-analyzer"})),r="";this.patternAnalyzerTimer=setInterval(async()=>{let c=new Date,l=c.toISOString().slice(0,10);if(!(c.getHours()!==3||c.getMinutes()<30||r===l)){r=l;try{let u=await s.listAll();for(let h of u){let p=await n.analyze(h.id);p>0&&this.logger.info({userId:h.id,patterns:p},"Pattern analysis completed")}}catch(u){this.logger.warn({err:u},"Pattern analysis failed")}}},60*6e4);let a=new Za(this.activityRepo,this.memoryRepo,this.logger.child({component:"temporal-analyzer"})),o="";this.temporalAnalyzerTimer=setInterval(async()=>{let c=new Date,l=`${c.getFullYear()}-W${String(kR(c)).padStart(2,"0")}`;if(!(c.getDay()!==0||c.getHours()!==4||o===l)){if(o=l,this.database.getAdapter().type==="postgres")try{let u=`maintenance:${l}`;if((await this.database.getAdapter().execute("INSERT INTO reasoning_slots (slot_key, node_id, claimed_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING",[u,this.config.cluster?.nodeId??"single",c.toISOString()])).changes===0){this.logger.debug("Weekly maintenance slot already claimed by another node");return}}catch{}try{let u=await s.listAll(),h=this.reasoningEngine?new rr(new rs(this.database.getAdapter()),this.logger.child({component:"knowledge-graph"}),this.memoryRepo):void 0;for(let p of u){let m=await a.analyze(p.id);if((m.trends.length>0||m.anomalies.length>0)&&this.logger.info({userId:p.id,trends:m.trends.length,anomalies:m.anomalies.length},"Temporal analysis completed"),h&&await h.maintenance(p.id),this.activityRepo&&this.memoryRepo&&await new Ai(this.activityRepo,this.memoryRepo,this.logger.child({component:"action-feedback"})).analyze(p.id),this.memoryRepo)try{let y=await this.memoryRepo.cleanupExpired();y>0&&this.logger.info({cleaned:y},"Expired memories cleaned up")}catch(y){this.logger.warn({err:y.message},"Memory cleanup failed")}if(this.bmwTelematicRepo){let y=await this.bmwTelematicRepo.prune(90);y>0&&this.logger.info({pruned:y},"BMW telematic history pruned")}if(h?.getLLMLinker())try{let g=await this.database.getAdapter().query(`SELECT role, content FROM messages WHERE conversation_id IN (
5322
+ `)}catch{}w=_.size})}catch{}});return()=>{T.close()}},"streamAppLog")})}if(e&&"setClusterCallbacks"in e){let t=this.database?.getAdapter(),s=this.config.cluster?.nodeId??"single",i=this.config.cluster?.enabled===!0,n=this.config.reasoning?.schedule??"hourly",r=this.startedAt;e.setClusterCallbacks({getHealth:f(async()=>{let a=[],o=[],c=[];if(t){try{let l=await t.query("SELECT * FROM node_heartbeats ORDER BY last_seen_at DESC",[]),u=Date.now();for(let h of l)a.push({nodeId:h.node_id,host:h.host??"",lastSeenAt:h.last_seen_at,startedAt:h.started_at,uptimeS:h.uptime_s??0,adapters:JSON.parse(h.adapters??"[]"),version:h.version??"",alive:u-new Date(h.last_seen_at).getTime()<6e4})}catch{}try{let l=await t.query("SELECT * FROM adapter_claims ORDER BY platform",[]),u=new Date().toISOString();for(let h of l)o.push({platform:h.platform,nodeId:h.node_id,claimedAt:h.claimed_at,expiresAt:h.expires_at,active:h.expires_at>u})}catch{}try{let l=await t.query("SELECT * FROM reasoning_slots ORDER BY claimed_at DESC LIMIT 20",[]);for(let u of l)c.push({slotKey:u.slot_key,nodeId:u.node_id,claimedAt:u.claimed_at})}catch{}}if(!i&&a.length===0){let l=Math.floor((Date.now()-new Date(r).getTime())/1e3),u=[...this.adapters?.keys()??[]];a.push({nodeId:s,host:Wd("os").hostname(),lastSeenAt:new Date().toISOString(),startedAt:r,uptimeS:l,adapters:u,version:"",alive:!0})}return{clusterEnabled:i,thisNodeId:s,nodes:a,claims:o,recentReasoningSlots:c,operations:{reasoning:{schedule:n},backup:this.config.backup?.schedule?{schedule:this.config.backup.schedule}:void 0}}},"getHealth")})}try{let t={audit:await this.auditRepo?.cleanup(90)??0,summaries:await this.summaryRepo?.cleanup(180)??0,activity:await this.activityRepo?.cleanup(90)??0,usage:await this.usageRepo?.cleanup(365)??0,expiredMemories:await this.memoryRepo?.cleanupExpired()??0,processedMessages:this.config.cluster?.enabled?await new(await Promise.resolve().then(()=>(Je(),Ze))).ProcessedMessageRepository(this.database.getAdapter()).cleanup():0};(t.audit||t.summaries||t.activity||t.usage)&&this.logger.info(t,"Startup DB cleanup completed")}catch(t){this.logger.warn({err:t},"Startup DB cleanup failed")}if(this.skillHealthTracker&&(this.healthCheckTimer=setInterval(()=>this.skillHealthTracker.checkReEnables(),5*6e4)),this.config.activeLearning?.enabled!==!1&&this.memoryRepo){let t=new Ja(this.llmProvider,this.memoryRepo,this.logger.child({component:"memory-consolidator"}));if(this.database){let{EmbeddingRepository:n}=await Promise.resolve().then(()=>(Je(),Ze)),r=new n(this.database.getAdapter());t.setEmbeddingRepo(r)}let s=this.userRepo;try{let n=Intl.DateTimeFormat().resolvedOptions().timeZone,r=await s.listAll();for(let a of r){let o=await t.migrateLegacyMemoriesV582(a.id,n);(o.resolved>0||o.relevantUntilSet>0||o.refsSet>0||o.resolvedExpirySet>0)&&this.logger.info({userId:a.id,...o},"Legacy memory migration v582 applied")}}catch(n){this.logger.warn({err:n},"Legacy memory migration v582 startup hook failed")}let i="";if(this.memoryConsolidatorTimer=setInterval(async()=>{let n=new Date,r=n.toISOString().slice(0,10);if(!(n.getHours()!==3||i===r)){i=r;try{let a=await s.listAll();for(let o of a){let c=await t.consolidate(o.id);(c.deleted>0||c.merged>0)&&this.logger.info({userId:o.id,...c},"Memory consolidation completed")}}catch(a){this.logger.warn({err:a},"Memory consolidation failed")}}},60*6e4),this.activityRepo){let n=new Kl(this.llmProvider,this.memoryRepo,this.activityRepo,this.logger.child({component:"pattern-analyzer"})),r="";this.patternAnalyzerTimer=setInterval(async()=>{let c=new Date,l=c.toISOString().slice(0,10);if(!(c.getHours()!==3||c.getMinutes()<30||r===l)){r=l;try{let u=await s.listAll();for(let h of u){let p=await n.analyze(h.id);p>0&&this.logger.info({userId:h.id,patterns:p},"Pattern analysis completed")}}catch(u){this.logger.warn({err:u},"Pattern analysis failed")}}},60*6e4);let a=new Za(this.activityRepo,this.memoryRepo,this.logger.child({component:"temporal-analyzer"})),o="";this.temporalAnalyzerTimer=setInterval(async()=>{let c=new Date,l=`${c.getFullYear()}-W${String(kR(c)).padStart(2,"0")}`;if(!(c.getDay()!==0||c.getHours()!==4||o===l)){if(o=l,this.database.getAdapter().type==="postgres")try{let u=`maintenance:${l}`;if((await this.database.getAdapter().execute("INSERT INTO reasoning_slots (slot_key, node_id, claimed_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING",[u,this.config.cluster?.nodeId??"single",c.toISOString()])).changes===0){this.logger.debug("Weekly maintenance slot already claimed by another node");return}}catch{}try{let u=await s.listAll(),h=this.reasoningEngine?new rr(new rs(this.database.getAdapter()),this.logger.child({component:"knowledge-graph"}),this.memoryRepo):void 0;for(let p of u){let m=await a.analyze(p.id);if((m.trends.length>0||m.anomalies.length>0)&&this.logger.info({userId:p.id,trends:m.trends.length,anomalies:m.anomalies.length},"Temporal analysis completed"),h&&await h.maintenance(p.id),this.activityRepo&&this.memoryRepo&&await new Ai(this.activityRepo,this.memoryRepo,this.logger.child({component:"action-feedback"})).analyze(p.id),this.memoryRepo)try{let y=await this.memoryRepo.cleanupExpired();y>0&&this.logger.info({cleaned:y},"Expired memories cleaned up")}catch(y){this.logger.warn({err:y.message},"Memory cleanup failed")}if(this.bmwTelematicRepo){let y=await this.bmwTelematicRepo.prune(90);y>0&&this.logger.info({pruned:y},"BMW telematic history pruned")}if(h?.getLLMLinker())try{let g=await this.database.getAdapter().query(`SELECT role, content FROM messages WHERE conversation_id IN (
5312
5323
  SELECT id FROM conversations WHERE user_id = ?
5313
- ) ORDER BY created_at DESC LIMIT 100`,[p.id]);if(g.length>10){let w=await h.getLLMLinker().analyzeRecentChats(p.id,g.reverse());(w.relations>0||w.newEntities>0)&&this.logger.info({...w},"Weekly chat analysis completed")}}catch(y){this.logger.debug({err:y},"Weekly chat analysis failed")}}}catch(u){this.logger.warn({err:u},"Temporal analysis failed")}try{if(this.config.cmdb?.enabled!==!1&&this.database){let u=this.database.getAdapter(),{CmdbRepository:h,ItsmRepository:p}=await Promise.resolve().then(()=>(Je(),tt)),m=new h(u),y=new p(u),g=this.userRepo?await this.userRepo.findOrCreate("telegram",this.config.security?.ownerUserId??""):void 0,w=g?.masterUserId??g?.id??this.config.security?.ownerUserId??"";if(w){let T=await m.listAssets(w),_=T.filter($=>["server","vm","lxc","container","application","service"].includes($.assetType)&&$.status==="active"),k=await y.listServices(w),b=new Set;for(let $ of k)for(let C of $.assetIds??[])b.add(C);let v=0;for(let $ of _){if(b.has($.id))continue;let C=["server","vm","lxc"].includes($.assetType)?"infrastructure":$.assetType==="container"||$.assetType==="application"?"application":"infrastructure",L=$.environment==="production"?"high":"medium";try{await y.createService(w,{name:`${$.name} Service`,description:`Automatisch abgeleitet aus CMDB-Asset (${$.assetType}). ${$.purpose??""}`.trim(),category:C,environment:$.environment,criticality:L,assetIds:[$.id],tags:"auto-discovered"}),v++}catch{}}v>0&&this.logger.info({createdServices:v,totalAssets:T.length},"Weekly service-discovery completed")}}}catch(u){this.logger.warn({err:u},"Weekly service-discovery failed")}}},60*6e4)}}if(this.config.reflection?.enabled!==!1&&this.watchRepo&&this.memoryRepo&&this.activityRepo&&this.skillRegistry&&this.skillSandbox)try{let t=Ql(this.config.reflection),s=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",i=this.database?.getAdapter(),n=this.config.cmdb?.enabled!==!1&&i?new Hs(i):void 0,r=this.config.telegram?.enabled?this.config.security?.ownerUserId??"":"";this.reflectionEngine=new go({watchRepo:this.watchRepo,memoryRepo:this.memoryRepo,activityRepo:this.activityRepo,cmdbRepo:n,projectRepo:this.projectRepo,runbookRepo:this.runbookRepo,ownerUserId:this.ownerMasterUserId??this.config.security?.ownerUserId,skillRegistry:this.skillRegistry,skillSandbox:this.skillSandbox,llm:this.llmProvider,adapters:this.adapters,logger:this.logger.child({component:"reflection-engine"}),defaultChatId:r,defaultPlatform:s,nodeId:this.config.cluster?.nodeId??"single",config:t},this.database?.getAdapter()),this.reflectionEngine.start(),this.logger.info("Reflection engine initialized")}catch(t){this.logger.warn({err:t},"Reflection engine initialization failed")}if(this.runbookRepo&&this.memoryRepo&&this.confirmationQueue&&this.database&&this.llmProvider)try{let{ChatSessionRunbookReflector:t}=await Promise.resolve().then(()=>(cE(),oE)),{ConversationRepository:s}=await Promise.resolve().then(()=>(Je(),tt)),i=this.database.getAdapter(),n=new s(i),r=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";this.chatSessionRunbookReflector=new t(i,n,this.runbookRepo,this.memoryRepo,this.confirmationQueue,this.llmProvider,this.logger.child({component:"runbook-reflector"}),r,this.config.security?.ownerUserId??""),this.chatSessionRunbookReflector.start(),this.logger.info("Chat-session runbook reflector started")}catch(t){this.logger.warn({err:t},"Chat-session runbook reflector init failed")}if(this.activityRepo&&this.confirmationQueue&&this.runbookRepo)try{let{SkillFailureReflector:t}=await Promise.resolve().then(()=>(dE(),lE)),s=new t(this.activityRepo,this.logger.child({component:"skill-failure-reflector"}));setInterval(async()=>{let i=this.ownerMasterUserId??this.config.security?.ownerUserId;if(!(!i||!this.confirmationQueue))try{let n=await s.detect(i);for(let r of n){let a=`skill-failure-runbook-${r.failedSkill}-${(r.scope??"").replace(/[^a-z0-9]/gi,"_").slice(0,30)}-${r.errorClass}`,o=`Skill "${r.failedSkill}" auf ${r.scope??"?"} \u2192 Workaround`,c=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";if(await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:c,source:"reasoning",sourceId:a,description:`Runbook aus Skill-Failure-Workaround erstellen: "${o}"?`,skillName:"runbook",skillParams:{action:"create",title:o,symptom:`Skill "${r.failedSkill}" scheiterte ${r.errorClass} bei ${r.scope??"(unbekannter Scope)"}`,steps:r.workaroundSteps.map((l,u)=>`${u+1}. ${l}`),source_type:"chat_session",source_id:a,status:"draft",tags:["skill-failure","workaround","auto",r.failedSkill,r.errorClass.toLowerCase()]},timeoutMinutes:1440}),this.logger.info({skill:r.failedSkill,scope:r.scope,errorClass:r.errorClass},"SkillFailureReflector: runbook-confirmation enqueued"),r.workaroundSteps.length>=2&&r.scope?.startsWith("host=")){let l=`${r.failedSkill}-workaround-${r.errorClass.toLowerCase()}`.replace(/[^a-z0-9-]/gi,"-").replace(/-+/g,"-").slice(0,40),u=r.workaroundSteps.map(h=>({type:"action",skillName:"shell",inputMapping:{command:h},onError:"stop"}));await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:c,source:"reasoning",sourceId:`${a}-workflow`,description:`Workflow '${l}' aus Skill-Failure-Workaround speichern (${u.length} Schritte)?`,skillName:"workflow",skillParams:{action:"create",name:l,description:`Auto-extrahiert aus Workaround f\xFCr ${r.failedSkill}/${r.errorClass} auf ${r.scope}`,steps:u,triggerType:"manual",autoExtracted:!0},timeoutMinutes:1440}),this.logger.info({workflowName:l,steps:u.length},"SkillFailureReflector: workflow-confirmation enqueued (D4)")}}}catch(n){this.logger.debug({err:n},"SkillFailureReflector sweep failed (non-critical)")}},15*6e4),this.logger.info("Skill-failure reflector started (15min sweep interval)")}catch(t){this.logger.warn({err:t},"Skill-failure reflector init failed")}if(this.clusterManager&&(this.clusterMonitorTimer=setInterval(async()=>{try{let t=await this.clusterManager.getNodesAny();t.length>0&&this.logger.debug({liveNodes:t.map(s=>s.id)},"Cluster node status")}catch{}},6e4)),this.insightTracker&&this.ownerMasterUserId){let t=this.ownerMasterUserId;this.insightExpiryTimer=setInterval(()=>{this.insightTracker.processExpired(t).catch(s=>{this.logger.warn({err:s},"Insight expiry processing failed")})},30*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(()=>(xs(),Os)),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.bmwSkill&&"stopStreaming"in this.bmwSkill&&this.bmwSkill.stopStreaming(),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.triggerManager?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.projectHealthMonitor?.stop(),this.adapterClaimManager?.stop(),this.clusterManager?.stopPgHeartbeat(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.memoryConsolidatorTimer&&(clearInterval(this.memoryConsolidatorTimer),this.memoryConsolidatorTimer=void 0),this.patternAnalyzerTimer&&(clearInterval(this.patternAnalyzerTimer),this.patternAnalyzerTimer=void 0),this.temporalAnalyzerTimer&&(clearInterval(this.temporalAnalyzerTimer),this.temporalAnalyzerTimer=void 0),this.insightExpiryTimer&&(clearInterval(this.insightExpiryTimer),this.insightExpiryTimer=void 0),this.clusterMonitorTimer&&(clearInterval(this.clusterMonitorTimer),this.clusterMonitorTimer=void 0),this.cmdbDiscoveryTimer&&(clearInterval(this.cmdbDiscoveryTimer),this.cmdbDiscoveryTimer=void 0),this.cmdbHealthCheckTimer&&(clearInterval(this.cmdbHealthCheckTimer),this.cmdbHealthCheckTimer=void 0),this.reflectionEngine?.stop(),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(i=>setTimeout(i,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(i){this.logger.error({platform:t,err:i},"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{Zd();let t=new at().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(fe(),ye));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(()=>(fe(),ye));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(()=>(fe(),ye));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:i}=await Promise.resolve().then(()=>(fe(),ye)),n=await i(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(()=>(fe(),ye));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(()=>(fe(),ye));this.bmwSkill=new s(t.bmw),this.skillRegistry.register(this.bmwSkill),this.userServiceResolverRef&&"setServiceResolver"in this.bmwSkill&&this.bmwSkill.setServiceResolver(this.userServiceResolverRef,this.ownerMasterUserId),this.bmwTelematicRepo&&"setTelematicRepo"in this.bmwSkill&&this.bmwSkill.setTelematicRepo(this.bmwTelematicRepo),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="goe_charger"&&t.goeCharger?.host){let{GoeChargerSkill:s}=await Promise.resolve().then(()=>(fe(),ye));this.skillRegistry.register(new s(t.goeCharger,t.energy)),this.config.goeCharger=t.goeCharger,this.logger.info("go-e Charger skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(fe(),ye));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(()=>(fe(),ye));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}}}getConfiguredServices(){let e=[],t=this.config.speech;if(t){let i=t.sttProvider??t.provider,n=t.ttsProvider??t.provider;if(i){let r=i==="mistral"?"voxtral-mini-latest":i==="groq"?"whisper-large-v3-turbo":"whisper-1";e.push({name:"Speech-to-Text",provider:i,model:r,status:"active"})}if(t.ttsEnabled!==!1&&n){let r=n==="mistral"?"voxtral-mini-tts-2603":"tts-1";e.push({name:"Text-to-Speech",provider:n,model:r,status:"active"})}}if(this.config.mistralApiKey&&e.push({name:"OCR",provider:"mistral",model:"mistral-ocr-latest",status:"active"}),this.config.security?.moderation?.enabled){let i=this.config.security.moderation.provider??"mistral",n=this.config.security.moderation.model??(i==="mistral"?"mistral-moderation-latest":"omni-moderation-latest");e.push({name:"Moderation",provider:i,model:n,status:"active"})}let s=this.config.llm.embeddings;if(s?.provider&&e.push({name:"Embeddings",provider:s.provider,model:s.model??"unknown",status:"active"}),this.config.reasoning?.llmLinking?.enabled){let i=this.config.reasoning.llmLinking;e.push({name:"KG Entity-Linking",provider:i.provider??"mistral",model:i.model??"mistral-small-latest",status:"active"})}return e}resolveWebUiPath(){let e;try{e=Lt.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Lt.join(process.cwd(),"web-ui"),Lt.join(e,"..","web-ui"),Lt.join(e,"web-ui"),Lt.join(e,"..","..","web-ui"),Lt.join(e,"..","..","apps","web","out")];for(let s of t)try{let i=Lt.resolve(s);if(hr.existsSync(Lt.join(i,"index.html")))return this.logger.info({path:i},"Web UI found"),i}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}async buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let i=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 ${i.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 ${i.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 ${i.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,r]of Object.entries(i.byModel)){let a=`model="${n}"`;e.push(`alfred_llm_calls_total{${a}} ${r.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,r]of Object.entries(i.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${r.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,r]of Object.entries(i.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${r.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,r]of Object.entries(i.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${r.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${await this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${await this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),r=await this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${r.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 ${r.totalCalls}`)}return e.push(""),e.join(`
5324
+ ) ORDER BY created_at DESC LIMIT 100`,[p.id]);if(g.length>10){let w=await h.getLLMLinker().analyzeRecentChats(p.id,g.reverse());(w.relations>0||w.newEntities>0)&&this.logger.info({...w},"Weekly chat analysis completed")}}catch(y){this.logger.debug({err:y},"Weekly chat analysis failed")}}}catch(u){this.logger.warn({err:u},"Temporal analysis failed")}try{if(this.config.cmdb?.enabled!==!1&&this.database){let u=this.database.getAdapter(),{CmdbRepository:h,ItsmRepository:p}=await Promise.resolve().then(()=>(Je(),Ze)),m=new h(u),y=new p(u),g=this.userRepo?await this.userRepo.findOrCreate("telegram",this.config.security?.ownerUserId??""):void 0,w=g?.masterUserId??g?.id??this.config.security?.ownerUserId??"";if(w){let T=await m.listAssets(w),_=T.filter($=>["server","vm","lxc","container","application","service"].includes($.assetType)&&$.status==="active"),k=await y.listServices(w),b=new Set;for(let $ of k)for(let C of $.assetIds??[])b.add(C);let v=0;for(let $ of _){if(b.has($.id))continue;let C=["server","vm","lxc"].includes($.assetType)?"infrastructure":$.assetType==="container"||$.assetType==="application"?"application":"infrastructure",L=$.environment==="production"?"high":"medium";try{await y.createService(w,{name:`${$.name} Service`,description:`Automatisch abgeleitet aus CMDB-Asset (${$.assetType}). ${$.purpose??""}`.trim(),category:C,environment:$.environment,criticality:L,assetIds:[$.id],tags:"auto-discovered"}),v++}catch{}}v>0&&this.logger.info({createdServices:v,totalAssets:T.length},"Weekly service-discovery completed")}}}catch(u){this.logger.warn({err:u},"Weekly service-discovery failed")}}},60*6e4)}}if(this.config.reflection?.enabled!==!1&&this.watchRepo&&this.memoryRepo&&this.activityRepo&&this.skillRegistry&&this.skillSandbox)try{let t=Ql(this.config.reflection),s=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api",i=this.database?.getAdapter(),n=this.config.cmdb?.enabled!==!1&&i?new Hs(i):void 0,r=this.config.telegram?.enabled?this.config.security?.ownerUserId??"":"";this.reflectionEngine=new go({watchRepo:this.watchRepo,memoryRepo:this.memoryRepo,activityRepo:this.activityRepo,cmdbRepo:n,projectRepo:this.projectRepo,runbookRepo:this.runbookRepo,ownerUserId:this.ownerMasterUserId??this.config.security?.ownerUserId,skillRegistry:this.skillRegistry,skillSandbox:this.skillSandbox,llm:this.llmProvider,adapters:this.adapters,logger:this.logger.child({component:"reflection-engine"}),defaultChatId:r,defaultPlatform:s,nodeId:this.config.cluster?.nodeId??"single",config:t},this.database?.getAdapter()),this.reflectionEngine.start(),this.logger.info("Reflection engine initialized")}catch(t){this.logger.warn({err:t},"Reflection engine initialization failed")}if(this.runbookRepo&&this.memoryRepo&&this.confirmationQueue&&this.database&&this.llmProvider)try{let{ChatSessionRunbookReflector:t}=await Promise.resolve().then(()=>(cE(),oE)),{ConversationRepository:s}=await Promise.resolve().then(()=>(Je(),Ze)),i=this.database.getAdapter(),n=new s(i),r=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";this.chatSessionRunbookReflector=new t(i,n,this.runbookRepo,this.memoryRepo,this.confirmationQueue,this.llmProvider,this.logger.child({component:"runbook-reflector"}),r,this.config.security?.ownerUserId??""),this.chatSessionRunbookReflector.start(),this.logger.info("Chat-session runbook reflector started")}catch(t){this.logger.warn({err:t},"Chat-session runbook reflector init failed")}if(this.activityRepo&&this.confirmationQueue&&this.runbookRepo)try{let{SkillFailureReflector:t}=await Promise.resolve().then(()=>(dE(),lE)),s=new t(this.activityRepo,this.logger.child({component:"skill-failure-reflector"}));setInterval(async()=>{let i=this.ownerMasterUserId??this.config.security?.ownerUserId;if(!(!i||!this.confirmationQueue))try{let n=await s.detect(i);for(let r of n){let a=`skill-failure-runbook-${r.failedSkill}-${(r.scope??"").replace(/[^a-z0-9]/gi,"_").slice(0,30)}-${r.errorClass}`,o=`Skill "${r.failedSkill}" auf ${r.scope??"?"} \u2192 Workaround`,c=this.config.telegram?.enabled?"telegram":this.config.discord?.enabled?"discord":this.config.whatsapp?.enabled?"whatsapp":"api";if(await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:c,source:"reasoning",sourceId:a,description:`Runbook aus Skill-Failure-Workaround erstellen: "${o}"?`,skillName:"runbook",skillParams:{action:"create",title:o,symptom:`Skill "${r.failedSkill}" scheiterte ${r.errorClass} bei ${r.scope??"(unbekannter Scope)"}`,steps:r.workaroundSteps.map((l,u)=>`${u+1}. ${l}`),source_type:"chat_session",source_id:a,status:"draft",tags:["skill-failure","workaround","auto",r.failedSkill,r.errorClass.toLowerCase()]},timeoutMinutes:1440}),this.logger.info({skill:r.failedSkill,scope:r.scope,errorClass:r.errorClass},"SkillFailureReflector: runbook-confirmation enqueued"),r.workaroundSteps.length>=2&&r.scope?.startsWith("host=")){let l=`${r.failedSkill}-workaround-${r.errorClass.toLowerCase()}`.replace(/[^a-z0-9-]/gi,"-").replace(/-+/g,"-").slice(0,40),u=r.workaroundSteps.map(h=>({type:"action",skillName:"shell",inputMapping:{command:h},onError:"stop"}));await this.confirmationQueue.enqueue({chatId:this.config.security?.ownerUserId??"",platform:c,source:"reasoning",sourceId:`${a}-workflow`,description:`Workflow '${l}' aus Skill-Failure-Workaround speichern (${u.length} Schritte)?`,skillName:"workflow",skillParams:{action:"create",name:l,description:`Auto-extrahiert aus Workaround f\xFCr ${r.failedSkill}/${r.errorClass} auf ${r.scope}`,steps:u,triggerType:"manual",autoExtracted:!0},timeoutMinutes:1440}),this.logger.info({workflowName:l,steps:u.length},"SkillFailureReflector: workflow-confirmation enqueued (D4)")}}}catch(n){this.logger.debug({err:n},"SkillFailureReflector sweep failed (non-critical)")}},15*6e4),this.logger.info("Skill-failure reflector started (15min sweep interval)")}catch(t){this.logger.warn({err:t},"Skill-failure reflector init failed")}if(this.clusterManager&&(this.clusterMonitorTimer=setInterval(async()=>{try{let t=await this.clusterManager.getNodesAny();t.length>0&&this.logger.debug({liveNodes:t.map(s=>s.id)},"Cluster node status")}catch{}},6e4)),this.insightTracker&&this.ownerMasterUserId){let t=this.ownerMasterUserId;this.insightExpiryTimer=setInterval(()=>{this.insightTracker.processExpired(t).catch(s=>{this.logger.warn({err:s},"Insight expiry processing failed")})},30*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(()=>(xs(),Os)),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.bmwSkill&&"stopStreaming"in this.bmwSkill&&this.bmwSkill.stopStreaming(),this.reminderScheduler?.stop(),this.backgroundTaskRunner?.stop(),this.proactiveScheduler?.stop(),this.watchEngine?.stop(),this.triggerManager?.stop(),this.confirmationQueue?.stop(),this.calendarWatcher?.stop(),this.todoWatcher?.stop(),this.reasoningEngine?.stop(),this.projectHealthMonitor?.stop(),this.adapterClaimManager?.stop(),this.clusterManager?.stopPgHeartbeat(),this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=void 0),this.memoryConsolidatorTimer&&(clearInterval(this.memoryConsolidatorTimer),this.memoryConsolidatorTimer=void 0),this.patternAnalyzerTimer&&(clearInterval(this.patternAnalyzerTimer),this.patternAnalyzerTimer=void 0),this.temporalAnalyzerTimer&&(clearInterval(this.temporalAnalyzerTimer),this.temporalAnalyzerTimer=void 0),this.insightExpiryTimer&&(clearInterval(this.insightExpiryTimer),this.insightExpiryTimer=void 0),this.clusterMonitorTimer&&(clearInterval(this.clusterMonitorTimer),this.clusterMonitorTimer=void 0),this.cmdbDiscoveryTimer&&(clearInterval(this.cmdbDiscoveryTimer),this.cmdbDiscoveryTimer=void 0),this.cmdbHealthCheckTimer&&(clearInterval(this.cmdbHealthCheckTimer),this.cmdbHealthCheckTimer=void 0),this.reflectionEngine?.stop(),this.mcpManager&&await this.mcpManager.shutdown();let e=5e3;for(let[t,s]of this.adapters)try{await Promise.race([s.disconnect(),new Promise(i=>setTimeout(i,e))]),this.logger.info({platform:t},"Adapter disconnected")}catch(i){this.logger.error({platform:t,err:i},"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{Zd();let t=new at().loadConfig();if(this.skillRegistry.has(e)&&this.skillRegistry.unregister(e),e==="proxmox"&&t.proxmox){let{ProxmoxSkill:s}=await Promise.resolve().then(()=>(fe(),ye));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(()=>(fe(),ye));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(()=>(fe(),ye));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:i}=await Promise.resolve().then(()=>(fe(),ye)),n=await i(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(()=>(fe(),ye));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(()=>(fe(),ye));this.bmwSkill=new s(t.bmw),this.skillRegistry.register(this.bmwSkill),this.userServiceResolverRef&&"setServiceResolver"in this.bmwSkill&&this.bmwSkill.setServiceResolver(this.userServiceResolverRef,this.ownerMasterUserId),this.bmwTelematicRepo&&"setTelematicRepo"in this.bmwSkill&&this.bmwSkill.setTelematicRepo(this.bmwTelematicRepo),this.config.bmw=t.bmw,this.logger.info("BMW CarData skill hot-reloaded")}if(e==="goe_charger"&&t.goeCharger?.host){let{GoeChargerSkill:s}=await Promise.resolve().then(()=>(fe(),ye));this.skillRegistry.register(new s(t.goeCharger,t.energy)),this.config.goeCharger=t.goeCharger,this.logger.info("go-e Charger skill hot-reloaded")}if(e==="routing"&&t.routing){let{RoutingSkill:s}=await Promise.resolve().then(()=>(fe(),ye));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(()=>(fe(),ye));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}}}getConfiguredServices(){let e=[],t=this.config.speech;if(t){let i=t.sttProvider??t.provider,n=t.ttsProvider??t.provider;if(i){let r=i==="mistral"?"voxtral-mini-latest":i==="groq"?"whisper-large-v3-turbo":"whisper-1";e.push({name:"Speech-to-Text",provider:i,model:r,status:"active"})}if(t.ttsEnabled!==!1&&n){let r=n==="mistral"?"voxtral-mini-tts-2603":"tts-1";e.push({name:"Text-to-Speech",provider:n,model:r,status:"active"})}}if(this.config.mistralApiKey&&e.push({name:"OCR",provider:"mistral",model:"mistral-ocr-latest",status:"active"}),this.config.security?.moderation?.enabled){let i=this.config.security.moderation.provider??"mistral",n=this.config.security.moderation.model??(i==="mistral"?"mistral-moderation-latest":"omni-moderation-latest");e.push({name:"Moderation",provider:i,model:n,status:"active"})}let s=this.config.llm.embeddings;if(s?.provider&&e.push({name:"Embeddings",provider:s.provider,model:s.model??"unknown",status:"active"}),this.config.reasoning?.llmLinking?.enabled){let i=this.config.reasoning.llmLinking;e.push({name:"KG Entity-Linking",provider:i.provider??"mistral",model:i.model??"mistral-small-latest",status:"active"})}return e}resolveWebUiPath(){let e;try{e=Lt.dirname(new URL(import.meta.url).pathname),process.platform==="win32"&&e.startsWith("/")&&(e=e.slice(1))}catch{e=process.cwd()}let t=[Lt.join(process.cwd(),"web-ui"),Lt.join(e,"..","web-ui"),Lt.join(e,"web-ui"),Lt.join(e,"..","..","web-ui"),Lt.join(e,"..","..","apps","web","out")];for(let s of t)try{let i=Lt.resolve(s);if(hr.existsSync(Lt.join(i,"index.html")))return this.logger.info({path:i},"Web UI found"),i}catch{}this.logger.debug("Web UI not found \u2014 serving API only")}async buildPrometheusMetrics(){let e=[],t=Math.floor(process.uptime());e.push("# HELP alfred_uptime_seconds Process uptime in seconds"),e.push("# TYPE alfred_uptime_seconds gauge"),e.push(`alfred_uptime_seconds ${t}`);let s=this.pipeline.getMetrics();e.push("# HELP alfred_requests_total Total messages processed"),e.push("# TYPE alfred_requests_total counter"),e.push(`alfred_requests_total ${s.requestsTotal}`),e.push("# HELP alfred_requests_success_total Successful requests"),e.push("# TYPE alfred_requests_success_total counter"),e.push(`alfred_requests_success_total ${s.requestsSuccess}`),e.push("# HELP alfred_requests_failed_total Failed requests"),e.push("# TYPE alfred_requests_failed_total counter"),e.push(`alfred_requests_failed_total ${s.requestsFailed}`),e.push("# HELP alfred_request_duration_avg_ms Average request duration"),e.push("# TYPE alfred_request_duration_avg_ms gauge"),e.push(`alfred_request_duration_avg_ms ${s.avgDurationMs}`);let i=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 ${i.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 ${i.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 ${i.totalCostUsd}`),e.push("# HELP alfred_llm_calls_total LLM calls by model"),e.push("# TYPE alfred_llm_calls_total counter");for(let[n,r]of Object.entries(i.byModel)){let a=`model="${n}"`;e.push(`alfred_llm_calls_total{${a}} ${r.calls}`)}e.push("# HELP alfred_llm_cost_usd LLM cost by model"),e.push("# TYPE alfred_llm_cost_usd counter");for(let[n,r]of Object.entries(i.byModel))e.push(`alfred_llm_cost_usd{model="${n}"} ${r.costUsd}`);e.push("# HELP alfred_llm_input_tokens LLM input tokens by model"),e.push("# TYPE alfred_llm_input_tokens counter");for(let[n,r]of Object.entries(i.byModel))e.push(`alfred_llm_input_tokens{model="${n}"} ${r.inputTokens}`);e.push("# HELP alfred_llm_output_tokens LLM output tokens by model"),e.push("# TYPE alfred_llm_output_tokens counter");for(let[n,r]of Object.entries(i.byModel))e.push(`alfred_llm_output_tokens{model="${n}"} ${r.outputTokens}`);if(this.watchRepo&&(e.push("# HELP alfred_watches_active Number of enabled watches"),e.push("# TYPE alfred_watches_active gauge"),e.push(`alfred_watches_active ${await this.watchRepo.countEnabled()}`)),this.scheduledActionRepo&&(e.push("# HELP alfred_schedulers_active Number of enabled scheduled actions"),e.push("# TYPE alfred_schedulers_active gauge"),e.push(`alfred_schedulers_active ${await this.scheduledActionRepo.countEnabled()}`)),this.usageRepo){let n=new Date().toISOString().slice(0,10),r=await this.usageRepo.getDaily(n);e.push("# HELP alfred_llm_today_cost_usd Total LLM cost today (persisted)"),e.push("# TYPE alfred_llm_today_cost_usd gauge"),e.push(`alfred_llm_today_cost_usd ${r.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 ${r.totalCalls}`)}return e.push(""),e.join(`
5314
5325
  `)}async autoLinkApiUser(e){if(e.platform==="api")try{let t=await this.userRepo.findOrCreate("api",e.userId,e.userName);if(await this.userRepo.getMasterUserId(t.id)!==t.id)return;let i=await this.userRepo.findFirstByPlatformNotIn(["api","cli"]);if(i){let n=await this.userRepo.getMasterUserId(i.id);await this.userRepo.setMasterUser(t.id,n),this.logger.info({apiUserId:t.id,masterUserId:n},"Auto-linked API user")}}catch(t){this.logger.debug({err:t},"Auto-link API user failed")}}setupAdapterHandlers(e,t){t.on("message",async s=>{try{if(s.text?.trim().toLowerCase()==="/stop"){let h=this.pipeline.cancelRequest(s.chatId,s.userId)?"\u23F9 Anfrage abgebrochen.":"Keine laufende Anfrage zum Abbrechen.";try{await t.sendMessage(s.chatId,h)}catch{}return}this.autoLinkApiUser(s);let i,n="",r=f(async u=>{if(u!==n){n=u;try{e==="api"?await t.editMessage(s.chatId,i??"",u):i?await t.editMessage(s.chatId,i,u):i=await t.sendMessage(s.chatId,u)}catch(h){this.logger.debug({err:h,chatId:s.chatId},"Status message edit failed")}}},"onProgress"),a=await this.pipeline.process(s,r),o=new Set(["email","calendar","contacts","bmw","todo","microsoft_todo","onedrive","database","memory","note","reminder","file","shell"]);if(s.chatType==="group"&&a.usedSkills?.some(u=>o.has(u))&&a.text){try{let u=this.formatter.format(a.text,s.platform),h=u.parseMode!=="text"?{parseMode:u.parseMode}:void 0;if(await t.sendDirectMessage(s.userId,u.text,h)){if(await t.sendMessage(s.chatId,`@${s.userName??s.userId}, Antwort per DM gesendet (pers\xF6nliche Daten).`),a.attachments)for(let m of a.attachments)try{await t.sendDirectMessage(s.userId,m.fileName??"file")}catch{}}else await t.sendMessage(s.chatId,u.text,h)}catch(u){this.logger.warn({err:u,chatId:s.chatId},"Group privacy DM redirect failed, sending in group");let h=this.formatter.format(a.text,s.platform);await t.sendMessage(s.chatId,h.text)}"endStream"in t&&t.endStream(s.chatId);return}if(a.text){let u=this.formatter.format(a.text,s.platform),h=u.parseMode!=="text"?{parseMode:u.parseMode}:void 0;try{if(i&&e!=="api")try{await t.editMessage(s.chatId,i,u.text,h)}catch(p){this.logger.debug({err:p,chatId:s.chatId},"Final response edit failed, sending as new message"),await t.sendMessage(s.chatId,u.text,h)}else await t.sendMessage(s.chatId,u.text,h)}catch(p){this.logger.warn({err:p,chatId:s.chatId},"Formatted send failed, retrying as plain text");let m=this.formatter.format(a.text,"signal");await t.sendMessage(s.chatId,m.text)}}if(a.attachments)for(let u of a.attachments)try{let h=u.mimeType?.startsWith("image/")??!1,p=u.mimeType?.startsWith("audio/")??!1,m=u.mimeType==="audio/ogg"||u.mimeType==="audio/opus";h?await t.sendPhoto(s.chatId,u.data,u.fileName):m?await t.sendVoice(s.chatId,u.data):p?await t.sendVoice(s.chatId,u.data):await t.sendFile(s.chatId,u.data,u.fileName)}catch(h){this.logger.warn({err:h,fileName:u.fileName,chatId:s.chatId},"Failed to send attachment")}"endStream"in t&&t.endStream(s.chatId)}catch(i){this.logger.error({platform:e,err:i,chatId:s.chatId},"Failed to handle message");try{await t.sendMessage(s.chatId,"Sorry, I encountered an error processing your message. Please try again.")}catch(n){this.logger.error({err:n},"Failed to send error message")}"endStream"in t&&t.endStream(s.chatId)}}),t.on("error",s=>{this.logger.error({platform:e,err:s},"Adapter error")}),t.on("connected",()=>{this.logger.info({platform:e},"Adapter connected")}),t.on("disconnected",()=>{this.logger.warn({platform:e},"Adapter disconnected")})}detectImageGenProvider(){let e=["default","strong","fast","embeddings","local"];for(let t of["openai","google"])for(let s of e){let i=this.config.llm[s];if(i?.provider===t&&i.apiKey)return{provider:t,apiKey:i.apiKey,baseUrl:i.baseUrl}}}detectMistralApiKey(){if(this.config.mistralApiKey)return this.config.mistralApiKey;let e=["default","strong","fast","embeddings","local"];for(let t of e){let s=this.config.llm[t];if(s?.provider==="mistral"&&s.apiKey)return s.apiKey}}loadSecurityRules(){let e=Lt.resolve(this.config.security.rulesPath),t=[];if(!hr.existsSync(e))return this.logger.warn({rulesPath:e},"Security rules directory not found, using default deny"),t;if(!hr.statSync(e).isDirectory())return this.logger.warn({rulesPath:e},"Security rules path is not a directory"),t;let i=hr.readdirSync(e).filter(n=>n.endsWith(".yml")||n.endsWith(".yaml"));for(let n of i)try{let r=Lt.join(e,n),a=hr.readFileSync(r,"utf-8"),o=ER.load(a);if(o?.rules&&Array.isArray(o.rules)){let l=new Ts().loadFromObject({rules:o.rules});t.push(...l),this.logger.info({file:n,count:l.length},"Loaded security rules")}}catch(r){this.logger.error({err:r,file:n},"Failed to load security rules file")}return t}}});var tm=S(()=>{"use strict";ap();np()});var hE=S(()=>{"use strict";zp();Gp()});var sm=S(()=>{"use strict";uE();Bh();Uh();Hh();Xh();zh();qh();Gh();Yh();Jh();Zh();ps();Vh();Wh();Kh();rp();op();ip();lp();sp();pp();za();_p();ep();tm();Xp();hE();qp();tm();mp();fp();gp();Xl();yp();Tp();Sp();vp();Ep();kp();bp();Ip();Ap();La();Gl();Vl();dp();xp();Mp()});import gd from"node:fs";import pE from"node:path";import bR from"node:os";function mE(){try{let d=gd.readFileSync(im,"utf-8"),e=JSON.parse(d);if(e?.version===1&&e.providers)return e}catch{}return{version:1,providers:{}}}function fE(d){try{let e=pE.dirname(im);gd.existsSync(e)||gd.mkdirSync(e,{recursive:!0}),gd.writeFileSync(im,JSON.stringify(d,null,2),"utf-8")}catch{}}async function $i(d,e){let t=new AbortController,s=setTimeout(()=>t.abort(),vR);try{return await fetch(d,{...e,signal:t.signal})}finally{clearTimeout(s)}}async function gE(d,e,t){switch(d){case"anthropic":{let s=await $i("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",i=await $i(s,{headers:{Authorization:`Bearer ${e??""}`}});return i.ok?((await i.json()).data??[]).map(r=>({id:r.id})):[]}case"google":{let s=`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(e??"")}`,i=await $i(s);return i.ok?((await i.json()).models??[]).map(r=>({id:r.name.replace(/^models\//,""),name:r.displayName})):[]}case"mistral":{let s=await $i("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 $i("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(/\/+$/,""),i=await $i(`${s}/api/tags`);return i.ok?((await i.json()).models??[]).map(r=>({id:r.name})):[]}case"openwebui":{let s=(t??"http://localhost:3000/api/v1").replace(/\/+$/,""),i=await $i(`${s}/models`,{headers:{Authorization:`Bearer ${e??""}`}});return i.ok?((await i.json()).data??[]).map(r=>({id:r.id})):[]}default:return[]}}async function nm(d,e,t){let s=mE(),i=s.providers[d];if(i&&Date.now()-i.fetchedAt<SR)return i.models;try{let n=await gE(d,e,t);if(n.length>0)return s.providers[d]={fetchedAt:Date.now(),models:n},fE(s),n}catch{}return i?i.models:[]}function yd(d,e,t){gE(d,e,t).then(s=>{if(s.length>0){let i=mE();i.providers[d]={fetchedAt:Date.now(),models:s},fE(i)}}).catch(()=>{})}function rm(d,e){let t=new Set,s=[];for(let i of d)if(!t.has(i.id)){t.add(i.id);let n=e.find(r=>r.id===i.id);s.push({id:i.id,name:i.name,desc:n?.desc})}for(let i of e)t.has(i.id)||(t.add(i.id),s.push({id:i.id,desc:i.desc}));return s}var SR,vR,im,am=S(()=>{"use strict";SR=1440*60*1e3,vR=5e3,im=pE.join(bR.homedir(),".alfred","model-cache.json");f(mE,"readCache");f(fE,"writeCache");f($i,"fetchWithTimeout");f(gE,"fetchModelsFromAPI");f(nm,"getModels");f(yd,"refreshCacheInBackground");f(rm,"mergeModels")});var yE={};Ne(yE,{startCommand:()=>AR});async function AR(){let d=new at,e=Po(),t;try{t=d.loadConfig()}catch(a){console.error("Failed to load configuration:",a.message),process.exit(1)}let s=xi("alfred",t.logger.level,{version:e,file:t.logger.file});s.info({nodeVersion:process.version},"Alfred starting");let i=new Ii(t),n=!1,r=f(async a=>{if(!n){n=!0,s.info({signal:a},"Received shutdown signal");try{await i.stop(),s.info("Graceful shutdown complete"),process.exit(0)}catch(o){s.error({error:o},"Error during shutdown"),process.exit(1)}}},"shutdown");process.on("SIGINT",()=>r("SIGINT")),process.on("SIGTERM",()=>r("SIGTERM")),process.on("uncaughtException",a=>{s.fatal({err:a},"Uncaught exception"),r("uncaughtException")}),process.on("unhandledRejection",a=>{s.fatal({err:a},"Unhandled rejection"),r("unhandledRejection")});try{await i.initialize(),await i.start(),s.info("Alfred is ready");let a=t.llm;a?.default?.provider?yd(a.default.provider,a.default.apiKey,a.default.baseUrl):a?.provider&&yd(a.provider,void 0,a.baseUrl);for(let o of["strong","fast"]){let c=a?.[o];c?.provider&&yd(c.provider,c.apiKey,c.baseUrl)}}catch(a){let o=a instanceof Error?a:new Error(String(a));s.fatal({err:o},"Failed to start Alfred"),process.exit(1)}}var wE=S(()=>{"use strict";ws();jo();sm();am();Kd();f(AR,"startCommand")});var TE={};Ne(TE,{chatCommand:()=>$R});import _E from"node:http";import wo from"node:readline";function RR(d,e){return new Promise(t=>{let s=_E.get(`http://${d}:${e}/api/health`,{timeout:2e3},i=>{let n="";i.on("data",r=>{n+=r.toString()}),i.on("end",()=>{try{let r=JSON.parse(n);t(r.status==="ok")}catch{t(!1)}})});s.on("error",()=>t(!1)),s.on("timeout",()=>{s.destroy(),t(!1)})})}function IR(d,e){let t=wo.createInterface({input:process.stdin,output:process.stdout,prompt:"You: "});console.log(`
5315
5326
  Alfred Chat (connected to server) \u2014 type your message and press Enter. Use /quit or /exit to leave.
5316
5327
  `),t.prompt(),t.on("line",s=>{let i=s.trim();if(!i){t.prompt();return}(i==="/quit"||i==="/exit")&&(console.log(`
@@ -5360,9 +5371,9 @@ ${ae}> ${j}${R("[y/N] ")}`)).trim().toLowerCase();if(V==="y"||V==="yes"){pt="0.0
5360
5371
  ${z("TLS/HTTPS aktivieren?")}`),console.log(`${R("Empfohlen bei Remote-Zugriff. Selbstsigniertes Zertifikat wird automatisch generiert.")}`);let I=(await d.question(`${ae}> ${j}${R("[Y/n] ")}`)).trim().toLowerCase();St=I===""||I==="y"||I==="yes",console.log(St?` ${te(">")} TLS ${z("enabled")}`:` ${R("TLS disabled \u2014 API l\xE4uft \xFCber HTTP.")}`),console.log(`
5361
5372
  ${z("API Token setzen?")}`),console.log(`${R("Sch\xFCtzt die API mit Bearer-Token-Authentifizierung.")}`),G=(await d.question(` ${De}API Token${j} ${R("[Enter to skip]")}: ${ae}`)).trim(),process.stdout.write(j),G&&console.log(` ${te(">")} API Token gesetzt`)}else console.log(` ${R("API nur auf localhost erreichbar.")}`);let K=t.config.cluster,U=K?.enabled??!1,re=K?.nodeId??"",Ae=K?.role??"primary",xe=K?.redisUrl??"",ne=K?.token??"";console.log(`
5362
5373
  ${z("Cluster / Hochverf\xFCgbarkeit?")}`),console.log(`${R("Mehrere Alfred-Nodes f\xFCr Failover und Last-Verteilung.")}`);let ve=U?"Y/n":"y/N",Ye=(await d.question(`${ae}> ${j}${R(`[${ve}] `)}`)).trim().toLowerCase();if(U=Ye===""?U:Ye==="y"||Ye==="yes",U){let I=xe||"redis://localhost:6379";if(xe=(await d.question(`
5363
- ${De}Redis URL${j} ${R(`[${I}]`)}: ${ae}`)).trim()||I,process.stdout.write(j),ne){let B=(await d.question(` ${De}Cluster-Token${j} ${R("[bestehend beibehalten: Enter]")}: ${ae}`)).trim();process.stdout.write(j),B&&(ne=B)}else ne=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,console.log(` ${te(">")} Cluster-Token: ${z(ne)}`),console.log(` ${R(" Diesen Token auf allen Nodes identisch setzen.")}`);re||(re=`node-${Math.random().toString(36).slice(2,8)}`),console.log(` ${te(">")} Node-ID: ${z(re)}`),Ae="primary"}else console.log(` ${R("Einzelinstanz \u2014 kein Cluster.")}`);let Qe="sqlite",he="",Re=t.config.storage?.backend??"sqlite",ke=t.env.ALFRED_STORAGE_CONNECTION_STRING??t.config.storage?.connectionString??"";if(U||Re==="postgres"){console.log(`
5364
- ${z("Datenbank-Backend")}`),console.log(`${R("SQLite ist Standard. PostgreSQL empfohlen f\xFCr Cluster/HA (gemeinsamer Zustand).")}`),console.log(` ${it("1)")} SQLite (lokal, Standard)`),console.log(` ${it("2)")} PostgreSQL (HA, gemeinsame DB)`);let I=Re==="postgres"||U?"2":"1";((await d.question(`${ae}> ${j}${R(`[${I}] `)}`)).trim()||I)==="2"?(Qe="postgres",he=await ge(d," PostgreSQL Connection-String",ke||"postgres://alfred:password@localhost:5432/alfred"),console.log(` ${te(">")} PostgreSQL: ${R(he.replace(/:[^:@]+@/,":***@"))}`),Re==="sqlite"&&ke!==he&&console.log(` ${kE("i")} Bestehende SQLite-Daten migrieren: ${z("alfred migrate-db")}`)):console.log(` ${te(">")} SQLite (Standard)`)}let ze="local",et="",$t="",jt="",Vt="",Bt="",ts=t.config.fileStore;if(U||ts){console.log(`
5365
- ${z("Datei-Storage")}`),console.log(`${R("Wo sollen Datei-Uploads (Dokumente, Inbox) gespeichert werden?")}`),console.log(` ${it("1)")} Lokal (Standard \u2014 ./data/files)`),console.log(` ${it("2)")} NFS / Netzwerk-Pfad`),console.log(` ${it("3)")} S3 / MinIO`);let I=ts?.backend==="s3"?"3":ts?.backend==="nfs"?"2":"1",B=(await d.question(`${ae}> ${j}${R(`[${I}] `)}`)).trim()||I;B==="3"?(ze="s3",$t=await ge(d," S3/MinIO Endpoint (z.B. http://minio:9000)",ts?.s3Endpoint??""),jt=await ge(d," Bucket-Name",ts?.s3Bucket??"alfred-files"),Vt=await ge(d," Access Key",t.env.ALFRED_S3_ACCESS_KEY??ts?.s3AccessKey??""),Bt=await ge(d," Secret Key",t.env.ALFRED_S3_SECRET_KEY??ts?.s3SecretKey??""),console.log(` ${te(">")} S3: ${R($t)} / ${jt}`)):B==="2"?(ze="nfs",et=await ge(d," NFS-Pfad",ts?.basePath??"/mnt/alfred-files"),console.log(` ${te(">")} NFS: ${R(et)}`)):console.log(` ${te(">")} Lokal (./data/files)`)}console.log(`
5374
+ ${De}Redis URL${j} ${R(`[${I}]`)}: ${ae}`)).trim()||I,process.stdout.write(j),ne){let B=(await d.question(` ${De}Cluster-Token${j} ${R("[bestehend beibehalten: Enter]")}: ${ae}`)).trim();process.stdout.write(j),B&&(ne=B)}else ne=`alf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`,console.log(` ${te(">")} Cluster-Token: ${z(ne)}`),console.log(` ${R(" Diesen Token auf allen Nodes identisch setzen.")}`);re||(re=`node-${Math.random().toString(36).slice(2,8)}`),console.log(` ${te(">")} Node-ID: ${z(re)}`),Ae="primary"}else console.log(` ${R("Einzelinstanz \u2014 kein Cluster.")}`);let et="sqlite",he="",Re=t.config.storage?.backend??"sqlite",ke=t.env.ALFRED_STORAGE_CONNECTION_STRING??t.config.storage?.connectionString??"";if(U||Re==="postgres"){console.log(`
5375
+ ${z("Datenbank-Backend")}`),console.log(`${R("SQLite ist Standard. PostgreSQL empfohlen f\xFCr Cluster/HA (gemeinsamer Zustand).")}`),console.log(` ${it("1)")} SQLite (lokal, Standard)`),console.log(` ${it("2)")} PostgreSQL (HA, gemeinsame DB)`);let I=Re==="postgres"||U?"2":"1";((await d.question(`${ae}> ${j}${R(`[${I}] `)}`)).trim()||I)==="2"?(et="postgres",he=await ge(d," PostgreSQL Connection-String",ke||"postgres://alfred:password@localhost:5432/alfred"),console.log(` ${te(">")} PostgreSQL: ${R(he.replace(/:[^:@]+@/,":***@"))}`),Re==="sqlite"&&ke!==he&&console.log(` ${kE("i")} Bestehende SQLite-Daten migrieren: ${z("alfred migrate-db")}`)):console.log(` ${te(">")} SQLite (Standard)`)}let ze="local",tt="",$t="",jt="",Vt="",Bt="",ts=t.config.fileStore;if(U||ts){console.log(`
5376
+ ${z("Datei-Storage")}`),console.log(`${R("Wo sollen Datei-Uploads (Dokumente, Inbox) gespeichert werden?")}`),console.log(` ${it("1)")} Lokal (Standard \u2014 ./data/files)`),console.log(` ${it("2)")} NFS / Netzwerk-Pfad`),console.log(` ${it("3)")} S3 / MinIO`);let I=ts?.backend==="s3"?"3":ts?.backend==="nfs"?"2":"1",B=(await d.question(`${ae}> ${j}${R(`[${I}] `)}`)).trim()||I;B==="3"?(ze="s3",$t=await ge(d," S3/MinIO Endpoint (z.B. http://minio:9000)",ts?.s3Endpoint??""),jt=await ge(d," Bucket-Name",ts?.s3Bucket??"alfred-files"),Vt=await ge(d," Access Key",t.env.ALFRED_S3_ACCESS_KEY??ts?.s3AccessKey??""),Bt=await ge(d," Secret Key",t.env.ALFRED_S3_SECRET_KEY??ts?.s3SecretKey??""),console.log(` ${te(">")} S3: ${R($t)} / ${jt}`)):B==="2"?(ze="nfs",tt=await ge(d," NFS-Pfad",ts?.basePath??"/mnt/alfred-files"),console.log(` ${te(">")} NFS: ${R(tt)}`)):console.log(` ${te(">")} Lokal (./data/files)`)}console.log(`
5366
5377
  ${z("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.log(`${R("Control VMs, containers, network devices, and smart home through Alfred.")}`);let Nt=t.config.proxmox,mr=t.env.ALFRED_PROXMOX_BASE_URL??Nt?.baseUrl??"",WE=mr?"Y/n":"y/N",um=(await d.question(` ${De}Enable Proxmox VE?${j} ${R(`[${WE}]`)}: ${ae}`)).trim().toLowerCase()||(mr?"y":"n");process.stdout.write(j);let Eo=um==="y"||um==="yes",fr="",Ed="",gr="",kd=!0;if(Eo){fr=await ge(d," Proxmox URL (e.g. https://pve.local:8006)",mr||"https://pve.local:8006");let I=t.env.ALFRED_PROXMOX_TOKEN_ID??Nt?.tokenId??"";I&&console.log(` ${R(`Current token ID: ${I}`)}`),console.log(` ${R("Create: Datacenter \u2192 Permissions \u2192 API Tokens")}`),Ed=await ge(d," API Token ID (user@realm!name)",I);let B=t.env.ALFRED_PROXMOX_TOKEN_SECRET??Nt?.tokenSecret??"";B&&console.log(` ${R(`Current secret: ${Et(B)}`)}`),gr=(await d.question(` ${De}API Token Secret${j}: ${ae}`)).trim(),process.stdout.write(j),!gr&&B&&(gr=B);let W=Nt?.verifyTls===!1?"y/N":"Y/n",Oe=(await d.question(` ${De}Verify TLS?${j} ${R(`(self-signed? \u2192 no) [${W}]`)}: ${ae}`)).trim().toLowerCase()||(Nt?.verifyTls===!1?"n":"y");process.stdout.write(j),kd=Oe==="y"||Oe==="yes",console.log(` ${te(">")} Proxmox: ${z(fr)} ${R(`(TLS verify: ${kd?"yes":"no"})`)}`)}else console.log(` ${R("Proxmox disabled.")}`);let Ci=t.config.proxmoxBackup,bd=t.env.ALFRED_PBS_BASE_URL??Ci?.baseUrl??"",KE=bd?"Y/n":"y/N",hm=(await d.question(`
5367
5378
  ${De}Enable Proxmox Backup Server?${j} ${R(`[${KE}]`)}: ${ae}`)).trim().toLowerCase()||(bd?"y":"n");process.stdout.write(j);let ko=hm==="y"||hm==="yes",yr="",Sd="",wr="",_r=24,bo=!0;if(ko){yr=await ge(d," PBS URL (e.g. https://pbs.local:8007)",bd||"https://pbs.local:8007");let I=t.env.ALFRED_PBS_TOKEN_ID??Ci?.tokenId??"";I&&console.log(` ${R(`Current token ID: ${I}`)}`),console.log(` ${R("Create: Configuration \u2192 Access Control \u2192 API Token")}`),Sd=await ge(d," API Token ID (user@realm!name)",I);let B=t.env.ALFRED_PBS_TOKEN_SECRET??Ci?.tokenSecret??"";B&&console.log(` ${R(`Current secret: ${Et(B)}`)}`),wr=(await d.question(` ${De}API Token Secret${j}: ${ae}`)).trim(),process.stdout.write(j),!wr&&B&&(wr=B);let W=t.env.ALFRED_PBS_MAX_AGE_HOURS??Ci?.maxAgeHours?.toString()??"24";_r=parseInt(await ge(d," Max backup age (hours, alert if older)",W),10)||24;let Oe=Ci?.verifyTls===!1?"y/N":"Y/n",de=(await d.question(` ${De}Verify TLS?${j} ${R(`(self-signed? \u2192 no) [${Oe}]`)}: ${ae}`)).trim().toLowerCase()||(Ci?.verifyTls===!1?"n":"y");process.stdout.write(j),bo=de==="y"||de==="yes",console.log(` ${te(">")} PBS: ${z(yr)} ${R(`(max age: ${_r}h, TLS verify: ${bo?"yes":"no"})`)}`)}else console.log(` ${R("Proxmox Backup Server disabled.")}`);let Ys=t.config.unifi,vd=t.env.ALFRED_UNIFI_BASE_URL??Ys?.baseUrl??"",qE=vd?"Y/n":"y/N",pm=(await d.question(`
5368
5379
  ${De}Enable UniFi Network?${j} ${R(`[${qE}]`)}: ${ae}`)).trim().toLowerCase()||(vd?"y":"n");process.stdout.write(j);let Tr=pm==="y"||pm==="yes",Di="",Js="",Ad="",Er="",Rd=!0;if(Tr){Di=await ge(d," UniFi URL (e.g. https://unifi.local)",vd||"https://unifi.local"),console.log(` ${R("Auth: API Key (recommended) or Username/Password")}`);let I=t.env.ALFRED_UNIFI_API_KEY??Ys?.apiKey??"",B=[{num:"1",name:"apikey",label:"API Key (UniFi OS)"},{num:"2",name:"password",label:"Username / Password"}],W=I?"1":Ys?.username?"2":"1";for(let He of B)console.log(` ${ae}${He.num}${j}) ${He.label}`);if(((await d.question(` ${ae}> ${j}${R(`[${W}] `)}`)).trim()||W)==="1")I&&console.log(` ${R(`Current key: ${Et(I)}`)}`),console.log(` ${R("Create: Settings \u2192 Admins \u2192 API Keys (UniFi OS)")}`),Js=(await d.question(` ${De}API Key${j}: ${ae}`)).trim(),process.stdout.write(j),!Js&&I&&(Js=I);else{let He=t.env.ALFRED_UNIFI_USERNAME??Ys?.username??"";Ad=await ge(d," Username",He||"alfred");let rt=t.env.ALFRED_UNIFI_PASSWORD??Ys?.password??"";rt&&console.log(` ${R(`Current password: ${Et(rt)}`)}`),Er=(await d.question(` ${De}Password${j}: ${ae}`)).trim(),process.stdout.write(j),!Er&&rt&&(Er=rt)}let de=Ys?.verifyTls===!1?"y/N":"Y/n",Ce=(await d.question(` ${De}Verify TLS?${j} ${R(`(self-signed? \u2192 no) [${de}]`)}: ${ae}`)).trim().toLowerCase()||(Ys?.verifyTls===!1?"n":"y");process.stdout.write(j),Rd=Ce==="y"||Ce==="yes",console.log(` ${te(">")} UniFi: ${z(Di)} ${R(`(TLS verify: ${Rd?"yes":"no"})`)}`)}else console.log(` ${R("UniFi disabled.")}`);let So=t.config.homeassistant,Id=t.env.ALFRED_HOMEASSISTANT_URL??So?.baseUrl??"",GE=Id?"Y/n":"y/N",mm=(await d.question(`
@@ -5377,7 +5388,7 @@ ${z("Infrastructure Management (Proxmox / UniFi / Home Assistant)?")}`),console.
5377
5388
  ${De}Enable energy prices (aWATTar HOURLY / EPEX Spot AT)?${j} ${R(`[${dk}]`)}: ${ae}`)).trim().toLowerCase()||(jd?"y":"n");process.stdout.write(j);let Co=Am==="y"||Am==="yes",si="",ii="",Do="",Sr="",vr="";Co?(console.log(` ${R('Die Werte findest du auf deiner Stromrechnung unter "Netzentgelte".')}`),console.log(` ${R("Marktpreis + aWATTar-Aufschlag + Abgaben werden automatisch berechnet.")}`),console.log(""),si=await ge(d," Netzbetreiber Name (z.B. Netz Nieder\xF6sterreich)",ak),ii=await ge(d," Netznutzungsentgelt (ct/kWh netto)",jd),Do=await ge(d," Netzverlustentgelt (ct/kWh netto)",ok||"0.38"),Sr=await ge(d," Leistungspauschale (\u20AC/Monat netto)",ck),vr=await ge(d," Messentgelt (\u20AC/Monat netto)",lk||"2.22"),console.log(` ${te(">")} Energy: ${z(si||"enabled")} (${ii} + ${Do} ct/kWh)`)):console.log(` ${R("Energy prices disabled (Marktpreise weiterhin ohne Netzentgelte verf\xFCgbar).")}`),console.log(`
5378
5389
  ${z("Security configuration:")}`);let Rm=t.config.security?.ownerUserId??t.env.ALFRED_OWNER_USER_ID??"",Ht;if(Rm)Ht=await ge(d,"Owner user ID (for elevated permissions)",Rm);else{let I=(await d.question(`${De}Owner user ID${j} ${R("(optional, for elevated permissions)")}: ${ae}`)).trim();process.stdout.write(j),Ht=I}let Ar=!1;if(Ht){let I=t.shellEnabled?"Y/n":"y/N";console.log(""),console.log(` ${z("Enable shell access (admin commands) for the owner?")}`),console.log(` ${R("Allows Alfred to execute shell commands. Only for the owner.")}`);let B=(await d.question(` ${ae}> ${j}${R(`[${I}] `)}`)).trim().toLowerCase();B===""?Ar=t.shellEnabled:Ar=B==="y"||B==="yes",console.log(Ar?` ${te(">")} Shell access ${z("enabled")} for owner ${R(Ht)}`:` ${R("Shell access disabled.")}`)}let uk=t.writeInGroups?"Y/n":"y/N";console.log(""),console.log(` ${z("Allow write actions (notes, reminders, memory) in group chats?")}`),console.log(` ${R("By default, write actions are only allowed in DMs.")}`);let Bd=(await d.question(` ${ae}> ${j}${R(`[${uk}] `)}`)).trim().toLowerCase(),Rr;Bd===""?Rr=t.writeInGroups:Rr=Bd==="y"||Bd==="yes",console.log(Rr?` ${te(">")} Write actions ${z("enabled")} in groups`:` ${R("Write actions only in DMs (default).")}`);let hk=t.rateLimit??30;console.log("");let pk=await ge(d," Rate limit (max write actions per hour per user)",String(hk)),Oo=Math.max(1,parseInt(pk,10)||30);console.log(` ${te(">")} Rate limit: ${z(String(Oo))} per hour`),console.log(`
5379
5390
  ${z("Writing configuration files...")}`);let F=["# Alfred Environment Variables","# Generated by `alfred setup`","","# === LLM ===","",`ALFRED_LLM_PROVIDER=${o.name}`];if(c){let I=o.envKeyName||"ALFRED_OLLAMA_API_KEY";F.push(`${I}=${c}`)}if(m!==o.defaultModel&&F.push(`ALFRED_LLM_MODEL=${m}`),u&&F.push(`ALFRED_LLM_BASE_URL=${u}`),Object.keys(b).length>0){F.push("","# === Additional Model Tiers ===");for(let[I,B]of Object.entries(b)){let W=`ALFRED_LLM_${I.toUpperCase()}`;F.push(""),F.push(`${W}_PROVIDER=${B.provider}`),F.push(`${W}_MODEL=${B.model}`),B.apiKey&&F.push(`${W}_API_KEY=${B.apiKey}`),B.baseUrl&&F.push(`${W}_BASE_URL=${B.baseUrl}`)}}F.push("","# === Messaging Platforms ===","");for(let[I,B]of Object.entries(Us))F.push(`${I}=${B}`);if(F.push("","# === Web Search ===",""),Z?(F.push(`ALFRED_SEARCH_PROVIDER=${Z}`),oe&&F.push(`ALFRED_SEARCH_API_KEY=${oe}`),H&&F.push(`ALFRED_SEARCH_BASE_URL=${H}`)):(F.push("# ALFRED_SEARCH_PROVIDER=brave"),F.push("# ALFRED_SEARCH_API_KEY=")),F.push("","# === Email ===",""),kt&&st.length>0){let I=st[0];I.provider==="microsoft"?(F.push("ALFRED_EMAIL_PROVIDER=microsoft"),I.msClientId?(F.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_ID=${I.msClientId}`),F.push(`ALFRED_MICROSOFT_EMAIL_CLIENT_SECRET=${I.msClientSecret}`),F.push(`ALFRED_MICROSOFT_EMAIL_TENANT_ID=${I.msTenantId}`),F.push(`ALFRED_MICROSOFT_EMAIL_REFRESH_TOKEN=${I.msRefreshToken}`)):F.push("# Microsoft email credentials shared from calendar config")):(F.push(`ALFRED_EMAIL_USER=${I.user}`),F.push(`ALFRED_EMAIL_PASS=${I.pass}`)),st.length>1&&F.push("# Additional email accounts configured in config/default.yml")}else F.push("# ALFRED_EMAIL_USER="),F.push("# ALFRED_EMAIL_PASS=");if(F.push("","# === Speech ===",""),bt?(F.push(`ALFRED_SPEECH_PROVIDER=${bt}`),F.push(`ALFRED_SPEECH_API_KEY=${It}`),Q&&F.push(`ALFRED_SPEECH_BASE_URL=${Q}`),ie&&(F.push("ALFRED_TTS_ENABLED=true"),F.push(`ALFRED_TTS_VOICE=${ce}`))):(F.push("# ALFRED_SPEECH_PROVIDER=groq"),F.push("# ALFRED_SPEECH_API_KEY=")),F.push("","# === Mistral AI Services ===",""),ue&&!ht&&F.push(`ALFRED_MISTRAL_API_KEY=${ue}`),$e?(F.push("ALFRED_MODERATION_ENABLED=true"),F.push("ALFRED_MODERATION_PROVIDER=mistral")):F.push("# ALFRED_MODERATION_ENABLED=true"),pe&&(F.push("ALFRED_STT_PROVIDER=mistral"),F.push(`ALFRED_STT_API_KEY=${ue}`)),wt&&(F.push("ALFRED_TTS_PROVIDER=mistral"),F.push(`ALFRED_TTS_API_KEY=${ue}`)),F.push("","# === Forge (GitHub / GitLab) ===",""),me==="github"?(F.push("ALFRED_FORGE_PROVIDER=github"),F.push(`ALFRED_GITHUB_TOKEN=${Y}`)):me==="gitlab"?(F.push("ALFRED_FORGE_PROVIDER=gitlab"),F.push(`ALFRED_GITLAB_TOKEN=${Te}`)):(F.push("# ALFRED_FORGE_PROVIDER=github"),F.push("# ALFRED_GITHUB_TOKEN=")),F.push("","# === Infrastructure (Proxmox / UniFi / Home Assistant) ===",""),Eo?(F.push(`ALFRED_PROXMOX_BASE_URL=${fr}`),F.push(`ALFRED_PROXMOX_TOKEN_ID=${Ed}`),F.push(`ALFRED_PROXMOX_TOKEN_SECRET=${gr}`)):(F.push("# ALFRED_PROXMOX_BASE_URL="),F.push("# ALFRED_PROXMOX_TOKEN_ID="),F.push("# ALFRED_PROXMOX_TOKEN_SECRET=")),ko?(F.push(`ALFRED_PBS_BASE_URL=${yr}`),F.push(`ALFRED_PBS_TOKEN_ID=${Sd}`),F.push(`ALFRED_PBS_TOKEN_SECRET=${wr}`),F.push(`ALFRED_PBS_MAX_AGE_HOURS=${_r}`),bo||F.push("ALFRED_PBS_VERIFY_TLS=false")):(F.push("# ALFRED_PBS_BASE_URL="),F.push("# ALFRED_PBS_TOKEN_ID="),F.push("# ALFRED_PBS_TOKEN_SECRET=")),Tr&&Js?(F.push(`ALFRED_UNIFI_BASE_URL=${Di}`),F.push(`ALFRED_UNIFI_API_KEY=${Js}`)):Tr?(F.push(`ALFRED_UNIFI_BASE_URL=${Di}`),F.push(`ALFRED_UNIFI_USERNAME=${Ad}`),F.push(`ALFRED_UNIFI_PASSWORD=${Er}`)):(F.push("# ALFRED_UNIFI_BASE_URL="),F.push("# ALFRED_UNIFI_API_KEY=")),vo?(F.push(`ALFRED_HOMEASSISTANT_URL=${kr}`),F.push(`ALFRED_HOMEASSISTANT_TOKEN=${br}`)):(F.push("# ALFRED_HOMEASSISTANT_URL="),F.push("# ALFRED_HOMEASSISTANT_TOKEN=")),F.push("","# === Contacts ===",""),Ao)for(let[I,B]of Object.entries(vt))F.push(`${I}=${B}`);else F.push("# ALFRED_CONTACTS_PROVIDER=carddav");if(F.push("","# === Docker ===",""),Ro?(Zs&&F.push(`ALFRED_DOCKER_SOCKET_PATH=${Zs}`),Qs&&F.push(`ALFRED_DOCKER_HOST=${Qs}`)):(F.push("# ALFRED_DOCKER_SOCKET_PATH="),F.push("# ALFRED_DOCKER_HOST=")),F.push("","# === BMW CarData ===",""),_m?F.push(`ALFRED_BITPANDA_API_KEY=${Tm}`):F.push("# ALFRED_BITPANDA_API_KEY="),ei.length>0){F.push(`ALFRED_TRADING_EXCHANGES=${ei.map(I=>I.name).join(",")}`),F.push(`ALFRED_TRADING_DEFAULT_EXCHANGE=${ei[0].name}`),F.push("ALFRED_TRADING_MAX_ORDER_EUR=500");for(let I of ei){let B=I.name.toUpperCase();F.push(`ALFRED_TRADING_${B}_API_KEY=${I.apiKey}`),F.push(`ALFRED_TRADING_${B}_SECRET=${I.secret}`)}}else F.push("# ALFRED_TRADING_EXCHANGES=binance,kraken");$o?F.push(`ALFRED_BMW_CLIENT_ID=${xd}`):F.push("# ALFRED_BMW_CLIENT_ID="),F.push("","# === Routing ===",""),No?F.push(`ALFRED_ROUTING_API_KEY=${Ud}`):F.push("# ALFRED_ROUTING_API_KEY="),F.push("","# === YouTube ===",""),Lo?(F.push(`ALFRED_YOUTUBE_API_KEY=${Fd}`),ti&&F.push(`ALFRED_SUPADATA_API_KEY=${ti}`)):(F.push("# ALFRED_YOUTUBE_API_KEY="),F.push("# ALFRED_SUPADATA_API_KEY=")),F.push("","# === Energy / aWATTar ===",""),Co&&ii?(si&&F.push(`ALFRED_ENERGY_GRID_NAME=${si}`),F.push(`ALFRED_ENERGY_GRID_USAGE_CT=${ii}`),F.push(`ALFRED_ENERGY_GRID_LOSS_CT=${Do}`),Sr&&F.push(`ALFRED_ENERGY_GRID_CAPACITY_FEE=${Sr}`),vr&&F.push(`ALFRED_ENERGY_GRID_METER_FEE=${vr}`)):(F.push("# ALFRED_ENERGY_GRID_NAME="),F.push("# ALFRED_ENERGY_GRID_USAGE_CT="),F.push("# ALFRED_ENERGY_GRID_LOSS_CT="),F.push("# ALFRED_ENERGY_GRID_CAPACITY_FEE="),F.push("# ALFRED_ENERGY_GRID_METER_FEE=")),he&&(F.push("","# === Storage (PostgreSQL) ===",""),F.push(`ALFRED_STORAGE_CONNECTION_STRING=${he}`)),ze==="s3"&&(F.push("","# === File Store (S3/MinIO) ===",""),Vt&&F.push(`ALFRED_S3_ACCESS_KEY=${Vt}`),Bt&&F.push(`ALFRED_S3_SECRET_KEY=${Bt}`)),F.push("","# === Security ===",""),Ht?F.push(`ALFRED_OWNER_USER_ID=${Ht}`):F.push("# ALFRED_OWNER_USER_ID="),F.push("");let mk=Ft.join(e,".env");At.writeFileSync(mk,F.join(`
5380
- `),"utf-8"),console.log(` ${te("+")} ${R(".env")} written`);let xo=Ft.join(e,"config");At.existsSync(xo)||At.mkdirSync(xo,{recursive:!0});let Im={name:i,telegram:{token:Rt.telegram?.token??"",enabled:Pe.some(I=>I.name==="telegram")},discord:{token:Rt.discord?.token??"",enabled:Pe.some(I=>I.name==="discord")},whatsapp:{enabled:Pe.some(I=>I.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:Rt.matrix?.homeserverUrl??"https://matrix.org",accessToken:Rt.matrix?.accessToken??"",userId:Rt.matrix?.userId??"",enabled:Pe.some(I=>I.name==="matrix")},signal:{apiUrl:Rt.signal?.apiUrl??"http://localhost:8080",phoneNumber:Rt.signal?.phoneNumber??"",enabled:Pe.some(I=>I.name==="signal")},llm:Object.keys(b).length>0?{default:{provider:o.name,model:m,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...b}:{provider:o.name,model:m,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...Z?{search:{provider:Z,...oe?{apiKey:oe}:{},...H?{baseUrl:H}:{}}}:{},...kt&&st.length>0?{email:{accounts:st.map(I=>I.provider==="microsoft"?{name:I.name,provider:"microsoft",...I.msClientId?{microsoft:{clientId:I.msClientId,clientSecret:I.msClientSecret,tenantId:I.msTenantId,refreshToken:I.msRefreshToken}}:{}}:{name:I.name,imap:{host:I.imapHost,port:I.imapPort,secure:I.imapPort===993},smtp:{host:I.smtpHost,port:I.smtpPort,secure:I.smtpPort===465},auth:{user:I.user,pass:I.pass}})}}:{},...bt?{speech:{provider:bt,apiKey:It,...Q?{baseUrl:Q}:{},...ie?{ttsEnabled:!0,ttsVoice:ce}:{}}}:{},...X?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Ee.length>0||me?{codeAgents:{enabled:Ee.length>0,agents:Ee,...me==="github"?{forge:{provider:"github",github:{token:Y}}}:me==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:Te}}}:{}}}:{},...Eo?{proxmox:{baseUrl:fr,tokenId:Ed,tokenSecret:gr,verifyTls:kd}}:{},...ko?{proxmoxBackup:{baseUrl:yr,tokenId:Sd,tokenSecret:wr,maxAgeHours:_r,verifyTls:bo}}:{},...Tr?{unifi:{baseUrl:Di,...Js?{apiKey:Js}:{username:Ad,password:Er},site:"default",verifyTls:Rd}}:{},...vo?{homeassistant:{baseUrl:kr,accessToken:br,verifyTls:$d}}:{},...Ao?{contacts:{provider:is,...is==="carddav"?{carddav:{serverUrl:vt.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:vt.ALFRED_CARDDAV_CONTACTS_USERNAME}}:is==="google"?{google:{clientId:vt.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:is==="microsoft"?{microsoft:{clientId:vt.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:vt.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Ro?{docker:{...Zs?{socketPath:Zs}:{},...Qs?{host:Qs}:{}}}:{},...$o?{bmw:{clientId:xd}}:{},...No?{routing:{apiKey:Ud}}:{},...Lo?{youtube:{apiKey:Fd,...ti?{supadata:{enabled:!0,apiKey:ti}}:{}}}:{},...Co&&ii?{energy:{...si?{gridName:si}:{},gridUsageCt:parseFloat(ii),gridLossCt:parseFloat(Do||"0"),...Sr?{gridCapacityFee:parseFloat(Sr)}:{},...vr?{gridMeterFee:parseFloat(vr)}:{}}}:{},api:{enabled:!0,port:3420,host:pt,webUi:_e,...G?{token:G}:{},...St?{tls:{enabled:!0}}:{}},...U?{cluster:{enabled:!0,nodeId:re,role:Ae,redisUrl:xe,token:ne}}:{},storage:{path:"./data/alfred.db",...Qe==="postgres"?{backend:"postgres"}:{},...he?{connectionString:he}:{}},...ze!=="local"?{fileStore:{backend:ze,...et?{basePath:et}:{},...$t?{s3Endpoint:$t}:{},...jt?{s3Bucket:jt}:{},...Vt?{s3AccessKey:Vt}:{},...Bt?{s3SecretKey:Bt}:{}}}:{},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};Ht&&(Im.security.ownerUserId=Ht);let fk="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+om.dump(Im,{lineWidth:120,noRefs:!0,sortKeys:!1}),gk=Ft.join(xo,"default.yml");At.writeFileSync(gk,fk,"utf-8"),console.log(` ${te("+")} ${R("config/default.yml")} written`);let Hd=Ft.join(xo,"rules");At.existsSync(Hd)||At.mkdirSync(Hd,{recursive:!0});let yk=Ar&&Ht?`
5391
+ `),"utf-8"),console.log(` ${te("+")} ${R(".env")} written`);let xo=Ft.join(e,"config");At.existsSync(xo)||At.mkdirSync(xo,{recursive:!0});let Im={name:i,telegram:{token:Rt.telegram?.token??"",enabled:Pe.some(I=>I.name==="telegram")},discord:{token:Rt.discord?.token??"",enabled:Pe.some(I=>I.name==="discord")},whatsapp:{enabled:Pe.some(I=>I.name==="whatsapp"),dataPath:"./data/whatsapp"},matrix:{homeserverUrl:Rt.matrix?.homeserverUrl??"https://matrix.org",accessToken:Rt.matrix?.accessToken??"",userId:Rt.matrix?.userId??"",enabled:Pe.some(I=>I.name==="matrix")},signal:{apiUrl:Rt.signal?.apiUrl??"http://localhost:8080",phoneNumber:Rt.signal?.phoneNumber??"",enabled:Pe.some(I=>I.name==="signal")},llm:Object.keys(b).length>0?{default:{provider:o.name,model:m,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...b}:{provider:o.name,model:m,...u?{baseUrl:u}:{},temperature:.7,maxTokens:4096},...Z?{search:{provider:Z,...oe?{apiKey:oe}:{},...H?{baseUrl:H}:{}}}:{},...kt&&st.length>0?{email:{accounts:st.map(I=>I.provider==="microsoft"?{name:I.name,provider:"microsoft",...I.msClientId?{microsoft:{clientId:I.msClientId,clientSecret:I.msClientSecret,tenantId:I.msTenantId,refreshToken:I.msRefreshToken}}:{}}:{name:I.name,imap:{host:I.imapHost,port:I.imapPort,secure:I.imapPort===993},smtp:{host:I.smtpHost,port:I.smtpPort,secure:I.smtpPort===465},auth:{user:I.user,pass:I.pass}})}}:{},...bt?{speech:{provider:bt,apiKey:It,...Q?{baseUrl:Q}:{},...ie?{ttsEnabled:!0,ttsVoice:ce}:{}}}:{},...X?{codeSandbox:{enabled:!0,allowedLanguages:["javascript","python"]}}:{},...Ee.length>0||me?{codeAgents:{enabled:Ee.length>0,agents:Ee,...me==="github"?{forge:{provider:"github",github:{token:Y}}}:me==="gitlab"?{forge:{provider:"gitlab",gitlab:{token:Te}}}:{}}}:{},...Eo?{proxmox:{baseUrl:fr,tokenId:Ed,tokenSecret:gr,verifyTls:kd}}:{},...ko?{proxmoxBackup:{baseUrl:yr,tokenId:Sd,tokenSecret:wr,maxAgeHours:_r,verifyTls:bo}}:{},...Tr?{unifi:{baseUrl:Di,...Js?{apiKey:Js}:{username:Ad,password:Er},site:"default",verifyTls:Rd}}:{},...vo?{homeassistant:{baseUrl:kr,accessToken:br,verifyTls:$d}}:{},...Ao?{contacts:{provider:is,...is==="carddav"?{carddav:{serverUrl:vt.ALFRED_CARDDAV_CONTACTS_SERVER_URL,username:vt.ALFRED_CARDDAV_CONTACTS_USERNAME}}:is==="google"?{google:{clientId:vt.ALFRED_GOOGLE_CONTACTS_CLIENT_ID}}:is==="microsoft"?{microsoft:{clientId:vt.ALFRED_MICROSOFT_CONTACTS_CLIENT_ID,tenantId:vt.ALFRED_MICROSOFT_CONTACTS_TENANT_ID}}:{}}}:{},...Ro?{docker:{...Zs?{socketPath:Zs}:{},...Qs?{host:Qs}:{}}}:{},...$o?{bmw:{clientId:xd}}:{},...No?{routing:{apiKey:Ud}}:{},...Lo?{youtube:{apiKey:Fd,...ti?{supadata:{enabled:!0,apiKey:ti}}:{}}}:{},...Co&&ii?{energy:{...si?{gridName:si}:{},gridUsageCt:parseFloat(ii),gridLossCt:parseFloat(Do||"0"),...Sr?{gridCapacityFee:parseFloat(Sr)}:{},...vr?{gridMeterFee:parseFloat(vr)}:{}}}:{},api:{enabled:!0,port:3420,host:pt,webUi:_e,...G?{token:G}:{},...St?{tls:{enabled:!0}}:{}},...U?{cluster:{enabled:!0,nodeId:re,role:Ae,redisUrl:xe,token:ne}}:{},storage:{path:"./data/alfred.db",...et==="postgres"?{backend:"postgres"}:{},...he?{connectionString:he}:{}},...ze!=="local"?{fileStore:{backend:ze,...tt?{basePath:tt}:{},...$t?{s3Endpoint:$t}:{},...jt?{s3Bucket:jt}:{},...Vt?{s3AccessKey:Vt}:{},...Bt?{s3SecretKey:Bt}:{}}}:{},logger:{level:"info",pretty:!0,auditLogPath:"./data/audit.log"},security:{rulesPath:"./config/rules",defaultEffect:"deny"}};Ht&&(Im.security.ownerUserId=Ht);let fk="# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n"+om.dump(Im,{lineWidth:120,noRefs:!0,sortKeys:!1}),gk=Ft.join(xo,"default.yml");At.writeFileSync(gk,fk,"utf-8"),console.log(` ${te("+")} ${R("config/default.yml")} written`);let Hd=Ft.join(xo,"rules");At.existsSync(Hd)||At.mkdirSync(Hd,{recursive:!0});let yk=Ar&&Ht?`
5381
5392
  # Allow admin actions (shell, etc.) for the owner only
5382
5393
  - id: allow-owner-admin
5383
5394
  effect: allow
@@ -5453,7 +5464,7 @@ ${yk}
5453
5464
  scope: global
5454
5465
  actions: ["*"]
5455
5466
  riskLevels: [read, write, destructive, admin]
5456
- `,_k=Ft.join(Hd,"default-rules.yml");At.writeFileSync(_k,wk,"utf-8"),console.log(` ${te("+")} ${R("config/rules/default-rules.yml")} written`);let $m=Ft.join(e,"data");At.existsSync($m)||(At.mkdirSync($m,{recursive:!0}),console.log(` ${te("+")} ${R("data/")} directory created`)),console.log(""),console.log(`${wd}${"=".repeat(52)}${j}`),console.log(`${wd}${De} Setup complete!${j}`),console.log(`${wd}${"=".repeat(52)}${j}`),console.log(""),console.log(` ${z("Bot name:")} ${i}`),console.log(` ${z("LLM default:")} ${o.name} (${m})`),c&&console.log(` ${z("API key:")} ${Et(c)}`);for(let[I,B]of Object.entries(b)){let W=I.charAt(0).toUpperCase()+I.slice(1);console.log(` ${z(`LLM ${W}:`)}${" ".repeat(Math.max(1,10-W.length))}${B.provider} (${B.model})`)}if(Pe.length>0?console.log(` ${z("Platforms:")} ${Pe.map(I=>I.label).join(", ")}`):console.log(` ${z("Platforms:")} none (configure later)`),Z){let I={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${H})`};console.log(` ${z("Web search:")} ${I[Z]}`)}else console.log(` ${z("Web search:")} ${R("disabled")}`);if(kt&&st.length>0){let I=st.map(B=>B.provider==="microsoft"?`${B.name} (Microsoft 365)${B.msClientId?"":" \u2014 shared from Calendar"}`:`${B.name} (${B.imapHost})`);console.log(` ${z("Email:")} ${I.join(", ")}`)}else console.log(` ${z("Email:")} ${R("disabled")}`);if(bt){let I={openai:"OpenAI Whisper",groq:"Groq Whisper"},B=ie?`, TTS: ${ce}`:"";console.log(` ${z("Voice:")} ${I[bt]}${B}`)}else console.log(` ${z("Voice:")} ${R("disabled")}`);console.log(` ${z("Code Sandbox:")} ${X?te("enabled"):R("disabled")}`),console.log(` ${z("Web Chat UI:")} ${_e?te("enabled (/alfred/)"):R("disabled")}`),console.log(` ${z("TLS/HTTPS:")} ${St?te("enabled (self-signed)"):R("disabled")}`),Qe==="postgres"&&console.log(` ${z("Storage:")} ${te("PostgreSQL")}`),ze!=="local"&&console.log(` ${z("File Store:")} ${te(ze.toUpperCase())}${ze==="s3"?` (${jt})`:` (${et})`}`),U&&(console.log(` ${z("Cluster:")} ${te(`${Ae} (${re})`)}`),console.log(` ${z("Redis:")} ${xe}`)),Lo&&console.log(` ${z("YouTube:")} ${te("enabled")}${ti?" + Supadata":""}`),Eo&&console.log(` ${z("Proxmox:")} ${te(fr)}`),ko&&console.log(` ${z("PBS:")} ${te(yr)} ${R(`(max age: ${_r}h)`)}`),Tr&&console.log(` ${z("UniFi:")} ${te(Di)}`),vo&&console.log(` ${z("Home Assist.:")} ${te(kr)}`),Ao&&console.log(` ${z("Contacts:")} ${te(is)}`),Ro&&console.log(` ${z("Docker:")} ${te(Qs||Zs)}`),$o&&console.log(` ${z("BMW CarData:")} ${te("enabled")}`),No&&console.log(` ${z("Routing:")} ${te("enabled")}`),Co&&console.log(` ${z("Energy:")} ${te(si||"enabled")} ${R(`(${ii} ct/kWh)`)}`),Ht&&(console.log(` ${z("Owner ID:")} ${Ht}`),console.log(` ${z("Shell access:")} ${Ar?te("enabled"):R("disabled")}`)),console.log(` ${z("Write scope:")} ${Rr?"DMs + Groups":"DMs only"}`),console.log(` ${z("Rate limit:")} ${Oo}/hour per user`),console.log(""),console.log(`${_d}Next steps:${j}`),console.log(` ${z("alfred start")} Start Alfred`),console.log(` ${z("alfred status")} Check configuration`),console.log(` ${z("alfred --help")} Show all commands`),console.log(""),console.log(`${Vs}Edit ${z(".env")}${Vs} or ${z("config/default.yml")}${Vs} for manual configuration.${j}`),console.log("")}finally{d.close()}}async function ge(d,e,t){let s=(await d.question(`${De}${e}${j} ${R(`[${t}]`)}: ${ae}`)).trim();return process.stdout.write(j),s||t}async function Pt(d,e){for(;;){let t=(await d.question(`${De}${e}${j}: ${ae}`)).trim();if(process.stdout.write(j),t)return t;console.log(` ${SE("!")} This field is required. Please enter a value.`)}}async function _o(d,e,t,s,i){for(;;){let n=(await d.question(`${ae}${e}${j}`)).trim();if(!n)return i;let r=parseInt(n,10);if(!Number.isNaN(r)&&r>=t&&r<=s)return r;console.log(` ${SE("!")} Please enter a number between ${t} and ${s}.`)}}function jR(){console.log(`
5467
+ `,_k=Ft.join(Hd,"default-rules.yml");At.writeFileSync(_k,wk,"utf-8"),console.log(` ${te("+")} ${R("config/rules/default-rules.yml")} written`);let $m=Ft.join(e,"data");At.existsSync($m)||(At.mkdirSync($m,{recursive:!0}),console.log(` ${te("+")} ${R("data/")} directory created`)),console.log(""),console.log(`${wd}${"=".repeat(52)}${j}`),console.log(`${wd}${De} Setup complete!${j}`),console.log(`${wd}${"=".repeat(52)}${j}`),console.log(""),console.log(` ${z("Bot name:")} ${i}`),console.log(` ${z("LLM default:")} ${o.name} (${m})`),c&&console.log(` ${z("API key:")} ${Et(c)}`);for(let[I,B]of Object.entries(b)){let W=I.charAt(0).toUpperCase()+I.slice(1);console.log(` ${z(`LLM ${W}:`)}${" ".repeat(Math.max(1,10-W.length))}${B.provider} (${B.model})`)}if(Pe.length>0?console.log(` ${z("Platforms:")} ${Pe.map(I=>I.label).join(", ")}`):console.log(` ${z("Platforms:")} none (configure later)`),Z){let I={brave:"Brave Search",tavily:"Tavily",duckduckgo:"DuckDuckGo",searxng:`SearXNG (${H})`};console.log(` ${z("Web search:")} ${I[Z]}`)}else console.log(` ${z("Web search:")} ${R("disabled")}`);if(kt&&st.length>0){let I=st.map(B=>B.provider==="microsoft"?`${B.name} (Microsoft 365)${B.msClientId?"":" \u2014 shared from Calendar"}`:`${B.name} (${B.imapHost})`);console.log(` ${z("Email:")} ${I.join(", ")}`)}else console.log(` ${z("Email:")} ${R("disabled")}`);if(bt){let I={openai:"OpenAI Whisper",groq:"Groq Whisper"},B=ie?`, TTS: ${ce}`:"";console.log(` ${z("Voice:")} ${I[bt]}${B}`)}else console.log(` ${z("Voice:")} ${R("disabled")}`);console.log(` ${z("Code Sandbox:")} ${X?te("enabled"):R("disabled")}`),console.log(` ${z("Web Chat UI:")} ${_e?te("enabled (/alfred/)"):R("disabled")}`),console.log(` ${z("TLS/HTTPS:")} ${St?te("enabled (self-signed)"):R("disabled")}`),et==="postgres"&&console.log(` ${z("Storage:")} ${te("PostgreSQL")}`),ze!=="local"&&console.log(` ${z("File Store:")} ${te(ze.toUpperCase())}${ze==="s3"?` (${jt})`:` (${tt})`}`),U&&(console.log(` ${z("Cluster:")} ${te(`${Ae} (${re})`)}`),console.log(` ${z("Redis:")} ${xe}`)),Lo&&console.log(` ${z("YouTube:")} ${te("enabled")}${ti?" + Supadata":""}`),Eo&&console.log(` ${z("Proxmox:")} ${te(fr)}`),ko&&console.log(` ${z("PBS:")} ${te(yr)} ${R(`(max age: ${_r}h)`)}`),Tr&&console.log(` ${z("UniFi:")} ${te(Di)}`),vo&&console.log(` ${z("Home Assist.:")} ${te(kr)}`),Ao&&console.log(` ${z("Contacts:")} ${te(is)}`),Ro&&console.log(` ${z("Docker:")} ${te(Qs||Zs)}`),$o&&console.log(` ${z("BMW CarData:")} ${te("enabled")}`),No&&console.log(` ${z("Routing:")} ${te("enabled")}`),Co&&console.log(` ${z("Energy:")} ${te(si||"enabled")} ${R(`(${ii} ct/kWh)`)}`),Ht&&(console.log(` ${z("Owner ID:")} ${Ht}`),console.log(` ${z("Shell access:")} ${Ar?te("enabled"):R("disabled")}`)),console.log(` ${z("Write scope:")} ${Rr?"DMs + Groups":"DMs only"}`),console.log(` ${z("Rate limit:")} ${Oo}/hour per user`),console.log(""),console.log(`${_d}Next steps:${j}`),console.log(` ${z("alfred start")} Start Alfred`),console.log(` ${z("alfred status")} Check configuration`),console.log(` ${z("alfred --help")} Show all commands`),console.log(""),console.log(`${Vs}Edit ${z(".env")}${Vs} or ${z("config/default.yml")}${Vs} for manual configuration.${j}`),console.log("")}finally{d.close()}}async function ge(d,e,t){let s=(await d.question(`${De}${e}${j} ${R(`[${t}]`)}: ${ae}`)).trim();return process.stdout.write(j),s||t}async function Pt(d,e){for(;;){let t=(await d.question(`${De}${e}${j}: ${ae}`)).trim();if(process.stdout.write(j),t)return t;console.log(` ${SE("!")} This field is required. Please enter a value.`)}}async function _o(d,e,t,s,i){for(;;){let n=(await d.question(`${ae}${e}${j}`)).trim();if(!n)return i;let r=parseInt(n,10);if(!Number.isNaN(r)&&r>=t&&r<=s)return r;console.log(` ${SE("!")} Please enter a number between ${t} and ${s}.`)}}function jR(){console.log(`
5457
5468
  ${MR}${De} _ _ _____ ____ _____ ____
5458
5469
  / \\ | | | ___| _ \\| ____| _ \\
5459
5470
  / _ \\ | | | |_ | |_) | _| | | | |