agentix-cli 0.141.0 → 0.141.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,7 +48,7 @@ The "modified" field is optional and can contain updated values to pass forward.
48
48
  ... (output truncated)`:i;return s.exitCode!==0?{tool_use_id:e.id,content:`Command exited with code ${s.exitCode}:
49
49
  ${c}`,is_error:!0}:{tool_use_id:e.id,content:c||"(no output)"}}async editFile(e){let t=String(e.input.path||""),o=e.input.edits,n=ge.resolve(this.cwd,t);if(!o||o.length===0)return{tool_use_id:e.id,content:"No edits provided.",is_error:!0};let s=await W.checkFileWrite(t);if(s==="deny")return{tool_use_id:e.id,content:`File write blocked by permissions: ${t}`,is_error:!0};if(s==="skip")return{tool_use_id:e.id,content:`File write skipped (plan mode): ${t}`};if(f.has("pre:file-write")){let a=await f.execute("pre:file-write",{event:"pre:file-write",file:n,cwd:this.cwd});if(a.blocked)return{tool_use_id:e.id,content:a.message||`File edit blocked by pre:file-write hook: ${t}`,is_error:!0}}let i=await re.readFile(n,"utf8"),c=[];for(let a of o)i.includes(a.old_text)?(i=i.replace(a.old_text,a.new_text),c.push(`Replaced: "${a.old_text.slice(0,40)}..."`)):c.push(`Not found: "${a.old_text.slice(0,40)}..."`);return this.options.dryRun||await re.writeFile(n,i,"utf8"),f.has("post:file-write")&&await f.execute("post:file-write",{event:"post:file-write",file:n,fileContent:i,cwd:this.cwd}),{tool_use_id:e.id,content:`Edited ${t}:
50
50
  ${c.join(`
51
- `)}`}}async createFiles(e){let t=e.input,o=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${o.length} file(s) for creation.`,files:o}}async spawnAgent(e){let t=String(e.input.agent_id||""),o=String(e.input.prompt||""),n=Number(e.input.timeout_seconds)||300;if(!t||!o)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-XY5N7TUU.js"),{getGlobalRegistry:i}=await import("./registry-HYQ3N4B6.js"),c=i();if(!c)return{tool_use_id:e.id,content:"Sub-agent spawning requires the daemon to be running.",is_error:!0};let p=await new s(c).spawn({targetAgentId:t,prompt:o,parentAgentId:"orchestrator",timeout:n*1e3});return p.success?{tool_use_id:e.id,content:`Sub-agent "${t}" completed (${Math.round(p.duration/1e3)}s):
51
+ `)}`}}async createFiles(e){let t=e.input,o=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${o.length} file(s) for creation.`,files:o}}async spawnAgent(e){let t=String(e.input.agent_id||""),o=String(e.input.prompt||""),n=Number(e.input.timeout_seconds)||300;if(!t||!o)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-XY5N7TUU.js"),{getGlobalRegistry:i}=await import("./registry-LGXDCWCL.js"),c=i();if(!c)return{tool_use_id:e.id,content:"Sub-agent spawning requires the daemon to be running.",is_error:!0};let p=await new s(c).spawn({targetAgentId:t,prompt:o,parentAgentId:"orchestrator",timeout:n*1e3});return p.success?{tool_use_id:e.id,content:`Sub-agent "${t}" completed (${Math.round(p.duration/1e3)}s):
52
52
 
53
53
  ${p.content}`}:{tool_use_id:e.id,content:`Sub-agent "${t}" failed: ${p.error}`,is_error:!0}}catch(s){return{tool_use_id:e.id,content:`Failed to spawn sub-agent: ${s.message}`,is_error:!0}}}async askUser(e){let t=String(e.input.question||""),o=e.input.options,n=t;return o?.length&&(n+=`
54
54
  Options: ${o.join(", ")}`),{tool_use_id:e.id,content:"Question sent to user.",followUp:n}}};async function Ae(r){let{provider:e,systemPrompt:t,messages:o,providerOptions:n,cwd:s,maxIterations:i=20,enabledTools:c,interactive:a=!0,overwrite:p=!1,dryRun:l=!1,onProgress:d,abortSignal:u}=r,m=u?{...n,abortSignal:u}:n;if(!e.generateRaw)return dt(r);let I=new se(s,{interactive:a,overwrite:p,dryRun:l,acmeContext:r.acmeContext,abortSignal:u}),D=be(c);if(r.acmeContext)for(let g of at)D.push({name:g.name,description:g.description,input_schema:g.input_schema});let E=new Set;if(r.mcpTools?.length)for(let g of r.mcpTools)D.push({name:g.name,description:g.description,input_schema:g.input_schema}),E.add(g.name);let C=o.filter(g=>g.role!=="system").map(g=>({role:g.role,content:g.content})),B=[],G=0,F=0,A=0,O="",j,_=0;for(;_<i;){if(_++,u?.aborted)throw new Error("cancelled");d?.({type:"iteration_start",iteration:_}),b.step(_,`Agentic loop iteration (${D.length} tools available)`);let g,M=!!e.generateRawStream&&!!d;try{if(M){let T=null,U=null,v="";for await(let x of e.generateRawStream(C,t,D,m))x.type==="text_delta"?(v+=x.text,d?.({type:"text_delta",text:x.text})):x.type==="thinking_delta"?d?.({type:"thinking_delta",text:x.text}):x.type==="raw_result"?T=x.result:x.type==="error"&&(U=x.error);if(U&&!T)throw new Error(U);if(!T)throw new Error("generateRawStream returned no raw_result event");g=T,g._streamedText=v}else g=await e.generateRaw(C,t,D,m)}catch(T){if(T.message?.includes("not available"))return dt(r);throw T}G+=g.usage.input_tokens+g.usage.output_tokens,F+=g.usage.input_tokens,A+=g.usage.output_tokens;let P=g._streamedText;for(let T of g.content)T.type==="text"&&(O+=T.text,P===void 0&&d?.({type:"text_delta",text:T.text}));if(P!==void 0&&delete g._streamedText,g.stop_reason==="end_turn"||g.stop_reason==="max_tokens")break;if(g.stop_reason==="tool_use"){let T=g.content.filter(v=>v.type==="tool_use");if(T.length===0)break;C.push({role:"assistant",content:g.content});let U=[];for(let v of T){d?.({type:"tool_call",name:v.name,id:v.id,input:v.input}),b.step(_,`Tool call: ${v.name}`);let x;if(E.has(v.name)&&r.mcpDispatch){let h=await r.mcpDispatch(v.name,v.input);x={tool_use_id:v.id,content:h.content,is_error:h.isError}}else x=await I.execute({name:v.name,id:v.id,input:v.input});d?.({type:"tool_result",name:v.name,id:v.id,content:x.content.slice(0,200),is_error:x.is_error}),x.files?.length&&(B.push(...x.files),d?.({type:"files_created",files:x.files})),x.followUp&&(j=x.followUp),U.push({type:"tool_result",tool_use_id:x.tool_use_id,content:x.content,is_error:x.is_error})}if(C.push({role:"user",content:U}),j)break;continue}break}return d?.({type:"complete",iterations:_,totalTokens:G}),{files:B,content:O,followUp:j,tokensUsed:G,inputTokens:F||void 0,outputTokens:A||void 0,iterations:_}}async function dt(r){let{provider:e,systemPrompt:t,messages:o,providerOptions:n,maxIterations:s=5}=r,c=[{role:"system",content:t+`
@@ -123,4 +123,4 @@ ${r.projectInstructions}`),r.memoryContext&&o.push(r.memoryContext),o.push(`# Ou
123
123
  Generate output appropriate for: ${e}. Use the \`create_files\` tool to output all files.`),o.join(`
124
124
 
125
125
  `)}export{qe as a,Vt as b,Yt as c,We as d,ze as e,Ve as f,Ye as g,Pe as h,ee as i,Re as j,le as k,te as l,Tt as m,oe as n,Mt as o,f as p,et as q,tt as r,Me as s,de as t,W as u,ne as v,it as w,Ee as x,$e as y,se as z,mt as A,Zn as B,er as C};
126
- //# sourceMappingURL=chunk-S5DS2V3X.js.map
126
+ //# sourceMappingURL=chunk-LR4FYHWS.js.map
@@ -1,4 +1,4 @@
1
- import{Ba as yh,D as es,F as Gu,Fa as wh,Ga as is,Ha as eo,Ia as bh,Ja as kh,K as Wu,Ka as vh,La as Sh,M as Hu,Na as $h,O as Bu,P as Ki,Q as qu,R as qe,S as Vu,T as ts,Ua as Ih,V as zi,Va as Th,W as Ju,X as Qi,Y as st,Z as nh,_ as sh,a as Zl,b as Gi,ba as rt,ca as rh,cb as to,da as ih,db as no,ea as oh,f as Wi,fa as ah,fb as xh,g as eu,ga as ch,h as tu,ha as dh,i as He,j as nu,ja as ve,k as su,ka as ns,la as Zi,m as ru,ma as lh,na as Qt,o as iu,oa as uh,p as ku,pa as Pe,q as vu,qa as hh,r as Su,ra as gh,s as $u,sa as ph,t as Iu,ta as ss,u as Tu,ua as rs,v as xu,va as fh,w as Au,wa as mh,x as Ru,y as Ji}from"./chunk-HYOXWAQP.js";import{d as zl,g as Yl,h as Ql}from"./chunk-6MARQ33D.js";import{m as du,n as lu,o as Bi,p as Ce,r as uu,s as ke}from"./chunk-S2GAEH2F.js";import{b as th}from"./chunk-7LN4VKDU.js";import{a as ou}from"./chunk-ZVP6GB4G.js";import{b as Eu}from"./chunk-MRIVENBY.js";import{i as Cu,m as Xi,n as Pu,p as _u,q as Mu,r as Ou,s as Du,t as Nu,u as Lu}from"./chunk-UNIXYV3U.js";import{f as qi,g as mu,h as Qn,i as xt,k as Be,m as yu,n as wu,o as bu,p as Vi,q as Zn}from"./chunk-AKWBDCMU.js";import{a as ju}from"./chunk-PPUN7YHA.js";import{a as Fu,b as Uu}from"./chunk-VZLIBDLH.js";import{b as Xu,c as Ku,d as Yi,e as zu,f as Yu,g as Qu,h as Zu,i as eh}from"./chunk-EKJG63EJ.js";import{o as Hi}from"./chunk-YDPXS6T4.js";import{b as Yn}from"./chunk-EMGB23H5.js";import{d as hu}from"./chunk-JAML6222.js";import{g as gu}from"./chunk-LQE73AZR.js";import{b as pu,c as fu}from"./chunk-2D3RYIDU.js";import{a as We}from"./chunk-Y4CYQV7G.js";import{a as Vl,b as Tt,c as Jl,d as Xl,e as Kl}from"./chunk-3W2BHUGM.js";import{a as $t,b as It}from"./chunk-SHEUCITK.js";import{a as au,b as cu}from"./chunk-A5GYG56I.js";import{$ as nt,A as Ud,B as Gd,C as Wd,D as le,E as Bd,F as qd,G as Vd,H as Jd,I as Xd,J as Kd,K as zd,L as Ol,M as Dl,N as Nl,O as Ll,P as jl,Q as Fl,S as ue,T as Ge,U as ji,V as kt,W as Fi,X as Kn,Y as vt,Z as St,_ as ge,a as hd,aa as se,b as Ai,c as pd,d as Sd,da as Wl,e as $d,f as zt,h as Ei,i as Ci,j as Pi,k as _i,l as Id,na as Hl,s as xd,t as Ed,u as et,v as Cd,w as Md,x as J,z as Fd}from"./chunk-CELYB3UW.js";import{A as $l,B as Il,C as Tl,D as xl,E as Al,F as Rl,H as El,K as Cl,P as Pl,Q as _l,T as Ml,X as Ul,a as Ad,ba as Gl,c as Pd,d as _d,e as tt,f as Le,l as Yd,n as Qd,p as hl,q as gl,r as yl,s as wl,t as bl,u as kl,w as Li,x as Xn,y as vl,z as Sl}from"./chunk-I6P3BKWJ.js";import{b as ol,c as al,d as Di,f as Vn,g as cl,h as dl,i as ll,j as Yt,k as Jn,l as ul}from"./chunk-QSKG754X.js";import{a as Mi,b as Rd}from"./chunk-MEFPXHQJ.js";import{A as Bl,B as zn,C as ql,h as xc,n as Ac,o as gi}from"./chunk-S5DS2V3X.js";import{b as $c}from"./chunk-SFQUP3BP.js";import{a as Ui}from"./chunk-6TTGRTDO.js";import{a as Zd,b as Oi,c as el,d as tl,e as nl,i as sl,j as rl}from"./chunk-VE3SSOQX.js";import{b as Hd}from"./chunk-W4YR2RO2.js";import{b as de,d as bt,f as je,g as Bn,i as he,j as il,k as Fe,l as Ue,m as ml,s as Ni}from"./chunk-6DZSDM35.js";import{a as pl,b as fl}from"./chunk-VJC372D6.js";import{d as Od,e as Dd,f as Nd,g as Ld,h as jd,j as qn}from"./chunk-X5C5W3E4.js";import{c as Hn}from"./chunk-OWNQ2FD4.js";import{c as Td}from"./chunk-MWNCS57L.js";import{d as Ec,e as ek,m as cd,n as dk,q as dd,v as ld,x as xi,y as Ne,z as Kt}from"./chunk-MSRFTAWH.js";import{a as Ee,b as Xt,f as Gn}from"./chunk-72SZI2UW.js";import{a as Vt,b as Rc}from"./chunk-FCPTN6NF.js";import{c as ud}from"./chunk-MYVHVJWZ.js";import{e as gd}from"./chunk-6TURWSMN.js";import{d as fd,e as md,f as Ri,g as Wn,h as yd,i as wd,j as bd,k as kd,q as vd}from"./chunk-AV7T3SYT.js";import{a as Nn,b as Zb}from"./chunk-7I7IEX4S.js";import{b as Ic,e as Tc}from"./chunk-JHCI6XCJ.js";import{e as Ye}from"./chunk-DSYKYZMT.js";import{A as zc,Ca as ck,D as Yc,E as vi,F as Si,H as $i,J as Qc,K as Zc,M as Jt,N as ed,O as td,P as nd,Q as sd,R as ik,U as rd,X as id,Y as od,aa as ok,ca as Ii,d as wt,e as Pc,ea as ak,f as fi,g as tk,h as Ln,i as mi,j as jn,l as Qe,m as yi,n as _c,o as nk,p as Fn,q as sk,r as Un,s as Mc,t as rk,u as Oc,ua as Ti,v as Dc,va as ad,w as Nc,z as Kc}from"./chunk-HW5FTKTU.js";import{e as Ze,f as Lc,g as jc,h as wi}from"./chunk-BRK6M6LA.js";import{a as Fc,b as Uc,c as Gc,e as Wc,f as bi,g as Hc,h as Bc,i as ki,j as qc,k as Vc,m as Jc,n as Xc}from"./chunk-UIBUZ2N3.js";import{b as pi,e as Cc}from"./chunk-2QNT5JDS.js";import{d as yt}from"./chunk-QIJLFPWE.js";import{existsSync as ao,readFileSync as co}from"fs";Nc();var Ah=["answer","narration","line"],Rh=5e3;function Eh(r){return r==="/voice/queue"||r.startsWith("/voice/queue/")}async function Ch(r,e,t,n,s,i){if(n==="/voice/queue"){if(t==="GET")return{status:200,body:{...r.view(),...i?{floor:i.view()}:{}}};if(t!=="POST")return{status:405,body:{error:"GET or POST"}};let d=String(s.text??"").trim(),l=String(s.agentId??s.agent??""),u=String(s.kind??"line");if(!d||!l||!Ah.includes(u))return{status:400,body:{error:`Required: text and agentId; kind is ${Ah.join(" | ")}`}};if(d.length>Rh)return{status:413,body:{error:`text is over ${Rh} characters`}};let g=e(l);if(!g)return{status:404,body:{error:`Unknown agent: ${l}`}};let{item:m,done:f}=r.enqueue({voice:g,text:d,agentId:l,kind:u,...typeof s.floor=="string"?{floor:s.floor}:{}});return s.wait!==!0?{status:202,body:{item:m}}:{status:200,body:{item:m,played:await f}}}if(t==="POST"&&n==="/voice/queue/pause")return r.pause(),{status:200,body:r.view()};if(t==="POST"&&n==="/voice/queue/resume")return r.resume(),{status:200,body:r.view()};let[,,,o,a,c]=n.split("/");if(t!=="POST"||!o||c!==void 0)return{status:404,body:{error:"Not found"}};switch(a){case"skip":return r.skip(o)?{status:200,body:r.view()}:so(o);case"front":return r.front(o)?{status:200,body:r.view()}:so(o);case"replay":{let d=r.replay(o);return d?{status:202,body:{item:d}}:so(o)}default:return{status:404,body:{error:"Not found"}}}}function Ph(r){let e=n=>`${n.agentId??"someone"} (${n.kind}): "${n.text.length>80?`${n.text.slice(0,79)}\u2026`:n.text}" [${n.id}]`,t=r.playing?`Speaking: ${e(r.playing)}`:r.paused?"Paused: the listener is speaking; the queue plays on after.":"Nothing is speaking.";return[...r.floor?.held?[Dc(r.floor)]:[],t,...r.waiting.map((n,s)=>`${s+1}. waiting: ${e(n)}`)].join(`
1
+ import{Ba as yh,D as es,F as Gu,Fa as wh,Ga as is,Ha as eo,Ia as bh,Ja as kh,K as Wu,Ka as vh,La as Sh,M as Hu,Na as $h,O as Bu,P as Ki,Q as qu,R as qe,S as Vu,T as ts,Ua as Ih,V as zi,Va as Th,W as Ju,X as Qi,Y as st,Z as nh,_ as sh,a as Zl,b as Gi,ba as rt,ca as rh,cb as to,da as ih,db as no,ea as oh,f as Wi,fa as ah,fb as xh,g as eu,ga as ch,h as tu,ha as dh,i as He,j as nu,ja as ve,k as su,ka as ns,la as Zi,m as ru,ma as lh,na as Qt,o as iu,oa as uh,p as ku,pa as Pe,q as vu,qa as hh,r as Su,ra as gh,s as $u,sa as ph,t as Iu,ta as ss,u as Tu,ua as rs,v as xu,va as fh,w as Au,wa as mh,x as Ru,y as Ji}from"./chunk-HYOXWAQP.js";import{d as zl,g as Yl,h as Ql}from"./chunk-6MARQ33D.js";import{m as du,n as lu,o as Bi,p as Ce,r as uu,s as ke}from"./chunk-S2GAEH2F.js";import{b as th}from"./chunk-7LN4VKDU.js";import{a as ou}from"./chunk-ZVP6GB4G.js";import{b as Eu}from"./chunk-MRIVENBY.js";import{i as Cu,m as Xi,n as Pu,p as _u,q as Mu,r as Ou,s as Du,t as Nu,u as Lu}from"./chunk-UNIXYV3U.js";import{f as qi,g as mu,h as Qn,i as xt,k as Be,m as yu,n as wu,o as bu,p as Vi,q as Zn}from"./chunk-AKWBDCMU.js";import{a as ju}from"./chunk-PPUN7YHA.js";import{a as Fu,b as Uu}from"./chunk-VZLIBDLH.js";import{b as Xu,c as Ku,d as Yi,e as zu,f as Yu,g as Qu,h as Zu,i as eh}from"./chunk-EKJG63EJ.js";import{o as Hi}from"./chunk-YDPXS6T4.js";import{b as Yn}from"./chunk-EMGB23H5.js";import{d as hu}from"./chunk-JAML6222.js";import{g as gu}from"./chunk-LQE73AZR.js";import{b as pu,c as fu}from"./chunk-2D3RYIDU.js";import{a as We}from"./chunk-Y4CYQV7G.js";import{a as Vl,b as Tt,c as Jl,d as Xl,e as Kl}from"./chunk-3W2BHUGM.js";import{a as $t,b as It}from"./chunk-SHEUCITK.js";import{a as au,b as cu}from"./chunk-A5GYG56I.js";import{$ as nt,A as Ud,B as Gd,C as Wd,D as le,E as Bd,F as qd,G as Vd,H as Jd,I as Xd,J as Kd,K as zd,L as Ol,M as Dl,N as Nl,O as Ll,P as jl,Q as Fl,S as ue,T as Ge,U as ji,V as kt,W as Fi,X as Kn,Y as vt,Z as St,_ as ge,a as hd,aa as se,b as Ai,c as pd,d as Sd,da as Wl,e as $d,f as zt,h as Ei,i as Ci,j as Pi,k as _i,l as Id,na as Hl,s as xd,t as Ed,u as et,v as Cd,w as Md,x as J,z as Fd}from"./chunk-HIEJXGYD.js";import{A as $l,B as Il,C as Tl,D as xl,E as Al,F as Rl,H as El,K as Cl,P as Pl,Q as _l,T as Ml,X as Ul,a as Ad,ba as Gl,c as Pd,d as _d,e as tt,f as Le,l as Yd,n as Qd,p as hl,q as gl,r as yl,s as wl,t as bl,u as kl,w as Li,x as Xn,y as vl,z as Sl}from"./chunk-I6P3BKWJ.js";import{b as ol,c as al,d as Di,f as Vn,g as cl,h as dl,i as ll,j as Yt,k as Jn,l as ul}from"./chunk-QSKG754X.js";import{a as Mi,b as Rd}from"./chunk-MEFPXHQJ.js";import{A as Bl,B as zn,C as ql,h as xc,n as Ac,o as gi}from"./chunk-LR4FYHWS.js";import{b as $c}from"./chunk-SFQUP3BP.js";import{a as Ui}from"./chunk-6TTGRTDO.js";import{a as Zd,b as Oi,c as el,d as tl,e as nl,i as sl,j as rl}from"./chunk-VE3SSOQX.js";import{b as Hd}from"./chunk-W4YR2RO2.js";import{b as de,d as bt,f as je,g as Bn,i as he,j as il,k as Fe,l as Ue,m as ml,s as Ni}from"./chunk-6DZSDM35.js";import{a as pl,b as fl}from"./chunk-VJC372D6.js";import{d as Od,e as Dd,f as Nd,g as Ld,h as jd,j as qn}from"./chunk-X5C5W3E4.js";import{c as Hn}from"./chunk-OWNQ2FD4.js";import{c as Td}from"./chunk-MWNCS57L.js";import{d as Ec,e as ek,m as cd,n as dk,q as dd,v as ld,x as xi,y as Ne,z as Kt}from"./chunk-MSRFTAWH.js";import{a as Ee,b as Xt,f as Gn}from"./chunk-72SZI2UW.js";import{a as Vt,b as Rc}from"./chunk-FCPTN6NF.js";import{c as ud}from"./chunk-MYVHVJWZ.js";import{e as gd}from"./chunk-6TURWSMN.js";import{d as fd,e as md,f as Ri,g as Wn,h as yd,i as wd,j as bd,k as kd,q as vd}from"./chunk-AV7T3SYT.js";import{a as Nn,b as Zb}from"./chunk-7I7IEX4S.js";import{b as Ic,e as Tc}from"./chunk-JHCI6XCJ.js";import{e as Ye}from"./chunk-DSYKYZMT.js";import{A as zc,Ca as ck,D as Yc,E as vi,F as Si,H as $i,J as Qc,K as Zc,M as Jt,N as ed,O as td,P as nd,Q as sd,R as ik,U as rd,X as id,Y as od,aa as ok,ca as Ii,d as wt,e as Pc,ea as ak,f as fi,g as tk,h as Ln,i as mi,j as jn,l as Qe,m as yi,n as _c,o as nk,p as Fn,q as sk,r as Un,s as Mc,t as rk,u as Oc,ua as Ti,v as Dc,va as ad,w as Nc,z as Kc}from"./chunk-HW5FTKTU.js";import{e as Ze,f as Lc,g as jc,h as wi}from"./chunk-BRK6M6LA.js";import{a as Fc,b as Uc,c as Gc,e as Wc,f as bi,g as Hc,h as Bc,i as ki,j as qc,k as Vc,m as Jc,n as Xc}from"./chunk-UIBUZ2N3.js";import{b as pi,e as Cc}from"./chunk-2QNT5JDS.js";import{d as yt}from"./chunk-QIJLFPWE.js";import{existsSync as ao,readFileSync as co}from"fs";Nc();var Ah=["answer","narration","line"],Rh=5e3;function Eh(r){return r==="/voice/queue"||r.startsWith("/voice/queue/")}async function Ch(r,e,t,n,s,i){if(n==="/voice/queue"){if(t==="GET")return{status:200,body:{...r.view(),...i?{floor:i.view()}:{}}};if(t!=="POST")return{status:405,body:{error:"GET or POST"}};let d=String(s.text??"").trim(),l=String(s.agentId??s.agent??""),u=String(s.kind??"line");if(!d||!l||!Ah.includes(u))return{status:400,body:{error:`Required: text and agentId; kind is ${Ah.join(" | ")}`}};if(d.length>Rh)return{status:413,body:{error:`text is over ${Rh} characters`}};let g=e(l);if(!g)return{status:404,body:{error:`Unknown agent: ${l}`}};let{item:m,done:f}=r.enqueue({voice:g,text:d,agentId:l,kind:u,...typeof s.floor=="string"?{floor:s.floor}:{}});return s.wait!==!0?{status:202,body:{item:m}}:{status:200,body:{item:m,played:await f}}}if(t==="POST"&&n==="/voice/queue/pause")return r.pause(),{status:200,body:r.view()};if(t==="POST"&&n==="/voice/queue/resume")return r.resume(),{status:200,body:r.view()};let[,,,o,a,c]=n.split("/");if(t!=="POST"||!o||c!==void 0)return{status:404,body:{error:"Not found"}};switch(a){case"skip":return r.skip(o)?{status:200,body:r.view()}:so(o);case"front":return r.front(o)?{status:200,body:r.view()}:so(o);case"replay":{let d=r.replay(o);return d?{status:202,body:{item:d}}:so(o)}default:return{status:404,body:{error:"Not found"}}}}function Ph(r){let e=n=>`${n.agentId??"someone"} (${n.kind}): "${n.text.length>80?`${n.text.slice(0,79)}\u2026`:n.text}" [${n.id}]`,t=r.playing?`Speaking: ${e(r.playing)}`:r.paused?"Paused: the listener is speaking; the queue plays on after.":"Nothing is speaking.";return[...r.floor?.held?[Dc(r.floor)]:[],t,...r.waiting.map((n,s)=>`${s+1}. waiting: ${e(n)}`)].join(`
2
2
  `)}var so=r=>({status:404,body:{error:`No such line in the queue: ${r}`}});import{resolve as lo}from"path";ak();var lk={name:"agentx",version:"0.1.0"},uk=["2024-11-05","2025-03-26","2025-06-18","2025-11-25"],hk="2024-11-05";function gk(r){return typeof r=="string"&&uk.includes(r)?r:hk}var pk={tools:{},elicitation:{form:{}}},fk=0;async function _h(r,e){let t=++fk;return it({jsonrpc:"2.0",id:`elicit-${t}`,method:"elicitation/create",params:{mode:"form",message:r,requestedSchema:e}}),new Promise(n=>{Zt.set(`elicit-${t}`,s=>{s?.action==="accept"&&s.content?n(s.content):n(null)}),setTimeout(()=>{Zt.has(`elicit-${t}`)&&(Zt.delete(`elicit-${t}`),n(null))},6e4)})}var Zt=new Map,mk="http://localhost:18800",ro;function yk(){if(process.env.AGENTX_DAEMON_URL)return process.env.AGENTX_DAEMON_URL;for(let r of["agentx.json",".agentx/config.json"])try{let e=lo(process.cwd(),r);if(!ao(e))continue;let t=JSON.parse(co(e,"utf-8"))?.node?.bind;if(typeof t!="string"||!t.includes(":"))continue;{let n=t.lastIndexOf(":"),s=t.slice(0,n),i=t.slice(n+1),o=!s||s==="0.0.0.0"||s==="::"||s==="*"?"127.0.0.1":s;if(i)return`http://${o}:${i}`}}catch{}return mk}function X(){return ro===void 0&&(ro=yk()),ro}var io;function wk(r){try{let e=lo(process.cwd(),".env");if(!ao(e))return"";for(let t of co(e,"utf-8").split(`
3
3
  `)){let n=t.trim().replace(/^export\s+/,"");if(!n.startsWith(`${r}=`))continue;let s=n.slice(r.length+1).trim();return/^(["']).*\1$/.test(s)?s.slice(1,-1):s}}catch{}return""}function bk(r=process.env){if(r.AGENTX_TOKEN)return r.AGENTX_TOKEN;if(r.MESH_TOKEN)return r.MESH_TOKEN;let e=wk("MESH_TOKEN");if(e)return e;for(let t of["agentx.json",".agentx/config.json"])try{let n=lo(process.cwd(),t);if(!ao(n))continue;let s=JSON.parse(co(n,"utf-8"))?.dashboard?.token;if(typeof s=="string"&&s)return s}catch{}return""}function kk(){return io===void 0&&(io=bk()),io}var K=(r,e)=>{let t=kk();if(!t)return fetch(r,e);let n=new Headers(e?.headers);return n.has("Authorization")||n.set("Authorization",`Bearer ${t}`),fetch(r,{...e,headers:n})};function oo(r=process.env){let e={};return r.AGENTX_TASK_ID&&(e.callerTaskId=r.AGENTX_TASK_ID),r.AGENTX_CHANNEL&&(e.callerChannel=r.AGENTX_CHANNEL),r.AGENTX_CHAT_ID&&(e.callerChatId=r.AGENTX_CHAT_ID),e}async function vk(){let r=process.env.AGENTX_AGENT_ID,e=oo();if(!(!r||!e.callerChannel||!e.callerChatId))try{let t=new URLSearchParams({channel:e.callerChannel,chatId:e.callerChatId}),n=await K(`${X()}/agents/${encodeURIComponent(r)}/intent-path?${t}`,{signal:AbortSignal.timeout(2e3)});if(!n.ok)return;let s=await n.json();return{...Array.isArray(s.path)&&s.path.length?{path:s.path}:{},...typeof s.graphWeight=="number"?{graphWeight:s.graphWeight}:{}}}catch{return}}var Sk=1e4,$k=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN","EHOSTUNREACH","ENETUNREACH"]);function Ik(r,e){let t=e,n=t?.cause?.code??t?.code;if(n&&$k.has(n))return`Error: the AgentX daemon could not be reached (${n}); the message to ${r} was not sent.`;let s=t?.name==="TimeoutError"||t?.name==="AbortError"?"no answer in time":t?.message||String(e);return`Probably delivered to ${r}: the daemon did not confirm (${s}), but the request was sent and is most likely queued. Do not treat this as a failure. If unsure, send the same message again: within 10 minutes a repeat returns the existing task id instead of a second task, and delivers it if the first never arrived. A busy ${r} shows no trace until its turn starts; later, \`agentx trace list --agent ${r} --since 1h\` or the daemon log ("[send/agent]") shows it.`}var Tk=/\x1B\[[0-9;]*[A-Za-z]/g;function At(r){return r.replace(Tk,"")}async function xk(r,e,t){let n=await K(`${X()}/recall`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agent:r,channel:e,limit:Math.min(Math.max(t??30,1),100)})}),s=await n.json().catch(()=>({}));if(!n.ok)return{content:[{type:"text",text:`Error: ${s.error||n.statusText}`}]};let i=s.turns||[],o=e?`on ${e}`:"on any channel";return i.length===0?{content:[{type:"text",text:`No other messages ${o} today for ${r}.`}]}:{content:[{type:"text",text:Ak(i,!!s.hasMore)}]}}function Ak(r,e){let t=new Map;for(let s of r){let i=`${s.channel}/${s.chatId}`;t.has(i)||t.set(i,[]),t.get(i).push(s)}let n=[];for(let[s,i]of t){let o=[...i].sort((a,c)=>a.ts.localeCompare(c.ts)).map(a=>{let c=a.role==="agent"?"you":a.senderName||"user";return` [${a.ts.slice(11,16)}] ${c}: ${a.content.slice(0,300)}`});n.push(`From ${s}:
4
4
  ${o.join(`
@@ -78,7 +78,7 @@ Question: ${d.followUp}`})):c.state="completed",c.messages.push(u),c.artifacts=l
78
78
  `+t;let o=Math.max(s.lastIndexOf(" "),s.lastIndexOf(" "));return o>n*.6?s.slice(0,o)+t:s+t}function go(r,e,t){if(!r)return"";let s=r.split(`
79
79
  `).slice(0,e).join(`
80
80
  `);return nn(s,t)}var Hk=30,Uh=6e3,Bk=1500,qk=6e4;function Vk(r){let e=new Date(r),t=e.getUTCHours().toString().padStart(2,"0"),n=Math.floor(e.getUTCMinutes()/15)*15;return`${t}:${n.toString().padStart(2,"0")}`}var os=class{dir;cache=new Map;constructor(e=Fh(process.cwd(),".agentx/groups")){this.dir=e,Wk(this.dir,{recursive:!0})}add(e,t,n){let s=this.load(e),i=Date.now(),o=nn(n,Bk),a=s[s.length-1];if(!(a&&a.sender===t&&a.text===o&&i-a.timestamp<qk)){for(s.push({sender:t,text:o,timestamp:i});s.length>Hk;)s.shift();this.cache.set(e,s),this.save(e,s)}}buildContext(e){let t=this.load(e);if(t.length<=1)return"";let n=["[Recent group conversation]"],s=0,i=null,o=[],a="",c=()=>{if(!i)return!0;let d=i.repeat>1?`${i.line} [\xD7${i.repeat}]`:i.line;if(s+d.length>Uh)return!1;if(o.push(d),s+=d.length,i.bucket!==a){let l=`\u2014 ${i.bucket} \u2014`;if(s+l.length>Uh)return i=null,!1;o.push(l),s+=l.length,a=i.bucket}return i=null,!0};for(let d=t.length-2;d>=0;d--){let l=t[d],u=`${l.sender}: ${l.text}`,g=Vk(l.timestamp);if(i&&i.line===u&&i.bucket===g){i.repeat++;continue}if(!c())break;i={line:u,repeat:1,bucket:g}}c();for(let d=o.length-1;d>=0;d--)n.splice(1,0,o[d]);return n.length<=1?"":(n.push("[End of conversation \u2014 respond to the latest message]"),n.join(`
81
- `))}getEntries(e){return[...this.load(e)]}filePath(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"_");return Fh(this.dir,`${t}.json`)}load(e){if(this.cache.has(e))return this.cache.get(e);let t=this.filePath(e);if(!Gk(t))return this.cache.set(e,[]),[];try{let n=JSON.parse(Fk(t,"utf-8")),s=Array.isArray(n)?n:[];return this.cache.set(e,s),s}catch{return this.cache.set(e,[]),[]}}save(e,t){try{Uk(this.filePath(e),JSON.stringify(t))}catch{}}};var Jk={minChars:80,maxChars:4e3,idleFlushMs:2e3,minIntervalMs:1500,humanPacing:!1},Xk={telegram:{minChars:60,maxChars:3900,minIntervalMs:1500},whatsapp:{minChars:40,maxChars:3e3,minIntervalMs:2e3,humanPacing:!0},discord:{minChars:80,maxChars:2e3,minIntervalMs:1e3},gitlab:{minChars:200,maxChars:6e4,minIntervalMs:3e3}},as=class{config;buffer="";emitter;lastEmitTime=0;idleTimer;insideCodeFence=!1;fencePattern=/^```/;lastEmission=Promise.resolve();constructor(e,t,n){let s=n?Xk[n]:{};this.config={...Jk,...s,...t},this.emitter=e}push(e){this.buffer+=e,this.idleTimer&&clearTimeout(this.idleTimer),this.updateCodeFenceState(e),this.shouldEmit()?this.emit():this.idleTimer=setTimeout(()=>{this.buffer.length>0&&this.emit()},this.config.idleFlushMs)}async flush(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.buffer.length>0&&(this.emitImmediate(this.buffer),this.buffer=""),await this.lastEmission}get pendingLength(){return this.buffer.length}shouldEmit(){return this.insideCodeFence||this.buffer.length<this.config.minChars||Date.now()-this.lastEmitTime<this.config.minIntervalMs?!1:this.findBreakPoint()>0}emit(){let e=this.findBreakPoint();if(e<=0&&this.buffer.length<this.config.maxChars)return;let t=e>0?e:Math.min(this.buffer.length,this.config.maxChars),n=this.buffer.slice(0,t);if(this.buffer=this.buffer.slice(t),this.config.humanPacing){let s=800+Math.random()*1700;setTimeout(()=>this.emitImmediate(n),s)}else this.emitImmediate(n)}emitImmediate(e){this.lastEmitTime=Date.now(),this.lastEmission=this.lastEmission.then(()=>Promise.resolve().then(()=>this.emitter(e)).catch(()=>{}))}findBreakPoint(){let e=this.buffer,t=Math.min(e.length,this.config.maxChars),n=e.lastIndexOf(`
81
+ `))}getEntries(e){return[...this.load(e)]}filePath(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"_");return Fh(this.dir,`${t}.json`)}load(e){if(this.cache.has(e))return this.cache.get(e);let t=this.filePath(e);if(!Gk(t))return this.cache.set(e,[]),[];try{let n=JSON.parse(Fk(t,"utf-8")),s=Array.isArray(n)?n:[];return this.cache.set(e,s),s}catch{return this.cache.set(e,[]),[]}}save(e,t){try{Uk(this.filePath(e),JSON.stringify(t))}catch{}}};var Jk={minChars:80,maxChars:4e3,idleFlushMs:2e3,minIntervalMs:1500,humanPacing:!1},Xk={telegram:{minChars:60,maxChars:3900,minIntervalMs:1500},whatsapp:{minChars:40,maxChars:3e3,minIntervalMs:2e3,humanPacing:!0},discord:{minChars:80,maxChars:2e3,minIntervalMs:1e3},gitlab:{minChars:200,maxChars:6e4,minIntervalMs:3e3}},as=class{config;buffer="";emitter;lastEmitTime=0;idleTimer;insideCodeFence=!1;fencePattern=/^```/;lastEmission=Promise.resolve();constructor(e,t,n){let s=n?Xk[n]:{};this.config={...Jk,...s,...t},this.emitter=e}push(e){this.buffer+=e,this.idleTimer&&clearTimeout(this.idleTimer),this.updateCodeFenceState(e),this.shouldEmit()?this.emit():this.idleTimer=setTimeout(()=>{this.buffer.length>0&&this.emit()},this.config.idleFlushMs)}async flush(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.buffer.length>0&&(this.emitImmediate(this.buffer),this.buffer=""),await this.lastEmission}get pendingLength(){return this.buffer.length}shouldEmit(){return this.insideCodeFence||this.buffer.length<this.config.minChars||Date.now()-this.lastEmitTime<this.config.minIntervalMs?!1:this.findBreakPoint()>0}emit(){let e=this.findBreakPoint();if(e<=0&&this.buffer.length<this.config.maxChars)return;let t=e>0?e:Math.min(this.buffer.length,this.config.maxChars),n=this.buffer.slice(0,t);this.buffer=this.buffer.slice(t);let s=this.config.humanPacing?800+Math.random()*1700:0;this.emitImmediate(n,s)}emitImmediate(e,t=0){this.lastEmitTime=Date.now(),this.lastEmission=this.lastEmission.then(()=>(t>0?new Promise(n=>setTimeout(n,t)):Promise.resolve()).then(()=>this.emitter(e)).catch(()=>{}))}findBreakPoint(){let e=this.buffer,t=Math.min(e.length,this.config.maxChars),n=e.lastIndexOf(`
82
82
 
83
83
  `,t);if(n>=this.config.minChars)return n+2;let s=e.lastIndexOf(`
84
84
  `,t);if(s>=this.config.minChars)return s+1;for(let i=t-1;i>=this.config.minChars;i--)if((e[i]==="."||e[i]==="!"||e[i]==="?")&&(i+1>=e.length||e[i+1]===" "||e[i+1]===`
@@ -91,7 +91,7 @@ Question: ${d.followUp}`})):c.state="completed",c.messages.push(u),c.artifacts=l
91
91
  `)}catch{}}loadUnfinished(){if(!mo(this.filePath))return[];try{let e=ng(this.filePath,"utf-8"),t=new Map;for(let n of e.split(`
92
92
  `))if(n.trim())try{let s=JSON.parse(n);s.type==="start"?t.set(s.id,s):s.type==="done"&&t.delete(s.id)}catch{}return[...t.values()]}catch{return[]}}compact(){try{let e=this.loadUnfinished(),t=e.map(n=>JSON.stringify(n)).join(`
93
93
  `)+(e.length?`
94
- `:"");sg(this.filePath,t)}catch{}}};function ev(r){return{id:r.id,channel:r.channel,accountId:r.accountId,sender:r.sender,group:r.group,text:r.text,replyTo:r.replyTo,replyToText:r.replyToText,timestamp:(r.timestamp instanceof Date?r.timestamp:new Date).toISOString(),resolvedAgent:r.resolvedAgent,preferNode:r.preferNode,channelMeta:r.channelMeta,runbookPath:r.runbookPath,runbookFiles:r.runbookFiles,media:r.media}}function tg(r){return{...r,timestamp:new Date(r.timestamp??Date.now())}}var tv=4e3;function nv(r){return Pd(r).replace(/\s*[—-]\s*AgentX will retry[^.]*\.?\s*$/i,"").trim()}var bo=class{registry;config;channels=new Map;hooks;mesh;serviceMatcher;business;groupLog;handoverStore;log;getHandoverStore(){return this.handoverStore}recentMessageIds=new Map;activeMessageKeys=new Set;sendDedupeMap=new Map;SEND_DEDUPE_MAX=5e3;MESSAGE_ID_TTL_MS=5*60*1e3;MESSAGE_ID_MAX_ENTRIES=2e3;DEDUP_STORE_PATH=".agentx/router/dedup.json";dedupDirtyCount=0;dedupSaveTimer;inflight;activeMeshForwards=0;getActiveMeshForwardCount(){return this.activeMeshForwards}deferredByPeer=new Map;MESH_DEFER_TTL_MS=30*60*1e3;MESH_DEFER_MAX_PER_PEER=50;constructor(e,t,n,s=console.error.bind(console,"[router]")){this.registry=e,this.config=t,this.hooks=n,this.log=s,this.groupLog=new os,this.handoverStore=new Ad({log:(...i)=>s("[handover]",...i)}),this.inflight=new wo(process.cwd()),this.loadDedupFromDisk()}loadDedupFromDisk(){try{let e=yo(process.cwd(),this.DEDUP_STORE_PATH);if(!mo(e))return;let t=JSON.parse(ng(e,"utf-8")),n=Date.now(),s=0;for(let[i,o]of Object.entries(t))typeof o=="number"&&n-o<this.MESSAGE_ID_TTL_MS&&(this.recentMessageIds.set(i,o),s++);s>0&&this.log(`Router dedup: restored ${s} recent message ids from disk`)}catch{}}scheduleDedupSave(){if(this.dedupDirtyCount++,this.dedupDirtyCount>=20){this.flushDedupToDisk();return}this.dedupSaveTimer||(this.dedupSaveTimer=setTimeout(()=>this.flushDedupToDisk(),5e3))}flushDedupToDisk(){this.dedupSaveTimer&&(clearTimeout(this.dedupSaveTimer),this.dedupSaveTimer=void 0),this.dedupDirtyCount=0;try{let e=Date.now(),t={};for(let[i,o]of this.recentMessageIds)e-o<this.MESSAGE_ID_TTL_MS&&(t[i]=o);let n=yo(process.cwd(),this.DEDUP_STORE_PATH),s=ig(n);mo(s)||rg(s,{recursive:!0}),sg(n,JSON.stringify(t))}catch{}}flushPersistence(){this.flushDedupToDisk(),this.inflight.compact()}setMesh(e){this.mesh=e,e.onPeerChange(t=>{t.delta==="recovered"&&this.replayDeferred(t.peer)})}setServiceMatcher(e){this.serviceMatcher=e}getServiceMatcher(){return this.serviceMatcher}setBusiness(e){this.business=e}updateConfig(e){this.config=e}getChannel(e){return this.channels.get(e)}addChannel(e){this.channels.set(e.name,e),e.onMessage(t=>this.handleMessage(e,t))}async sendOutbound(e,t){let n=this.channels.get(e.channel);if(!n)throw new Error(`Unknown channel: "${e.channel}". Available: ${[...this.channels.keys()].join(", ")}`);let s=t?.idempotencyKey!==void 0?this.sendDedupeKey(e.channel,e.chatId,e.text,t.idempotencyKey):void 0;if(s){let a=t?.dedupeWindowMs??6e4,c=this.sendDedupeGet(s,a);if(c!==void 0)return this.log(`Outbound [${e.channel}] -> ${e.chatId}: dedup hit (suppressed within ${a}ms window)`),c??void 0}let i=e.accountId;if(n.name==="telegram"&&!i&&e.agentId&&(i=this.getAccountForAgent(e.agentId)),(e.channel==="telegram"||e.channel==="whatsapp")&&e.text?.includes("agentx:ui")&&!e.buttons&&!e.poll&&!e.media){let{cleanText:a,ui:c}=He(e.text);if(c){c.skippedActions?.length&&this.log(`Outbound [${e.channel}] -> ${e.chatId}: agentx:ui dropped ${c.skippedActions.length} action button(s) (callback support is Phase 2): ${c.skippedActions.join(", ")}`);let l=e.agentId===void 0||this.richMessagesAllowed(e.agentId,e.channel)?fo(c):{},u=a||(l.buttons?"\u2304":"");if(!u&&!l.poll&&!l.media){this.log(`Outbound [${e.channel}] -> ${e.chatId}: only an agentx:ui block and rich messages are off \u2014 nothing to send`);return}e={...e,text:u,...l}}}this.log(`${new Date().toISOString()} Outbound [${e.channel}] -> ${e.chatId}: ${e.text.slice(0,80)}`);let o;try{n.name==="telegram"&&i?o=await this.adapterSend(n,{...e,accountId:i}):o=await n.send(e)}catch(a){let c=a?.cause?.code?` code=${a.cause.code}`:"";throw this.log(`${new Date().toISOString()} Outbound [${e.channel}] -> ${e.chatId}: send failed: ${a?.message??a}${c}`),a}if(s&&this.sendDedupeStore(s,typeof o=="string"?o:null),e.agentId&&t?.recordInSession!==!1)try{this.registry.getSessionStore().addAgentMessage(e.agentId,e.channel,e.chatId,e.text)}catch(a){this.log(`Failed to record outbound in recipient session: ${a.message}`)}return o}getChannelNames(){return[...this.channels.keys()]}async startAll(){for(let[e,t]of this.channels)this.log(`Starting channel: ${e}`),await t.start();this.replayInflight().catch(e=>this.log(`Inflight replay error: ${e.message}`))}async replayInflight(){let e=this.inflight.loadUnfinished();if(e.length!==0){this.log(`Inflight replay: ${e.length} task(s) to resume from previous run`);for(let t of e){let n=this.channels.get(t.channel);if(!n){this.log(`Inflight replay: adapter "${t.channel}" not available, skipping task ${t.id}`),this.inflight.done(t.id);continue}let s={id:t.id,channel:t.channel,accountId:t.accountId,sender:t.sender,group:t.group,text:t.text,replyTo:t.replyTo,replyToText:t.replyToText,timestamp:new Date(t.timestamp),resolvedAgent:t.resolvedAgent,preferNode:t.preferNode};this.log(`Inflight replay: ${t.channel}/${t.id} (agent=${t.resolvedAgent||"resolve"})`),this.handleMessage(n,s,{replay:!0}).catch(i=>this.log(`Inflight replay failed for ${t.id}: ${i.message}`)).finally(()=>this.inflight.done(t.id))}this.inflight.compact()}}createResumer(){return{resume:async({origin:e,note:t,attempt:n,run:s,rootId:i})=>{if(e.kind!=="router")throw new Error("not a router run");let o=this.channels.get(e.adapter);if(!o)throw new Error(`channel "${e.adapter}" is not running`);let a=tg(e.message);a.resume={note:t,attempt:n,resumedFrom:s.taskId,...i?{rootId:i}:{}},this.handleMessage(o,a,{replay:!0}).catch(c=>this.log(`Resume of ${s.taskId} failed: ${c.message}`))},tell:async(e,t)=>{if(e.kind!=="router")return;let n=this.channels.get(e.adapter);if(!n)throw new Error(`channel "${e.adapter}" is not running`);let s=tg(e.message);await this.adapterSend(n,{channel:s.channel,chatId:s.group?.id||s.sender.id,text:t,replyTo:s.channel==="telegram"?s.id:void 0,accountId:s.accountId,agentId:s.resolvedAgent,parseMode:"plain"})}}}async stopAll(){for(let[e,t]of this.channels)this.log(`Stopping channel: ${e}`),await t.stop()}isDuplicateMessage(e){let t=this.messageKey(e);if(!t)return!1;let n=Date.now();if(this.recentMessageIds.size>=this.MESSAGE_ID_MAX_ENTRIES)for(let[i,o]of this.recentMessageIds)n-o>this.MESSAGE_ID_TTL_MS&&this.recentMessageIds.delete(i);let s=this.recentMessageIds.get(t);return s&&n-s<this.MESSAGE_ID_TTL_MS?!0:(this.recentMessageIds.set(t,n),this.scheduleDedupSave(),!1)}messageKey(e){if(e.id)return`${e.channel}:${e.accountId||"default"}:${e.id}`}recordRouterDecisionInLedger(e,t){let n=Qh(e.channel);if(n&&he(n)!=="off")try{let s=Zh(de(),e,n,JSON.stringify(e),t);return s.outcome==="dispatched"?{eventId:s.eventId,decidedBy:s.decidedBy}:void 0}catch(s){this.log(`[ledger] router ${e.channel}/${e.id} record failed: ${s?.message??s}`);return}}handleMessage(e,t,n={}){let s=t.resume?.rootId;return s?je({rootId:s},()=>this.routeMessage(e,t,n)):Bn(()=>this.routeMessage(e,t,n))}async routeMessage(e,t,n){if(!n.replay&&this.isDuplicateMessage(t)){this.log(`Duplicate ${t.channel} message dropped: ${t.accountId||"default"}/${t.id}`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"deduped",reason:"isDuplicateMessage"});return}if(this.hooks?.has("pre:channel-message")){let d=await this.hooks.execute("pre:channel-message",{event:"pre:channel-message",channel:t.channel,sender:t.sender.name,text:t.text,group:t.group?.name,msg:t});if(d.blocked){this.log(`Message blocked by hook: ${d.message}`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`pre-hook blocked: ${d.message??""}`.trim()});return}d.modified?.text&&(t={...t,text:d.modified.text})}if(t.group){let d=t.group.id;this.groupLog.add(d,t.sender.name,t.text)}if(this.serviceMatcher){let d=t.group?.id||t.sender.id,l=this.serviceMatcher.match(t.text,t.sender.id,t.channel);if(l){this.log(`Service matched: "${l.service.name}" for ${t.sender.name} (trigger: ${l.trigger})`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`service-match: ${l.service.name} (trigger: ${l.trigger})`});let u=t.accountId;this.adapterReact(e,d,t.id,"\u{1F440}",u);let g=this.startTypingLoop(e,d,u);await this.serviceMatcher.execute(l.service,this.registry,{channel:t.channel,sender:t.sender.name,chatId:d},async m=>{clearInterval(g),await this.adapterSend(e,{channel:t.channel,chatId:d,text:m,replyTo:t.id,accountId:u})});return}}let s=this.runRoutingPipeline(t),i=s.agentId;if(!i){this.traceRoute(t,"drop",s.reason,s.decidingStage),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`routing:${s.reason}`});return}if(t.group&&t.channel==="telegram"){let d=this.getAccountForAgent(i,t.group.id);if(d&&d!==t.accountId){this.traceRoute(t,"drop",`multi-account-dedup (bound=${d} got=${t.accountId})`,"multi-account-dedup"),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`multi-account-dedup (bound=${d} got=${t.accountId})`});return}}this.traceRoute(t,"match",`${s.decidingStage} agent=${i}`,s.decidingStage,i);let o=this.recordRouterDecisionInLedger(t,{agentId:i,outcome:"dispatched",reason:s.decidingStage});o&&(t={...t,intentRef:o});let a=t.group?.id||t.sender.id,c=this.messageKey(t);if(c&&this.activeMessageKeys.has(c)){this.log(`Duplicate in-flight ${t.channel} message dropped: ${t.accountId||"default"}/${t.id}`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"deduped",reason:"in-flight duplicate"});return}c&&this.activeMessageKeys.add(c),this.inflight.start({id:t.id,channel:t.channel,accountId:t.accountId,text:t.text,sender:t.sender,group:t.group,replyTo:t.replyTo,replyToText:t.replyToText,timestamp:(t.timestamp instanceof Date?t.timestamp:new Date).toISOString(),resolvedAgent:i,preferNode:t.preferNode});try{return await this.processResolvedMessage(e,t,i,a)}finally{c&&this.activeMessageKeys.delete(c),this.inflight.done(t.id)}}async processResolvedMessage(e,t,n,s){if(t.preferNode){this.log(`preferNode="${t.preferNode}" \u2014 forcing mesh routing for agent "${n}"`),await this.handleViaMeshByPeer(e,t,n,t.preferNode)||(this.log(`Mesh peer "${t.preferNode}" not found or unhealthy for agent "${n}"`),this.deferForPeer(e,t,n,t.preferNode));return}let i=this.registry.getAgent(n);if(!i){if(!await this.handleViaMeshByAgentId(e,t,n)){let h=this.mesh?.findAgentPeer(n);h&&!h.healthy?this.deferForPeer(e,t,n,h.peer):this.log(`Agent "${n}" not found locally or on any mesh peer`)}return}let o=i.name||n,a=this.getAccountForAgent(n,t.group?.id)||t.accountId;this.log(`Routing [${t.channel}/${t.sender.name}] -> "${o}": ${t.text.slice(0,80)}`),this.adapterReact(e,s,t.id,"\u{1F440}",a);let c=this.startTypingLoop(e,s,a),d=typeof e.editMessage=="function",l="",u=0,g=d?new cs({maxChars:t.channel==="telegram"?3900:3900,send:async C=>{let h=u===0?t.id:void 0;u++;try{return await this.adapterSend(e,{channel:t.channel,chatId:s,text:C,replyTo:h,accountId:a})}catch(p){return this.log(`Stream preview send failed for ${t.channel}:${s}: ${p?.message||p}`),""}},edit:async(C,h)=>{try{return await this.adapterEdit(e,s,C,h,void 0,a)}catch(p){return this.log(`Stream preview edit failed for ${t.channel}:${s} message ${C}: ${p?.message||p}`),!1}}}):void 0,m=g?new as(async C=>{l+=C,await g.update(Zk(l))},void 0,t.channel):void 0,f=m?(C,h)=>{m.push(C)}:void 0;if(t.channelMeta?.agents){for(let C of t.channelMeta.agents)if(!C.handle){let h=this.registry.getAgent(C.id);h&&(C.handle=h.mentions.find(p=>p.startsWith("@")),C.name=h.name)}}let y=t.group?this.groupLog.buildContext(s):"",k=y?`${y}
94
+ `:"");sg(this.filePath,t)}catch{}}};function ev(r){return{id:r.id,channel:r.channel,accountId:r.accountId,sender:r.sender,group:r.group,text:r.text,replyTo:r.replyTo,replyToText:r.replyToText,timestamp:(r.timestamp instanceof Date?r.timestamp:new Date).toISOString(),resolvedAgent:r.resolvedAgent,preferNode:r.preferNode,channelMeta:r.channelMeta,runbookPath:r.runbookPath,runbookFiles:r.runbookFiles,media:r.media}}function tg(r){return{...r,timestamp:new Date(r.timestamp??Date.now())}}var tv=4e3;function nv(r){return Pd(r).replace(/\s*[—-]\s*AgentX will retry[^.]*\.?\s*$/i,"").trim()}var bo=class{registry;config;channels=new Map;hooks;mesh;serviceMatcher;business;groupLog;handoverStore;log;getHandoverStore(){return this.handoverStore}recentMessageIds=new Map;activeMessageKeys=new Set;sendDedupeMap=new Map;SEND_DEDUPE_MAX=5e3;MESSAGE_ID_TTL_MS=5*60*1e3;MESSAGE_ID_MAX_ENTRIES=2e3;DEDUP_STORE_PATH=".agentx/router/dedup.json";dedupDirtyCount=0;dedupSaveTimer;inflight;activeMeshForwards=0;getActiveMeshForwardCount(){return this.activeMeshForwards}deferredByPeer=new Map;MESH_DEFER_TTL_MS=30*60*1e3;MESH_DEFER_MAX_PER_PEER=50;constructor(e,t,n,s=console.error.bind(console,"[router]")){this.registry=e,this.config=t,this.hooks=n,this.log=s,this.groupLog=new os,this.handoverStore=new Ad({log:(...i)=>s("[handover]",...i)}),this.inflight=new wo(process.cwd()),this.loadDedupFromDisk()}loadDedupFromDisk(){try{let e=yo(process.cwd(),this.DEDUP_STORE_PATH);if(!mo(e))return;let t=JSON.parse(ng(e,"utf-8")),n=Date.now(),s=0;for(let[i,o]of Object.entries(t))typeof o=="number"&&n-o<this.MESSAGE_ID_TTL_MS&&(this.recentMessageIds.set(i,o),s++);s>0&&this.log(`Router dedup: restored ${s} recent message ids from disk`)}catch{}}scheduleDedupSave(){if(this.dedupDirtyCount++,this.dedupDirtyCount>=20){this.flushDedupToDisk();return}this.dedupSaveTimer||(this.dedupSaveTimer=setTimeout(()=>this.flushDedupToDisk(),5e3))}flushDedupToDisk(){this.dedupSaveTimer&&(clearTimeout(this.dedupSaveTimer),this.dedupSaveTimer=void 0),this.dedupDirtyCount=0;try{let e=Date.now(),t={};for(let[i,o]of this.recentMessageIds)e-o<this.MESSAGE_ID_TTL_MS&&(t[i]=o);let n=yo(process.cwd(),this.DEDUP_STORE_PATH),s=ig(n);mo(s)||rg(s,{recursive:!0}),sg(n,JSON.stringify(t))}catch{}}flushPersistence(){this.flushDedupToDisk(),this.inflight.compact()}setMesh(e){this.mesh=e,e.onPeerChange(t=>{t.delta==="recovered"&&this.replayDeferred(t.peer)})}setServiceMatcher(e){this.serviceMatcher=e}getServiceMatcher(){return this.serviceMatcher}setBusiness(e){this.business=e}updateConfig(e){this.config=e}getChannel(e){return this.channels.get(e)}addChannel(e){this.channels.set(e.name,e),e.onMessage(t=>this.handleMessage(e,t))}async sendOutbound(e,t){let n=this.channels.get(e.channel);if(!n)throw new Error(`Unknown channel: "${e.channel}". Available: ${[...this.channels.keys()].join(", ")}`);let s=t?.idempotencyKey!==void 0?this.sendDedupeKey(e.channel,e.chatId,e.text,t.idempotencyKey):void 0;if(s){let a=t?.dedupeWindowMs??6e4,c=this.sendDedupeGet(s,a);if(c!==void 0)return this.log(`Outbound [${e.channel}] -> ${e.chatId}: dedup hit (suppressed within ${a}ms window)`),c??void 0}let i=e.accountId;if(n.name==="telegram"&&!i&&e.agentId&&(i=this.getAccountForAgent(e.agentId)),(e.channel==="telegram"||e.channel==="whatsapp")&&e.text?.includes("agentx:ui")&&!e.buttons&&!e.poll&&!e.media){let{cleanText:a,ui:c}=He(e.text);if(c){c.skippedActions?.length&&this.log(`Outbound [${e.channel}] -> ${e.chatId}: agentx:ui dropped ${c.skippedActions.length} action button(s) (callback support is Phase 2): ${c.skippedActions.join(", ")}`);let l=e.agentId===void 0||this.richMessagesAllowed(e.agentId,e.channel)?fo(c):{},u=a||(l.buttons?"\u2304":"");if(!u&&!l.poll&&!l.media){this.log(`Outbound [${e.channel}] -> ${e.chatId}: only an agentx:ui block and rich messages are off \u2014 nothing to send`);return}e={...e,text:u,...l}}}this.log(`${new Date().toISOString()} Outbound [${e.channel}] -> ${e.chatId}: ${e.text.slice(0,80)}`);let o;try{n.name==="telegram"&&i?o=await this.adapterSend(n,{...e,accountId:i}):o=await n.send(e)}catch(a){let c=a?.cause?.code?` code=${a.cause.code}`:"";throw this.log(`${new Date().toISOString()} Outbound [${e.channel}] -> ${e.chatId}: send failed: ${a?.message??a}${c}`),a}if(s&&this.sendDedupeStore(s,typeof o=="string"?o:null),e.agentId&&t?.recordInSession!==!1)try{this.registry.getSessionStore().addAgentMessage(e.agentId,e.channel,e.chatId,e.text)}catch(a){this.log(`Failed to record outbound in recipient session: ${a.message}`)}return o}getChannelNames(){return[...this.channels.keys()]}async startAll(){for(let[e,t]of this.channels)this.log(`Starting channel: ${e}`),await t.start();this.replayInflight().catch(e=>this.log(`Inflight replay error: ${e.message}`))}async replayInflight(){let e=this.inflight.loadUnfinished();if(e.length!==0){this.log(`Inflight replay: ${e.length} task(s) to resume from previous run`);for(let t of e){let n=this.channels.get(t.channel);if(!n){this.log(`Inflight replay: adapter "${t.channel}" not available, skipping task ${t.id}`),this.inflight.done(t.id);continue}let s={id:t.id,channel:t.channel,accountId:t.accountId,sender:t.sender,group:t.group,text:t.text,replyTo:t.replyTo,replyToText:t.replyToText,timestamp:new Date(t.timestamp),resolvedAgent:t.resolvedAgent,preferNode:t.preferNode};this.log(`Inflight replay: ${t.channel}/${t.id} (agent=${t.resolvedAgent||"resolve"})`),this.handleMessage(n,s,{replay:!0}).catch(i=>this.log(`Inflight replay failed for ${t.id}: ${i.message}`)).finally(()=>this.inflight.done(t.id))}this.inflight.compact()}}createResumer(){return{resume:async({origin:e,note:t,attempt:n,run:s,rootId:i})=>{if(e.kind!=="router")throw new Error("not a router run");let o=this.channels.get(e.adapter);if(!o)throw new Error(`channel "${e.adapter}" is not running`);let a=tg(e.message);a.resume={note:t,attempt:n,resumedFrom:s.taskId,...i?{rootId:i}:{}},this.handleMessage(o,a,{replay:!0}).catch(c=>this.log(`Resume of ${s.taskId} failed: ${c.message}`))},tell:async(e,t)=>{if(e.kind!=="router")return;let n=this.channels.get(e.adapter);if(!n)throw new Error(`channel "${e.adapter}" is not running`);let s=tg(e.message);await this.adapterSend(n,{channel:s.channel,chatId:s.group?.id||s.sender.id,text:t,replyTo:s.channel==="telegram"?s.id:void 0,accountId:s.accountId,agentId:s.resolvedAgent,parseMode:"plain"})}}}async stopAll(){for(let[e,t]of this.channels)this.log(`Stopping channel: ${e}`),await t.stop()}isDuplicateMessage(e){let t=this.messageKey(e);if(!t)return!1;let n=Date.now();if(this.recentMessageIds.size>=this.MESSAGE_ID_MAX_ENTRIES)for(let[i,o]of this.recentMessageIds)n-o>this.MESSAGE_ID_TTL_MS&&this.recentMessageIds.delete(i);let s=this.recentMessageIds.get(t);return s&&n-s<this.MESSAGE_ID_TTL_MS?!0:(this.recentMessageIds.set(t,n),this.scheduleDedupSave(),!1)}messageKey(e){if(e.id)return`${e.channel}:${e.accountId||"default"}:${e.id}`}recordRouterDecisionInLedger(e,t){let n=Qh(e.channel);if(n&&he(n)!=="off")try{let s=Zh(de(),e,n,JSON.stringify(e),t);return s.outcome==="dispatched"?{eventId:s.eventId,decidedBy:s.decidedBy}:void 0}catch(s){this.log(`[ledger] router ${e.channel}/${e.id} record failed: ${s?.message??s}`);return}}handleMessage(e,t,n={}){let s=t.resume?.rootId;return s?je({rootId:s},()=>this.routeMessage(e,t,n)):Bn(()=>this.routeMessage(e,t,n))}async routeMessage(e,t,n){if(!n.replay&&this.isDuplicateMessage(t)){this.log(`Duplicate ${t.channel} message dropped: ${t.accountId||"default"}/${t.id}`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"deduped",reason:"isDuplicateMessage"});return}if(this.hooks?.has("pre:channel-message")){let d=await this.hooks.execute("pre:channel-message",{event:"pre:channel-message",channel:t.channel,sender:t.sender.name,text:t.text,group:t.group?.name,msg:t});if(d.blocked){this.log(`Message blocked by hook: ${d.message}`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`pre-hook blocked: ${d.message??""}`.trim()});return}d.modified?.text&&(t={...t,text:d.modified.text})}if(t.group){let d=t.group.id;this.groupLog.add(d,t.sender.name,t.text)}if(this.serviceMatcher){let d=t.group?.id||t.sender.id,l=this.serviceMatcher.match(t.text,t.sender.id,t.channel);if(l){this.log(`Service matched: "${l.service.name}" for ${t.sender.name} (trigger: ${l.trigger})`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`service-match: ${l.service.name} (trigger: ${l.trigger})`});let u=t.accountId;this.adapterReact(e,d,t.id,"\u{1F440}",u);let g=this.startTypingLoop(e,d,u);await this.serviceMatcher.execute(l.service,this.registry,{channel:t.channel,sender:t.sender.name,chatId:d},async m=>{clearInterval(g),await this.adapterSend(e,{channel:t.channel,chatId:d,text:m,replyTo:t.id,accountId:u})});return}}let s=this.runRoutingPipeline(t),i=s.agentId;if(!i){this.traceRoute(t,"drop",s.reason,s.decidingStage),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`routing:${s.reason}`});return}if(t.group&&t.channel==="telegram"){let d=this.getAccountForAgent(i,t.group.id);if(d&&d!==t.accountId){this.traceRoute(t,"drop",`multi-account-dedup (bound=${d} got=${t.accountId})`,"multi-account-dedup"),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"halted",reason:`multi-account-dedup (bound=${d} got=${t.accountId})`});return}}this.traceRoute(t,"match",`${s.decidingStage} agent=${i}`,s.decidingStage,i);let o=this.recordRouterDecisionInLedger(t,{agentId:i,outcome:"dispatched",reason:s.decidingStage});o&&(t={...t,intentRef:o});let a=t.group?.id||t.sender.id,c=this.messageKey(t);if(c&&this.activeMessageKeys.has(c)){this.log(`Duplicate in-flight ${t.channel} message dropped: ${t.accountId||"default"}/${t.id}`),this.recordRouterDecisionInLedger(t,{agentId:null,outcome:"deduped",reason:"in-flight duplicate"});return}c&&this.activeMessageKeys.add(c),this.inflight.start({id:t.id,channel:t.channel,accountId:t.accountId,text:t.text,sender:t.sender,group:t.group,replyTo:t.replyTo,replyToText:t.replyToText,timestamp:(t.timestamp instanceof Date?t.timestamp:new Date).toISOString(),resolvedAgent:i,preferNode:t.preferNode});try{return await this.processResolvedMessage(e,t,i,a)}finally{c&&this.activeMessageKeys.delete(c),this.inflight.done(t.id)}}async processResolvedMessage(e,t,n,s){if(t.preferNode){this.log(`preferNode="${t.preferNode}" \u2014 forcing mesh routing for agent "${n}"`),await this.handleViaMeshByPeer(e,t,n,t.preferNode)||(this.log(`Mesh peer "${t.preferNode}" not found or unhealthy for agent "${n}"`),this.deferForPeer(e,t,n,t.preferNode));return}let i=this.registry.getAgent(n);if(!i){if(!await this.handleViaMeshByAgentId(e,t,n)){let h=this.mesh?.findAgentPeer(n);h&&!h.healthy?this.deferForPeer(e,t,n,h.peer):this.log(`Agent "${n}" not found locally or on any mesh peer`)}return}let o=i.name||n,a=this.getAccountForAgent(n,t.group?.id)||t.accountId;this.log(`Routing [${t.channel}/${t.sender.name}] -> "${o}": ${t.text.slice(0,80)}`),this.adapterReact(e,s,t.id,"\u{1F440}",a);let c=this.startTypingLoop(e,s,a),d=typeof e.editMessage=="function"&&t.channel!=="whatsapp",l="",u=0,g=d?new cs({maxChars:t.channel==="telegram"?3900:3900,send:async C=>{let h=u===0?t.id:void 0;u++;try{return await this.adapterSend(e,{channel:t.channel,chatId:s,text:C,replyTo:h,accountId:a})}catch(p){return this.log(`Stream preview send failed for ${t.channel}:${s}: ${p?.message||p}`),""}},edit:async(C,h)=>{try{return await this.adapterEdit(e,s,C,h,void 0,a)}catch(p){return this.log(`Stream preview edit failed for ${t.channel}:${s} message ${C}: ${p?.message||p}`),!1}}}):void 0,m=g?new as(async C=>{l+=C,await g.update(Zk(l))},void 0,t.channel):void 0,f=m?(C,h)=>{m.push(C)}:void 0;if(t.channelMeta?.agents){for(let C of t.channelMeta.agents)if(!C.handle){let h=this.registry.getAgent(C.id);h&&(C.handle=h.mentions.find(p=>p.startsWith("@")),C.name=h.name)}}let y=t.group?this.groupLog.buildContext(s):"",k=y?`${y}
95
95
 
96
96
  ${t.sender.name}: ${t.text}`:t.text,w=await this.registry.execute({message:t.resume?`${t.resume.note}
97
97
  ${k}`:k,agentId:n,origin:{kind:"router",adapter:t.channel,message:ev(t)},resumeAttempt:t.resume?.attempt,resumedFrom:t.resume?.resumedFrom,onStart:()=>this.inflight.done(t.id),intentRef:t.intentRef,context:{channel:t.channel,sender:t.sender.name,senderId:t.sender.id,senderUsername:t.sender.username,group:t.group?.name,chatId:s,mediaPath:t.media?.path,mediaType:t.media?.type,replyToText:t.replyToText,channelMeta:t.channelMeta,runbookPath:t.runbookPath,runbookFiles:t.runbookFiles}},f);if(clearInterval(c),await m?.flush(),w.error){if(tt(w.error)){clearInterval(c),this.log(`Message queued for ${o}`);return}if(w.errorKind==="cancelled"){this.log(`Task cancelled for ${o} \u2014 suppressing channel error echo`);return}if(w.errorKind==="interrupted"){this.log(`Task interrupted for ${o} (${w.error}) \u2014 resume handles the reply after restart`);return}if(w.errorKind==="stopped"){this.log(`Task stopped for ${o} (${w.error}) \u2014 paused with a resume plan`);return}this.log(`Agent error: ${w.error}`);let C=`Error: ${w.error}`;g?.primaryId?await this.adapterEdit(e,s,g.primaryId,C,"plain",a)||(this.log(`Error response edit returned false for ${t.channel}:${s} message ${g.primaryId}; sending fallback`),await this.adapterSend(e,{channel:t.channel,chatId:s,text:C,replyTo:t.id,parseMode:"plain",accountId:a,agentId:n})):await this.adapterSend(e,{channel:t.channel,chatId:s,text:C,replyTo:t.id,parseMode:"plain",accountId:a,agentId:n});return}let S=w.content;if(this.hooks?.has("post:channel-message")){let C=await this.hooks.execute("post:channel-message",{event:"post:channel-message",channel:t.channel,sender:t.sender.name,response:S,agentId:n});if(C.blocked){this.log(`Response blocked by hook: ${C.message}`);return}C.modified?.response&&(S=C.modified.response)}t.channel==="gitlab"&&S&&(this.channels.get("gitlab")?.getAgentToken?.(n)||(S=`> **${o}** (${n})
@@ -524,7 +524,7 @@ ${d}`)}let S={agentId:o,message:w,context:{channel:y,sender:f?"opencode":"openai
524
524
 
525
525
  `)}}function Xg(r){r.writeHead(200,{"Content-Type":"text/event-stream; charset=utf-8","Cache-Control":"no-cache",Connection:"keep-alive","X-Accel-Buffering":"no"})}function Kg(r,e,t,n,s,i){r.write(`data: ${JSON.stringify({id:e,object:"chat.completion.chunk",created:t,model:n,choices:[{index:0,delta:s,finish_reason:i}]})}
526
526
 
527
- `)}function zg(r,e,t,n,s,i){let o=i?.usage?.inputTokens??0,a=i?.usage?.outputTokens??Math.ceil(s.length/4);Do(r,200,{id:e,object:"chat.completion",created:t,model:n,choices:[{index:0,message:{role:"assistant",content:s},finish_reason:"stop"}],usage:{prompt_tokens:o,completion_tokens:a,total_tokens:o+a}})}function Do(r,e,t){r.writeHead(e,{"Content-Type":"application/json"}),r.end(JSON.stringify(t))}var ln=class{module;minLevel;constructor(e,t="info"){this.module=e,this.minLevel=t}child(e){return new ln(`${this.module}:${e}`,this.minLevel)}debug(e,t){this.emit("debug",e,t)}info(e,t){this.emit("info",e,t)}warn(e,t){this.emit("warn",e,t)}error(e,t){this.emit("error",e,t)}asConsoleLog(){return(...e)=>{let n=e.map(s=>typeof s=="string"?s:JSON.stringify(s)).join(" ").replace(/^\[agentx\]\s*/,"");n&&this.info(n)}}emit(e,t,n){if(ln.levelOrder[e]<ln.levelOrder[this.minLevel])return;let s={time:new Date().toISOString(),level:e,module:this.module,msg:t,...n},i=e==="error"?"ERROR":e==="warn"?"WARN":"",o=`[${this.module}]`,a=i?`${o} ${i}: ${t}`:`${o} ${t}`;console.error(a)}},dn=ln;yt(dn,"levelOrder",{debug:0,info:1,warn:2,error:3});import{realpathSync as MS,statSync as OS}from"fs";var ut={version:"0.141.0",commit:"1825246",startedAt:new Date(Date.now()-process.uptime()*1e3).toISOString()};function DS(r,e){let t=e.mtimeMs!==null&&e.mtimeMs>Date.parse(r.startedAt),n=!!e.version&&!!r.version&&e.version!==r.version;return{newer:t||n,changedAt:e.mtimeMs===null?null:new Date(e.mtimeMs).toISOString(),version:e.version}}function Qg(){let r=null;try{r=OS(MS(process.argv[1])).mtimeMs}catch{}let e=bg().version;return DS(ut,{mtimeMs:r,version:e&&e!=="0.0.0"?e:null})}import{randomUUID as NS}from"crypto";var Ms=class{constructor(e=new Md){this.core=e}count=0;subscribe(e,t){this.count++;let n=this.core.subscribe((i,o)=>{if(!o||!LS.includes(o.kind))return;let a={...o,rootId:i.rootId,node:i.node};FS(e,a)&&t(a)}),s=!0;return()=>{s&&(s=!1,this.count--,n())}}publish(e){let t={id:typeof e.id=="string"?e.id:NS(),at:typeof e.at=="string"?e.at:new Date().toISOString(),...e},{type:n,summary:s,ref:i,agentId:o}=jS(t);this.core.publish({id:t.id,at:t.at,kind:t.kind,type:n,summary:s,ref:i,agentId:o,rootId:typeof e.rootId=="string"?e.rootId:void 0,data:t})}get size(){return this.count}},LS=["run","task","signal","mesh","channel","status"];function jS(r){switch(r.kind){case"run":return{type:r.phase,ref:r.runId,summary:[r.workflowId,r.nodeId,r.phase,r.note].filter(Boolean).join(" ")};case"task":return{type:r.phase,ref:r.taskId,summary:`${r.title??r.taskId} ${r.phase}`};case"signal":return{type:"emitted",summary:`signal ${r.name} (${r.scope})`};case"mesh":return{type:r.delta,summary:`peer ${r.peer} ${r.delta}`};case"channel":return{type:r.direction,ref:r.messageId,agentId:r.agentId,summary:`${r.channel} ${r.direction==="in"?"inbound":"outbound"}`};case"status":return{type:"status",summary:r.message}}}function FS(r,e){return!(r.kinds&&r.kinds.length>0&&!r.kinds.includes(e.kind)||r.workflowId&&(e.kind==="run"&&e.workflowId!==r.workflowId||e.kind==="task"&&e.workflowId!==r.workflowId||e.kind==="signal"&&e.workflowId&&e.workflowId!==r.workflowId)||r.runId&&(e.kind==="run"&&e.runId!==r.runId||e.kind==="task"&&e.runId!==r.runId)||r.actor&&(e.kind!=="task"||!(e.assignedTo?.includes(r.actor)||e.submittedBy===r.actor))||r.channel&&(e.kind!=="channel"||e.channel!==r.channel))}function Zg(r){if(!r)return;let e=["run","task","signal","mesh","channel","status"],n=r.split(",").map(s=>s.trim()).filter(Boolean).filter(s=>e.includes(s));return n.length?n:void 0}import{createHmac as Os,timingSafeEqual as ep}from"crypto";var Ds=class{registry;config;mesh;webhookEntries;log;workflowDispatcher;hooks;constructor(e,t={},n=console.error.bind(console,"[webhook]"),s,i=[],o){this.registry=e,this.config=t,this.log=n,this.mesh=s,this.webhookEntries=i,this.hooks=o}hookEventFor(e,t){if(e==="stripe")return"on:stripe-event";if(e==="sentry")return"on:sentry-issue";if(e==="vercel")return"on:vercel-deployment";if(e==="hubspot")return"on:hubspot-event";if(e==="odoo")return"on:odoo-event";if(e==="github"){let n=(t??"").split(".")[0];return n==="issues"||n==="issue_comment"?"on:github-issue":n==="pull_request"||n==="pull_request_review"?"on:github-pr":n==="push"?"on:github-push":null}return null}async fireHookSafe(e,t,n,s){let i=this.hookEventFor(e,t);if(!i||!this.hooks||!this.hooks.has(i))return;let o={};if(e==="github"){let a=s;typeof a.sender?.login=="string"&&(o.author=a.sender.login),typeof a.repository?.full_name=="string"&&(o.repo=a.repository.full_name);let c=a.issue?.number??a.pull_request?.number;typeof c=="number"&&(o.number=c)}try{await this.hooks.execute(i,{event:i,source:e,eventType:t,agentId:n,payload:s,...o})}catch(a){this.log(`${i} hook error (non-fatal): ${a?.message??a}`)}}setWorkflowDispatcher(e){this.workflowDispatcher=e}setWebhookEntries(e){this.webhookEntries=e}async handle(e,t,n){let s=n.replace(/^\/webhook\/?/,"").split("/").filter(Boolean),i=s[0],o=s[1];if(!i){this.sendJson(t,400,{error:"Missing agent ID. Use /webhook/:agentId"});return}let{raw:a,parsed:c}=await this.readBody(e),d=o||this.detectSource(e.headers);if(process.env.AGENTX_WEBHOOK_DEBUG_HEADERS==="1"){let k={};for(let[w,S]of Object.entries(e.headers))(w.startsWith("x-hubspot")||w.startsWith("x-hub")||w.startsWith("x-github")||w.startsWith("x-gitlab")||w.startsWith("stripe")||w.startsWith("sentry")||w.startsWith("x-vercel")||w.startsWith("x-odoo")||w.startsWith("x-webhook")||w==="user-agent"||w==="content-type"||w==="host"||w==="x-forwarded-host"||w==="x-forwarded-proto"||w==="x-forwarded-for")&&(k[w]=S);this.log(`Webhook [${d}] reqUrl=${e.url} headers: ${JSON.stringify(k)}`)}let l=this.validateSignature(e.headers,a,d,i,e.url);if(l){this.log(`Webhook [${d}] -> ${i}: REJECTED (${l})`),this.sendJson(t,401,{error:l});return}let u=this.buildSummary(d,c,e.headers);this.log(`Webhook [${d}] -> ${i}: ${u.slice(0,100)}`);let g=this.extractEventType(d,c,e.headers),m=this.webhookEntries.find(k=>k.enabled&&k.agentId===i&&k.source===d),f=g&&m?.triggers?.[g]||m?.defaultWorkflow||null;if(await this.fireHookSafe(d,g,i,c),f&&this.workflowDispatcher)try{let k=await this.workflowDispatcher.dispatchWorkflow({workflowId:f,entityRef:{kind:"webhook",id:`${d}:${i}:${g??"\u2014"}:${Date.now()}`},event:{kind:"webhook",source:d,eventType:g,payload:c},trigger:{source:d}});this.log(`Webhook [${d}/${g??"\u2014"}] -> workflow=${f} (claimed=${k.claimed})`),this.sendJson(t,202,{ok:!0,agent:i,source:d,eventType:g,workflow:f,claimed:k.claimed});return}catch(k){this.log(`Workflow dispatch failed [${d}/${g}/${f}]: ${k.message}`)}let y=this.webhookEntries.find(k=>k.enabled&&k.node&&k.agentId===i&&k.source===d);if(y?.node&&this.mesh){this.sendJson(t,202,{ok:!0,agent:i,source:d,node:y.node,status:"accepted"}),this.mesh.sendTask(y.node,u,i,{context:{channel:`webhook:${d}`,sender:`webhook:${d}`}}).then(k=>this.log(`Mesh-forwarded webhook [${d}] -> ${y.node}/${i}: ${k?.slice(0,100)||"ok"}`),k=>this.log(`Mesh forward failed [${d}] -> ${y.node}/${i}: ${k.message}`));return}try{let k=await this.registry.execute({message:u,agentId:i,context:{channel:`webhook:${d}`,sender:`webhook:${d}`}});this.sendJson(t,k.error?500:200,{ok:!k.error,agent:i,source:d,response:k.content?.slice(0,500),error:k.error,duration:k.duration})}catch(k){this.sendJson(t,500,{error:k.message})}}extractEventType(e,t,n){let s=i=>{let o=n[i.toLowerCase()];return Array.isArray(o)?o[0]:o};if(e==="github"){let i=s("x-github-event");if(!i)return;let o=typeof t.action=="string"?t.action:void 0;return o?`${i}.${o}`:i}if(e==="gitlab")return s("x-gitlab-event")||(typeof t.object_kind=="string"?t.object_kind:void 0);if(e==="stripe")return typeof t.type=="string"?t.type:void 0;if(e==="sentry")return s("sentry-hook-resource");if(e==="hubspot"){if(Array.isArray(t)&&t.length>0){let i=t[0];if(i&&typeof i.subscriptionType=="string")return i.subscriptionType}return typeof t.subscriptionType=="string"?t.subscriptionType:void 0}if(e==="odoo")return typeof t.event=="string"?t.event:typeof t.subscriptionType=="string"?t.subscriptionType:typeof t.model=="string"?typeof t.action=="string"?`${t.model}.${t.action}`:t.model:void 0}detectSource(e){return e["x-gitlab-event"]||e["x-gitlab-token"]?"gitlab":e["x-github-event"]?"github":e["stripe-signature"]?"stripe":e["sentry-hook-resource"]?"sentry":e["x-vercel-signature"]?"vercel":e["x-hubspot-signature-v3"]||e["x-hubspot-signature-version"]?"hubspot":e["x-odoo-database"]||e["x-odoo-signature"]?"odoo":e["x-hub-signature-256"]?"github":"unknown"}buildSummary(e,t,n){let s=[`[Webhook from ${e}]`];switch(e){case"gitlab":{let o=n["x-gitlab-event"]||t.object_kind||"event",a=t.project?.path_with_namespace||"",c=t.user?.name||t.user_username||"";if(s.push(`Event: ${o}`),a&&s.push(`Project: ${a}`),c&&s.push(`User: ${c}`),t.ref&&s.push(`Ref: ${t.ref}`),t.commits&&Array.isArray(t.commits)){s.push(`Commits: ${t.commits.length}`);for(let l of t.commits.slice(0,3))s.push(` - ${l.message?.split(`
527
+ `)}function zg(r,e,t,n,s,i){let o=i?.usage?.inputTokens??0,a=i?.usage?.outputTokens??Math.ceil(s.length/4);Do(r,200,{id:e,object:"chat.completion",created:t,model:n,choices:[{index:0,message:{role:"assistant",content:s},finish_reason:"stop"}],usage:{prompt_tokens:o,completion_tokens:a,total_tokens:o+a}})}function Do(r,e,t){r.writeHead(e,{"Content-Type":"application/json"}),r.end(JSON.stringify(t))}var ln=class{module;minLevel;constructor(e,t="info"){this.module=e,this.minLevel=t}child(e){return new ln(`${this.module}:${e}`,this.minLevel)}debug(e,t){this.emit("debug",e,t)}info(e,t){this.emit("info",e,t)}warn(e,t){this.emit("warn",e,t)}error(e,t){this.emit("error",e,t)}asConsoleLog(){return(...e)=>{let n=e.map(s=>typeof s=="string"?s:JSON.stringify(s)).join(" ").replace(/^\[agentx\]\s*/,"");n&&this.info(n)}}emit(e,t,n){if(ln.levelOrder[e]<ln.levelOrder[this.minLevel])return;let s={time:new Date().toISOString(),level:e,module:this.module,msg:t,...n},i=e==="error"?"ERROR":e==="warn"?"WARN":"",o=`[${this.module}]`,a=i?`${o} ${i}: ${t}`:`${o} ${t}`;console.error(a)}},dn=ln;yt(dn,"levelOrder",{debug:0,info:1,warn:2,error:3});import{realpathSync as MS,statSync as OS}from"fs";var ut={version:"0.141.1",commit:"db03b43",startedAt:new Date(Date.now()-process.uptime()*1e3).toISOString()};function DS(r,e){let t=e.mtimeMs!==null&&e.mtimeMs>Date.parse(r.startedAt),n=!!e.version&&!!r.version&&e.version!==r.version;return{newer:t||n,changedAt:e.mtimeMs===null?null:new Date(e.mtimeMs).toISOString(),version:e.version}}function Qg(){let r=null;try{r=OS(MS(process.argv[1])).mtimeMs}catch{}let e=bg().version;return DS(ut,{mtimeMs:r,version:e&&e!=="0.0.0"?e:null})}import{randomUUID as NS}from"crypto";var Ms=class{constructor(e=new Md){this.core=e}count=0;subscribe(e,t){this.count++;let n=this.core.subscribe((i,o)=>{if(!o||!LS.includes(o.kind))return;let a={...o,rootId:i.rootId,node:i.node};FS(e,a)&&t(a)}),s=!0;return()=>{s&&(s=!1,this.count--,n())}}publish(e){let t={id:typeof e.id=="string"?e.id:NS(),at:typeof e.at=="string"?e.at:new Date().toISOString(),...e},{type:n,summary:s,ref:i,agentId:o}=jS(t);this.core.publish({id:t.id,at:t.at,kind:t.kind,type:n,summary:s,ref:i,agentId:o,rootId:typeof e.rootId=="string"?e.rootId:void 0,data:t})}get size(){return this.count}},LS=["run","task","signal","mesh","channel","status"];function jS(r){switch(r.kind){case"run":return{type:r.phase,ref:r.runId,summary:[r.workflowId,r.nodeId,r.phase,r.note].filter(Boolean).join(" ")};case"task":return{type:r.phase,ref:r.taskId,summary:`${r.title??r.taskId} ${r.phase}`};case"signal":return{type:"emitted",summary:`signal ${r.name} (${r.scope})`};case"mesh":return{type:r.delta,summary:`peer ${r.peer} ${r.delta}`};case"channel":return{type:r.direction,ref:r.messageId,agentId:r.agentId,summary:`${r.channel} ${r.direction==="in"?"inbound":"outbound"}`};case"status":return{type:"status",summary:r.message}}}function FS(r,e){return!(r.kinds&&r.kinds.length>0&&!r.kinds.includes(e.kind)||r.workflowId&&(e.kind==="run"&&e.workflowId!==r.workflowId||e.kind==="task"&&e.workflowId!==r.workflowId||e.kind==="signal"&&e.workflowId&&e.workflowId!==r.workflowId)||r.runId&&(e.kind==="run"&&e.runId!==r.runId||e.kind==="task"&&e.runId!==r.runId)||r.actor&&(e.kind!=="task"||!(e.assignedTo?.includes(r.actor)||e.submittedBy===r.actor))||r.channel&&(e.kind!=="channel"||e.channel!==r.channel))}function Zg(r){if(!r)return;let e=["run","task","signal","mesh","channel","status"],n=r.split(",").map(s=>s.trim()).filter(Boolean).filter(s=>e.includes(s));return n.length?n:void 0}import{createHmac as Os,timingSafeEqual as ep}from"crypto";var Ds=class{registry;config;mesh;webhookEntries;log;workflowDispatcher;hooks;constructor(e,t={},n=console.error.bind(console,"[webhook]"),s,i=[],o){this.registry=e,this.config=t,this.log=n,this.mesh=s,this.webhookEntries=i,this.hooks=o}hookEventFor(e,t){if(e==="stripe")return"on:stripe-event";if(e==="sentry")return"on:sentry-issue";if(e==="vercel")return"on:vercel-deployment";if(e==="hubspot")return"on:hubspot-event";if(e==="odoo")return"on:odoo-event";if(e==="github"){let n=(t??"").split(".")[0];return n==="issues"||n==="issue_comment"?"on:github-issue":n==="pull_request"||n==="pull_request_review"?"on:github-pr":n==="push"?"on:github-push":null}return null}async fireHookSafe(e,t,n,s){let i=this.hookEventFor(e,t);if(!i||!this.hooks||!this.hooks.has(i))return;let o={};if(e==="github"){let a=s;typeof a.sender?.login=="string"&&(o.author=a.sender.login),typeof a.repository?.full_name=="string"&&(o.repo=a.repository.full_name);let c=a.issue?.number??a.pull_request?.number;typeof c=="number"&&(o.number=c)}try{await this.hooks.execute(i,{event:i,source:e,eventType:t,agentId:n,payload:s,...o})}catch(a){this.log(`${i} hook error (non-fatal): ${a?.message??a}`)}}setWorkflowDispatcher(e){this.workflowDispatcher=e}setWebhookEntries(e){this.webhookEntries=e}async handle(e,t,n){let s=n.replace(/^\/webhook\/?/,"").split("/").filter(Boolean),i=s[0],o=s[1];if(!i){this.sendJson(t,400,{error:"Missing agent ID. Use /webhook/:agentId"});return}let{raw:a,parsed:c}=await this.readBody(e),d=o||this.detectSource(e.headers);if(process.env.AGENTX_WEBHOOK_DEBUG_HEADERS==="1"){let k={};for(let[w,S]of Object.entries(e.headers))(w.startsWith("x-hubspot")||w.startsWith("x-hub")||w.startsWith("x-github")||w.startsWith("x-gitlab")||w.startsWith("stripe")||w.startsWith("sentry")||w.startsWith("x-vercel")||w.startsWith("x-odoo")||w.startsWith("x-webhook")||w==="user-agent"||w==="content-type"||w==="host"||w==="x-forwarded-host"||w==="x-forwarded-proto"||w==="x-forwarded-for")&&(k[w]=S);this.log(`Webhook [${d}] reqUrl=${e.url} headers: ${JSON.stringify(k)}`)}let l=this.validateSignature(e.headers,a,d,i,e.url);if(l){this.log(`Webhook [${d}] -> ${i}: REJECTED (${l})`),this.sendJson(t,401,{error:l});return}let u=this.buildSummary(d,c,e.headers);this.log(`Webhook [${d}] -> ${i}: ${u.slice(0,100)}`);let g=this.extractEventType(d,c,e.headers),m=this.webhookEntries.find(k=>k.enabled&&k.agentId===i&&k.source===d),f=g&&m?.triggers?.[g]||m?.defaultWorkflow||null;if(await this.fireHookSafe(d,g,i,c),f&&this.workflowDispatcher)try{let k=await this.workflowDispatcher.dispatchWorkflow({workflowId:f,entityRef:{kind:"webhook",id:`${d}:${i}:${g??"\u2014"}:${Date.now()}`},event:{kind:"webhook",source:d,eventType:g,payload:c},trigger:{source:d}});this.log(`Webhook [${d}/${g??"\u2014"}] -> workflow=${f} (claimed=${k.claimed})`),this.sendJson(t,202,{ok:!0,agent:i,source:d,eventType:g,workflow:f,claimed:k.claimed});return}catch(k){this.log(`Workflow dispatch failed [${d}/${g}/${f}]: ${k.message}`)}let y=this.webhookEntries.find(k=>k.enabled&&k.node&&k.agentId===i&&k.source===d);if(y?.node&&this.mesh){this.sendJson(t,202,{ok:!0,agent:i,source:d,node:y.node,status:"accepted"}),this.mesh.sendTask(y.node,u,i,{context:{channel:`webhook:${d}`,sender:`webhook:${d}`}}).then(k=>this.log(`Mesh-forwarded webhook [${d}] -> ${y.node}/${i}: ${k?.slice(0,100)||"ok"}`),k=>this.log(`Mesh forward failed [${d}] -> ${y.node}/${i}: ${k.message}`));return}try{let k=await this.registry.execute({message:u,agentId:i,context:{channel:`webhook:${d}`,sender:`webhook:${d}`}});this.sendJson(t,k.error?500:200,{ok:!k.error,agent:i,source:d,response:k.content?.slice(0,500),error:k.error,duration:k.duration})}catch(k){this.sendJson(t,500,{error:k.message})}}extractEventType(e,t,n){let s=i=>{let o=n[i.toLowerCase()];return Array.isArray(o)?o[0]:o};if(e==="github"){let i=s("x-github-event");if(!i)return;let o=typeof t.action=="string"?t.action:void 0;return o?`${i}.${o}`:i}if(e==="gitlab")return s("x-gitlab-event")||(typeof t.object_kind=="string"?t.object_kind:void 0);if(e==="stripe")return typeof t.type=="string"?t.type:void 0;if(e==="sentry")return s("sentry-hook-resource");if(e==="hubspot"){if(Array.isArray(t)&&t.length>0){let i=t[0];if(i&&typeof i.subscriptionType=="string")return i.subscriptionType}return typeof t.subscriptionType=="string"?t.subscriptionType:void 0}if(e==="odoo")return typeof t.event=="string"?t.event:typeof t.subscriptionType=="string"?t.subscriptionType:typeof t.model=="string"?typeof t.action=="string"?`${t.model}.${t.action}`:t.model:void 0}detectSource(e){return e["x-gitlab-event"]||e["x-gitlab-token"]?"gitlab":e["x-github-event"]?"github":e["stripe-signature"]?"stripe":e["sentry-hook-resource"]?"sentry":e["x-vercel-signature"]?"vercel":e["x-hubspot-signature-v3"]||e["x-hubspot-signature-version"]?"hubspot":e["x-odoo-database"]||e["x-odoo-signature"]?"odoo":e["x-hub-signature-256"]?"github":"unknown"}buildSummary(e,t,n){let s=[`[Webhook from ${e}]`];switch(e){case"gitlab":{let o=n["x-gitlab-event"]||t.object_kind||"event",a=t.project?.path_with_namespace||"",c=t.user?.name||t.user_username||"";if(s.push(`Event: ${o}`),a&&s.push(`Project: ${a}`),c&&s.push(`User: ${c}`),t.ref&&s.push(`Ref: ${t.ref}`),t.commits&&Array.isArray(t.commits)){s.push(`Commits: ${t.commits.length}`);for(let l of t.commits.slice(0,3))s.push(` - ${l.message?.split(`
528
528
  `)[0]||"no message"} (${l.author?.name||""})`)}let d=t.object_attributes;if(d?.title&&(s.push(`Title: ${d.title}`),s.push(`State: ${d.state||""}`),s.push(`Action: ${d.action||""}`),d.source_branch&&s.push(`Branch: ${d.source_branch} -> ${d.target_branch}`),d.url&&s.push(`URL: ${d.url}`)),d?.iid&&!d?.source_branch&&(s.push(`Issue #${d.iid}: ${d.title||""}`),d.description&&s.push(`Description: ${d.description.slice(0,200)}`)),t.object_kind==="pipeline"){let l=t.object_attributes;s.push(`Pipeline: ${l?.status||""} (${l?.ref||""})`),s.push(`Duration: ${l?.duration||0}s`)}break}case"github":{let o=n["x-github-event"]||"event",a=t.repository?.full_name||"",c=t.sender?.login||"";if(s.push(`Event: ${o}`),a&&s.push(`Repository: ${a}`),c&&s.push(`Sender: ${c}`),t.ref&&s.push(`Ref: ${t.ref}`),t.commits&&Array.isArray(t.commits))for(let u of t.commits.slice(0,3))s.push(` - ${u.message?.split(`
529
529
  `)[0]||""} (${u.author?.name||""})`);let d=t.pull_request;d&&(s.push(`PR #${d.number}: ${d.title}`),s.push(`Action: ${t.action}`),s.push(`Branch: ${d.head?.ref} -> ${d.base?.ref}`));let l=t.issue;l&&(s.push(`Issue #${l.number}: ${l.title}`),s.push(`Action: ${t.action}`));break}case"stripe":{let o=t.type||"event",a=t.data?.object||{};s.push(`Event: ${o}`),a.amount&&s.push(`Amount: ${(a.amount/100).toFixed(2)} ${a.currency?.toUpperCase()||""}`),a.customer_email&&s.push(`Customer: ${a.customer_email}`),a.description&&s.push(`Description: ${a.description}`),a.status&&s.push(`Status: ${a.status}`);break}case"sentry":{let o=n["sentry-hook-resource"]||"event";s.push(`Resource: ${o}`);let a=t.data||t;a.error?.title&&s.push(`Error: ${a.error.title}`),a.error?.culprit&&s.push(`Culprit: ${a.error.culprit}`),a.error?.metadata?.value&&s.push(`Message: ${a.error.metadata.value}`),t.url&&s.push(`URL: ${t.url}`);break}case"hubspot":{let o=Array.isArray(t)?t:null,a=o||null;if(a&&a.length){s.push(`Events: ${a.length}`);for(let d of a.slice(0,3)){let l=d.subscriptionType??"?",u=d.objectId??"?",g=d.changeFlag??d.changeSource??"";s.push(` - ${l} (object ${u}${g?`, ${g}`:""})`)}}else{let d=t.subscriptionType??"event",l=t.objectId??"?";s.push(`Event: ${d} (object ${l})`)}let c=a?.[0]?.portalId??t.portalId;c!=null&&s.push(`Portal: ${c}`);break}case"odoo":{let o=typeof t.event=="string"&&t.event||typeof t.subscriptionType=="string"&&t.subscriptionType||typeof t.model=="string"&&(typeof t.action=="string"?`${t.model}.${t.action}`:t.model)||"event";s.push(`Event: ${o}`);let a=n["x-odoo-database"]||(typeof t.database=="string"?t.database:"");a&&s.push(`Database: ${a}`);let c=t.record||t;c?.id&&s.push(`Record id: ${c.id}`),c?.name&&s.push(`Name: ${String(c.name).slice(0,200)}`),c?.partner_id?.[1]&&s.push(`Partner: ${c.partner_id[1]}`),c?.email&&s.push(`Email: ${c.email}`),c?.amount_total!=null&&s.push(`Amount: ${c.amount_total}`),c?.state&&s.push(`State: ${c.state}`);break}default:s.push(`Headers: ${JSON.stringify(Object.keys(n).filter(o=>o.startsWith("x-")).slice(0,5))}`),s.push(`Payload keys: ${Object.keys(t).slice(0,10).join(", ")}`);let i=JSON.stringify(t).slice(0,500);s.push(`Body: ${i}`)}return s.join(`
530
530
  `)}async readBody(e){return new Promise(t=>{let n="";e.on("data",s=>n+=s.toString()),e.on("end",()=>{let s;try{s=n?JSON.parse(n):{}}catch{s={raw:n}}t({raw:n,parsed:s})}),e.on("error",()=>t({raw:"",parsed:{}}))})}validateSignature(e,t,n,s,i){let o=this.webhookEntries.find(l=>l.enabled&&l.agentId===s&&l.source===n);if(!o?.secretEnv)return null;let a=process.env[o.secretEnv];if(!a)return`webhook entry "${o.id}" expects env ${o.secretEnv} but it is unset`;let c=l=>{let u=e[l.toLowerCase()];return Array.isArray(u)?u[0]:u};if(n==="github"){let l=c("x-hub-signature-256");if(!l)return"missing X-Hub-Signature-256";let u="sha256="+Os("sha256",a).update(t).digest("hex");return _t(u,l)}if(n==="gitlab"){let l=c("x-gitlab-token");return l?_t(a,l):"missing X-Gitlab-Token"}if(n==="stripe"){let l=c("stripe-signature");if(!l)return"missing Stripe-Signature";let u=Object.fromEntries(l.split(",").map(m=>m.split("=")));if(!u.t||!u.v1)return"malformed Stripe-Signature";let g=Os("sha256",a).update(`${u.t}.${t}`).digest("hex");return _t(g,u.v1)}if(n==="hubspot"){let l=c("x-hubspot-signature-v3"),u=c("x-hubspot-request-timestamp");if(!l)return"missing X-HubSpot-Signature-v3";if(!u)return"missing X-HubSpot-Request-Timestamp";let g=parseInt(u,10);if(!Number.isFinite(g))return"malformed X-HubSpot-Request-Timestamp";let m=Date.now()-g;if(m>5*6e4)return`HubSpot webhook is ${Math.floor(m/1e3)}s old (>5min replay window)`;let f="POST",y=i||e["x-original-uri"]||e["x-forwarded-path"]||"",k=e["x-forwarded-host"],w=e.host,S=e["x-forwarded-proto"]||"https",$=new Set;k&&y&&$.add(`${S}://${k}${y}`),w&&y&&$.add(`https://${w}${y}`),w&&y&&$.add(`http://${w}${y}`),y&&$.add(y),$.add("");for(let R of $){let L=Os("sha256",a).update(`${f}${R}${t}${u}`).digest("base64");if(l.length===L.length&&ep(Buffer.from(l),Buffer.from(L)))return null}return`signature mismatch (tried ${$.size} URI variants)`}if(n==="odoo"){let l=c("x-odoo-signature");if(l){let g=Os("sha256",a).update(t).digest("hex"),m=l.startsWith("sha256=")?l.slice(7):l;return _t(g,m)}let u=c("x-odoo-webhook-token")??c("x-webhook-secret");return u?_t(a,u):"missing X-Odoo-Signature or X-Odoo-Webhook-Token"}let d=c("x-webhook-secret");return d?_t(a,d):"missing X-Webhook-Secret"}sendJson(e,t,n){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(n,null,2))}};function _t(r,e){if(r.length!==e.length)return"signature mismatch";let t=Buffer.from(r),n=Buffer.from(e);return ep(t,n)?null:"signature mismatch"}Xc();Rc();Wc();function US(r){return{insertTaskHistory:r.prepare(`
@@ -1217,4 +1217,4 @@ data: ${JSON.stringify(G)}
1217
1217
  `)}catch{}},D=setInterval(()=>{try{t.write(`: ping
1218
1218
 
1219
1219
  `)}catch{}},15e3);D.unref?.();let F=new AbortController;t.on("close",()=>{t.writableEnded||F.abort()});try{for await(let j of this.mesh.sendTaskStream(h.peer,h.message,h.agent,{context:h.context,signal:F.signal,vouchOwner:v}))x(j.event,j.data)}catch(j){x("error",{error:j?.message??String(j)})}finally{clearInterval(D);try{t.end()}catch{}}break}let P=h.context,_=typeof h.senderAgentId=="string"?h.senderAgentId:void 0;if(kb(h,!0)==="callback"){let x=this.delegationGate(e,h,{callee:h.agent,peer:h.peer,message:h.message,calleeContext:P});if(!("track"in x)){let D=Kr(x);this.json(t,D.status,D.body);break}}if(h.async===!0){let x=P?.channel,D=P?.chatId;if(!x||!D){this.json(t,400,{error:"async requires context.channel and context.chatId \u2014 there is no route back otherwise"});return}let F=`mesh-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;this.json(t,202,{accepted:!0,taskId:F,deliverTo:`${x}:${D}`,note:"result will be delivered to the originating chat when the peer finishes"});let j=h.peer,G=h.agent,Z=this.mesh;(async()=>{let W=Date.now(),V;try{V=await Z.sendTask(j,h.message,G,{vouchOwner:v,context:P,senderAgentId:_}),this.log(`[mesh/task async ${F}] ${j}/${G??"default"} finished in ${Date.now()-W}ms`)}catch(H){V=`Delegation to ${j}/${G??"default"} failed: ${H?.message??H}`,this.log(`[mesh/task async ${F}] failed: ${H?.message??H}`)}try{await this.router.sendOutbound({channel:x,chatId:D,text:V,agentId:P?.agentId??_,accountId:P?.accountId})}catch(H){this.log(`[mesh/task async ${F}] delivery failed: ${H?.message??H}`)}})();break}let O=await this.mesh.sendTask(h.peer,h.message,h.agent,{context:P,senderAgentId:_,vouchOwner:v});this.json(t,200,{response:O});break}case"POST /webrtc/signal/out":{if(!this.webrtc){this.json(t,404,{error:"WebRTC signaling not enabled"});return}let p=await B(e);if(!p.kind||!p.callId||!p.from||!p.to){this.json(t,400,{error:"Missing: kind, callId, from, to"});return}let b=await this.webrtc.handleOutgoing(p);this.json(t,b.ok?200:400,b);break}case"POST /webrtc/signal":{if(!this.webrtc){this.json(t,404,{error:"WebRTC signaling not enabled"});return}let p=await B(e);if(!p.kind||!p.callId||!p.from||!p.to){this.json(t,400,{error:"Missing: kind, callId, from, to"});return}let b=this.webrtc.handleIncoming(p);this.json(t,b.ok?200:400,b);break}case"POST /webrtc/bot/invite":{if(!this.botManager){this.json(t,404,{error:"WebRTC bot not enabled (channels.webrtc.bot.enabled=false)"});return}let h=await B(e),p=h.callId,b=h.target,v=h.agentId||this.config.channels.webrtc?.bot.defaultAgentId;if(!p||!b||!v){this.json(t,400,{error:"Missing: callId, target, agentId (or defaultAgentId in config)"});return}let I=await this.botManager.invite({callId:p,target:b,agentId:v});this.json(t,I.ok?200:500,I);break}case"GET /webrtc/bots":{if(!this.botManager){this.json(t,404,{error:"WebRTC bot not enabled"});return}this.json(t,200,{active:this.botManager.active()});break}case"GET /webrtc/history":{if(!this.botManager){this.json(t,404,{error:"WebRTC bot not enabled"});return}this.json(t,200,{active:this.botManager.active(),history:this.botManager.history()});break}case"GET /webrtc/config":{let h=this.config.channels.webrtc;if(!h?.enabled){this.json(t,404,{error:"WebRTC signaling not enabled"});return}this.json(t,200,{localName:this.config.node.name,iceServers:[...h.stunServers.map(p=>({urls:p})),...h.turnServers],peers:this.mesh?.directory().map(p=>({name:p.peer,healthy:p.healthy}))||[],camera:h.camera,agents:this.registry.list().map(p=>({id:p.id,name:p.name}))});break}case"GET /.well-known/agent-card.json":this.json(t,200,{name:this.config.node.name,description:`AgentX daemon node "${this.config.node.name}"`,url:`http://${this.config.node.bind}`,version:"1.0.0",capabilities:{streaming:!1,pushNotifications:!1,stateTransitionHistory:!1},skills:this.registry.list().map(h=>{let p=this.config.agents[h.id]||{},b=typeof p.description=="string"&&p.description.trim()||RR(p.systemPrompt)||`Agent "${h.name}" (${h.tier})`,v=Array.isArray(p.mentions)?p.mentions.slice(0,4):[];return{id:h.id,name:h.name,description:b,tags:[h.tier,...v],color:me(h.id,p).color}}),channels:this.router.getChannelNames(),githubLogins:this.github?.postingAccounts()??[],defaultInputModes:["text"],defaultOutputModes:["text"]});break;case"GET /wiki/agents":{let h=this.registry.getWikiHub();this.json(t,200,{nodeId:this.config.node.id,agents:h.summary()});break}case"GET /wiki/entries":{let h=this.registry.getWikiHub(),p=n.searchParams.get("agent")||void 0,b=n.searchParams.get("after")||void 0,v=p?h.getAgentEntries(p):h.getSharedStore().listEntries({after:b});this.json(t,200,{nodeId:this.config.node.id,count:v.length,entries:v.map(I=>({id:I.id,date:I.date,agentId:I.agentId,source:I.source,sourceContext:I.sourceContext,content:I.content}))});break}case"GET /wiki/articles":{let h=this.registry.getWikiHub(),p=n.searchParams.get("agent");if(!p){this.json(t,400,{error:"?agent= required"});break}let v=h.getAgentWiki(p).rebuildIndex();this.json(t,200,{nodeId:this.config.node.id,agentId:p,articles:v.articles});break}case"GET /wiki/article":{let h=this.registry.getWikiHub(),p=n.searchParams.get("agent"),b=n.searchParams.get("path");if(!p||!b){this.json(t,400,{error:"?agent= and ?path= required"});break}let I=h.getAgentWiki(p).readArticle(b);if(!I){this.json(t,404,{error:"Article not found"});break}this.json(t,200,{nodeId:this.config.node.id,agentId:p,path:I.path,title:I.meta.title,tags:I.meta.tags,owner:I.meta.owner,created:I.meta.created,lastUpdated:I.meta.lastUpdated,sources:I.meta.sources,content:I.content});break}case"GET /wiki/notes":{let{NoteStore:h}=await import("./notes-WJJEJ4CJ.js"),p=n.searchParams.get("status")||"waiting";if(!["waiting","open","patched","rejected","deferred","expired","all"].includes(p)){this.json(t,400,{error:"status must be waiting, open, patched, rejected, deferred, expired or all"});break}let b=Math.max(1,Math.min(200,parseInt(n.searchParams.get("limit")||"50",10)||50)),I=new h(this.registry.getWikiHub().getBaseDir()).list(p==="all"?void 0:p);this.json(t,200,{nodeId:this.config.node.id,enabled:this.config.wikiNotes.enabled,inbox:this.config.wikiNotes.inbox??null,crons:this.config.wikiNotes.crons,absorbAgent:this.config.wikiNotes.absorbAgent??null,total:I.length,notes:I.slice(-b).reverse()});break}case"POST /wiki/notes":{let{NoteStore:h,validateNote:p}=await import("./notes-WJJEJ4CJ.js"),b=this.config.wikiNotes;if(!b.enabled||!b.inbox){this.json(t,409,{error:"wiki notes are off on this node: set wikiNotes.enabled and wikiNotes.inbox"});break}let v=await B(e),I=p({...v,to:b.inbox});if("error"in I){this.json(t,400,{error:I.error});break}let T=I.note;if(this.registry.getAgent(b.inbox)){try{let{note:O,added:x}=new h(this.registry.getWikiHub().getBaseDir()).add(T);this.json(t,x?201:200,{ok:!0,added:x,note:O,node:this.config.node.id})}catch(O){this.json(t,507,{error:O?.message??String(O)})}break}if(v.forwarded===!0){this.json(t,404,{error:`inbox agent "${b.inbox}" is not on this node`});break}let P=this.mesh?.findAgentPeer(b.inbox);if(!P){this.json(t,404,{error:`inbox agent "${b.inbox}" is not on this node or any known peer`});break}let _=this.mesh.directory().find(O=>O.peer===P.peer)?.peerUrl;if(!P.healthy||!_){this.json(t,503,{error:`the node hosting "${b.inbox}" (${P.peer}) is unreachable; try again later`});break}try{let O=await fetch(`${_.replace(/\/$/,"")}/wiki/notes`,{method:"POST",headers:{"Content-Type":"application/json",...this.mesh.authHeaders(P.peer)},body:JSON.stringify({...T,fromNode:T.fromNode||this.config.node.id,forwarded:!0}),signal:AbortSignal.timeout(1e4)}),x=await O.json().catch(()=>({}));this.json(t,O.status,{...x,peer:P.peer})}catch(O){this.json(t,502,{error:`forward to ${P.peer} failed: ${O?.message??O}`,peer:P.peer})}break}case"GET /graph/schema":{let h=this.registry.getGraphStore();if(!h){this.json(t,404,{error:"graph disabled on this node"});break}this.json(t,200,{nodeId:this.config.node.id,schema:h.loadSchema()});break}case"GET /graph/nodes":{let h=this.registry.getGraphStore();if(!h){this.json(t,404,{error:"graph disabled on this node"});break}this.json(t,200,{nodeId:this.config.node.id,...h.loadNodes()});break}case"GET /graph/classifications":{let h=this.registry.getGraphStore();if(!h){this.json(t,404,{error:"graph disabled on this node"});break}let p=n.searchParams.get("status")||"approved",b=Math.max(1,Math.min(1e3,parseInt(n.searchParams.get("limit")||"200",10)||200)),v=h.listByStatus(p,b);this.json(t,200,{nodeId:this.config.node.id,status:p,count:v.length,classifications:v});break}default:this.json(t,404,{error:"Not found",endpoints:["GET /health","GET /agents","GET /crons","GET /routines \u2014 schedules + cron/hook workflows with staleness flags","GET /mesh","GET /wiki/agents","GET /wiki/entries[?agent=X&after=YYYY-MM-DD]","GET /wiki/articles?agent=X","GET /wiki/notes[?status=waiting|open|patched|rejected|deferred|expired|all&limit=N]","POST /wiki/notes { from, change, source, date? } \u2014 a note for the wiki observe/sweep run","GET /graph/schema","GET /graph/nodes","GET /graph/classifications[?status=approved|pending|rejected&limit=N]","POST /task { agent, message, context?, freshSession?: bool }","GET /agents/:id \u2014 resolved agent config (permission, tier, model, persistentProcess, toolUseRequired)","POST /agents/:id/selftest { message? } \u2014 canary probe; runs a fresh-session task and reports {ok, durationMs, tokens, billedModel}","GET /traces[?agentId=&channel=&chatId=&workflowRunId=&status=&since=&until=&limit=]","GET /traces/:taskId \u2014 full per-task execution trace (steps + tokens)","GET /voice/history[?agent=&limit=&before=] \u2014 past voice exchanges, bounded summaries","GET /voice/history/:id \u2014 one voice exchange in full; POST /voice/history/:id/replay","GET /api/processes \u2014 live persistent claude processes (JSON)","POST /api/processes/kill { agentId, channel, chatId, reason? }","GET /api/actions/builtin \u2014 list shipped built-in typed actions","POST /api/actions/builtin/:name \u2014 run a built-in with JSON body input","POST /mesh/task { peer, message }","POST /webhook/:agentId[/:source] \u2014 webhook callback","POST /reload \u2014 re-read agentx.json (hot-swaps crons)","GET /usage/plan \u2014 Claude plan windows, cold-dispatch counters, active holds","POST /usage/plan/lift \u2014 drop the active Claude plan holds","GET /daemon/restart \u2014 in-flight count, service manager, pending restart","POST /daemon/restart \u2014 restart when idle { timeoutMinutes?, onTimeout? }","POST /daemon/restart/cancel","GET /.well-known/agent-card.json","GET /call \u2014 browser UI for P2P A/V calls (requires channels.webrtc.enabled)","GET /webrtc/config \u2014 ICE servers + peer directory for the call page","GET /webrtc/events?callId=&as= \u2014 SSE stream of signaling events","POST /webrtc/signal/out \u2014 browser-originated signal, forwarded to remote peer","POST /webrtc/signal \u2014 remote-peer-originated signal, fanned out to local browser","POST /webrtc/bot/invite { callId, target, agentId } \u2014 spawn a transcribing bot peer for a call","GET /webrtc/bots \u2014 active bot sessions","POST /webrtc/camera/watch { callId, agentId } \u2014 an agent watches the phone camera share","GET /webrtc/camera/watch \u2014 agents watching a camera now","POST /webrtc/camera/watch/:id/look { note? } \u2014 ask the watching agent what it sees","POST /webrtc/camera/watch/:id/stream { seconds, note? } \u2014 the agent keeps watching for a while (0 stops)","POST /webrtc/camera/look { agentId } \u2014 from an agent's run: the newest frame as a PNG path"]})}}catch(i){this.json(t,500,{error:i.message})}}async handleOpenAICompat(e,t,n){let s=await B(e);await Yg(e,t,n,s,{execute:(i,o,a,c)=>this.registry.execute(i,o,a,c),agentIds:Object.keys(this.config.agents),cancel:(i,o,a,c)=>{let d=this.registry.list().find(l=>l.id===i)?.runningTasks.filter(l=>l.channel===o&&l.chatId===a)||[];for(let l of d)this.registry.cancelRunningTask(l.id,c)},log:i=>this.log(i)})}json(e,t,n){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(n,null,2))}resolveGitlabTokenForAgent(e){if(!e)return{token:this.config.channels.gitlab?.token,source:"global"};let t=(this.config.channels.gitlab?.agentMappings||[]).find(s=>s.agentId===e);if(t?.token)return{token:t.token,source:"agentMappings"};let n=oy(this.config,e,"gitlab-user","tokenEnv");return n.status==="ok"&&n.value?{token:n.value,source:`integrations(${n.envVar})`}:this.config.channels.gitlab?.token?{token:this.config.channels.gitlab.token,source:"global"}:{token:void 0,source:n.status}}resolveTodayUsage(){let e=Ip();if(e==="json")return this.registry.getTodayUsage();let t=$p(this.db);return e==="sqlite"||Object.keys(t.agents).length>0?t:this.registry.getTodayUsage()}installAgentMemorySurface(){let e=parseInt(this.config.node.bind.split(":")[1]||"18800",10);for(let t of this.registry.list()){let n=t.workspace;if(!(!n||!qt(n)))try{let s=ne(n,".claude","skills");Yb(s,{recursive:!0});let i=ne(s,ay);if(!qt(i))bc(i,wa(e)),this.log(` memory-skill: installed remember.md \u2192 ${t.id}`);else{let o=dy(On(i,"utf-8"),e);o&&(bc(i,o),this.log(` memory-skill: updated remember.md \u2192 ${t.id}`))}this.agentMemory.syncToWorkspace(t.id,n,this.config.session.memoryIndexMaxChars)}catch(s){this.log(` memory-skill: ${t.id} install failed \u2014 ${s?.message??s}`)}}}installAgentMcpConfig(){for(let[e,t]of Object.entries(this.config.agents)){let n=t.workspace;if(!n||!qt(n))continue;let s=this.config.workflows.enabled&&(this.config.workflows.followUp.enabled&&(this.config.workflows.followUp.agents[e]??!0)||El(this.config.workflows,e)),i=Kd(fd(t),this.config.requests.enabled||s?Xd():null);try{switch(zd(n,i)){case"installed":this.log(` mcp: installed ${Object.keys(i).length} server(s) \u2192 ${e}`);break;case"updated":this.log(` mcp: updated .mcp.json (${Object.keys(i).length} server(s)) \u2192 ${e}`);break;case"removed":this.log(` mcp: removed managed .mcp.json (config now empty) \u2192 ${e}`);break;case"skipped-operator-owned":Object.keys(i).length>0&&this.log(` mcp: ${e} has operator-owned .mcp.json \u2014 skipping (delete file or marker to let agentx manage)`);break;case"noop":break}}catch(o){this.log(` mcp: ${e} install failed \u2014 ${o?.message??o}`)}}}workspaceFor(e){for(let t of this.registry.list())if(t.id===e)return t.workspace;return null}handleMemoryApi(e,t,n,s){return Fm(e,t,n,s,{mem:this.agentMemory,workspaceFor:i=>this.workspaceFor(i),runningTaskOwner:i=>this.registry.runningTaskOwner(i),indexMaxChars:()=>this.config.session.memoryIndexMaxChars})}async handleWorkflowEvent(e,t){if(!this.workflowDispatcher){this.json(t,503,{error:"workflow engine not enabled on this node"});return}let n;try{n=await te(e)}catch(c){this.json(t,400,{error:"invalid JSON body",message:c.message});return}let s=n?.payload??n,i=s?.event,o=s?.entityRef;if(!i?.id||!o?.backend||!o?.id){this.json(t,400,{error:"missing event or entityRef"});return}let a=n?.kind;try{if(a==="trigger"&&s.trigger){let g=typeof n?.fromPeer=="string"?n.fromPeer:"unknown";this.log(`[workflows/mesh] received trigger from "${g}" source="${s.trigger.source}" chat="${s.trigger.chat??"*"}"`);let m=await this.workflowDispatcher.dispatch({trigger:s.trigger,entityRef:o,event:i,fromRemote:{peer:g}});this.log(`[workflows/mesh] dispatched broadcast: matched=${m.claimed.length} ${m.claimed.length?`(${m.claimed.map(f=>f.id).join(", ")})`:"[none \u2014 no workflow with mesh.allowRemote matched]"}`),this.json(t,202,{ok:!0,mode:"trigger-broadcast",matched:m.claimed.map(f=>f.id)});return}let l=(s.workflowId?this.workflowStore?.get(s.workflowId):null)?.nodes.find(g=>g.type.startsWith("trigger."))?.config??{},u={source:String(l.source??"hook"),project:l.filter?.project,repo:l.filter?.repo,chat:l.filter?.chat,labels:l.filter?.labels};await this.workflowDispatcher.dispatch({trigger:u,entityRef:o,event:i}),this.json(t,202,{ok:!0})}catch(c){this.log(`[workflows] /workflow/event failed: ${c.message}`),this.json(t,500,{error:c.message})}}async postToPushHost(e,t,n){let s=e.toLowerCase(),i=this.mesh?.directory().find(c=>c.peer.toLowerCase()===s);if(!i)throw new Error(`push: channels.push.relayTo "${e}" is not a mesh peer of this node`);let o=await fetch(`${i.peerUrl}${t}`,{method:"POST",headers:{"Content-Type":"application/json",...this.mesh.authHeaders(i.peer)},body:JSON.stringify(n),signal:AbortSignal.timeout(15e3)});if(!o.ok)throw new Error(`push: ${i.peer} ${t} -> ${o.status} ${(await o.text().catch(()=>"")).slice(0,200)}`);let a=await o.json().catch(()=>({}));if(t==="/channel/send")return a.messageId??void 0;if(typeof a.status!="number")throw new Error(`push: ${i.peer} ${t} gave no answer`);return{status:a.status,body:a.body??{}}}async handlePushApp(e,t){let n;try{n=await te(e)}catch(c){this.json(t,400,{error:"invalid JSON body",message:c.message});return}let{handlePushBridge:s,pushOrigin:i}=await import("./push-bridge-P7HH25VN.js"),o=this.config.channels.push;if(!o?.enabled){this.json(t,200,{status:503,body:{error:`Notifications are off on ${this.config.node.name}.`}});return}if(o.relayTo){if(n?.origin!==void 0){this.json(t,200,{status:409,body:{error:`${this.config.node.name} relays its notifications too (channels.push.relayTo = ${o.relayTo})`}});return}if(n?.op!=="app"){this.json(t,400,{error:"op must be app"});return}try{this.json(t,200,await this.postToPushHost(o.relayTo,"/push/app",{op:"app",origin:i(this.config.node.name),call:n.call}))}catch(c){this.log(`[push] /push/app to ${o.relayTo} failed: ${c.message}`),this.json(t,502,{error:c.message})}return}let a=this.pushBridgeCaller(e);"error"in a&&n?.op!=="roster"&&this.log(`[push] /push/app from ${e.socket?.remoteAddress||"?"} refused: ${a.error}`),this.json(t,200,s(n,a,this.pushHost??null,this.pushHost?void 0:`Notifications are not running on ${this.config.node.name}. Check channels.push.subject and the database there.`))}pushBridgeCaller(e){return hu(String(e.headers.authorization||""),this.config.mesh.peers,process.env.MESH_TOKEN)}async handleChannelSend(e,t){let n;try{n=await te(e)}catch(d){this.json(t,400,{error:"invalid JSON body",message:d.message});return}let s=String(n?.channel??""),i=String(n?.chatId??""),o=String(n?.text??"");if(!s||!i||!o){this.json(t,400,{error:"channel, chatId, and text are required"});return}if(!this.router.getChannel(s)){this.json(t,404,{error:`channel "${s}" not hosted on this node`});return}let c;if(n.relayed===!0&&n.origin!==void 0){let d=this.pushBridgeCaller(e);if("origin"in d)c=d.origin;else if(i!=="default"){this.json(t,403,{error:d.error});return}}if(s==="push"&&i.includes(":")){let{scopedPushTarget:d}=await import("./push-bridge-P7HH25VN.js"),l=d(i,this.pushBridgeCaller(e));if("error"in l){this.json(t,403,{error:l.error});return}}try{let d=await this.router.sendOutbound({channel:s,chatId:i,text:o,accountId:typeof n.accountId=="string"?n.accountId:void 0,parseMode:typeof n.parseMode=="string"?n.parseMode:void 0,replyTo:typeof n.replyTo=="string"?n.replyTo:void 0,buttons:Array.isArray(n.buttons)?n.buttons:void 0,agentId:typeof n.agentId=="string"?n.agentId:void 0,relayed:n.relayed===!0?!0:void 0,origin:c},{recordInSession:!1});this.json(t,200,{ok:!0,messageId:d??null})}catch(d){this.log(`[mesh] /channel/send "${s}" failed: ${d.message}`),this.json(t,500,{error:d.message})}}async handleChannelChats(e,t,n={}){let s=new Set,i=[],o=[],a=(d,l)=>{let u=0;for(let g of d)!g.id||s.has(g.id)||(s.add(g.id),i.push({...g,source:l}),u++);u>0&&o.push(`${l}:${u}`)},c=this.router.getChannel(t);if(c?.listKnownChats)try{a(c.listKnownChats(),"local")}catch{}else if(c?.listChats)try{a(c.listChats().map(d=>({id:d.jid,name:d.name,kind:d.isGroup?"group":"dm"})),"local")}catch{}if(!n.localOnly&&this.mesh){let d=this.mesh.directory().filter(l=>l.healthy&&l.channels?.includes(t));await Promise.allSettled(d.map(async l=>{try{let u=await fetch(`${l.peerUrl}/channels/${encodeURIComponent(t)}/chats?local=1`,{headers:this.mesh.authHeaders(l.peer),signal:AbortSignal.timeout(5e3)});if(!u.ok)return;let g=await u.json();Array.isArray(g.chats)&&a(g.chats.map(m=>({id:m.id,name:m.name,kind:m.kind??"dm",accountId:m.accountId})),`mesh:${l.peer}`)}catch{}}))}this.json(e,200,{channel:t,source:o.join(", ")||"none",chats:i})}async handleWorkflowManualRun(e,t,n){if(!this.workflowDispatcher||!this.workflowStore){this.json(t,503,{error:"workflow engine not enabled on this node"});return}let s;try{s=await te(e)}catch{s={}}try{let i=await iy({get:o=>this.workflowStore.get(o),dispatchWorkflow:o=>this.workflowDispatcher.dispatchWorkflow(o),startRun:o=>this.workflowDispatcher.startRun(o)},n,s);this.json(t,i.status,i.body)}catch(i){this.log(`[workflows] manual run "${n}" failed: ${i.message}`),this.json(t,500,{error:i.message})}}},kc=vc;yt(kc,"MESH_PROTECTED_PATHS",new Set(["/task","/ask","/mesh/task","/mesh/inbox/send","/workflow/event","/workflow/transition","/channel/send","/push/app","/webrtc/signal","/gitlab/react","/gitlab/send-note","/gitlab/log-time","/channel/edit-comment","/github/send-comment"]));function RR(r){if(typeof r!="string")return"";let e=r.trim();if(!e)return"";let t=e.match(/^[^.!?\n]+[.!?]?/),n=(t?t[0]:e).trim();return n.length>140?n.slice(0,137)+"\u2026":n}function te(r){return new Promise((e,t)=>{let n="";r.setEncoding("utf8"),r.on("data",s=>{n+=s}),r.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(s){t(s)}}),r.on("error",t)})}function ER(r,e){let t=["model","workspace","tier","permissionMode","mcpServers"],n=new Set,s=new Set([...Object.keys(r),...Object.keys(e)]);for(let i of s){let o=r[i],a=e[i];if(!o||!a){n.add("add/remove");continue}for(let c of t)JSON.stringify(o[c])!==JSON.stringify(a[c])&&n.add(`${i}.${c}`)}return Array.from(n).slice(0,6)}async function B(r){return new Promise((e,t)=>{let n="";r.on("data",s=>n+=s.toString()),r.on("end",()=>{try{e(n?JSON.parse(n):{})}catch{e({})}}),r.on("error",t)})}Zb();function gW(r){typeof r=="string"&&(Nn.error(r),process.exit(1)),r instanceof Error&&(Nn.error(r.message),process.exit(1)),Nn.error("Something went wrong. Please try again."),process.exit(1)}export{BR as a,uo as b,ot as c,tn as d,sn as e,dt as f,ms as g,bg as h,gp as i,zS as j,YS as k,wp as l,Ve as m,ht as n,vp as o,gt as p,C_ as q,P_ as r,Zs as s,KM as t,hI as u,ua as v,yD as w,wD as x,bD as y,Xm as z,BI as A,ID as B,TD as C,wn as D,Ft as E,bn as F,YD as G,xy as H,DT as I,HN as J,vr as K,Pa as L,_a as M,xr as N,me as O,yw as P,Cr as Q,_x as R,Cw as S,Ox as T,Ow as U,Mr as V,An as W,Lr as X,Fr as Y,Uw as Z,Va as _,Ke as $,Ae as aa,Xw as ba,Kw as ca,zw as da,Yw as ea,ri as fa,Ob as ga,gc as ha,Nb as ia,YA as ja,o2 as ka,kc as la,gW as ma};
1220
- //# sourceMappingURL=chunk-L7OTWV5X.js.map
1220
+ //# sourceMappingURL=chunk-X4ZARQET.js.map