agentix-cli 0.139.0 → 0.139.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/{agent-PRHZGF6J.js → agent-5CEDGNDW.js} +2 -2
  2. package/dist/{board-dashboard-GBEBQUFJ.js → board-dashboard-F5GP2X22.js} +2 -2
  3. package/dist/{builtin-YD7MC572.js → builtin-U5S2XCNJ.js} +2 -2
  4. package/dist/chunk-3W2BHUGM.js +11 -0
  5. package/dist/chunk-3W2BHUGM.js.map +1 -0
  6. package/dist/{chunk-KO6BU3B3.js → chunk-4LNJR5PC.js} +2 -2
  7. package/dist/{chunk-34XYHSL6.js → chunk-65LN6GQP.js} +230 -229
  8. package/dist/chunk-65LN6GQP.js.map +1 -0
  9. package/dist/chunk-6TTGRTDO.js +3 -0
  10. package/dist/chunk-6TTGRTDO.js.map +1 -0
  11. package/dist/{chunk-MUC7MMTT.js → chunk-BUKXFZEO.js} +2 -2
  12. package/dist/{chunk-2BEZU5OF.js → chunk-HWYU6XG2.js} +2 -2
  13. package/dist/chunk-HWYU6XG2.js.map +1 -0
  14. package/dist/{chunk-RIYQNADV.js → chunk-LGB6ILTW.js} +3 -3
  15. package/dist/{chunk-JBYLG3CQ.js → chunk-P4TSZDVO.js} +2 -2
  16. package/dist/{chunk-HF5EF335.js → chunk-VE3SSOQX.js} +4 -4
  17. package/dist/chunk-VE3SSOQX.js.map +1 -0
  18. package/dist/{chunk-XQVL2RYG.js → chunk-WTMZW5X7.js} +2 -2
  19. package/dist/{chunk-H4NSB54D.js → chunk-XVTD6I34.js} +2 -2
  20. package/dist/{chunk-U6EJ53DA.js → chunk-YWEGKAE2.js} +2 -2
  21. package/dist/cli.js +1 -1
  22. package/dist/{enrich-R2LIDLPZ.js → enrich-FPK3OW77.js} +2 -2
  23. package/dist/{event-levels-WOYYEWSZ.js → event-levels-NBOMTB23.js} +2 -2
  24. package/dist/{follow-up-tool-QRECR3AH.js → follow-up-tool-M2KCLRQQ.js} +2 -2
  25. package/dist/index.d.ts +14 -1
  26. package/dist/index.js +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/{program-7VHY5RVZ.js → program-SJT7PIFO.js} +6 -6
  29. package/dist/program-SJT7PIFO.js.map +1 -0
  30. package/dist/{registry-B276QJ75.js → registry-Q7VNRLZA.js} +2 -2
  31. package/dist/{rules-UVUJTVOE.js → rules-5ZZQZLQA.js} +2 -2
  32. package/dist/send-answer-ZG7UHCVS.js +2 -0
  33. package/dist/{tool-UPXUWIMM.js → tool-DFPOFXGA.js} +2 -2
  34. package/dist/{tool-5WCC7SKQ.js → tool-GJ75MWV5.js} +2 -2
  35. package/dist/wiki-enrich-JNQ2RPWU.js +2 -0
  36. package/dist/wiki-enrich-JNQ2RPWU.js.map +1 -0
  37. package/package.json +1 -1
  38. package/dist/chunk-2BEZU5OF.js.map +0 -1
  39. package/dist/chunk-34XYHSL6.js.map +0 -1
  40. package/dist/chunk-HF5EF335.js.map +0 -1
  41. package/dist/chunk-Q4XP5TBI.js +0 -11
  42. package/dist/chunk-Q4XP5TBI.js.map +0 -1
  43. package/dist/program-7VHY5RVZ.js.map +0 -1
  44. package/dist/wiki-enrich-7SBCPK2E.js +0 -2
  45. /package/dist/{agent-PRHZGF6J.js.map → agent-5CEDGNDW.js.map} +0 -0
  46. /package/dist/{board-dashboard-GBEBQUFJ.js.map → board-dashboard-F5GP2X22.js.map} +0 -0
  47. /package/dist/{builtin-YD7MC572.js.map → builtin-U5S2XCNJ.js.map} +0 -0
  48. /package/dist/{chunk-KO6BU3B3.js.map → chunk-4LNJR5PC.js.map} +0 -0
  49. /package/dist/{chunk-MUC7MMTT.js.map → chunk-BUKXFZEO.js.map} +0 -0
  50. /package/dist/{chunk-RIYQNADV.js.map → chunk-LGB6ILTW.js.map} +0 -0
  51. /package/dist/{chunk-JBYLG3CQ.js.map → chunk-P4TSZDVO.js.map} +0 -0
  52. /package/dist/{chunk-XQVL2RYG.js.map → chunk-WTMZW5X7.js.map} +0 -0
  53. /package/dist/{chunk-H4NSB54D.js.map → chunk-XVTD6I34.js.map} +0 -0
  54. /package/dist/{chunk-U6EJ53DA.js.map → chunk-YWEGKAE2.js.map} +0 -0
  55. /package/dist/{enrich-R2LIDLPZ.js.map → enrich-FPK3OW77.js.map} +0 -0
  56. /package/dist/{event-levels-WOYYEWSZ.js.map → event-levels-NBOMTB23.js.map} +0 -0
  57. /package/dist/{follow-up-tool-QRECR3AH.js.map → follow-up-tool-M2KCLRQQ.js.map} +0 -0
  58. /package/dist/{registry-B276QJ75.js.map → registry-Q7VNRLZA.js.map} +0 -0
  59. /package/dist/{rules-UVUJTVOE.js.map → rules-5ZZQZLQA.js.map} +0 -0
  60. /package/dist/{wiki-enrich-7SBCPK2E.js.map → send-answer-ZG7UHCVS.js.map} +0 -0
  61. /package/dist/{tool-UPXUWIMM.js.map → tool-DFPOFXGA.js.map} +0 -0
  62. /package/dist/{tool-5WCC7SKQ.js.map → tool-GJ75MWV5.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{a as Sm,b as Mr,g as Am}from"./chunk-QN2OTBVC.js";import{b as km}from"./chunk-O6WW7ATO.js";import{A as mm,B as um,D as Ta,E as pm,G as fm,H as hm,I as ym,a as Gg,e as Ht,f as Yg,g as Vg,h as Zg,i as em,k as tm,l as om,m as nm,n as Ca,o as sm,t as rm,u as im,v as Oa,w as am,z as gm}from"./chunk-JBYLG3CQ.js";import{n as Ia}from"./chunk-NQGLKWDO.js";import{a as wm,b as $m,d as Ss,e as bm}from"./chunk-B65EC44C.js";import{a as vm,b as xm}from"./chunk-XQVL2RYG.js";import"./chunk-H4NSB54D.js";import"./chunk-MTX4UPNB.js";import{d as Xg,e as Ea,h as Kg,i as Qg}from"./chunk-YXFTUOZR.js";import{a as cm,c as lm,d as dm}from"./chunk-5NTWGUSJ.js";import"./chunk-QAWKN2N4.js";import"./chunk-B2QYMUTD.js";import{a as vt}from"./chunk-EJIY45FZ.js";import{a as Hg,c as zg}from"./chunk-IMUTN7PT.js";import{a as Sa}from"./chunk-LNY6N73E.js";import{a as ia,b as pd}from"./chunk-RKPAVWXF.js";import{$ as Mg,A as pg,B as pa,C as fg,D as hg,E as yg,F as wg,G as $g,H as bg,I as kg,J as vg,K as Tg,L as Rr,M as no,N as wo,O as Rn,P as Nr,Q as jr,R as $a,S as Ig,T as Rg,U as Ng,V as jg,W as _g,X as Dg,Y as Nn,Z as jn,_ as Pg,a as vd,aa as ot,b as xd,ba as _r,ca as xs,da as ba,ea as Lg,fa as Ug,ga as xa,h as yr,ha as Bg,i as Cd,ia as Dr,j as bs,ja as _n,k as wr,ka as Pr,l as Td,la as Aa,m as Id,ma as Jg,n as Wd,o as Bd,p as Sr,q as ga,r as Xd,s as ng,t as sg,u as ig,v as ag,w as dg,x as gg,y as mg,z as ug}from"./chunk-34XYHSL6.js";import{$ as fa,A as tg,D as og,E as Or,J as rg,Pa as Fg,Qa as ka,Ra as qg,Sa as va,Y as ks,aa as Tr,ba as xg,eb as Gt,gb as Wg,ia as yo,ja as Sg,ka as ha,ma as ya,oa as Ag,pa as Eg,qa as vs,ua as Ir,x as eg,xa as Cg,ya as Og,z as ua,za as wa}from"./chunk-KO6BU3B3.js";import"./chunk-GTJIKXDB.js";import{a as Sd,c as ca,e as Ad,f as Ed}from"./chunk-J7U3BASX.js";import"./chunk-7LN4VKDU.js";import"./chunk-IMLAPB7G.js";import"./chunk-ZVP6GB4G.js";import{a as $r,b as br,c as Rd,d as Nd,e as jd,g as _d,h as Dd,j as Pd,k as Md,l as Ld,m as Fd,p as kr,s as qd,t as Ud}from"./chunk-S2GAEH2F.js";import"./chunk-UNIXYV3U.js";import{a as Kd,b as Wo,c as Qd,d as Ar,e as Zd,f as ma,i as Er,j as Bo,k as Cr}from"./chunk-AKWBDCMU.js";import"./chunk-PPUN7YHA.js";import"./chunk-VZLIBDLH.js";import{a as cg,b as lg}from"./chunk-EKJG63EJ.js";import{b as kt}from"./chunk-EMGB23H5.js";import{c as Jd}from"./chunk-JAML6222.js";import"./chunk-YMX3QCV7.js";import"./chunk-JWDJMFU6.js";import{b as da}from"./chunk-5HLD66CW.js";import"./chunk-IS2IWRP7.js";import{c as Gd,e as vr,g as xr}from"./chunk-LQE73AZR.js";import{a as Hd,b as zd,c as Yd,d as Vd}from"./chunk-2D3RYIDU.js";import"./chunk-MRIVENBY.js";import"./chunk-A5GYG56I.js";import{a as la,p as Od}from"./chunk-Z5IHT6RK.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{L as ho,R as cd,ca as dd,g as Bl,r as Jl,y as na,z as Vl}from"./chunk-RIYQNADV.js";import{F as id,U as ad,W as ld,b as Sn,g as An,h as pr,i as fr,j as En,k as Xl,l as fo,n as qo}from"./chunk-2BEZU5OF.js";import{e as od,f as Uo,k as On}from"./chunk-QSKG754X.js";import{b as Fo}from"./chunk-MEFPXHQJ.js";import"./chunk-MUC7MMTT.js";import"./chunk-SFQUP3BP.js";import{a as oo}from"./chunk-Y4CYQV7G.js";import{b as In,e as ud}from"./chunk-Q4XP5TBI.js";import{a as gd,b as md}from"./chunk-SHEUCITK.js";import{a as aa,e as fd,f as hd,h as yd,i as wd,k as $d,l as bd,m as kd}from"./chunk-ANDEMOYE.js";import{c as Ql}from"./chunk-SZDACK6O.js";import{f as Zl,g as ed,h as sa}from"./chunk-HF5EF335.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{a as zl,k as td}from"./chunk-JS2LEURJ.js";import{a as hr,b as ge,c as We,d as Tn,e as nd}from"./chunk-NMYPZR4W.js";import{a as sd,b as ra,h as rd}from"./chunk-3UOTLMXD.js";import"./chunk-36AXN6ZB.js";import"./chunk-PE5V2LI7.js";import{a as oa,b as Hl}from"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import{j as Yl}from"./chunk-X5C5W3E4.js";import{a as Cn}from"./chunk-GV7S5BAX.js";import{e as Kl}from"./chunk-GSX4NK2N.js";import"./chunk-VWTBHLMX.js";import{a as ta}from"./chunk-AXHP6TMT.js";import"./chunk-STIZFWDJ.js";import{c as Gl}from"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import"./chunk-HXLB2XCT.js";import"./chunk-SKSYII3K.js";import{g as po,i as ur}from"./chunk-7KAQHNLT.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-JJZVFDG6.js";import{a as Xi,b as kl,c as oy,d as lr,e as vl,f as Dl,g as ly,h as Pl,i as dy,m as xn,n as Ll,q as Fl,u as ql,y as Jt,z as $s}from"./chunk-LMZCB7TT.js";import{a as to,b as vn,e as Nl,f as ws}from"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import{a as mr,b as Ml}from"./chunk-MCI3DIWW.js";import"./chunk-MYVHVJWZ.js";import{g as uo,i as Ul}from"./chunk-6TURWSMN.js";import{n as Wl}from"./chunk-AV7T3SYT.js";import"./chunk-Y5MFVVTM.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-JXF54PT7.js";import"./chunk-2PJKGZWP.js";import{a as Bt,b as ty}from"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import{Aa as le,D as Ol,E as ry,S as Tl,T as Qi,V as Zi,aa as iy,ba as ea,da as Il,ea as ay,h as xl,i as Sl,j as Al,k as El,l as Cl,m as ny,qa as Rl,ra as dr,sa as O,ta as gr,v as Ki,w as sy}from"./chunk-MGM33GOW.js";import"./chunk-BRK6M6LA.js";import{f as bt,n as ys}from"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import{g as jl,k as _l,l as cy}from"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{Command as gy}from"commander";var Em=new gy().name("a2a").description("start an A2A (Agent-to-Agent) protocol server for external agent integration").option("--port <port>","server port","3171").option("--host <host>","server host","0.0.0.0").option("-p, --provider <provider>","AI provider","claude-code").option("-m, --model <model>","model to use").option("--api-key <key>","API key for the provider").option("-c, --cwd <cwd>","working directory",process.cwd()).option("--no-cors","disable CORS headers").action(async e=>{await new xd({port:parseInt(e.port,10),host:e.host,provider:e.provider,model:e.model,apiKey:e.apiKey,cwd:e.cwd,cors:e.cors!==!1}).start()});le();import{Command as my}from"commander";import{execFileSync as Tt}from"node:child_process";import{cpSync as Cm,existsSync as ja,mkdirSync as Ra,mkdtempSync as uy,readdirSync as py,rmSync as Om,writeFileSync as Tm}from"node:fs";import{dirname as Im,join as nt}from"node:path";import{homedir as Lr,release as fy,tmpdir as hy}from"node:os";import{setTimeout as yy}from"node:timers/promises";function Fr(){let e=Rd(process.platform,process.arch,fy());if(e)throw new Error(e)}function qr(){let e=nt(Lr(),"Library/LaunchAgents"),t=[];try{t=py(e).filter(_d)}catch{}let o=t.flatMap(n=>{let s=nt(e,n);try{return[{file:s,plist:Tt("plutil",["-convert","xml1","-o","-",s],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}]}catch{return[]}});return Dd(e,o)}function As(e){return`gui/${process.getuid()}/${e.label}`}async function Na(e){try{Tt("launchctl",["bootout",As(e)],{stdio:"pipe"})}catch{}for(let t=0;t<30;t++){try{Tt("launchctl",["print",As(e)],{stdio:"pipe"})}catch{return}await yy(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function Rm(e){if(!ja(e.file))throw new Error("Run agentx desktop install first.");let t=!0;try{Tt("launchctl",["print",As(e)],{stdio:"pipe"})}catch{t=!1}t||Tt("launchctl",["bootstrap",`gui/${process.getuid()}`,e.file],{stdio:"pipe"}),Tt("launchctl",["kickstart",As(e)],{stdio:"pipe"})}function wy(){let e=Fd();if(e&&ja(nt(e,"apps/mac-voice/build.sh")))return e;throw new Error("Desktop sources are missing from this installation. Update AgentX to a release containing apps/mac-voice and apps/mac-helper.")}var Dn=new my("desktop").description("install and control the macOS desktop assistant");Dn.command("install").description("build, install, and start voice and computer-use helpers at login").option("--agent <id>","pin this agent; without it, pick the agent from the menu-bar icon").option("--dry-run","show the installation plan without building or changing login items").action(async e=>{Fr();let t=O(),o=Nd(t.agents,e.agent),n=e.agent,s=t.dashboard?.daemonUrl||`http://${t.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:")}`,r=wy(),i=nt(Lr(),"Applications"),{keep:a,remove:c}=qr();if(console.log(`Desktop assistant \u2192 ${nt(i,$r)}
1
+ import{a as Sm,b as Mr,g as Am}from"./chunk-QN2OTBVC.js";import{b as km}from"./chunk-O6WW7ATO.js";import{A as mm,B as um,D as Ta,E as pm,G as fm,H as hm,I as ym,a as Gg,e as Ht,f as Yg,g as Vg,h as Zg,i as em,k as tm,l as om,m as nm,n as Ca,o as sm,t as rm,u as im,v as Oa,w as am,z as gm}from"./chunk-P4TSZDVO.js";import{n as Ia}from"./chunk-NQGLKWDO.js";import{a as wm,b as $m,d as Ss,e as bm}from"./chunk-B65EC44C.js";import{a as vm,b as xm}from"./chunk-WTMZW5X7.js";import"./chunk-XVTD6I34.js";import"./chunk-QAWKN2N4.js";import"./chunk-MTX4UPNB.js";import{a as Hg,c as zg}from"./chunk-IMUTN7PT.js";import{d as Xg,e as Ea,h as Kg,i as Qg}from"./chunk-YXFTUOZR.js";import{a as cm,c as lm,d as dm}from"./chunk-5NTWGUSJ.js";import"./chunk-B2QYMUTD.js";import{a as vt}from"./chunk-EJIY45FZ.js";import{a as Sa}from"./chunk-LNY6N73E.js";import{a as ia,b as pd}from"./chunk-RKPAVWXF.js";import{$ as Mg,A as pg,B as pa,C as fg,D as hg,E as yg,F as wg,G as $g,H as bg,I as kg,J as vg,K as Tg,L as Rr,M as no,N as wo,O as Rn,P as Nr,Q as jr,R as $a,S as Ig,T as Rg,U as Ng,V as jg,W as _g,X as Dg,Y as Nn,Z as jn,_ as Pg,a as vd,aa as ot,b as xd,ba as _r,ca as xs,da as ba,ea as Lg,fa as Ug,ga as xa,h as yr,ha as Bg,i as Cd,ia as Dr,j as bs,ja as _n,k as wr,ka as Pr,l as Td,la as Aa,m as Id,ma as Jg,n as Wd,o as Bd,p as Sr,q as ga,r as Xd,s as ng,t as sg,u as ig,v as ag,w as dg,x as gg,y as mg,z as ug}from"./chunk-65LN6GQP.js";import{$ as fa,A as tg,D as og,E as Or,J as rg,Pa as Fg,Qa as ka,Ra as qg,Sa as va,Y as ks,aa as Tr,ba as xg,eb as Gt,gb as Wg,ia as yo,ja as Sg,ka as ha,ma as ya,oa as Ag,pa as Eg,qa as vs,ua as Ir,x as eg,xa as Cg,ya as Og,z as ua,za as wa}from"./chunk-4LNJR5PC.js";import"./chunk-GTJIKXDB.js";import{a as Sd,c as ca,e as Ad,f as Ed}from"./chunk-J7U3BASX.js";import{a as $r,b as br,c as Rd,d as Nd,e as jd,g as _d,h as Dd,j as Pd,k as Md,l as Ld,m as Fd,p as kr,s as qd,t as Ud}from"./chunk-S2GAEH2F.js";import"./chunk-7LN4VKDU.js";import"./chunk-IMLAPB7G.js";import"./chunk-ZVP6GB4G.js";import"./chunk-MRIVENBY.js";import"./chunk-UNIXYV3U.js";import{a as Kd,b as Wo,c as Qd,d as Ar,e as Zd,f as ma,i as Er,j as Bo,k as Cr}from"./chunk-AKWBDCMU.js";import"./chunk-PPUN7YHA.js";import"./chunk-VZLIBDLH.js";import{a as cg,b as lg}from"./chunk-EKJG63EJ.js";import{a as la,p as Od}from"./chunk-Z5IHT6RK.js";import{b as kt}from"./chunk-EMGB23H5.js";import{c as Jd}from"./chunk-JAML6222.js";import"./chunk-YMX3QCV7.js";import"./chunk-JWDJMFU6.js";import{b as da}from"./chunk-5HLD66CW.js";import"./chunk-IS2IWRP7.js";import{c as Gd,e as vr,g as xr}from"./chunk-LQE73AZR.js";import{a as Hd,b as zd,c as Yd,d as Vd}from"./chunk-2D3RYIDU.js";import{a as oo}from"./chunk-Y4CYQV7G.js";import{b as In,e as ud}from"./chunk-3W2BHUGM.js";import{a as gd,b as md}from"./chunk-SHEUCITK.js";import"./chunk-A5GYG56I.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{L as ho,R as cd,ca as dd,g as Bl,r as Jl,y as na,z as Vl}from"./chunk-LGB6ILTW.js";import{F as id,U as ad,W as ld,b as Sn,g as An,h as pr,i as fr,j as En,k as Xl,l as fo,n as qo}from"./chunk-HWYU6XG2.js";import{e as od,f as Uo,k as On}from"./chunk-QSKG754X.js";import{b as Fo}from"./chunk-MEFPXHQJ.js";import"./chunk-BUKXFZEO.js";import"./chunk-SFQUP3BP.js";import"./chunk-6TTGRTDO.js";import{a as aa,e as fd,f as hd,h as yd,i as wd,k as $d,l as bd,m as kd}from"./chunk-ANDEMOYE.js";import{c as Ql}from"./chunk-SZDACK6O.js";import{f as Zl,g as ed,h as sa}from"./chunk-VE3SSOQX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{a as zl,k as td}from"./chunk-JS2LEURJ.js";import{a as hr,b as ge,c as We,d as Tn,e as nd}from"./chunk-NMYPZR4W.js";import{a as sd,b as ra,h as rd}from"./chunk-3UOTLMXD.js";import"./chunk-36AXN6ZB.js";import"./chunk-PE5V2LI7.js";import{a as oa,b as Hl}from"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import{j as Yl}from"./chunk-X5C5W3E4.js";import{a as Cn}from"./chunk-GV7S5BAX.js";import{e as Kl}from"./chunk-GSX4NK2N.js";import"./chunk-VWTBHLMX.js";import{a as ta}from"./chunk-AXHP6TMT.js";import"./chunk-STIZFWDJ.js";import{c as Gl}from"./chunk-OWNQ2FD4.js";import"./chunk-KEXBEUSU.js";import"./chunk-ROLSSYXE.js";import"./chunk-HXLB2XCT.js";import"./chunk-SKSYII3K.js";import{g as po,i as ur}from"./chunk-7KAQHNLT.js";import"./chunk-WPNRDEHW.js";import"./chunk-MWNCS57L.js";import"./chunk-4LWFJ4MZ.js";import"./chunk-BIJHMWXK.js";import"./chunk-JJZVFDG6.js";import{a as Xi,b as kl,c as oy,d as lr,e as vl,f as Dl,g as ly,h as Pl,i as dy,m as xn,n as Ll,q as Fl,u as ql,y as Jt,z as $s}from"./chunk-LMZCB7TT.js";import{a as to,b as vn,e as Nl,f as ws}from"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import{a as mr,b as Ml}from"./chunk-MCI3DIWW.js";import"./chunk-MYVHVJWZ.js";import{g as uo,i as Ul}from"./chunk-6TURWSMN.js";import{n as Wl}from"./chunk-AV7T3SYT.js";import"./chunk-Y5MFVVTM.js";import"./chunk-QD6IICK7.js";import"./chunk-QOYAX2FT.js";import"./chunk-JXF54PT7.js";import"./chunk-2PJKGZWP.js";import{a as Bt,b as ty}from"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import{Aa as le,D as Ol,E as ry,S as Tl,T as Qi,V as Zi,aa as iy,ba as ea,da as Il,ea as ay,h as xl,i as Sl,j as Al,k as El,l as Cl,m as ny,qa as Rl,ra as dr,sa as O,ta as gr,v as Ki,w as sy}from"./chunk-MGM33GOW.js";import"./chunk-BRK6M6LA.js";import{f as bt,n as ys}from"./chunk-UIBUZ2N3.js";import"./chunk-2QNT5JDS.js";import{g as jl,k as _l,l as cy}from"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{Command as gy}from"commander";var Em=new gy().name("a2a").description("start an A2A (Agent-to-Agent) protocol server for external agent integration").option("--port <port>","server port","3171").option("--host <host>","server host","0.0.0.0").option("-p, --provider <provider>","AI provider","claude-code").option("-m, --model <model>","model to use").option("--api-key <key>","API key for the provider").option("-c, --cwd <cwd>","working directory",process.cwd()).option("--no-cors","disable CORS headers").action(async e=>{await new xd({port:parseInt(e.port,10),host:e.host,provider:e.provider,model:e.model,apiKey:e.apiKey,cwd:e.cwd,cors:e.cors!==!1}).start()});le();import{Command as my}from"commander";import{execFileSync as Tt}from"node:child_process";import{cpSync as Cm,existsSync as ja,mkdirSync as Ra,mkdtempSync as uy,readdirSync as py,rmSync as Om,writeFileSync as Tm}from"node:fs";import{dirname as Im,join as nt}from"node:path";import{homedir as Lr,release as fy,tmpdir as hy}from"node:os";import{setTimeout as yy}from"node:timers/promises";function Fr(){let e=Rd(process.platform,process.arch,fy());if(e)throw new Error(e)}function qr(){let e=nt(Lr(),"Library/LaunchAgents"),t=[];try{t=py(e).filter(_d)}catch{}let o=t.flatMap(n=>{let s=nt(e,n);try{return[{file:s,plist:Tt("plutil",["-convert","xml1","-o","-",s],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}]}catch{return[]}});return Dd(e,o)}function As(e){return`gui/${process.getuid()}/${e.label}`}async function Na(e){try{Tt("launchctl",["bootout",As(e)],{stdio:"pipe"})}catch{}for(let t=0;t<30;t++){try{Tt("launchctl",["print",As(e)],{stdio:"pipe"})}catch{return}await yy(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function Rm(e){if(!ja(e.file))throw new Error("Run agentx desktop install first.");let t=!0;try{Tt("launchctl",["print",As(e)],{stdio:"pipe"})}catch{t=!1}t||Tt("launchctl",["bootstrap",`gui/${process.getuid()}`,e.file],{stdio:"pipe"}),Tt("launchctl",["kickstart",As(e)],{stdio:"pipe"})}function wy(){let e=Fd();if(e&&ja(nt(e,"apps/mac-voice/build.sh")))return e;throw new Error("Desktop sources are missing from this installation. Update AgentX to a release containing apps/mac-voice and apps/mac-helper.")}var Dn=new my("desktop").description("install and control the macOS desktop assistant");Dn.command("install").description("build, install, and start voice and computer-use helpers at login").option("--agent <id>","pin this agent; without it, pick the agent from the menu-bar icon").option("--dry-run","show the installation plan without building or changing login items").action(async e=>{Fr();let t=O(),o=Nd(t.agents,e.agent),n=e.agent,s=t.dashboard?.daemonUrl||`http://${t.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:")}`,r=wy(),i=nt(Lr(),"Applications"),{keep:a,remove:c}=qr();if(console.log(`Desktop assistant \u2192 ${nt(i,$r)}
2
2
  Computer-use helper \u2192 ${nt(i,br)}
3
3
  Agent \u2192 ${n?`${o} (pinned)`:"picked from the menu-bar icon"}
4
4
  Daemon \u2192 ${s}
@@ -9,7 +9,7 @@ The AgentX daemon and a speech transcription backend must also be available. Run
9
9
  `)),{path:o,changed:l,events:a,guardInstalled:c}}function Pm(e={}){let t=e.path??Es();if(!Br(t))return{path:t,changed:!1,events:[],guardInstalled:!1};let o;try{o=JSON.parse(Jr(t,"utf-8"))}catch(a){throw new Error(`${t} is not valid JSON (${a?.message}) \u2014 refusing to rewrite it`)}let n=JSON.stringify(o),s=o.hooks,r=[];if(s&&typeof s=="object"){for(let a of Object.keys(s)){if(!Array.isArray(s[a]))continue;let c=a==="PreToolUse"?jm:Da;if(a==="PreToolUse"&&e.keepGuard!==!1)continue;let l=s[a].filter(g=>!Wr(g,c));l.length!==s[a].length&&r.push(a),l.length===0?delete s[a]:s[a]=l}Object.keys(s).length===0&&delete o.hooks}let i=JSON.stringify(o)!==n;return i&&Nm(t,`${JSON.stringify(o,null,2)}
10
10
  `),{path:t,changed:i,events:r,guardInstalled:!1}}function Cs(e=Es()){if(!Br(e))return!1;try{return!!JSON.parse(Jr(e,"utf-8"))?.hooks?.Stop?.some?.(o=>Wr(o,Da))}catch{return!1}}var Gr=new Sy("monitor").description("Register external CLI sessions and report ended runs to the briefing"),Mm=process.env.AGENTX_DAEMON_URL||`http://127.0.0.1:${Jo()}`;async function Lm(e,t,o){let n=process.env.MESH_TOKEN,s=await fetch(e.replace(/\/$/,"")+"/monitor/"+t,{method:"POST",headers:{"Content-Type":"application/json",...n?{Authorization:`Bearer ${n}`}:{}},body:JSON.stringify(o),signal:AbortSignal.timeout(8e3)});if(!s.ok)throw new Error(`Monitor HTTP ${s.status}: ${(await s.text()).slice(0,300)}`)}Gr.command("register").requiredOption("--session <id>","Native session ID").requiredOption("--runtime <name>","claude, codex, gemini, opencode, or another CLI").requiredOption("--label <label>","Human-readable task label").option("--url <url>","Daemon URL",Mm).action(async e=>{try{await Lm(e.url,"register",Ad.parse({id:e.session,runtime:e.runtime,label:e.label})),console.log("Session registered. Report each stopped run with agentx monitor ended.")}catch(t){console.error(t.message),process.exitCode=1}});Gr.command("ended").requiredOption("--session <id>","Registered session ID").requiredOption("--run <id>","Stable unique turn ID; reuse this ID when retrying delivery").requiredOption("--transcript <file>","Local transcript file; only the last 90 KB is submitted").option("--url <url>","Daemon URL",Mm).action(async e=>{try{let t=await Ay(e.transcript,"r"),o;try{let n=await t.stat();if(!n.isFile())throw new Error("Transcript must be a regular file");let s=Math.min(n.size,9e4),r=Buffer.alloc(s),{bytesRead:i}=await t.read(r,0,s,Math.max(0,n.size-s));o=(n.size>s?`[Transcript truncated: last 90 KB only]
11
11
  `:"")+r.subarray(0,i).toString("utf8")}finally{await t.close()}await Lm(e.url,"ended",Ed.parse({sessionId:e.session,runId:e.run,transcript:o})),console.log("Run queued for review.")}catch(t){console.error(t.message),process.exitCode=1}});import{Command as TS}from"commander";import{Command as Dy}from"commander";le();import R from"chalk";import{existsSync as Py,readFileSync as My}from"fs";le();import{Command as Ey}from"commander";import he from"chalk";import{spawn as qm}from"child_process";import{existsSync as Cy,readFileSync as Oy,unlinkSync as Ty}from"fs";import{resolve as Pa}from"path";var Ma=e=>new Promise(t=>setTimeout(t,e));function La(e){try{return process.kill(e,0),!0}catch{return!1}}async function Pn(e){try{let t=await fetch(e,{signal:AbortSignal.timeout(3e3)});return t.ok?await t.json():null}catch{return null}}async function Iy(e){let t=await Pn(`${e}/daemon/restart`);if(typeof t?.inflight?.total=="number")return t.inflight.total;let o=await Pn(`${e}/health`);return o?typeof o.inflight?.total=="number"?o.inflight.total:Array.isArray(o.agents)?o.agents.reduce((n,s)=>n+(Number(s.active)||0),0):null:null}function Ry(e){for(let t of[Pa(e,".agentx/daemon.pid"),"/tmp/agentx-daemon.pid"])try{let o=parseInt(Oy(t,"utf-8").trim(),10);if(Number.isFinite(o)&&La(o))return o}catch{}return null}function Ny(e){return new Promise(t=>{let o=qm(e[0],e.slice(1),{stdio:"inherit"});o.on("error",()=>t(127)),o.on("exit",n=>t(n??1))})}var Um=new Ey("restart").description("restart the daemon through launchd, systemd or a plain stop + start; --when-idle waits for running tasks first").option("-c, --config <path>","path to agentx.json").option("--when-idle","wait until no task is running before restarting").option("--timeout <minutes>","how long --when-idle waits","30").option("--abort-on-timeout","with --when-idle: give up instead of restarting when the wait runs out").option("--interval <seconds>","how often --when-idle checks","5").option("--reload-service","also re-read the service's settings file (launchd plist / systemd unit)").option("--dry-run","show what would run, without restarting").action(async e=>{let t=O(e.config),[o,n]=t.node.bind.split(":"),s=parseInt(n||"18800",10),r=`http://${!o||o==="0.0.0.0"?"127.0.0.1":o}:${s}`,i=await Pn(`${r}/health`);i||(console.log(he.red(` The daemon is not answering on ${r}; nothing to restart.`)),console.log(he.dim(" Start it with: agentx daemon start --detach (or through its service)")),process.exit(1));let a=await Pn(`${r}/daemon/restart`),c=a?.pid??fg(s)??Ry(process.cwd()),l=a?.service??(c?ug(c):{kind:"none"}),g=a?.cwd??process.cwd(),d=e.config??a?.configPath,f=process.getuid?.()===0,p=gg(l,{isRoot:f,reloadService:!!e.reloadService,plistPath:l.kind==="launchd"&&e.reloadService?pg(l):null,interactive:!!process.stdin.isTTY});if(console.log(),console.log(` Daemon ${he.bold(i.node?.name||i.node?.id||r)}${c?he.dim(` (PID ${c})`):""}`),console.log(` Run by: ${mg(l)}`),p.ok||(console.log(he.red(` ${p.reason}`)),console.log(he.dim(` Restart it by hand: ${p.manual}`)),process.exit(1)),l.kind==="none"&&!c&&(console.log(he.red(" Can't find the daemon's process, so it can't be stopped safely.")),console.log(he.dim(" Run `agentx daemon stop`, then `agentx daemon start --detach`, from the directory holding agentx.json.")),process.exit(1)),e.dryRun){console.log(he.dim(" Would run:"));for(let v of p.steps)console.log(he.dim(` ${Fm(v,c)}`));console.log();return}if(e.whenIdle){let v=Number(e.timeout),A=Math.max(1,Number(e.interval)||5);(!Number.isFinite(v)||v<0)&&(console.log(he.red(" --timeout must be a number of minutes")),process.exit(1));let x,k=await dg({read:()=>Iy(r),intervalMs:A*1e3,timeoutMs:v*6e4,onCheck:S=>{S!==x&&S!==null&&S>0&&console.log(he.dim(` Waiting: ${S} task(s) running...`)),x=S}});if(k.outcome==="unreachable"&&(console.log(he.red(" The daemon stopped answering while waiting. Not restarting it.")),console.log(he.dim(" Check with: agentx daemon status")),process.exit(1)),k.outcome==="timeout"){let S=k.inflight??"some";e.abortOnTimeout&&(console.log(he.yellow(` Still ${S} task(s) running after ${v} min. Not restarting (--abort-on-timeout).`)),process.exit(1)),console.log(he.yellow(` Still ${S} task(s) running after ${v} min. Restarting anyway:`)),console.log(he.yellow(" they get the usual time to finish, and anything cut off is picked up again after the restart."))}else console.log(he.green(` No tasks running${k.waitedMs>=1e3?` (waited ${Math.round(k.waitedMs/1e3)}s)`:""}.`))}let u=Pa(g,".agentx");try{lg(u,{by:"agentx daemon restart",pid:process.pid,at:new Date().toISOString()})}catch{}let h=Date.now(),y=parseInt(process.env.AGENTX_DRAIN_TIMEOUT_MS||"300000",10)+6e4;console.log(he.dim(" Restarting..."));for(let v of p.steps){if(await jy(v,{pid:c,daemonCwd:g,configPath:d,drainLimitMs:y,service:l})||v.kind==="exec"&&v.mayFail)continue;let x=v===p.steps[0];try{x&&Ty(Pa(u,cg))}catch{}console.log(he.red(` Step failed: ${Fm(v,c)}`)),console.log(x?he.dim(` The daemon is still running. Restart it with: ${p.manual}`):he.red(` The daemon may be down. Start it with: ${p.manual}`)),process.exit(1)}let $=12e4,b=Date.now();for(;Date.now()-b<$;){let v=await Pn(`${r}/health`);if(v&&typeof v.uptime=="number"&&v.uptime*1e3<=Date.now()-h+2e3){let A=await Pn(`${r}/daemon/restart`);console.log(he.green(` Daemon is back${A?.pid?` (PID ${A.pid})`:""} after ${Math.round((Date.now()-h)/1e3)}s.`)),console.log();return}await Ma(1e3)}console.log(he.red(` The daemon did not come back within ${$/6e4} min.`)),console.log(he.dim(` Start it with: ${p.manual}`)),console.log(he.dim(" Then check the log: agentx daemon logs")),process.exit(1)});function Fm(e,t){switch(e.kind){case"exec":return e.argv.join(" ");case"sigterm":return`kill -TERM ${t??"<pid>"} (the daemon finishes running tasks, then exits)`;case"wait-exit":return"wait for the old daemon to exit";case"wait-unloaded":return"wait until launchd has unloaded the job";case"start-detached":return"agentx daemon start --detach"}}async function jy(e,t){switch(e.kind){case"exec":return await Ny(e.argv)===0;case"sigterm":if(!t.pid)return!1;try{return process.kill(t.pid,"SIGTERM"),!0}catch{return!1}case"wait-exit":{if(!t.pid)return!0;let o=Date.now(),n=!1;for(;La(t.pid)&&Date.now()-o<t.drainLimitMs;)!n&&Date.now()-o>3e3&&(console.log(he.dim(" Waiting for the old daemon to finish its tasks and exit...")),n=!0),await Ma(500);return La(t.pid)?(console.log(he.yellow(` The old daemon (PID ${t.pid}) is still finishing tasks; not starting a second one.`)),!1):!0}case"wait-unloaded":{if(t.service.kind!=="launchd")return!0;let o=Date.now();for(;pa(t.service)&&Date.now()-o<3e4;)await Ma(500);return!pa(t.service)}case"start-detached":{let o=process.argv[1];if(!o||!Cy(o))return!1;let n=[o,"daemon","start","--detach",...t.configPath?["-c",t.configPath]:[]];return new Promise(s=>{let r=qm(process.execPath,n,{cwd:t.daemonCwd,stdio:"inherit"});r.on("error",()=>s(!1)),r.on("exit",i=>s(i===0))})}}}function Go(e,t){return new Intl.DateTimeFormat("sv-SE",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(new Date(e))}function Wm(e){let t=Math.max(0,Math.floor(e/1e3));return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h ${String(Math.floor(t%3600/60)).padStart(2,"0")}m`:`${Math.floor(t/86400)}d ${Math.floor(t%86400/3600)}h`}function _y(e){if(!e.service)return null;if(e.service.kind==="none")return"none (started from a terminal, nothing starts it again)";let t=e.service.kind==="launchd"?`launchd ${e.service.label}`:`systemd ${e.service.unit}`;if(!e.selfRestart)return t;let o=e.selfRestart.ok?e.selfRestart.how.match(/\(([^)]+)\)$/)?.[1]:null;return e.selfRestart.ok?`${t}${o?` (${o})`:""}`:`${t} (does not start it again by itself)`}function Bm(e,t,o,n){let s=(a,c)=>`${a.padEnd(16)}${c}`,r=[`AgentX ${e.version??"unknown version"}${e.commit?` (${e.commit})`:""} node ${e.node?.id??"unknown"}`];if(e.startedAt&&r.push(s("Running since",`${Go(e.startedAt,n)} (${n}), ${Wm(o-Date.parse(e.startedAt))} ago${e.pid?`, pid ${e.pid}`:""}`)),e.lastRestart){let a=e.lastRestart,c=a.by?`by ${a.by}${a.reason?` (${a.reason})`:""}`:a.reason?`on ${a.reason}, sender unknown`:"no clean stop on record before it";r.push(s("Last restart",a.previousBootAt?`${Go(a.at,n)} ${c}, previous boot ${Go(a.previousBootAt,n)}`:`${Go(a.at,n)}, first start on record`))}if(e.restarts){let a=e.restarts.since&&Date.parse(e.restarts.since)>o-6048e5?` (on record since ${Go(e.restarts.since,n)})`:"";r.push(s("Restarts",`${e.restarts.today} today, ${e.restarts.last7d} in the last 7 days${a}`))}if(e.build){let a=e.build,c=[a.version&&a.version!==e.version?a.version:null,a.changedAt?`written ${Go(a.changedAt,n)}`:null].filter(Boolean).join(", ");r.push(s("Build on disk",a.newer?`dist newer than process: yes${c?` (${c})`:""}, restart to load it`:"dist newer than process: no"))}let i=_y(t);return i&&r.push(s("Service",i)),r}function Jm(e){let t=ig(e).at(-1);return t?{at:new Date(t.at).toISOString(),by:t.by,reason:t.reason}:null}function Gm(e,t,o,n,s="refused"){return[`${s==="timeout"?"AgentX did not answer within 3 seconds":"AgentX is stopped"} node ${e}`,t?`${"Last boot".padEnd(16)}${Go(t.at,n)} (${n}), ${Wm(o-Date.parse(t.at))} ago`:`${"Last boot".padEnd(16)}none on record in this folder`]}async function Ly(e){try{let{execFileSync:t}=await import("child_process"),o=t("ps",["-p",String(e),"-o","command="],{encoding:"utf-8",timeout:2e3}).trim();return o?/\bnode\b/.test(o)||/agentx|agentix|cli\.js/.test(o):!1}catch{return!0}}var It=new Dy().name("daemon").description("manage the agentx daemon \u2014 start, stop, status, logs");It.command("start").description("start the daemon (default if no subcommand)").option("-c, --config <path>","path to agentx.json").option("-d, --detach","run in background (detached)").option("--port <port>","override bind port").action(async e=>{if(e.detach){let{spawn:l}=await import("child_process"),{openSync:g,writeFileSync:d,existsSync:f}=await import("fs"),p=process.argv[1];(!p||!f(p))&&(console.error(R.red(` Cannot resolve agentx CLI entrypoint (process.argv[1]=${p||"?"}).`)),console.error(R.dim(" Try running without --detach to see the underlying error.")),process.exit(1));let u=[p,"daemon","start"];e.config&&u.push("-c",e.config),e.port&&u.push("--port",e.port);let h="/tmp/agentx-daemon.log",y;try{y=g(h,"a")}catch(b){console.error(R.red(` Failed to open ${h} for writing: ${b.message}`)),process.exit(1)}let $=l(process.execPath,u,{detached:!0,stdio:["ignore",y,y],cwd:process.cwd()});$.unref(),d("/tmp/agentx-daemon.pid",String($.pid)),console.log(R.green(`Daemon started in background (PID: ${$.pid})`)),console.log(R.dim(` Logs: tail -f ${h}`)),console.log(R.dim(" Stop: agentx daemon stop")),await new Promise(b=>setTimeout(b,1e3));try{process.kill($.pid,0)}catch{console.log(),console.log(R.yellow(` Daemon exited within 1s \u2014 check ${h} for the error:`)),console.log(R.dim(` tail -n 40 ${h}`))}return}let{readFileSync:t,writeFileSync:o,mkdirSync:n,existsSync:s}=await import("fs"),{resolve:r}=await import("path"),i=r(process.cwd(),".agentx");s(i)||n(i,{recursive:!0});let a=r(i,"daemon.pid");if(s(a)){let l=parseInt(t(a,"utf-8").trim(),10);if(l&&l!==process.pid){let g=!1;try{process.kill(l,0),g=!0}catch{}g&&await Ly(l)&&(console.error(`Another agentx daemon is already running (PID ${l}). Exiting.`),process.exit(0))}}o(a,String(process.pid));try{Fy(r(process.cwd(),".env"))}catch{}await new Aa(e.config).start()});function Fy(e){if(!Py(e))return;let t=My(e,"utf-8");for(let o of t.split(`
12
- `)){let n=o.trim();if(!n||n.startsWith("#"))continue;let s=n.indexOf("=");if(s<0)continue;let r=n.slice(0,s).trim();if(!r||process.env[r]!==void 0)continue;let i=n.slice(s+1).trim();(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))&&(i=i.slice(1,-1)),process.env[r]=i}}It.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:t,unlinkSync:o}=await import("fs"),{resolve:n}=await import("path"),s=[n(process.cwd(),".agentx/daemon.pid"),"/tmp/agentx-daemon.pid"];for(let i of s)if(t(i))try{let a=parseInt(e(i,"utf-8").trim(),10);try{let{writeShutdownRequest:d}=await import("./shutdown-SNI2B4LI.js");d(n(process.cwd(),".agentx"),{by:"agentx daemon stop",pid:process.pid,at:new Date().toISOString()})}catch{}process.kill(a,"SIGTERM");let c=parseInt(process.env.AGENTX_DRAIN_TIMEOUT_MS||"300000",10)+6e4,l=Date.now(),g=!1;for(;Hm(a)&&Date.now()-l<c;)!g&&Date.now()-l>3e3&&(console.log(R.dim(` Waiting for in-flight tasks to finish (up to ${Math.round(c/6e4)} min)...`)),g=!0),await new Promise(d=>setTimeout(d,500));if(Hm(a)){console.log(R.yellow(`Daemon (PID: ${a}) is still finishing tasks. Check again with: agentx daemon status`));return}try{o(i)}catch{}console.log(R.green(`Daemon stopped (PID: ${a})`));return}catch{try{o(i)}catch{}}let{execSync:r}=await import("child_process");try{r("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(R.green("Daemon stopped"))}catch{console.log(R.yellow("No daemon process found"))}});It.addCommand(Um);It.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let t=O(e.config),[o,n]=t.node.bind.split(":"),s=`http://${o||"127.0.0.1"}:${n}/health`,i=await(await fetch(s,{signal:AbortSignal.timeout(3e3)})).json(),a={};try{let l=await fetch(`http://${o||"127.0.0.1"}:${n}/daemon/restart`,{signal:AbortSignal.timeout(3e3)});if(l.ok){let g=await l.json();a={service:g.service,selfRestart:g.selfRestart}}}catch{}if(e.json){console.log(JSON.stringify({...i,...a},null,2));return}console.log(),console.log(R.bold(` ${i.node.name}`)+R.dim(` (${i.node.id})`)),console.log(R.green(" Status: running")+R.dim(` \u2014 uptime ${qy(i.uptime)}`));for(let l of Bm(i,a,Date.now(),Intl.DateTimeFormat().resolvedOptions().timeZone))console.log(` ${l}`);console.log(),console.log(R.bold(" Agents:"));for(let l of i.agents){let g=l.active>0?R.yellow(` [${l.active} active]`):"",d=l.errors>0?R.red(` (${l.errors} errors)`):"";console.log(` ${R.cyan(l.name)} ${R.dim(`(${l.tier})`)}${g}${d}`),console.log(R.dim(` ${l.workspace}`))}let c=i.crons.filter(l=>l.enabled);if(i.crons.length){console.log(),console.log(R.bold(` Crons: ${c.length} enabled / ${i.crons.length} total`));for(let l of i.crons){let g=l.enabled?R.green("\u25CF"):R.dim("\u25CB"),d=l.nextRun?R.dim(` next: ${new Date(l.nextRun).toLocaleTimeString()}`):"";console.log(` ${g} ${l.id}${d}`)}}if(i.mesh?.length){console.log(),console.log(R.bold(" Mesh:"));for(let l of i.mesh){let g=l.healthy?R.green("\u25CF"):R.red("\u25CF"),d=l.skills?.length?R.dim(` (${l.skills.length} agents)`):"";console.log(` ${g} ${l.peer} ${R.dim(l.peerUrl)}${d}`)}}console.log()}catch(t){if(t.cause?.code==="ECONNREFUSED"||t.name==="TimeoutError"){let{resolve:o}=await import("path"),n=Jm(o(process.cwd(),".agentx")),s="unknown";try{s=O(e.config).node.id}catch{}let r=t.name==="TimeoutError"?"timeout":"refused";if(e.json){console.log(JSON.stringify({status:r==="timeout"?"not answering":"stopped",node:{id:s},lastBoot:n},null,2));return}let[i,...a]=Gm(s,n,Date.now(),Intl.DateTimeFormat().resolvedOptions().timeZone,r);console.log(R.red(` ${i}`));for(let c of a)console.log(` ${c}`);r==="refused"&&console.log(R.dim(" Start with: agentx daemon start"))}else try{let o=O(e.config),n=gr(o);if(console.log(),console.log(R.bold(` ${o.node.name}`)+R.dim(` (${o.node.id})`)),console.log(R.yellow(" Status: stopped")),console.log(R.dim(` ${Object.keys(o.agents).length} agents, ${Object.keys(o.crons).length} crons configured`)),n.length){console.log();for(let s of n)console.log(R.yellow(` \u26A0 ${s}`))}console.log()}catch(o){console.log(R.red(` ${o.message}`))}}});It.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:t,spawn:o}=await import("child_process"),n="/tmp/agentx-daemon.log",{existsSync:s}=await import("fs");if(!s(n)){console.log(R.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let r=o("tail",["-f","-n",e.lines,n],{stdio:"inherit"});process.on("SIGINT",()=>{r.kill(),process.exit(0)})}else t(`tail -n ${e.lines} ${n}`,{stdio:"inherit"})});It.command("watch").description("stream live agent activity (SSE)").option("-c, --config <path>","path to agentx.json").action(async e=>{let n=`http://${(O(e.config).node.bind||"127.0.0.1:18800").replace("0.0.0.0","127.0.0.1")}/events`;console.log(R.dim(` Connecting to ${n}...`)),console.log(R.dim(` Press Ctrl+C to stop
12
+ `)){let n=o.trim();if(!n||n.startsWith("#"))continue;let s=n.indexOf("=");if(s<0)continue;let r=n.slice(0,s).trim();if(!r||process.env[r]!==void 0)continue;let i=n.slice(s+1).trim();(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))&&(i=i.slice(1,-1)),process.env[r]=i}}It.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:t,unlinkSync:o}=await import("fs"),{resolve:n}=await import("path"),s=[n(process.cwd(),".agentx/daemon.pid"),"/tmp/agentx-daemon.pid"];for(let i of s)if(t(i))try{let a=parseInt(e(i,"utf-8").trim(),10);try{let{writeShutdownRequest:d}=await import("./shutdown-SNI2B4LI.js");d(n(process.cwd(),".agentx"),{by:"agentx daemon stop",pid:process.pid,at:new Date().toISOString()})}catch{}process.kill(a,"SIGTERM");let c=parseInt(process.env.AGENTX_DRAIN_TIMEOUT_MS||"300000",10)+6e4,l=Date.now(),g=!1;for(;Hm(a)&&Date.now()-l<c;)!g&&Date.now()-l>3e3&&(console.log(R.dim(` Waiting for in-flight tasks to finish (up to ${Math.round(c/6e4)} min)...`)),g=!0),await new Promise(d=>setTimeout(d,500));if(Hm(a)){console.log(R.yellow(`Daemon (PID: ${a}) is still finishing tasks. Check again with: agentx daemon status`));return}try{o(i)}catch{}console.log(R.green(`Daemon stopped (PID: ${a})`));return}catch{try{o(i)}catch{}}let{execSync:r}=await import("child_process");try{r("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(R.green("Daemon stopped"))}catch{console.log(R.yellow("No daemon process found"))}});It.addCommand(Um);It.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let t=O(e.config),[o,n]=t.node.bind.split(":"),s=`http://${o||"127.0.0.1"}:${n}/health`,i=await(await fetch(s,{signal:AbortSignal.timeout(3e3)})).json(),a={};try{let l=await fetch(`http://${o||"127.0.0.1"}:${n}/daemon/restart`,{signal:AbortSignal.timeout(3e3)});if(l.ok){let g=await l.json();a={service:g.service,selfRestart:g.selfRestart}}}catch{}if(e.json){console.log(JSON.stringify({...i,...a},null,2));return}console.log(),console.log(R.bold(` ${i.node.name}`)+R.dim(` (${i.node.id})`)),console.log(R.green(" Status: running")+R.dim(` \u2014 uptime ${qy(i.uptime)}`));for(let l of Bm(i,a,Date.now(),Intl.DateTimeFormat().resolvedOptions().timeZone))console.log(` ${l}`);i.gitlab?.warning&&console.log(R.red(` GitLab: ${i.gitlab.warning}`)),console.log(),console.log(R.bold(" Agents:"));for(let l of i.agents){let g=l.active>0?R.yellow(` [${l.active} active]`):"",d=l.errors>0?R.red(` (${l.errors} errors)`):"";console.log(` ${R.cyan(l.name)} ${R.dim(`(${l.tier})`)}${g}${d}`),console.log(R.dim(` ${l.workspace}`))}let c=i.crons.filter(l=>l.enabled);if(i.crons.length){console.log(),console.log(R.bold(` Crons: ${c.length} enabled / ${i.crons.length} total`));for(let l of i.crons){let g=l.enabled?R.green("\u25CF"):R.dim("\u25CB"),d=l.nextRun?R.dim(` next: ${new Date(l.nextRun).toLocaleTimeString()}`):"";console.log(` ${g} ${l.id}${d}`)}}if(i.mesh?.length){console.log(),console.log(R.bold(" Mesh:"));for(let l of i.mesh){let g=l.healthy?R.green("\u25CF"):R.red("\u25CF"),d=l.skills?.length?R.dim(` (${l.skills.length} agents)`):"";console.log(` ${g} ${l.peer} ${R.dim(l.peerUrl)}${d}`)}}console.log()}catch(t){if(t.cause?.code==="ECONNREFUSED"||t.name==="TimeoutError"){let{resolve:o}=await import("path"),n=Jm(o(process.cwd(),".agentx")),s="unknown";try{s=O(e.config).node.id}catch{}let r=t.name==="TimeoutError"?"timeout":"refused";if(e.json){console.log(JSON.stringify({status:r==="timeout"?"not answering":"stopped",node:{id:s},lastBoot:n},null,2));return}let[i,...a]=Gm(s,n,Date.now(),Intl.DateTimeFormat().resolvedOptions().timeZone,r);console.log(R.red(` ${i}`));for(let c of a)console.log(` ${c}`);r==="refused"&&console.log(R.dim(" Start with: agentx daemon start"))}else try{let o=O(e.config),n=gr(o);if(console.log(),console.log(R.bold(` ${o.node.name}`)+R.dim(` (${o.node.id})`)),console.log(R.yellow(" Status: stopped")),console.log(R.dim(` ${Object.keys(o.agents).length} agents, ${Object.keys(o.crons).length} crons configured`)),n.length){console.log();for(let s of n)console.log(R.yellow(` \u26A0 ${s}`))}console.log()}catch(o){console.log(R.red(` ${o.message}`))}}});It.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:t,spawn:o}=await import("child_process"),n="/tmp/agentx-daemon.log",{existsSync:s}=await import("fs");if(!s(n)){console.log(R.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let r=o("tail",["-f","-n",e.lines,n],{stdio:"inherit"});process.on("SIGINT",()=>{r.kill(),process.exit(0)})}else t(`tail -n ${e.lines} ${n}`,{stdio:"inherit"})});It.command("watch").description("stream live agent activity (SSE)").option("-c, --config <path>","path to agentx.json").action(async e=>{let n=`http://${(O(e.config).node.bind||"127.0.0.1:18800").replace("0.0.0.0","127.0.0.1")}/events`;console.log(R.dim(` Connecting to ${n}...`)),console.log(R.dim(` Press Ctrl+C to stop
13
13
  `));try{let s=await fetch(n);if(!s.ok||!s.body){console.log(R.red(` Failed: ${s.status}`));return}let r=s.body.getReader(),i=new TextDecoder,a="";for(;;){let{done:c,value:l}=await r.read();if(c)break;a+=i.decode(l,{stream:!0});let g=a.split(`
14
14
  `);a=g.pop()||"";for(let d of g)if(d.startsWith("data: "))try{let f=JSON.parse(d.slice(6)),p=new Date(f.time).toLocaleTimeString(),u=f.message?.replace(/^\[agentx\]\s*/,"")||"";u.includes("executing")?console.log(`${R.dim(p)} ${R.cyan("\u25B6")} ${u}`):u.includes("completed")?console.log(`${R.dim(p)} ${R.green("\u2713")} ${u}`):u.includes("error")||u.includes("Error")?console.log(`${R.dim(p)} ${R.red("\u2717")} ${u}`):u.includes("Routing")?console.log(`${R.dim(p)} ${R.yellow("\u2192")} ${u}`):u.includes("mention")?console.log(`${R.dim(p)} ${R.magenta("@")} ${u}`):u.includes("Skipping")?console.log(`${R.dim(p)} ${R.dim("\u2298")} ${R.dim(u)}`):console.log(`${R.dim(p)} ${u}`)}catch{}else d.startsWith("event: status")}}catch(s){console.log(R.red(` Connection failed: ${s.message}`)),console.log(R.dim(" Is the daemon running? Diagnostic order:")),console.log(R.dim(" 1) agentx daemon status # is the daemon up?")),console.log(R.dim(" 2) tail -n 60 /tmp/agentx-daemon.log # detach-mode crash log")),console.log(R.dim(" 3) journalctl -u agentx -n 60 # systemd-managed installs")),console.log(R.dim(" If the log file is missing, the daemon never started \u2014 re-run without --detach")),console.log(R.dim(" to see the error in the foreground."))}});It.command("send <agent> <message...>").description("send a task to an agent via the daemon API").option("-c, --config <path>","path to agentx.json").option("--peer <peer>","send to a mesh peer's agent").option("--json","output raw JSON response").action(async(e,t,o)=>{let n=t.join(" ");try{let s=O(o.config),[r,i]=s.node.bind.split(":"),a=`http://${r||"127.0.0.1"}:${i}`,c,l;o.peer?(c=`${a}/mesh/task`,l={peer:o.peer,message:n,agent:e}):(c=`${a}/task`,l={agent:e,message:n}),console.log(R.dim(` Sending to ${o.peer?`${o.peer}/${e}`:e}...`));let d=await(await fetch(c,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)})).json();o.json?console.log(JSON.stringify(d,null,2)):d.error?console.log(R.red(` Error: ${d.error}`)):(console.log(),console.log(d.content||d.response||"No response"),d.duration&&console.log(R.dim(`
15
15
  (${(d.duration/1e3).toFixed(1)}s)`)))}catch(s){console.log(R.red(` Failed: ${s.message}`)),console.log(R.dim(" Is the daemon running? Try: agentx daemon status"))}});It.command("deploy <host>").description("deploy agentx to a remote server via rsync").option("-i, --identity <key>","SSH identity file").option("-u, --user <user>","SSH user","root").option("-p, --path <path>","remote agentx path","~/agentx").option("--restart","restart remote daemon after deploy",!1).option("--skip-checks","skip build and test before deploy",!1).action(async(e,t)=>{let{execSync:o}=await import("child_process"),n=t.identity?`-e "ssh -i ${t.identity}"`:"",s=`${t.user}@${e}:${t.path}/dist/`;if(!t.skipChecks){try{console.log(R.dim(" Running tests...")),o("npx vitest run --reporter=dot",{stdio:"pipe",cwd:process.cwd()}),console.log(R.green(" \u2713 Tests passed"))}catch{console.log(R.red(" \u2717 Tests failed \u2014 aborting deploy")),console.log(R.dim(" Use --skip-checks to deploy anyway"));return}let{existsSync:r,statSync:i}=await import("fs"),{resolve:a}=await import("path"),c=a(process.cwd(),"dist/cli.js");if(!r(c)){console.log(R.red(" \u2717 dist/ not found \u2014 run build first"));return}Date.now()-i(c).mtimeMs>3e5&&(console.log(R.yellow(" \u26A0 dist/ is older than 5 minutes \u2014 rebuilding...")),o("npx tsup --no-dts",{stdio:"pipe",cwd:process.cwd()}),console.log(R.green(" \u2713 Build complete")))}console.log(R.dim(` Deploying to ${t.user}@${e}:${t.path}...`));try{if(o(`rsync -avzL --delete ${n} dist/ ${s}`,{stdio:"inherit",cwd:process.cwd()}),console.log(R.green(" \u2713 Deploy complete")),t.restart){console.log(R.dim(" Restarting remote daemon once no task is running..."));let r=t.identity?`ssh -i ${t.identity}`:"ssh";o(`${r} -t ${t.user}@${e} "cd ${t.path} && node dist/cli.js daemon restart --when-idle"`,{stdio:"inherit"}),console.log(R.green(" Remote daemon restarted"))}}catch(r){console.log(R.red(` Deploy failed: ${r.message}`))}});It.action(async e=>{await new Aa(e.config).start()});function qy(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h ${Math.round(e%3600/60)}m`:`${Math.round(e/86400)}d ${Math.round(e%86400/3600)}h`}function Hm(e){try{return process.kill(e,0),!0}catch(t){return t?.code==="EPERM"}}import{Command as Uy}from"commander";import Rt from"chalk";import{existsSync as Os,readFileSync as Wy,writeFileSync as zm,mkdirSync as Ym}from"fs";import{hostname as Vm}from"os";import{resolve as Mn}from"path";var Xm=new Uy().name("init").description("initialize agentx configuration in the current directory").option("--force","overwrite existing config").action(async e=>{let t=process.cwd(),o=Mn(t,"agentx.json"),n=Mn(t,".env"),s=Mn(t,".agentx/sessions");if(console.log(),console.log(Rt.bold(" agentx init")),console.log(),Os(o)&&!e.force){console.log(Rt.yellow(" agentx.json already exists. Use --force to overwrite.")),console.log();return}let r=[Mn(t,"agentx.example.json"),Mn(t,"node_modules/agentix-cli/agentx.example.json")],i;for(let c of r)if(Os(c)){i=Wy(c,"utf-8");break}i||(i=JSON.stringify({node:{id:Vm().toLowerCase().replace(/[^a-z0-9-]/g,"-"),name:Vm(),bind:"127.0.0.1:18800"},providers:{claude:{apiKey:"${ANTHROPIC_API_KEY}"}},agents:{assistant:{name:"Assistant",workspace:t,tier:"claude-code",model:"claude-sonnet-4-6",mentions:["@assistant","assistant"],maxConcurrent:2,systemPrompt:"You are a helpful assistant.",permissionMode:"default"}},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}}},null,2)),zm(o,i),console.log(Rt.green(" \u2713 Created agentx.json")),Os(n)||(zm(n,["# AgentX environment variables","# ANTHROPIC_API_KEY=sk-ant-...","# TG_BOT_TOKEN=123456:ABC...","# MESH_TOKEN=your-mesh-secret",""].join(`
@@ -493,7 +493,7 @@ return aid ?? null`}function tk(e,t){if(e.kind==="path"){let s=e.pts,r=s[Math.fl
493
493
  Plan ${V.dim(`[${s.state}] by ${s.createdBy}, ${Qn(s.createdAt)}`)}`),gf(n.steps(e)),console.log(`
494
494
  Log`);for(let r of n.events(e))console.log(V.dim(` ${Qn(r.at)} ${r.step?`step ${r.step} `:""}${r.kind}: ${r.detail}`))}});mn.command("step <id> <step>").description("move a step of a request's plan on: --retry, --skip or --done").option("--retry","hand the step to its agent again, with a fresh count of nudges (approves a message whose card expired)").option("--skip","leave the step out; the plan goes on with the next one").option("--done","mark the step done yourself").option("--note <text>","why, or the evidence for --done").action((e,t,o)=>{let n=["retry","skip","done"].filter(c=>o[c]);if(n.length!==1){console.error(V.red(" give one of --retry, --skip or --done")),process.exitCode=1;return}let s=xi();if(!s)return;let r=df();if(!r){process.exitCode=1;return}let i=Number(t),a=sg(s,r,{requestId:e,step:i,action:n[0],detail:o.note},Date.now());if(a){console.error(V.red(` ${a}`)),process.exitCode=1;return}console.log(V.green(` \u2713 step ${i} of ${e}: ${n[0]==="retry"?"handed over again":n[0]==="skip"?"skipped":"done"}`)+V.dim(" (the daemon goes on within a minute)")),gf(r.steps(e))});function uf(e,t,o,n){mn.command(`${e} <id>`).description(t).option(o,e==="done"?"link to the proof: PR, issue, message, deploy":"why it is dropped").action((s,r)=>{let i=xi();if(!i)return;let a=e==="done"?r.evidence:r.reason??"dropped by the owner";if(!a){console.error(V.red(` ${n}`)),process.exitCode=1;return}let c=i.get(s);if(!c||c.state==="candidate"){console.error(V.red(` no request "${s}"`)),process.exitCode=1;return}if(!i.close(s,e==="done"?"done":"dropped",a,Date.now())){console.error(V.red(` ${s} is already closed (${lf[c.state]??c.state})`)),process.exitCode=1;return}console.log(V.green(` \u2713 ${s} ${e==="done"?"closed as done":"dropped"}`))})}uf("done","close a request as finished, with a link to the evidence","--evidence <link>","a finished request needs --evidence <link>");uf("drop","drop a request you no longer want","--reason <text>","");mn.command("settings").description("show or change the requests settings").option("--enabled <on|off>","record and follow your requests").option("--from <id,...>",'who counts as you on channels other people can reach, as channel:id (your login on GitLab and GitHub, your sender id elsewhere); "none" to clear').option("--channels <name,...>",'channels to record on; "all" for every channel a person writes on').option("--stale-hours <n>","hours without activity before an open request comes back to you").option("--retention-days <n>","days a closed request is kept").option("--plans <on|off>","follow requests of two or more steps as tracked plans").option("--stall-minutes <n>","minutes without progress before a plan step's agent is nudged").option("--max-nudges <n>","nudges per step before it counts as blocked and you are told").option("--approve-kinds <kind,...>",'step kinds you approve once when the plan is made; "none" to clear').option("--plans-off-for <agent,...>",'agents that may not open a plan; "none" to clear').action(async e=>{let t={};try{let s=(a,c)=>{if(c===void 0)return;let l=Number(c);if(!(l>0))throw new Error(`${a} must be a positive number`);return l},r=(a,c)=>a===void 0?void 0:a===c?[]:a.split(",").map(l=>l.trim()).filter(Boolean);if(e.enabled!==void 0){if(e.enabled!=="on"&&e.enabled!=="off")throw new Error("--enabled takes on or off");t.enabled=e.enabled==="on"}t.from=r(e.from,"none"),t.channels=r(e.channels,"all"),t.staleAfterHours=s("--stale-hours",e.staleHours),t.retentionDays=s("--retention-days",e.retentionDays);let i={};if(e.plans!==void 0){if(e.plans!=="on"&&e.plans!=="off")throw new Error("--plans takes on or off");i.enabled=e.plans==="on"}if(i.stallMinutes=s("--stall-minutes",e.stallMinutes),e.maxNudges!==void 0){let a=Number(e.maxNudges);if(!Number.isInteger(a)||a<0)throw new Error("--max-nudges must be a whole number, 0 or more");i.maxNudges=a}i.approveKinds=r(e.approveKinds,"none"),i.disabledAgents=r(e.plansOffFor,"none"),Object.values(i).some(a=>a!==void 0)&&(t.plans=i)}catch(s){console.error(V.red(` ${s.message}`)),process.exitCode=1;return}if(Object.values(t).some(s=>s!==void 0)){let s=await tg(t);if(!s.success){console.error(V.red(` ${s.error}`)),process.exitCode=1;return}console.log(V.green(" \u2713 saved")+(s.reloaded?V.dim(" (daemon reloaded)"):""))}let o=ua();console.log(` Requests ${o.enabled?"on":"off"}`),console.log(` Channels ${o.channels.length?o.channels.join(", "):"every channel a person writes on"}`),console.log(` Counts as you ${o.from.length?o.from.join(", "):"only voice, the app and the dashboard on this machine"}`),console.log(` Comes back after ${o.staleAfterHours} hour(s) without activity`),console.log(` Closed requests kept ${o.retentionDays} day(s)`);let n=o.plans??ng;console.log(` Plans ${n.enabled?"on":"off"}`),console.log(` Nudge a quiet step after ${n.stallMinutes} minute(s), up to ${n.maxNudges} time(s)`),console.log(` You approve up front ${n.approveKinds.length?n.approveKinds.join(", "):"nothing"}`),console.log(` Plans off for ${n.disabledAgents.length?n.disabledAgents.join(", "):"no agent"}`)});import{Command as Ev}from"commander";import Zn from"chalk";le();var pf=new Ev("request-status").description("show each person the state of their request in the thread where they asked (GitLab, GitHub)").argument("[channel]",Oa.join(" or ")).argument("[state]","on or off").action(async(e,t)=>{if(e!==void 0){t!=="on"&&t!=="off"&&(console.error(Zn.red("\u2717 say on or off, for example: agentx request-status gitlab on")),process.exit(1));let n="",s=await ge(r=>{n=am(r,e,t==="on")});s.success||(console.error(Zn.red(`\u2717 ${s.error}`)),process.exit(1)),console.log(Zn.green(`\u2713 ${n}`)),s.reloaded&&console.log(Zn.dim(" daemon hot-reloaded"))}let o=O().requestStatus.channels.map(n=>n.toLowerCase());for(let n of Oa)console.log(` ${n.padEnd(8)} ${o.includes(n)?Zn.green("on"):Zn.dim("off")}`)});import{Command as Vv}from"commander";import es from"chalk";import ye from"chalk";import zs from"prompts";import{readFileSync as Cv,writeFileSync as Ov,existsSync as Tv}from"fs";import{resolve as ff}from"path";var Iv=/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;function Rv(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function jc(e){return/[\s#"'\\]/.test(e)||e===""?JSON.stringify(e):e}function hf(e=".env"){let t=ff(e);if(!Tv(t))return[];let o=Cv(t,"utf-8"),n=[];for(let s of o.split(/\r?\n/)){if(s.trim()===""){n.push({kind:"blank",raw:s});continue}if(s.trim().startsWith("#")){n.push({kind:"comment",raw:s});continue}let r=s.match(Iv);r?n.push({kind:"kv",key:r[1],value:Rv(r[2]),raw:s}):n.push({kind:"comment",raw:s})}return n.length&&n[n.length-1].kind==="blank"&&n.pop(),n}function Nv(e){return e.map(t=>t.kind==="kv"?`${t.key}=${jc(t.value)}`:t.raw).join(`
495
495
  `)+`
496
- `}function Hs(e,t,o=".env"){let n=ff(o),s=hf(n),r=s.findIndex(i=>i.kind==="kv"&&i.key===e);r>=0?s[r]={kind:"kv",key:e,value:t,raw:`${e}=${jc(t)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:t,raw:`${e}=${jc(t)}`})),Ov(n,Nv(s))}function _c(e,t=".env"){return hf(t).find(s=>s.kind==="kv"&&s.key===e)?.value}var yf="https://t.me/BotFather";async function jv(e){try{let t=await fetch(`https://api.telegram.org/bot${e}/getMe`,{signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;let o=await t.json();return o?.ok?o.result:null}catch{return null}}async function _v(e,t){let o=Date.now()+t,n=0;try{let r=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=-1&timeout=0`,{signal:AbortSignal.timeout(5e3)})).json();r?.result?.length&&(n=r.result[0].update_id+1)}catch{}for(;Date.now()<o;)try{let r=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=${n}&timeout=10`,{signal:AbortSignal.timeout(15e3)})).json();for(let i of r?.result||[]){n=Math.max(n,i.update_id+1);let a=i.message||i.edited_message||i.channel_post;if(a?.chat?.id)return{chatId:a.chat.id,chatTitle:a.chat.title||a.chat.username||a.chat.first_name,from:a.from?.first_name||a.from?.username||"unknown"}}}catch{}return null}async function wf(e={}){console.log(),console.log(ye.bold(" Connect Telegram")),console.log(),console.log(ye.dim(` 1. Open ${yf}`)),console.log(ye.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(ye.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{wantsBrowser:t}=await zs({type:"confirm",name:"wantsBrowser",message:"Open BotFather in your browser?",initial:!0});t&&Ho(yf);let{token:o}=await zs({type:"password",name:"token",message:"Paste the bot token from BotFather:",validate:b=>/^\d+:[A-Za-z0-9_-]{20,}$/.test(b.trim())||"That doesn't look like a Telegram token"});o||(console.log(ye.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await jv(o.trim());n||(console.log(ye.red("\u2717 invalid or revoked")),process.exit(1)),console.log(ye.green(`\u2713 ${n.first_name} (@${n.username})`));let{readFileSync:s,existsSync:r}=await import("fs"),{resolve:i}=await import("path"),a=e.configPath||i(process.cwd(),"agentx.json");r(a)||(console.log(ye.red(` No agentx.json at ${a}. Run: agentx init`)),process.exit(1));let c=JSON.parse(s(a,"utf-8")),l=Object.keys(c.agents||{});l.length===0&&(console.log(ye.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await zs({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:l.map(v=>({title:v,value:v})),initial:0})).agent),g||(console.log(ye.red(" Aborted")),process.exit(1));let d=c.channels?.telegram?.accounts||{},f=e.account||g;d[f]&&d[f].agentBinding!==g&&(f=(await zs({type:"text",name:"account",message:`Account "${f}" is already in use. Pick a different label:`,initial:`${g}-2`,validate:v=>/^[a-z0-9-]+$/i.test(v)||"lowercase letters, digits, hyphens only"})).account),f||(console.log(ye.red(" Aborted")),process.exit(1));let p=`TG_${f.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Hs(p,o.trim()),process.env[p]=o.trim();let u=await ge(b=>{We(b,"channels.telegram.enabled",!0),We(b,`channels.telegram.accounts.${f}`,{token:`\${${p}}`,agentBinding:g});let v=Tn(b,`agents.${g}.mentions`)||[],A=`@${n.username}`;v.includes(A)||(v.push(A),We(b,`agents.${g}.mentions`,v))},{configPath:e.configPath});if(u.success||(console.log(ye.red(` \u2717 ${u.error}`)),process.exit(1)),console.log(),console.log(ye.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(ye.dim(` Token stored in .env as ${p}`)),console.log(ye.dim(` Mentions updated to include @${n.username}`)),u.reloaded?console.log(ye.dim(" Daemon hot-reloaded.")):console.log(ye.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:h}=await zs({type:"confirm",name:"capture",message:"Listen for a message so we can set this as your default --notify target?",initial:!0});if(!h)return;console.log(),console.log(ye.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(ye.dim(" Waiting up to 90s..."));let y=await _v(o.trim(),9e4);if(!y){console.log(ye.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(ye.dim(" agentx config set notifications.destination.channel telegram")),console.log(ye.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(ye.dim(` agentx config set notifications.destination.accountId ${f}`));return}let $=await ge(b=>{We(b,"notifications.destination",{channel:"telegram",chatId:String(y.chatId),accountId:f})},{configPath:e.configPath});if(!$.success){console.log(ye.red(` \u2717 failed to save destination: ${$.error}`));return}console.log(ye.green(" \u2713 Default --notify target set")),console.log(ye.dim(` Chat: ${y.chatTitle||y.chatId} (from ${y.from})`)),console.log(ye.dim(" From now on, --notify me resolves to this chat.")),$.reloaded&&console.log(ye.dim(" Daemon hot-reloaded."))}import Ce from"chalk";import Dc from"prompts";import{existsSync as Mc,mkdirSync as Dv,readdirSync as Pv,readFileSync as $f}from"fs";import{resolve as Pc}from"path";var Mv=".agentx/whatsapp-sessions";function Lv(){let e=Pc(process.cwd(),".agentx/daemon.pid");if(!Mc(e))return!1;try{let t=parseInt($f(e,"utf-8").trim(),10);return t?(process.kill(t,0),!0):!1}catch{return!1}}function Fv(e){if(!Mc(e))return!1;try{return Pv(e).some(t=>t.includes("creds")||t.endsWith(".json"))}catch{return!1}}async function qv(e,t){let o;try{o=await import("@whiskeysockets/baileys")}catch{return t(Ce.red(" WhatsApp pairing needs @whiskeysockets/baileys.")),t(Ce.red(" Install with: pnpm add @whiskeysockets/baileys (or npm install)")),!1}let{makeWASocket:n,useMultiFileAuthState:s}=o.default||o;Dv(e,{recursive:!0});let{state:r,saveCreds:i}=await s(e),a;try{a=(await o.fetchLatestBaileysVersion()).version}catch{}let c={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:()=>{},child:()=>c},l=n({auth:{creds:r.creds,keys:o.makeCacheableSignalKeyStore?o.makeCacheableSignalKeyStore(r.keys,c):r.keys},...a?{version:a}:{},logger:c,printQRInTerminal:!1,browser:["agentx-connect","pairing","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1});return l.ev.on("creds.update",i),await new Promise(g=>{let f=setTimeout(()=>{t(Ce.yellow(" Timed out waiting for scan (2min)."));try{l.end(void 0)}catch{}g(!1)},12e4);l.ev.on("connection.update",async p=>{if(p.qr){t(Ce.dim(" Scan this QR with WhatsApp \u2192 Linked devices \u2192 Link a device:")),t("");try{let{default:u}=await import("qrcode-terminal");u.generate(p.qr,{small:!0})}catch{t(` QR: ${p.qr}`)}t("")}if(p.connection==="open"){clearTimeout(f),t(Ce.green(" \u2713 Paired"));try{l.end(void 0)}catch{}g(!0)}p.connection==="close"&&!p.qr&&p.lastDisconnect?.error?.output?.statusCode===401&&(clearTimeout(f),t(Ce.red(" \u2717 Authorization failed \u2014 rescan required")),g(!1))})})}async function bf(e={}){if(console.log(),console.log(Ce.bold(" Connect WhatsApp")),console.log(),Lv()){console.log(Ce.yellow(" \u26A0 The daemon is running. Stop it first so pairing can open a fresh Baileys session:")),console.log(Ce.dim(" agentx daemon stop")),console.log();let{cont:l}=await Dc({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});l||(console.log(Ce.red(" Aborted")),process.exit(1))}let t=e.configPath||Pc(process.cwd(),"agentx.json");Mc(t)||(console.log(Ce.red(` No agentx.json at ${t}. Run: agentx init`)),process.exit(1));let o=JSON.parse($f(t,"utf-8")),n=e.sessionDir||o.channels?.whatsapp?.sessionDir||Mv,s=Pc(process.cwd(),n),r=Object.keys(o.agents||{});r.length===0&&(console.log(Ce.red(" No agents configured. Run: agentx agent add")),process.exit(1));let i=e.agent;i||(i=(await Dc({type:"select",name:"agent",message:"Default agent for incoming messages:",choices:r.map(g=>({title:g,value:g})),initial:0})).agent),i||(console.log(Ce.red(" Aborted")),process.exit(1));let a=!e.skipPair;if(Fv(s)&&a){let{keep:l}=await Dc({type:"confirm",name:"keep",message:`An existing session was found at ${n}. Keep it (recommended), or pair again?`,initial:!0});a=!l,l&&console.log(Ce.dim(" Keeping existing session \u2014 skipping QR pair."))}a&&(await qv(s,g=>console.log(g))||(console.log(Ce.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await ge(l=>{We(l,"channels.whatsapp.enabled",!0),We(l,"channels.whatsapp.sessionDir",n),We(l,"channels.whatsapp.defaultAgent",i)},{configPath:e.configPath});c.success||(console.log(Ce.red(` \u2717 ${c.error}`)),process.exit(1)),console.log(),console.log(Ce.green(` \u2713 WhatsApp bound to agent "${i}"`)),console.log(Ce.dim(` Session: ${n}`)),console.log(Ce.dim(" Start the daemon to begin receiving:")),console.log(Ce.dim(" agentx daemon start")),console.log(Ce.yellow(" No chat is answered until you list the allowed numbers (add your own to talk from your self-chat):")),console.log(Ce.dim(` agentx config set channels.whatsapp.allowFrom '["+15550001111"]'`)),console.log(Ce.dim(" Add routes later with:")),console.log(Ce.dim(` agentx config set channels.whatsapp.routes '[{"contact":"+1234567890","agent":"${i}"}]'`)),console.log()}import{randomBytes as Uv}from"crypto";import Fe from"chalk";import kf from"prompts";var Si="agentx-mesh:",Ai="//join/";function Wv(e){return Buffer.from(e,"utf-8").toString("base64url")}function Bv(e){return Buffer.from(e,"base64url").toString("utf-8")}function Jv(e){return`${Si}${Ai}${Wv(JSON.stringify(e))}`}function Gv(e){if(!e.startsWith(`${Si}${Ai}`))throw new Error(`Not a mesh invite link \u2014 expected ${Si}${Ai}\u2026`);let t=e.slice(Si.length+Ai.length),o=JSON.parse(Bv(t));if(o.version!==1)throw new Error(`Unsupported invite version: ${o.version}`);if(typeof o.url!="string"||typeof o.token!="string"||typeof o.name!="string")throw new Error("Invite payload missing required fields (url, token, name)");return o}function Hv(){return Uv(32).toString("hex")}function zv(e){let t=e?.node?.bind||"127.0.0.1:18800",[o,n]=t.split(":");return`http://${o}:${n}`}function Yv(e){return e?.node?.name||e?.node?.id||"node"}async function vf(e){let{readFileSync:t,existsSync:o}=await import("fs"),{resolve:n}=await import("path"),s=e.configPath||n(process.cwd(),"agentx.json");o(s)||(console.log(Fe.red(` No agentx.json at ${s}. Run: agentx init`)),process.exit(1));let r=JSON.parse(t(s,"utf-8")),i=_c("MESH_TOKEN");i||(i=Hv(),Hs("MESH_TOKEN",i),console.log(Fe.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||zv(r);if((a.includes("0.0.0.0")||a.includes("127.0.0.1")||a.includes("localhost"))&&!e.url){let{url:d}=await kf({type:"text",name:"url",message:"This node's URL as peers should reach it (e.g. http://100.x.x.x:18800):",initial:a,validate:f=>/^https?:\/\//.test(f)||"must start with http:// or https://"});d||(console.log(Fe.red(" Aborted")),process.exit(1)),a=d}let l=await ge(d=>{We(d,"mesh.enabled",!0)},{configPath:e.configPath});l.success||(console.log(Fe.red(` \u2717 ${l.error}`)),process.exit(1));let g=Jv({url:a,token:i,name:Yv(r),version:1});console.log(),console.log(Fe.bold(" Mesh invite")),console.log(),console.log(` ${Fe.cyan(g)}`),console.log(),console.log(Fe.dim(" Run on the other node:")),console.log(Fe.dim(` agentx connect mesh join "${g}"`)),console.log(),console.log(Fe.yellow(" Share over a trusted channel only \u2014 whoever holds this link can join your mesh.")),console.log()}async function xf(e,t={}){let o;try{o=Gv(e)}catch(r){console.log(Fe.red(` \u2717 ${r.message}`)),process.exit(1)}let n=_c("MESH_TOKEN");if(n&&n!==o.token){let{overwrite:r}=await kf({type:"confirm",name:"overwrite",message:"A different MESH_TOKEN already exists in .env. Overwrite with the invite's token?",initial:!1});r||(console.log(Fe.red(" Aborted (keeping existing .env)")),process.exit(1))}Hs("MESH_TOKEN",o.token);let s=await ge(r=>{We(r,"mesh.enabled",!0);let i=Tn(r,"mesh.peers")||[],a=i.findIndex(l=>l.name===o.name),c={name:o.name,url:o.url,token:"${MESH_TOKEN}"};a>=0?i[a]=c:i.push(c),We(r,"mesh.peers",i)},{configPath:t.configPath});s.success||(console.log(Fe.red(` \u2717 ${s.error}`)),process.exit(1)),console.log(Fe.green(" \u2713 Joined mesh")),console.log(Fe.dim(` Peer: ${o.name} @ ${o.url}`)),console.log(Fe.dim(" Shared token stored in .env as MESH_TOKEN")),s.reloaded?console.log(Fe.dim(" Daemon hot-reloaded.")):console.log(Fe.dim(" Restart the daemon to start the mesh (agentx daemon start).")),console.log();try{let r=await fetch(`${o.url.replace(/\/$/,"")}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)});if(r.ok){let i=await r.json(),a=Array.isArray(i.agents)?i.agents.length:"?";console.log(Fe.dim(` Reachable \u2014 ${o.name} exposes ${a} agents`))}else console.log(Fe.yellow(` Peer returned HTTP ${r.status} \u2014 double-check the URL`))}catch(r){console.log(Fe.yellow(` Could not reach ${o.url} right now (${r?.cause?.code||r.message}) \u2014 verify VPN / Tailscale when the peer daemon is up`))}}var ts=new Vv().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");ts.command("telegram").description("pair a Telegram bot \u2014 persists token in .env, binds to an agent, auto-detects default chat").option("--agent <id>","agent to bind the bot to (skips the prompt)").option("--account <name>","account label in channels.telegram.accounts (defaults to agent id)").option("--skip-chat-capture","don't listen for the first message after pairing").option("-c, --config <path>","path to agentx.json").action(async e=>{await wf({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});ts.command("whatsapp").description("pair WhatsApp via QR (prints in terminal), then writes channels.whatsapp config").option("--agent <id>","default agent for inbound messages").option("--session-dir <path>","session directory (default: .agentx/whatsapp-sessions)").option("--skip-pair","skip QR pairing (use when session already exists)").option("-c, --config <path>","path to agentx.json").action(async e=>{await bf({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var Sf=ts.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");Sf.command("invite").description("emit a single-use join link for another AgentX node").option("--url <url>","this node's URL as peers should reach it (Tailscale IP etc.)").option("-c, --config <path>","path to agentx.json").action(async e=>{await vf({url:e.url,configPath:e.config})});Sf.command("join <link>").description("accept an invite link from another AgentX node").option("-c, --config <path>","path to agentx.json").action(async(e,t)=>{await xf(e,{configPath:t.config})});ts.action(()=>{console.log(),console.log(es.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${es.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${es.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${es.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${es.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(es.dim(" GitLab connect is the next slice.")),console.log()});le();import{Command as Xv}from"commander";import te from"chalk";var un=new Xv().name("usage").description("token usage analysis and reporting");un.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=O(),[t,o]=e.node.bind.split(":"),s=await(await fetch(`http://${t||"127.0.0.1"}:${o}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(te.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(te.dim(" No tasks recorded yet")),console.log();return}let r=a=>a.toLocaleString();console.log(` Total: ${te.bold(r(s.totalTokens))} tokens across ${s.totalTasks} tasks`),console.log(` Input: ${r(s.totalInput)}`),console.log(` Output: ${r(s.totalOutput)}`),console.log(` Cache read: ${r(s.totalCacheRead)}`),console.log(` Cache create: ${r(s.totalCacheCreate)}`),s.cacheHitRatio>0&&console.log(` Cache hit: ${(s.cacheHitRatio*100).toFixed(1)}%`),s.totalErrors>0&&console.log(` Errors: ${te.red(String(s.totalErrors))}`),console.log(),console.log(te.bold(" By Agent:"));let i=Object.entries(s.byAgent||{});i.sort((a,c)=>c[1].total-a[1].total);for(let[a,c]of i){let l=r(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${te.cyan(a)}: ${l} tokens (${c.tasks} tasks) ${te.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(te.red(" Daemon not running. Start with: agentx daemon start")):console.log(te.red(` ${e.message}`))}});un.command("plan").description("show the Claude plan windows as Claude Code last reported them, and any hold on fresh sessions").option("--lift","lift the hold on fresh sessions now, without waiting for the reset time").option("--json","raw JSON output").action(async e=>{try{let t=O(),[o,n]=t.node.bind.split(":"),s=`http://${o||"127.0.0.1"}:${n}`,r=e.lift?await fetch(`${s}/usage/plan/lift`,{method:"POST",signal:AbortSignal.timeout(3e3)}):await fetch(`${s}/usage/plan`,{signal:AbortSignal.timeout(3e3)});if(!r.ok)throw new Error(`Daemon answered ${r.status}. It may be older than this command; restart it.`);let i=await r.json();if(e.json){console.log(JSON.stringify(i,null,2));return}let a=d=>d.replace(/_/g," ");if(console.log(),e.lift){let d=i.lifted.map(f=>a(f.window));console.log(d.length?` Lifted the hold on: ${d.join(", ")}. The next fresh session asks Claude again.`:te.dim(" No hold to lift.")),console.log();return}let c=i.now,l=new Set(i.holds.map(d=>d.window));console.log(te.bold(" Claude plan (as Claude Code last reported it)")),console.log(),i.provider.length===0&&console.log(te.dim(" No report yet. Claude Code reports on each turn; the list is empty after a daemon restart."));for(let d of i.provider){let f=d.usingOverage?"extra usage":d.status==="allowed_warning"?"nearly full":d.status,p=typeof d.utilization=="number"?`${Math.round(d.utilization*100)}% used`:"",u=Math.max(1,Math.round((d.resetsAt-c)/6e4)),h=d.resetsAt>c?u<60?`resets in ${u} min`:u<48*60?`resets in ${Math.round(u/60)} h`:`resets in ${Math.round(u/1440)} days`:"",y=l.has(d.window)?te.red("holding fresh sessions"):"";console.log(` ${a(d.window).padEnd(18)} ${f.padEnd(12)} ${[p,h,y].filter(Boolean).join(", ")}`)}console.log();let g=d=>d?` of ${d}`:"";console.log(` Fresh sessions started: ${i.lastHour}${g(i.maxPerHour)} in the last hour, ${i.last5h}${g(i.maxPer5h)} in the last 5 hours`),l.size&&console.log(te.dim(" To try again now: agentx usage plan --lift")),console.log()}catch(t){t.cause?.code==="ECONNREFUSED"?console.log(te.red(" Daemon not running. Start with: agentx daemon start")):console.log(te.red(` ${t.message}`))}});un.command("report").description("run full session analysis (parses Claude Code JSONL files)").option("--days <n>","analyze last N days","7").action(async e=>{let{execSync:t}=await import("child_process"),{existsSync:o}=await import("fs"),{resolve:n}=await import("path"),s=n(process.cwd(),"scripts/token-report.py");if(!o(s)){console.log(te.red(` Script not found: ${s}`)),console.log(te.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(te.dim(" Analyzing Claude Code sessions..."));try{t(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(te.red(" Analysis failed. Is Python 3 installed?"))}});un.command("channels").description("cost per channel over a fixed range of days, next to a saved baseline").requiredOption("--from <date>","first day, YYYY-MM-DD").requiredOption("--to <date>","last day, YYYY-MM-DD").option("--save <file>","write this range's figures to a JSON file").option("--baseline <file>","a file written by --save, shown beside this range").option("--json","raw JSON output").action(async e=>{let{readFileSync:t,writeFileSync:o}=await import("fs"),{TokenTracker:n}=await import("./token-tracker-W7DFDEFN.js"),{channelCosts:s,costPerTask:r}=await import("./usage-channels-KBLEC4NE.js"),i=u=>/^\d{4}-\d{2}-\d{2}$/.test(u)&&!Number.isNaN(Date.parse(u));if(!i(e.from)||!i(e.to)||e.from>e.to){console.log(te.red(" --from and --to must be YYYY-MM-DD, with --from not after --to")),process.exitCode=1;return}let a=s(new n,e.from,e.to);e.save&&o(e.save,JSON.stringify(a,null,2));let c=null;if(e.baseline)try{c=JSON.parse(t(e.baseline,"utf-8"))}catch(u){console.log(te.red(` Cannot read baseline ${e.baseline}: ${u.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify(c?{baseline:c,current:a}:a,null,2));return}let l=u=>u===null?"-":`$${u.toFixed(u<10?3:2)}`,g=u=>`${(u/1e6).toFixed(1)}M`;console.log(),console.log(te.bold(` Cost per channel, ${a.from} to ${a.to} (${a.days} day(s) with data)`)),c&&console.log(te.dim(` Baseline: ${c.from} to ${c.to} (${c.days} day(s) with data)`)),console.log();let d=` ${"channel".padEnd(14)} ${"tasks".padStart(6)} ${"cache read".padStart(11)} ${"cache write".padStart(11)} ${"output".padStart(8)} ${"cost".padStart(10)} ${"per task".padStart(9)}`;console.log(te.dim(c?`${d} ${"baseline".padStart(9)} ${"change".padStart(7)}`:d));let p=[...new Set([...Object.keys(a.channels),...Object.keys(c?.channels||{})])].map(u=>[u,a.channels[u],c?.channels[u]]).sort((u,h)=>(h[1]?.cost||0)-(u[1]?.cost||0));p.push(["TOTAL",a.total,c?.total]);for(let[u,h,y]of p){let $=r(h),b=` ${u.padEnd(14)} ${String(h?.tasks||0).padStart(6)} ${g(h?.cacheRead||0).padStart(11)} ${g(h?.cacheCreate||0).padStart(11)} ${g(h?.output||0).padStart(8)} ${l(h?.cost||0).padStart(10)} ${l($).padStart(9)}`;if(c){let v=r(y),A=$!==null&&v?`${(($-v)/v*100).toFixed(0)}%`:"-";b+=` ${l(v).padStart(9)} ${A.padStart(7)}`}console.log(b)}console.log(),c&&console.log(te.dim(" change = cost per task against the baseline; the two ranges do not have the same tasks.")),e.save&&console.log(te.dim(` Saved ${e.save}`)),console.log()});un.command("surfaces").description("which CLI commands and dashboard pages are actually used").option("--days <n>","window in days","30").option("--kind <kind>","cli | page (default: both)").option("--unused","list registered surfaces with ZERO recorded use instead").option("--json","raw JSON output").action(async e=>{let{listSurfaceUse:t}=await import("./surface-usage-WSY4SHHL.js"),o=e.kind==="cli"||e.kind==="page"?e.kind:void 0,n=t({kind:o,sinceDays:Number(e.days)||30});if(e.unused){let{buildProgram:r}=await import("./program-7VHY5RVZ.js"),i=await r(),a=new Set(n.filter(d=>d.kind==="cli").map(d=>d.name)),c=[],l=(d,f)=>{for(let p of d.commands??[]){let u=f?`${f} ${p.name()}`:p.name();c.push(u),l(p,u)}};l(i,"");let g=c.filter(d=>!a.has(d)).sort();if(e.json){console.log(JSON.stringify({windowDays:Number(e.days)||30,unused:g},null,2));return}console.log(),console.log(te.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let d of g)console.log(` ${te.dim("\xB7")} ${d}`);console.log(),console.log(te.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(te.dim(" it must also fail the impact test. See docs/architecture/surface-reduction.md")),console.log();return}if(e.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(),console.log(te.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(te.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(te.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let r of n){r.kind!==s&&(console.log(te.dim(` ${r.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=r.kind);let i=String(r.count).padStart(6),a=te.dim(`${r.days}d`);console.log(` ${te.cyan(i)} ${r.name.padEnd(28)} ${a}`)}console.log(),console.log(te.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as Kv}from"commander";import Pe from"chalk";import{readFileSync as Qv}from"fs";import{resolve as Zv}from"path";le();var Ro=new Kv().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");Ro.command("serve",{isDefault:!0}).description("start the dashboard server (live view always; boards if configured)").option("--port <n>","override dashboard.port").option("--bind <host>","override dashboard.bind (e.g. 0.0.0.0)").action(async e=>{try{try{Ul(Zv(process.cwd(),".env"))}catch{}let t=ex(e.port,e.bind),{startBoardDashboard:o}=await import("./board-dashboard-GBEBQUFJ.js");o(t)}catch(t){console.log(Pe.red(` ${t.message}`)),process.env.DEBUG&&t.stack&&console.log(Pe.dim(t.stack)),process.exit(1)}});function ex(e,t){try{let o=O();return e&&(o.dashboard.port=parseInt(e,10)),t&&(o.dashboard.bind=t),o}catch{return console.log(Pe.yellow(" No agentx.json found \u2014 starting dashboard in setup-only mode.")),console.log(Pe.dim(" Visit http://127.0.0.1:"+(e||"4202")+` to run the wizard.
496
+ `}function Hs(e,t,o=".env"){let n=ff(o),s=hf(n),r=s.findIndex(i=>i.kind==="kv"&&i.key===e);r>=0?s[r]={kind:"kv",key:e,value:t,raw:`${e}=${jc(t)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:t,raw:`${e}=${jc(t)}`})),Ov(n,Nv(s))}function _c(e,t=".env"){return hf(t).find(s=>s.kind==="kv"&&s.key===e)?.value}var yf="https://t.me/BotFather";async function jv(e){try{let t=await fetch(`https://api.telegram.org/bot${e}/getMe`,{signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;let o=await t.json();return o?.ok?o.result:null}catch{return null}}async function _v(e,t){let o=Date.now()+t,n=0;try{let r=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=-1&timeout=0`,{signal:AbortSignal.timeout(5e3)})).json();r?.result?.length&&(n=r.result[0].update_id+1)}catch{}for(;Date.now()<o;)try{let r=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=${n}&timeout=10`,{signal:AbortSignal.timeout(15e3)})).json();for(let i of r?.result||[]){n=Math.max(n,i.update_id+1);let a=i.message||i.edited_message||i.channel_post;if(a?.chat?.id)return{chatId:a.chat.id,chatTitle:a.chat.title||a.chat.username||a.chat.first_name,from:a.from?.first_name||a.from?.username||"unknown"}}}catch{}return null}async function wf(e={}){console.log(),console.log(ye.bold(" Connect Telegram")),console.log(),console.log(ye.dim(` 1. Open ${yf}`)),console.log(ye.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(ye.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{wantsBrowser:t}=await zs({type:"confirm",name:"wantsBrowser",message:"Open BotFather in your browser?",initial:!0});t&&Ho(yf);let{token:o}=await zs({type:"password",name:"token",message:"Paste the bot token from BotFather:",validate:b=>/^\d+:[A-Za-z0-9_-]{20,}$/.test(b.trim())||"That doesn't look like a Telegram token"});o||(console.log(ye.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await jv(o.trim());n||(console.log(ye.red("\u2717 invalid or revoked")),process.exit(1)),console.log(ye.green(`\u2713 ${n.first_name} (@${n.username})`));let{readFileSync:s,existsSync:r}=await import("fs"),{resolve:i}=await import("path"),a=e.configPath||i(process.cwd(),"agentx.json");r(a)||(console.log(ye.red(` No agentx.json at ${a}. Run: agentx init`)),process.exit(1));let c=JSON.parse(s(a,"utf-8")),l=Object.keys(c.agents||{});l.length===0&&(console.log(ye.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await zs({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:l.map(v=>({title:v,value:v})),initial:0})).agent),g||(console.log(ye.red(" Aborted")),process.exit(1));let d=c.channels?.telegram?.accounts||{},f=e.account||g;d[f]&&d[f].agentBinding!==g&&(f=(await zs({type:"text",name:"account",message:`Account "${f}" is already in use. Pick a different label:`,initial:`${g}-2`,validate:v=>/^[a-z0-9-]+$/i.test(v)||"lowercase letters, digits, hyphens only"})).account),f||(console.log(ye.red(" Aborted")),process.exit(1));let p=`TG_${f.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Hs(p,o.trim()),process.env[p]=o.trim();let u=await ge(b=>{We(b,"channels.telegram.enabled",!0),We(b,`channels.telegram.accounts.${f}`,{token:`\${${p}}`,agentBinding:g});let v=Tn(b,`agents.${g}.mentions`)||[],A=`@${n.username}`;v.includes(A)||(v.push(A),We(b,`agents.${g}.mentions`,v))},{configPath:e.configPath});if(u.success||(console.log(ye.red(` \u2717 ${u.error}`)),process.exit(1)),console.log(),console.log(ye.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(ye.dim(` Token stored in .env as ${p}`)),console.log(ye.dim(` Mentions updated to include @${n.username}`)),u.reloaded?console.log(ye.dim(" Daemon hot-reloaded.")):console.log(ye.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:h}=await zs({type:"confirm",name:"capture",message:"Listen for a message so we can set this as your default --notify target?",initial:!0});if(!h)return;console.log(),console.log(ye.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(ye.dim(" Waiting up to 90s..."));let y=await _v(o.trim(),9e4);if(!y){console.log(ye.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(ye.dim(" agentx config set notifications.destination.channel telegram")),console.log(ye.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(ye.dim(` agentx config set notifications.destination.accountId ${f}`));return}let $=await ge(b=>{We(b,"notifications.destination",{channel:"telegram",chatId:String(y.chatId),accountId:f})},{configPath:e.configPath});if(!$.success){console.log(ye.red(` \u2717 failed to save destination: ${$.error}`));return}console.log(ye.green(" \u2713 Default --notify target set")),console.log(ye.dim(` Chat: ${y.chatTitle||y.chatId} (from ${y.from})`)),console.log(ye.dim(" From now on, --notify me resolves to this chat.")),$.reloaded&&console.log(ye.dim(" Daemon hot-reloaded."))}import Ce from"chalk";import Dc from"prompts";import{existsSync as Mc,mkdirSync as Dv,readdirSync as Pv,readFileSync as $f}from"fs";import{resolve as Pc}from"path";var Mv=".agentx/whatsapp-sessions";function Lv(){let e=Pc(process.cwd(),".agentx/daemon.pid");if(!Mc(e))return!1;try{let t=parseInt($f(e,"utf-8").trim(),10);return t?(process.kill(t,0),!0):!1}catch{return!1}}function Fv(e){if(!Mc(e))return!1;try{return Pv(e).some(t=>t.includes("creds")||t.endsWith(".json"))}catch{return!1}}async function qv(e,t){let o;try{o=await import("@whiskeysockets/baileys")}catch{return t(Ce.red(" WhatsApp pairing needs @whiskeysockets/baileys.")),t(Ce.red(" Install with: pnpm add @whiskeysockets/baileys (or npm install)")),!1}let{makeWASocket:n,useMultiFileAuthState:s}=o.default||o;Dv(e,{recursive:!0});let{state:r,saveCreds:i}=await s(e),a;try{a=(await o.fetchLatestBaileysVersion()).version}catch{}let c={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:()=>{},child:()=>c},l=n({auth:{creds:r.creds,keys:o.makeCacheableSignalKeyStore?o.makeCacheableSignalKeyStore(r.keys,c):r.keys},...a?{version:a}:{},logger:c,printQRInTerminal:!1,browser:["agentx-connect","pairing","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1});return l.ev.on("creds.update",i),await new Promise(g=>{let f=setTimeout(()=>{t(Ce.yellow(" Timed out waiting for scan (2min)."));try{l.end(void 0)}catch{}g(!1)},12e4);l.ev.on("connection.update",async p=>{if(p.qr){t(Ce.dim(" Scan this QR with WhatsApp \u2192 Linked devices \u2192 Link a device:")),t("");try{let{default:u}=await import("qrcode-terminal");u.generate(p.qr,{small:!0})}catch{t(` QR: ${p.qr}`)}t("")}if(p.connection==="open"){clearTimeout(f),t(Ce.green(" \u2713 Paired"));try{l.end(void 0)}catch{}g(!0)}p.connection==="close"&&!p.qr&&p.lastDisconnect?.error?.output?.statusCode===401&&(clearTimeout(f),t(Ce.red(" \u2717 Authorization failed \u2014 rescan required")),g(!1))})})}async function bf(e={}){if(console.log(),console.log(Ce.bold(" Connect WhatsApp")),console.log(),Lv()){console.log(Ce.yellow(" \u26A0 The daemon is running. Stop it first so pairing can open a fresh Baileys session:")),console.log(Ce.dim(" agentx daemon stop")),console.log();let{cont:l}=await Dc({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});l||(console.log(Ce.red(" Aborted")),process.exit(1))}let t=e.configPath||Pc(process.cwd(),"agentx.json");Mc(t)||(console.log(Ce.red(` No agentx.json at ${t}. Run: agentx init`)),process.exit(1));let o=JSON.parse($f(t,"utf-8")),n=e.sessionDir||o.channels?.whatsapp?.sessionDir||Mv,s=Pc(process.cwd(),n),r=Object.keys(o.agents||{});r.length===0&&(console.log(Ce.red(" No agents configured. Run: agentx agent add")),process.exit(1));let i=e.agent;i||(i=(await Dc({type:"select",name:"agent",message:"Default agent for incoming messages:",choices:r.map(g=>({title:g,value:g})),initial:0})).agent),i||(console.log(Ce.red(" Aborted")),process.exit(1));let a=!e.skipPair;if(Fv(s)&&a){let{keep:l}=await Dc({type:"confirm",name:"keep",message:`An existing session was found at ${n}. Keep it (recommended), or pair again?`,initial:!0});a=!l,l&&console.log(Ce.dim(" Keeping existing session \u2014 skipping QR pair."))}a&&(await qv(s,g=>console.log(g))||(console.log(Ce.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await ge(l=>{We(l,"channels.whatsapp.enabled",!0),We(l,"channels.whatsapp.sessionDir",n),We(l,"channels.whatsapp.defaultAgent",i)},{configPath:e.configPath});c.success||(console.log(Ce.red(` \u2717 ${c.error}`)),process.exit(1)),console.log(),console.log(Ce.green(` \u2713 WhatsApp bound to agent "${i}"`)),console.log(Ce.dim(` Session: ${n}`)),console.log(Ce.dim(" Start the daemon to begin receiving:")),console.log(Ce.dim(" agentx daemon start")),console.log(Ce.yellow(" No chat is answered until you list the allowed numbers (add your own to talk from your self-chat):")),console.log(Ce.dim(` agentx config set channels.whatsapp.allowFrom '["+15550001111"]'`)),console.log(Ce.dim(" Add routes later with:")),console.log(Ce.dim(` agentx config set channels.whatsapp.routes '[{"contact":"+1234567890","agent":"${i}"}]'`)),console.log()}import{randomBytes as Uv}from"crypto";import Fe from"chalk";import kf from"prompts";var Si="agentx-mesh:",Ai="//join/";function Wv(e){return Buffer.from(e,"utf-8").toString("base64url")}function Bv(e){return Buffer.from(e,"base64url").toString("utf-8")}function Jv(e){return`${Si}${Ai}${Wv(JSON.stringify(e))}`}function Gv(e){if(!e.startsWith(`${Si}${Ai}`))throw new Error(`Not a mesh invite link \u2014 expected ${Si}${Ai}\u2026`);let t=e.slice(Si.length+Ai.length),o=JSON.parse(Bv(t));if(o.version!==1)throw new Error(`Unsupported invite version: ${o.version}`);if(typeof o.url!="string"||typeof o.token!="string"||typeof o.name!="string")throw new Error("Invite payload missing required fields (url, token, name)");return o}function Hv(){return Uv(32).toString("hex")}function zv(e){let t=e?.node?.bind||"127.0.0.1:18800",[o,n]=t.split(":");return`http://${o}:${n}`}function Yv(e){return e?.node?.name||e?.node?.id||"node"}async function vf(e){let{readFileSync:t,existsSync:o}=await import("fs"),{resolve:n}=await import("path"),s=e.configPath||n(process.cwd(),"agentx.json");o(s)||(console.log(Fe.red(` No agentx.json at ${s}. Run: agentx init`)),process.exit(1));let r=JSON.parse(t(s,"utf-8")),i=_c("MESH_TOKEN");i||(i=Hv(),Hs("MESH_TOKEN",i),console.log(Fe.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||zv(r);if((a.includes("0.0.0.0")||a.includes("127.0.0.1")||a.includes("localhost"))&&!e.url){let{url:d}=await kf({type:"text",name:"url",message:"This node's URL as peers should reach it (e.g. http://100.x.x.x:18800):",initial:a,validate:f=>/^https?:\/\//.test(f)||"must start with http:// or https://"});d||(console.log(Fe.red(" Aborted")),process.exit(1)),a=d}let l=await ge(d=>{We(d,"mesh.enabled",!0)},{configPath:e.configPath});l.success||(console.log(Fe.red(` \u2717 ${l.error}`)),process.exit(1));let g=Jv({url:a,token:i,name:Yv(r),version:1});console.log(),console.log(Fe.bold(" Mesh invite")),console.log(),console.log(` ${Fe.cyan(g)}`),console.log(),console.log(Fe.dim(" Run on the other node:")),console.log(Fe.dim(` agentx connect mesh join "${g}"`)),console.log(),console.log(Fe.yellow(" Share over a trusted channel only \u2014 whoever holds this link can join your mesh.")),console.log()}async function xf(e,t={}){let o;try{o=Gv(e)}catch(r){console.log(Fe.red(` \u2717 ${r.message}`)),process.exit(1)}let n=_c("MESH_TOKEN");if(n&&n!==o.token){let{overwrite:r}=await kf({type:"confirm",name:"overwrite",message:"A different MESH_TOKEN already exists in .env. Overwrite with the invite's token?",initial:!1});r||(console.log(Fe.red(" Aborted (keeping existing .env)")),process.exit(1))}Hs("MESH_TOKEN",o.token);let s=await ge(r=>{We(r,"mesh.enabled",!0);let i=Tn(r,"mesh.peers")||[],a=i.findIndex(l=>l.name===o.name),c={name:o.name,url:o.url,token:"${MESH_TOKEN}"};a>=0?i[a]=c:i.push(c),We(r,"mesh.peers",i)},{configPath:t.configPath});s.success||(console.log(Fe.red(` \u2717 ${s.error}`)),process.exit(1)),console.log(Fe.green(" \u2713 Joined mesh")),console.log(Fe.dim(` Peer: ${o.name} @ ${o.url}`)),console.log(Fe.dim(" Shared token stored in .env as MESH_TOKEN")),s.reloaded?console.log(Fe.dim(" Daemon hot-reloaded.")):console.log(Fe.dim(" Restart the daemon to start the mesh (agentx daemon start).")),console.log();try{let r=await fetch(`${o.url.replace(/\/$/,"")}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)});if(r.ok){let i=await r.json(),a=Array.isArray(i.agents)?i.agents.length:"?";console.log(Fe.dim(` Reachable \u2014 ${o.name} exposes ${a} agents`))}else console.log(Fe.yellow(` Peer returned HTTP ${r.status} \u2014 double-check the URL`))}catch(r){console.log(Fe.yellow(` Could not reach ${o.url} right now (${r?.cause?.code||r.message}) \u2014 verify VPN / Tailscale when the peer daemon is up`))}}var ts=new Vv().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");ts.command("telegram").description("pair a Telegram bot \u2014 persists token in .env, binds to an agent, auto-detects default chat").option("--agent <id>","agent to bind the bot to (skips the prompt)").option("--account <name>","account label in channels.telegram.accounts (defaults to agent id)").option("--skip-chat-capture","don't listen for the first message after pairing").option("-c, --config <path>","path to agentx.json").action(async e=>{await wf({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});ts.command("whatsapp").description("pair WhatsApp via QR (prints in terminal), then writes channels.whatsapp config").option("--agent <id>","default agent for inbound messages").option("--session-dir <path>","session directory (default: .agentx/whatsapp-sessions)").option("--skip-pair","skip QR pairing (use when session already exists)").option("-c, --config <path>","path to agentx.json").action(async e=>{await bf({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var Sf=ts.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");Sf.command("invite").description("emit a single-use join link for another AgentX node").option("--url <url>","this node's URL as peers should reach it (Tailscale IP etc.)").option("-c, --config <path>","path to agentx.json").action(async e=>{await vf({url:e.url,configPath:e.config})});Sf.command("join <link>").description("accept an invite link from another AgentX node").option("-c, --config <path>","path to agentx.json").action(async(e,t)=>{await xf(e,{configPath:t.config})});ts.action(()=>{console.log(),console.log(es.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${es.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${es.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${es.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${es.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(es.dim(" GitLab connect is the next slice.")),console.log()});le();import{Command as Xv}from"commander";import te from"chalk";var un=new Xv().name("usage").description("token usage analysis and reporting");un.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=O(),[t,o]=e.node.bind.split(":"),s=await(await fetch(`http://${t||"127.0.0.1"}:${o}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(te.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(te.dim(" No tasks recorded yet")),console.log();return}let r=a=>a.toLocaleString();console.log(` Total: ${te.bold(r(s.totalTokens))} tokens across ${s.totalTasks} tasks`),console.log(` Input: ${r(s.totalInput)}`),console.log(` Output: ${r(s.totalOutput)}`),console.log(` Cache read: ${r(s.totalCacheRead)}`),console.log(` Cache create: ${r(s.totalCacheCreate)}`),s.cacheHitRatio>0&&console.log(` Cache hit: ${(s.cacheHitRatio*100).toFixed(1)}%`),s.totalErrors>0&&console.log(` Errors: ${te.red(String(s.totalErrors))}`),console.log(),console.log(te.bold(" By Agent:"));let i=Object.entries(s.byAgent||{});i.sort((a,c)=>c[1].total-a[1].total);for(let[a,c]of i){let l=r(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${te.cyan(a)}: ${l} tokens (${c.tasks} tasks) ${te.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(te.red(" Daemon not running. Start with: agentx daemon start")):console.log(te.red(` ${e.message}`))}});un.command("plan").description("show the Claude plan windows as Claude Code last reported them, and any hold on fresh sessions").option("--lift","lift the hold on fresh sessions now, without waiting for the reset time").option("--json","raw JSON output").action(async e=>{try{let t=O(),[o,n]=t.node.bind.split(":"),s=`http://${o||"127.0.0.1"}:${n}`,r=e.lift?await fetch(`${s}/usage/plan/lift`,{method:"POST",signal:AbortSignal.timeout(3e3)}):await fetch(`${s}/usage/plan`,{signal:AbortSignal.timeout(3e3)});if(!r.ok)throw new Error(`Daemon answered ${r.status}. It may be older than this command; restart it.`);let i=await r.json();if(e.json){console.log(JSON.stringify(i,null,2));return}let a=d=>d.replace(/_/g," ");if(console.log(),e.lift){let d=i.lifted.map(f=>a(f.window));console.log(d.length?` Lifted the hold on: ${d.join(", ")}. The next fresh session asks Claude again.`:te.dim(" No hold to lift.")),console.log();return}let c=i.now,l=new Set(i.holds.map(d=>d.window));console.log(te.bold(" Claude plan (as Claude Code last reported it)")),console.log(),i.provider.length===0&&console.log(te.dim(" No report yet. Claude Code reports on each turn; the list is empty after a daemon restart."));for(let d of i.provider){let f=d.usingOverage?"extra usage":d.status==="allowed_warning"?"nearly full":d.status,p=typeof d.utilization=="number"?`${Math.round(d.utilization*100)}% used`:"",u=Math.max(1,Math.round((d.resetsAt-c)/6e4)),h=d.resetsAt>c?u<60?`resets in ${u} min`:u<48*60?`resets in ${Math.round(u/60)} h`:`resets in ${Math.round(u/1440)} days`:"",y=l.has(d.window)?te.red("holding fresh sessions"):"";console.log(` ${a(d.window).padEnd(18)} ${f.padEnd(12)} ${[p,h,y].filter(Boolean).join(", ")}`)}console.log();let g=d=>d?` of ${d}`:"";console.log(` Fresh sessions started: ${i.lastHour}${g(i.maxPerHour)} in the last hour, ${i.last5h}${g(i.maxPer5h)} in the last 5 hours`),l.size&&console.log(te.dim(" To try again now: agentx usage plan --lift")),console.log()}catch(t){t.cause?.code==="ECONNREFUSED"?console.log(te.red(" Daemon not running. Start with: agentx daemon start")):console.log(te.red(` ${t.message}`))}});un.command("report").description("run full session analysis (parses Claude Code JSONL files)").option("--days <n>","analyze last N days","7").action(async e=>{let{execSync:t}=await import("child_process"),{existsSync:o}=await import("fs"),{resolve:n}=await import("path"),s=n(process.cwd(),"scripts/token-report.py");if(!o(s)){console.log(te.red(` Script not found: ${s}`)),console.log(te.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(te.dim(" Analyzing Claude Code sessions..."));try{t(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(te.red(" Analysis failed. Is Python 3 installed?"))}});un.command("channels").description("cost per channel over a fixed range of days, next to a saved baseline").requiredOption("--from <date>","first day, YYYY-MM-DD").requiredOption("--to <date>","last day, YYYY-MM-DD").option("--save <file>","write this range's figures to a JSON file").option("--baseline <file>","a file written by --save, shown beside this range").option("--json","raw JSON output").action(async e=>{let{readFileSync:t,writeFileSync:o}=await import("fs"),{TokenTracker:n}=await import("./token-tracker-W7DFDEFN.js"),{channelCosts:s,costPerTask:r}=await import("./usage-channels-KBLEC4NE.js"),i=u=>/^\d{4}-\d{2}-\d{2}$/.test(u)&&!Number.isNaN(Date.parse(u));if(!i(e.from)||!i(e.to)||e.from>e.to){console.log(te.red(" --from and --to must be YYYY-MM-DD, with --from not after --to")),process.exitCode=1;return}let a=s(new n,e.from,e.to);e.save&&o(e.save,JSON.stringify(a,null,2));let c=null;if(e.baseline)try{c=JSON.parse(t(e.baseline,"utf-8"))}catch(u){console.log(te.red(` Cannot read baseline ${e.baseline}: ${u.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify(c?{baseline:c,current:a}:a,null,2));return}let l=u=>u===null?"-":`$${u.toFixed(u<10?3:2)}`,g=u=>`${(u/1e6).toFixed(1)}M`;console.log(),console.log(te.bold(` Cost per channel, ${a.from} to ${a.to} (${a.days} day(s) with data)`)),c&&console.log(te.dim(` Baseline: ${c.from} to ${c.to} (${c.days} day(s) with data)`)),console.log();let d=` ${"channel".padEnd(14)} ${"tasks".padStart(6)} ${"cache read".padStart(11)} ${"cache write".padStart(11)} ${"output".padStart(8)} ${"cost".padStart(10)} ${"per task".padStart(9)}`;console.log(te.dim(c?`${d} ${"baseline".padStart(9)} ${"change".padStart(7)}`:d));let p=[...new Set([...Object.keys(a.channels),...Object.keys(c?.channels||{})])].map(u=>[u,a.channels[u],c?.channels[u]]).sort((u,h)=>(h[1]?.cost||0)-(u[1]?.cost||0));p.push(["TOTAL",a.total,c?.total]);for(let[u,h,y]of p){let $=r(h),b=` ${u.padEnd(14)} ${String(h?.tasks||0).padStart(6)} ${g(h?.cacheRead||0).padStart(11)} ${g(h?.cacheCreate||0).padStart(11)} ${g(h?.output||0).padStart(8)} ${l(h?.cost||0).padStart(10)} ${l($).padStart(9)}`;if(c){let v=r(y),A=$!==null&&v?`${(($-v)/v*100).toFixed(0)}%`:"-";b+=` ${l(v).padStart(9)} ${A.padStart(7)}`}console.log(b)}console.log(),c&&console.log(te.dim(" change = cost per task against the baseline; the two ranges do not have the same tasks.")),e.save&&console.log(te.dim(` Saved ${e.save}`)),console.log()});un.command("surfaces").description("which CLI commands and dashboard pages are actually used").option("--days <n>","window in days","30").option("--kind <kind>","cli | page (default: both)").option("--unused","list registered surfaces with ZERO recorded use instead").option("--json","raw JSON output").action(async e=>{let{listSurfaceUse:t}=await import("./surface-usage-WSY4SHHL.js"),o=e.kind==="cli"||e.kind==="page"?e.kind:void 0,n=t({kind:o,sinceDays:Number(e.days)||30});if(e.unused){let{buildProgram:r}=await import("./program-SJT7PIFO.js"),i=await r(),a=new Set(n.filter(d=>d.kind==="cli").map(d=>d.name)),c=[],l=(d,f)=>{for(let p of d.commands??[]){let u=f?`${f} ${p.name()}`:p.name();c.push(u),l(p,u)}};l(i,"");let g=c.filter(d=>!a.has(d)).sort();if(e.json){console.log(JSON.stringify({windowDays:Number(e.days)||30,unused:g},null,2));return}console.log(),console.log(te.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let d of g)console.log(` ${te.dim("\xB7")} ${d}`);console.log(),console.log(te.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(te.dim(" it must also fail the impact test. See docs/architecture/surface-reduction.md")),console.log();return}if(e.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(),console.log(te.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(te.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(te.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let r of n){r.kind!==s&&(console.log(te.dim(` ${r.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=r.kind);let i=String(r.count).padStart(6),a=te.dim(`${r.days}d`);console.log(` ${te.cyan(i)} ${r.name.padEnd(28)} ${a}`)}console.log(),console.log(te.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as Kv}from"commander";import Pe from"chalk";import{readFileSync as Qv}from"fs";import{resolve as Zv}from"path";le();var Ro=new Kv().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");Ro.command("serve",{isDefault:!0}).description("start the dashboard server (live view always; boards if configured)").option("--port <n>","override dashboard.port").option("--bind <host>","override dashboard.bind (e.g. 0.0.0.0)").action(async e=>{try{try{Ul(Zv(process.cwd(),".env"))}catch{}let t=ex(e.port,e.bind),{startBoardDashboard:o}=await import("./board-dashboard-F5GP2X22.js");o(t)}catch(t){console.log(Pe.red(` ${t.message}`)),process.env.DEBUG&&t.stack&&console.log(Pe.dim(t.stack)),process.exit(1)}});function ex(e,t){try{let o=O();return e&&(o.dashboard.port=parseInt(e,10)),t&&(o.dashboard.bind=t),o}catch{return console.log(Pe.yellow(" No agentx.json found \u2014 starting dashboard in setup-only mode.")),console.log(Pe.dim(" Visit http://127.0.0.1:"+(e||"4202")+` to run the wizard.
497
497
  `)),{node:{id:"setup",name:"Setup",bind:"127.0.0.1:18800"},providers:{},agents:{},channels:{},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},boards:[],dashboard:{enabled:!0,port:e?parseInt(e,10):4202,bind:t||"127.0.0.1",daemonUrl:"http://localhost:18800",daemons:[]},business:void 0,session:{staleMinutes:120}}}}Ro.command("list").description("list configured boards").action(()=>{try{let e=O();if(!e.boards?.length){console.log(Pe.dim(`
498
498
  No boards configured.
499
499
  `));return}console.log();for(let t of e.boards){console.log(` ${Pe.cyan(t.id)} \u2014 ${t.name}`);let o=t.source;console.log(Pe.dim(` source: ${o.type}${o.projects?" ("+o.projects.join(", ")+")":""}`)),t.primaryToolLabel&&console.log(Pe.dim(` primary label: ${t.primaryToolLabel}`)),console.log(Pe.dim(` window: ${t.timeRangeDays} days`))}console.log()}catch(e){console.log(Pe.red(` ${e.message}`)),process.exit(1)}});Ro.command("add <id>").description("add a GitLab board to agentx.json").requiredOption("--name <name>","human-readable board name").requiredOption("--projects <paths>","comma-separated GitLab project paths (e.g. 'globex/system,globex/website')").option("--label <label>","primary tool label ANDed into every query (e.g. 'Tool::Claude')").option("--days <n>","open-window time range in days","30").option("--closed-days <n>","closed-window in days","30").action((e,t)=>{try{Ys(o=>{if(Array.isArray(o.boards)||(o.boards=[]),o.boards.find(r=>r.id===e))throw new Error(`board "${e}" already exists`);let n=String(t.projects).split(",").map(r=>r.trim()).filter(Boolean);if(n.length===0)throw new Error("--projects must include at least one path");let s={id:e,name:t.name,source:{type:"gitlab",projects:n},timeRangeDays:parseInt(t.days,10)||30,closedWindowDays:parseInt(t.closedDays,10)||30};return t.label&&(s.primaryToolLabel=t.label),o.boards.push(s),`added board "${e}" (${n.join(", ")})`})}catch(o){console.log(Pe.red(` ${o.message}`)),process.exit(1)}});Ro.command("edit <id>").description("edit board fields without re-creating it").option("--name <name>","rename").option("--projects <paths>","comma-separated GitLab project paths (replaces the list)").option("--label <label>","primary tool label (set to '-' to clear)").option("--days <n>","open-window time range in days").option("--closed-days <n>","closed-window in days").action((e,t)=>{try{Ys(o=>{let s=(Array.isArray(o.boards)?o.boards:[]).find(i=>i.id===e);if(!s)throw new Error(`board "${e}" not found`);let r=[];if(t.name&&(s.name=t.name,r.push(`name="${t.name}"`)),t.projects){let i=String(t.projects).split(",").map(a=>a.trim()).filter(Boolean);if(i.length===0)throw new Error("--projects must include at least one path");s.source={...s.source||{type:"gitlab"},type:"gitlab",projects:i},r.push(`projects=${i.length}`)}if(t.label!==void 0&&(t.label==="-"?(delete s.primaryToolLabel,r.push("label cleared")):(s.primaryToolLabel=t.label,r.push(`label="${t.label}"`))),t.days&&(s.timeRangeDays=parseInt(t.days,10)||s.timeRangeDays,r.push(`days=${s.timeRangeDays}`)),t.closedDays&&(s.closedWindowDays=parseInt(t.closedDays,10)||s.closedWindowDays,r.push(`closed-days=${s.closedWindowDays}`)),r.length===0)throw new Error("no changes \u2014 pass at least one option");return`board "${e}" updated (${r.join(", ")})`})}catch(o){console.log(Pe.red(` ${o.message}`)),process.exit(1)}});var Lc=Ro.command("column").description("manage a board's columns (add / remove / edit / list)");Lc.command("list <boardId>").description("list columns on a board, in order").action(e=>{try{let o=(JSON.parse(Qv("agentx.json","utf-8")).boards||[]).find(s=>s.id===e);if(!o)throw new Error(`board "${e}" not found`);let n=o.columns||[];if(n.length===0){console.log(Pe.dim(" no columns (board falls back to GitLab default flow)"));return}for(let s of n){let r=s.kind==="scoped-label"?`scoped="${s.scopedLabel}"`:s.kind==="label"?`label="${s.mapsToLabel||""}"`:s.kind==="open-backlog"?`prefix="${s.scopedPrefix}"`:s.kind;console.log(` ${Pe.cyan(s.id.padEnd(12))} ${s.title.padEnd(14)} ${Pe.dim(r)}`)}}catch(t){console.log(Pe.red(` ${t.message}`)),process.exit(1)}});Lc.command("add <boardId> <columnId>").description("add a column to a board").requiredOption("--title <title>","column title").option("--kind <kind>","open-backlog | scoped-label | closed | label","scoped-label").option("--scoped <label>","for kind=scoped-label, the full label (e.g. 'Status::Doing')").option("--label <label>","for kind=label, the label name to add/remove").option("--scoped-prefix <prefix>","for kind=open-backlog/scoped-label","Status").option("--accent <color>","hex/CSS color for the column accent bar").action((e,t,o)=>{try{Ys(n=>{let r=(Array.isArray(n.boards)?n.boards:[]).find(a=>a.id===e);if(!r)throw new Error(`board "${e}" not found`);if(r.columns=r.columns||[],r.columns.find(a=>a.id===t))throw new Error(`column "${t}" already exists on board "${e}"`);let i={id:t,title:o.title,kind:o.kind,scopedPrefix:o.scopedPrefix};if(o.kind==="scoped-label"){if(!o.scoped)throw new Error("--scoped required for kind=scoped-label");i.scopedLabel=o.scoped}if(o.kind==="label"){if(!o.label)throw new Error("--label required for kind=label");i.mapsToLabel=o.label}return o.accent&&(i.accent=o.accent),r.columns.push(i),`column "${t}" added to board "${e}"`})}catch(n){console.log(Pe.red(` ${n.message}`)),process.exit(1)}});Lc.command("remove <boardId> <columnId>").alias("rm").description("remove a column from a board").action((e,t)=>{try{Ys(o=>{let s=(Array.isArray(o.boards)?o.boards:[]).find(i=>i.id===e);if(!s)throw new Error(`board "${e}" not found`);let r=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(i=>i.id!==t),s.columns.length===r)throw new Error(`column "${t}" not found`);return`column "${t}" removed from board "${e}"`})}catch(o){console.log(Pe.red(` ${o.message}`)),process.exit(1)}});Ro.command("remove <id>").alias("rm").description("remove a board from agentx.json").action(e=>{try{Ys(t=>{if(!Array.isArray(t.boards)||t.boards.length===0)throw new Error("no boards configured");let o=t.boards.length;if(t.boards=t.boards.filter(n=>n.id!==e),t.boards.length===o)throw new Error(`board "${e}" not found`);return`removed board "${e}"`})}catch(t){console.log(Pe.red(` ${t.message}`)),process.exit(1)}});function Ys(e){let{summary:t,backupPath:o}=vt(n=>e(n));console.log(Pe.green(`
@@ -523,7 +523,7 @@ An edit that breaks these rules is refused and the note is deferred.
523
523
 
524
524
  ${t}
525
525
  `}function Of(e,t,o,n){let s=n.today??new Date().toISOString().slice(0,10),r=new Map;for(let i of t){let a=e.find(c=>c.id===i.id||i.id.length>=4&&c.id.startsWith(i.id));a&&!r.has(a.id)&&r.set(a.id,i)}return e.map(i=>{let a=r.get(i.id);if(!a)return{id:i.id,outcome:"deferred",reason:"absorb did not answer this note",patched:[]};let c=Ei(a.reason||"no reason given");if(a.outcome!=="patched")return{id:i.id,outcome:a.outcome,reason:c,patched:[]};let l=tx(a.edits,o,n.paths,n.agentId);if("refused"in l)return{id:i.id,outcome:"deferred",reason:Ei(`patch refused: ${l.refused}. Absorb said: ${c}`),patched:[]};let g=[],d="";for(let[p,{article:u,content:h}]of l.articles){let y=!1;try{y=o.writeArticle(p,{...u.meta,lastUpdated:s,sources:[...new Set([...u.meta.sources??[],qc(i.id)])]},h,n.agentId)}catch($){d=`${p}: ${$?.message??$}`}if(!y){d||=p;break}g.push({path:p,article:u})}if(d){for(let p of g)try{o.writeArticle(p.path,p.article.meta,p.article.content,n.agentId)}catch{}return{id:i.id,outcome:"deferred",reason:Ei(`patch not saved: could not write ${d}. Absorb said: ${c}`),patched:[]}}let f=g.map(p=>p.path);return{id:i.id,outcome:"patched",reason:Ei(`${c} (edited ${f.join(", ")})`),patched:f}})}function tx(e,t,o,n){if(e.length===0)return{refused:"patched with no edits"};if(e.length>Vs.edits)return{refused:`more than ${Vs.edits} edits`};let s=new Map;for(let r of e){if(!o.has(r.path))return{refused:`${r.path} is not an article shown in full`};let i=s.get(r.path);if(!i){let c=t.readArticle(r.path);if(!c)return{refused:`${r.path} is not an existing article`};if(t.canWrite&&!t.canWrite(c.meta,n))return{refused:`no permission to write ${r.path}`};i={article:c,content:c.content,replaced:0},s.set(r.path,i)}if(!r.find.trim())return{refused:`an edit to ${r.path} quotes nothing`};if(r.find.length>Vs.find||r.replace.length>Vs.replace)return{refused:`an edit to ${r.path} is too long for a patch`};if(i.replaced+=r.find.length,i.replaced>i.article.content.length*Vs.share)return{refused:`the edits replace most of ${r.path}; a note only patches`};let a=i.content.indexOf(r.find);if(a<0)return{refused:`the quoted passage is not in ${r.path}`};if(i.content.indexOf(r.find,a+1)>=0)return{refused:`the quoted passage appears more than once in ${r.path}`};i.content=i.content.slice(0,a)+r.replace+i.content.slice(a+r.find.length)}for(let[r,{article:i,content:a}]of s){let c=[...ox(i.content,a),...ix(i.content,a)];if(c.length>0)return{refused:`the edit to ${r} drops ${c.slice(0,4).join("; ")}${c.length>4?"; \u2026":""}`}}return{articles:s}}function ox(e,t){let o=Ss(e,t),n=Ss(t,e),s=i=>i.startsWith("link [[")?"wikilink":i.split(" ")[0],r=new Map;for(let i of n)r.set(s(i),(r.get(s(i))??0)+1);return o.filter(i=>{let a=r.get(s(i))??0;return a===0?!0:(r.set(s(i),a-1),!1)})}var nx=/[\w.+-]+@[\w-]+(?:\.[\w-]+)+/g,sx=/(?<![\w@.])@[A-Za-z0-9_]{3,}/g,rx=/^\s*(?:[-*]\s*)?(?:\|\s*)?\**\s*(role|job title|position|organi[sz]ation|company|team|employer|e-?mail|phone|mobile|tel|whatsapp|telegram|signal|slack|handle|contact|address)\s*\**\s*(?::|\|)\s*\**\s*(.+?)\s*\|?\s*$/gim;function ix(e,t){let o=t.toLowerCase(),n=[];for(let s of e.matchAll(nx))o.includes(s[0].toLowerCase())||n.push(`email ${s[0]}`);for(let s of e.matchAll(sx))o.includes(s[0].toLowerCase())||n.push(`handle ${s[0]}`);for(let s of e.matchAll(rx)){let r=s[2].replace(/\*+/g,"").trim();!r||/^(unknown|n\/a|none|-+|tbd)$/i.test(r)||o.includes(r.toLowerCase())||n.push(`${s[1].toLowerCase()} "${r}"`)}return[...new Set(n)]}function Ei(e){return e.length>ra.reason?`${e.slice(0,ra.reason-1)}\u2026`:e}import Le from"chalk";import{resolve as ax}from"path";var cx=e=>e||ax(process.cwd(),".agentx/wiki");async function os(e){let{FactLedger:t}=await import("./ledger-P62U3FHT.js");return new t(cx(e))}function ns(e){return async(...t)=>{try{await e(...t)}catch(o){o?.name!=="LedgerCorruptError"&&console.error(Le.red(` ${o?.message??o}`)),process.exitCode=1}}}function Tf(e){let t=e.command("facts").description("facts with a source and a check date: list, show, set, proposals");t.command("list").description("every recorded fact, with where and when it was checked").option("--dir <path>","wiki directory").option("--stale","only facts past their time limit, or never checked").option("--json").action(ns(async n=>{let{isStaleFact:s}=await import("./ledger-P62U3FHT.js"),r=(await os(n.dir)).list().filter(i=>!n.stale||s(i));if(n.json){console.log(JSON.stringify(r,null,2));return}if(r.length===0){console.log(Le.dim(" no facts recorded"));return}for(let i of r){let a=i.undated?Le.yellow(" UNCHECKED"):s(i)?Le.yellow(" STALE"):"";console.log(` ${Le.cyan(i.id)} ${Le.bold(i.subject)} \xB7 ${i.attribute}: ${i.value}${a}`),console.log(Le.dim(` ${i.volatility} \xB7 ${i.source} \xB7 checked ${i.verifiedAt.slice(0,10)} by ${i.verifiedBy}`))}})),t.command("show <id>").description("one fact, with its earlier values").option("--dir <path>","wiki directory").action(ns(async(n,s)=>{let r=(await os(s.dir)).get(n);if(!r){console.error(Le.red(` no fact "${n}"`)),process.exitCode=1;return}console.log(JSON.stringify(r,null,2))})),t.command("set").description("record a fact you checked; a different value needs a newer --checked-at, or --confirm by a person").requiredOption("--subject <text>",'what the fact is about, e.g. "vendor account"').requiredOption("--attribute <text>",'which property, e.g. "billing status"').requiredOption("--value <text>","the value you found").requiredOption("--source <text>",'where you checked: a system, URL, command, or "owner said"').option("--by <id>","who checked it (agent id or person)",process.env.AGENTX_AGENT_ID||"operator").option("--checked-at <iso>",`when you checked it: an ISO date, or "now". Without it the value can't replace a different one already recorded`).option("--class <class>",`volatility class: ${oa.join(" | ")}`).option("--ttl-days <n>","days it stays trusted, overriding the class").option("--confirm","a person confirms this value: replace a newer-dated one").option("--dir <path>","wiki directory").action(ns(async n=>{if(n.class&&!Hl(n.class)){console.error(Le.red(` --class must be one of ${oa.join(", ")}`)),process.exitCode=1;return}let r=(await os(n.dir)).write({subject:n.subject,attribute:n.attribute,value:n.value,source:n.source,verifiedBy:n.by,verifiedAt:n.checkedAt,volatility:n.class,ttlDays:n.ttlDays!==void 0?Number(n.ttlDays):void 0},n.confirm?{confirmedBy:n.by}:{});if(r.status==="contradiction"){let i=r.fact.confirmedBy?`${r.fact.confirmedBy} confirmed it, so only a person can change it`:n.checkedAt?"and this check is not newer":"and this value has no --checked-at";console.log(Le.yellow(` not replaced: the wiki says "${r.fact.value}" (checked ${r.fact.verifiedAt.slice(0,10)}), ${i}.`)),console.log(r.questionId?Le.dim(` Queued question ${r.questionId}: agentx wiki questions \xB7 agentx wiki answer ${r.questionId} "<true value>"`):r.questionClosed?Le.dim(` A person already ${r.questionClosed} this same claim, so it is not asked again.`):Le.red(" No question could be queued: the questions file is unreadable. Repair .agentx/wiki/_questions.json.")),process.exitCode=2;return}console.log(Le.green(` ${r.status}: ${r.fact.id} ${r.fact.subject} \xB7 ${r.fact.attribute}: ${r.fact.value}`))}));let o=t.command("proposals").description("claims from session summaries, waiting for a check (list, approve, reject)");o.command("list").description("claims waiting for a check (pending by default)").option("--dir <path>","wiki directory").option("--all","include approved and rejected").option("--json").action(ns(async n=>{let{listFactProposals:s}=await import("./fact-proposals-X2O4W7VN.js"),r=s(await os(n.dir),n.all?void 0:"pending");if(n.json){console.log(JSON.stringify(r,null,2));return}if(r.length===0){console.log(Le.dim(" no fact proposals waiting"));return}for(let i of r)console.log(` ${Le.cyan(i.id)} ${i.status==="pending"?"":Le.dim(`[${i.status}] `)}${i.claim}`),console.log(Le.dim(` ${i.agentId} \xB7 ${i.origin} \xB7 ${i.source} \xB7 ${i.verifiedAt.slice(0,10)}`));console.log(Le.dim(`
526
- Check each claim at its source, then: agentx wiki facts proposals approve <id> \xB7 reject <id>`))})),o.command("approve <id>").description("confirm a claim and record it as a fact").option("--subject <text>","correct the subject read from the claim").option("--attribute <text>","correct the attribute").option("--value <text>","correct the value").option("--source <text>","where you checked it").option("--by <id>","who confirms it","operator").option("--dir <path>","wiki directory").action(ns(async(n,s)=>{let{approveFactProposal:r}=await import("./fact-proposals-X2O4W7VN.js"),{write:i}=r(await os(s.dir),n,s.by,{subject:s.subject,attribute:s.attribute,value:s.value,source:s.source});console.log(Le.green(` ${i.status}: ${i.fact.id} ${i.fact.subject} \xB7 ${i.fact.attribute}: ${i.fact.value}`))})),o.command("reject <id>").description("drop a claim; it is not recorded").option("--reason <text>","why, kept with the decision").option("--by <id>","who rejects it","operator").option("--dir <path>","wiki directory").action(ns(async(n,s)=>{let{rejectFactProposal:r}=await import("./fact-proposals-X2O4W7VN.js"),i=r(await os(s.dir),n,s.by,s.reason);console.log(Le.dim(` rejected: ${i.claim}`))}))}import Ge from"chalk";import{existsSync as If,readFileSync as Rf}from"fs";import{resolve as Wc}from"path";var Uc=e=>e||Wc(process.cwd(),".agentx/wiki");function lx(e){if(e)return e.replace(/\/+$/,"");if(process.env.AGENTX_DAEMON_URL)return process.env.AGENTX_DAEMON_URL.replace(/\/+$/,"");try{let t=Wc(process.cwd(),"agentx.json");if(If(t)){let o=JSON.parse(Rf(t,"utf-8"))?.node?.bind;if(typeof o=="string"&&o.includes(":")){let[n,s]=o.split(":");return`http://${n==="0.0.0.0"?"127.0.0.1":n}:${s}`}}}catch{}return"http://127.0.0.1:18800"}function Qt(e){console.error(Ge.red(` ${e}`)),process.exitCode=1}function Ci(e){return async(...t)=>{try{await e(...t)}catch(o){Qt(o?.message??String(o))}}}function Nf(e){let t=e.command("notes").description("notes agents leave for the wiki observe/sweep run: add, list, handle, config");t.command("add").description("leave a note for the wiki observe/sweep run: what changed, the source, the date").requiredOption("--change <text>","what changed, in a sentence or two").requiredOption("--source <text>",'where you saw it: a system, URL, command, or "owner said"').option("--date <YYYY-MM-DD>","when it changed or when you saw it (default: today)").option("--from <agent>","your agent id",process.env.AGENTX_AGENT_ID).option("--daemon <url>","this node's daemon (default: AGENTX_DAEMON_URL, else node.bind in agentx.json)").option("--dir <path>","write straight into this wiki directory instead of going through the daemon (needs --to)").option("--to <agent>","inbox agent, with --dir").option("--json").action(Ci(async o=>{if(!o.from){Qt("say who you are with --from <agent id>");return}let n={from:o.from,change:o.change,source:o.source,date:o.date},s;if(o.dir){if(!o.to){Qt("--dir needs --to <inbox agent>");return}let{NoteStore:a,validateNote:c}=await import("./notes-WJJEJ4CJ.js"),l=c({...n,to:o.to});if("error"in l){Qt(l.error);return}s={ok:!0,...new a(Uc(o.dir)).add(l.note)}}else{let a=lx(o.daemon),c;try{c=await fetch(`${a}/wiki/notes`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(2e4)})}catch(l){Qt(`could not reach the daemon at ${a}: ${l?.message??l}`);return}if(s=await c.json().catch(()=>({})),!c.ok){Qt(s?.error||`daemon answered ${c.status}`);return}}if(o.json){console.log(JSON.stringify(s,null,2));return}let r=s.note,i=s.peer?` on ${s.peer}`:"";console.log(s.added===!1?Ge.dim(` already in the inbox${i}: ${r?.id} (${r?.status})`):Ge.green(` note ${r?.id} left for ${r?.to}${i}; the next observe/sweep run reads it`))})),t.command("list").description("notes in this node's inbox (waiting ones by default)").option("--status <status>","waiting | open | patched | rejected | deferred | expired | all","waiting").option("--dir <path>","wiki directory").option("--json").action(Ci(async o=>{let{NoteStore:n}=await import("./notes-WJJEJ4CJ.js"),s=["waiting","open","patched","rejected","deferred","expired","all"];if(!s.includes(o.status)){Qt(`--status must be one of ${s.join(", ")}`);return}let r=new n(Uc(o.dir)),i=r.load();if(i.unreadable){Qt(`${r.path} is unreadable (${i.unreadable}); repair or move it aside`);return}let a=r.list(o.status==="all"?void 0:o.status);if(o.json){console.log(JSON.stringify(a,null,2));return}if(a.length===0){console.log(Ge.dim(` no ${o.status==="all"?"":`${o.status} `}notes`));return}for(let c of a){let l=c.status==="open"?Ge.yellow("open"):c.status==="deferred"?Ge.yellow("deferred"):Ge.dim(c.status);console.log(` ${Ge.cyan(c.id)} ${l} \xB7 from ${c.from}${c.fromNode?` on ${c.fromNode}`:""} \xB7 ${c.date}`),console.log(` ${c.change}`),console.log(Ge.dim(` source: ${c.source}`)),c.listedIn?.length&&console.log(Ge.dim(` given to: ${c.listedIn.at(-1)}${c.listedIn.length>1?` (+${c.listedIn.length-1} earlier)`:""}`)),c.handled&&console.log(Ge.dim(` ${c.handled.outcome}${c.deferrals?` (deferred ${c.deferrals}x)`:""} by ${c.handled.by} ${c.handled.at.slice(0,10)}: ${c.handled.reason}`)),c.expired&&console.log(Ge.dim(` expired ${c.expired.at.slice(0,10)} after ${c.expired.after} deferrals; no longer offered to the run`))}})),t.command("handle <id>").description("record what the run did with a note: patched, rejected or deferred, with a reason").requiredOption("--outcome <outcome>","patched | rejected | deferred").requiredOption("--reason <text>","what you patched, why you rejected it, or why it waits").option("--run <id>","the run that used it").option("--by <agent>","who handled it",process.env.AGENTX_AGENT_ID||"operator").option("--dir <path>","wiki directory").action(Ci(async(o,n)=>{let{NoteStore:s}=await import("./notes-WJJEJ4CJ.js"),r=new s(Uc(n.dir)).handle(o,n.outcome,n.reason,n.by,n.run);console.log(Ge.green(` note ${r.id}: ${r.status}`))})),t.command("config").description("show or set the inbox agent, and the schedules and absorb pass that read it").option("--inbox <agent>",'agent that runs the wiki observe/sweep schedule ("" clears it)').option("--cron <ids>",'comma-separated schedule ids that read the inbox ("" for none)').option("--absorb <agent>",'agent whose `wiki absorb` pass reads and answers the notes ("" clears it)').option("--max <n>","most notes one run is given (1-100)").option("--max-deferrals <n>","times a note may be deferred before it expires (1-20)").option("--enable","turn wiki notes on").option("--disable","turn wiki notes off").option("--json").action(Ci(async o=>{let{patchWikiNotes:n,wikiNotesSettings:s}=await import("./notes-settings-VPXI5IIS.js"),r={};if(o.inbox!==void 0&&(r.inbox=o.inbox),o.cron!==void 0&&(r.crons=String(o.cron).split(",")),o.absorb!==void 0&&(r.absorbAgent=o.absorb),o.max!==void 0&&(r.maxNotesPerRun=Number(o.max)),o.maxDeferrals!==void 0&&(r.maxDeferrals=Number(o.maxDeferrals)),o.enable&&o.disable){Qt("pick one of --enable and --disable");return}if(o.enable&&(r.enabled=!0),o.disable&&(r.enabled=!1),Object.keys(r).length>0){let{mutateAgentxConfig:c}=await import("./config-mutate-HXWAXWHC.js"),{summary:l}=c(g=>n(g,r));console.log(Ge.green(` ${l}`))}let i=Wc(process.cwd(),"agentx.json");if(!If(i)){Qt(`agentx.json not found at ${i}`);return}let a=s(JSON.parse(Rf(i,"utf-8"))?.wikiNotes);if(o.json){console.log(JSON.stringify(a,null,2));return}console.log(` wiki notes: ${a.enabled?Ge.green("on"):Ge.dim("off")}`),console.log(` inbox agent: ${a.inbox||Ge.dim("not set")}`),console.log(` schedules that read it: ${a.crons.length?a.crons.join(", "):Ge.dim("none on this node")}`),console.log(` absorb that reads it: ${a.absorbAgent?`wiki absorb for ${a.absorbAgent}`:Ge.dim("none")}`),console.log(` most notes per run: ${a.maxNotesPerRun}`),console.log(` deferrals before a note expires: ${a.maxDeferrals}`)}))}import No from"chalk";import{resolve as dx}from"path";var Bc=e=>e||dx(process.cwd(),".agentx/wiki");function jf(e){let t=e.command("ontology").description("the wiki's pillars, types, typed relations and page lenses (show, init, check)");t.command("init").description("write the default ontology to ontology.yaml in the wiki, to edit").option("--dir <path>","wiki directory (default .agentx/wiki)").action(async o=>{let{writeDefaultOntology:n}=await import("./load-LQ2I2PQI.js");try{let s=n(Bc(o.dir));console.log(No.green(` wrote ${s}`))}catch(s){console.error(No.red(` ${s.message}`)),process.exitCode=1}}),t.command("check").description("report problems in ontology.yaml").option("--dir <path>","wiki directory (default .agentx/wiki)").action(async o=>{let{loadOntology:n}=await import("./load-LQ2I2PQI.js"),{file:s,errors:r}=n(Bc(o.dir));if(!s){console.log(No.dim(" no ontology.yaml: the built-in defaults are in use"));return}if(r.length===0){console.log(No.green(` ${s}: no problems`));return}console.log(No.yellow(` ${s}: ${r.length} problem(s)`));for(let i of r)console.log(` - ${i}`);process.exitCode=1}),t.command("show").description("pages per pillar and type, as the wiki view groups them").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--json","print JSON").action(async o=>{let{loadOntology:n}=await import("./load-LQ2I2PQI.js"),{GraphCache:s}=await import("./graph-ZVKV3JBD.js"),{WikiHub:r}=await import("./hub-XGWCWKMT.js"),i=Bc(o.dir),{loadRoster:a}=await import("./roster-BZGKG2ZA.js"),{ontology:c,errors:l}=n(i),g=new r(i,()=>{}),d=new s().get(g,c,a(i,g.listAgents([]),c.agent_names)),f=new Map;for(let p of d.entities.values())f.set(p.type,(f.get(p.type)??0)+1);if(o.json){console.log(JSON.stringify({entities:d.entities.size,types:Object.fromEntries(f),errors:l},null,2));return}console.log(No.bold(` ${d.entities.size} entities`));for(let p of c.pillars){let u=c.types.filter(y=>y.pillar===p.id),h=u.reduce((y,$)=>y+(f.get($.id)??0),0);console.log(` ${p.label.padEnd(26)} ${String(h).padStart(6)} ${No.dim(u.map(y=>`${y.id} ${f.get(y.id)??0}`).join(" \xB7 "))}`)}l.length&&console.log(No.yellow(` ontology.yaml has ${l.length} problem(s): agentx wiki ontology check`))})}import ze from"chalk";import{resolve as gx}from"path";var Jc=e=>e||gx(process.cwd(),".agentx/wiki"),mx=()=>new Date().toISOString().slice(0,10);async function Gc(e){let{WikiHub:t}=await import("./hub-XGWCWKMT.js"),{GraphCache:o}=await import("./graph-ZVKV3JBD.js"),{loadOntology:n}=await import("./load-LQ2I2PQI.js"),{loadRoster:s}=await import("./roster-BZGKG2ZA.js"),r=new t(e,()=>{}),{ontology:i}=n(e),a=new o().get(r,i,s(e,r.listAgents([]),i.agent_names));return{hub:r,g:a}}function _f(e,t){let o=Number(e);return Number.isInteger(o)&&o>=1?o:(console.error(ze.red(` ${t} must be a whole number, 1 or more`)),process.exitCode=1,null)}function Df(e){let t=e.command("events").description("give each event page an importance level (minor, normal, major) and the pages it is about").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--about <titles...>","only events linked to or naming these pages (a pilot)").option("--max <n>","most events per run","200").option("--batch <n>","events per model call","20").option("--max-cost <usd>","stop before the next call once the run spent this much","1").option("--model <m>","model","haiku").option("--rules-only","use only the importance rules in ontology.yaml; no model call").option("--force","redo events whose level this job set earlier").option("--dry-run","show what would be written, write nothing").option("--json","print the run as JSON").action(async o=>{let{runEvents:n,summariseAbout:s}=await import("./event-levels-WOYYEWSZ.js"),{claudeCall:r}=await import("./wiki-enrich-7SBCPK2E.js"),i=_f(o.max,"--max"),a=_f(o.batch,"--batch");if(i===null||a===null)return;let c=Number(o.maxCost);if(!Number.isFinite(c)||c<=0){console.error(ze.red(" --max-cost must be a positive number of dollars")),process.exitCode=1;return}let{hub:l,g}=await Gc(Jc(o.dir)),d=o.about??[],{normName:f}=await import("./graph-ZVKV3JBD.js"),p=d.filter($=>!g.names.has(f($))&&!g.entities.has($));if(p.length){console.error(ze.red(` no page is titled: ${p.join(", ")}`)),process.exitCode=1;return}let u=await n(l,g,r(o.model),{about:d,max:i,batch:a,maxCostUsd:c,dryRun:!!o.dryRun,force:!!o.force,rulesOnly:!!o.rulesOnly,today:mx()}),h=s(g,u,d);if(o.json){console.log(JSON.stringify({...u,about:h},null,2));return}for(let $ of u.outcomes){let b=$.status==="written"?ze.green("\u2713"):$.status==="dry-run"?ze.cyan("~"):ze.yellow("\xB7"),v=$.importance?`${$.importance}${$.proposed?` (proposed ${$.proposed})`:""}`:$.status;console.log(` ${b} ${$.date||"no date "} ${v.padEnd(8)} ${$.title} ${ze.dim(`${$.by??$.status}${$.about.length?` \xB7 about ${$.about.join(", ")}`:""}${$.why?` \xB7 ${$.why}`:""}`)}`);for(let A of $.dropped.slice(0,4))console.log(ze.dim(` dropped: ${A}`))}for(let $ of h)console.log(ze.bold(` ${$.title}`)+ze.dim(` (${$.type}): ${$.before} events in its History before \xB7 after: ${$.after.major} major, ${$.after.normal} normal, ${$.after.minor} minor (folded)`));let y=u.outcomes.filter($=>$.importance).length;u.outcomes.length===0&&console.log(ze.dim(" nothing to do: every event in scope already has a level (--force redoes the ones this job set)")),console.log(ze.dim(` ${y} event${y===1?"":"s"} ${o.dryRun?"would get":"got"} a level \xB7 ${u.left} left \xB7 ${u.calls} model call${u.calls===1?"":"s"} \xB7 spent $${u.costUsd.toFixed(3)} of $${c}${u.capped?" \xB7 stopped at the cap":""}`)),u.outcomes.some($=>$.status==="failed")&&(process.exitCode=1)});t.command("set <title> <level>").description("set an event's importance yourself (minor, normal or major); no later run changes it").option("--dir <path>","wiki directory (default .agentx/wiki)").action(async(o,n,s,r)=>{let{setEventLevel:i}=await import("./event-levels-WOYYEWSZ.js"),{IMPORTANCE_LEVELS:a}=await import("./types-YZX46RES.js"),c=n.toLowerCase();if(!a.includes(c)){console.error(ze.red(` level must be one of ${a.join(", ")}`)),process.exitCode=1;return}let{hub:l,g}=await Gc(Jc(r.optsWithGlobals().dir)),d=i(l,g,o,c);d.ok?console.log(ze.green(` ${d.title} is now ${c}`)+ze.dim(` (${d.page})`)):(console.error(ze.red(` not set: ${d.reason}`)),process.exitCode=1)}),t.command("proposed").description("list events a run suggests as major, waiting for you to decide").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--json","print as JSON").action(async(o,n)=>{let s=n.optsWithGlobals(),{g:r}=await Gc(Jc(s.dir)),i=[...r.entities.values()].filter(a=>a.type==="event"&&a.importanceProposed&&a.importanceProposed!==a.importance).sort((a,c)=>(c.date||"").localeCompare(a.date||""));if(s.json){console.log(JSON.stringify(i.map(a=>({id:a.id,title:a.title,date:a.date,importance:a.importance,proposed:a.importanceProposed})),null,2));return}for(let a of i)console.log(` ${a.date||"no date "} ${a.title} ${ze.dim(`now ${a.importance}, proposed ${a.importanceProposed}`)}`);console.log(ze.dim(i.length?` ${i.length} waiting. Decide each with: agentx wiki events set "<title>" major (or normal)`:" none waiting"))})}import $t from"chalk";import{resolve as ux}from"path";var px=e=>e||ux(process.cwd(),".agentx/wiki");function Pf(e){e.command("rules [pages...]").description("write one obligation page per rule the wiki states, with deadline, penalty, source and check date").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--words <list>","comma-separated words that mark a page as stating rules (default: deadline, penalty, filing\u2026 in English, French and Arabic)").option("--max <n>","most source pages per run","10").option("--max-cost <usd>","stop before the next call once the run spent this much","1").option("--model <m>","model","sonnet").option("--force","read again pages that did not change").option("--dry-run","show what would be written, write nothing").option("--json","print the run as JSON").action(async(t,o)=>{let{WikiHub:n}=await import("./hub-XGWCWKMT.js"),{GraphCache:s}=await import("./graph-ZVKV3JBD.js"),{loadOntology:r}=await import("./load-LQ2I2PQI.js"),{loadRoster:i}=await import("./roster-BZGKG2ZA.js"),{loadRulesState:a,ruleWordsPattern:c,runRules:l,saveRulesState:g}=await import("./rules-UVUJTVOE.js"),d=px(o.dir),f=Number(o.max);if(!Number.isInteger(f)||f<1){console.error($t.red(" --max must be a whole number of pages, 1 or more")),process.exitCode=1;return}let p=Number(o.maxCost);if(!Number.isFinite(p)||p<=0){console.error($t.red(" --max-cost must be a positive number of dollars")),process.exitCode=1;return}let u=o.words?.split(",").map(A=>A.trim()).filter(Boolean);if(o.words!==void 0&&!u?.length){console.error($t.red(" --words needs at least one word")),process.exitCode=1;return}let h=new n(d,()=>{}),{ontology:y}=r(d);if(!y.types.some(A=>A.id==="obligation")){console.error($t.red(" ontology.yaml has no `obligation` type; add it back to write rule pages")),process.exitCode=1;return}let $=new s().get(h,y,i(d,h.listAgents([]),y.agent_names)),b=a(d),v=await l(h,$,vm(o.model),{only:t,words:c(u),max:f,maxCostUsd:p,dryRun:!!o.dryRun,force:!!o.force,today:new Date().toISOString().slice(0,10),save:A=>g(d,A)},b);if(o.json){console.log(JSON.stringify(v,null,2));return}for(let A of v.outcomes){let x=A.status==="written"?$t.green("\u2713"):A.status==="dry-run"?$t.cyan("~"):$t.yellow("\xB7");console.log(` ${x} ${A.title} ${$t.dim(`${A.status} \xB7 ${A.page??"no page"} \xB7 ${A.rules.length} rules \xB7 $${A.costUsd.toFixed(3)}`)}`);for(let k of A.rules){let S=[k.deadline?"":"no deadline",k.penalty?"":"no penalty"].filter(Boolean);console.log(` ${k.created?"new":"updated"}: ${k.title} ${$t.dim(`\xB7 ${k.page}${S.length?` \xB7 ${S.join(", ")}`:""}${k.linked.length?` \xB7 linked from ${k.linked.join(", ")}`:""}`)}`),k.preview&&console.log($t.dim(k.preview.split(`
526
+ Check each claim at its source, then: agentx wiki facts proposals approve <id> \xB7 reject <id>`))})),o.command("approve <id>").description("confirm a claim and record it as a fact").option("--subject <text>","correct the subject read from the claim").option("--attribute <text>","correct the attribute").option("--value <text>","correct the value").option("--source <text>","where you checked it").option("--by <id>","who confirms it","operator").option("--dir <path>","wiki directory").action(ns(async(n,s)=>{let{approveFactProposal:r}=await import("./fact-proposals-X2O4W7VN.js"),{write:i}=r(await os(s.dir),n,s.by,{subject:s.subject,attribute:s.attribute,value:s.value,source:s.source});console.log(Le.green(` ${i.status}: ${i.fact.id} ${i.fact.subject} \xB7 ${i.fact.attribute}: ${i.fact.value}`))})),o.command("reject <id>").description("drop a claim; it is not recorded").option("--reason <text>","why, kept with the decision").option("--by <id>","who rejects it","operator").option("--dir <path>","wiki directory").action(ns(async(n,s)=>{let{rejectFactProposal:r}=await import("./fact-proposals-X2O4W7VN.js"),i=r(await os(s.dir),n,s.by,s.reason);console.log(Le.dim(` rejected: ${i.claim}`))}))}import Ge from"chalk";import{existsSync as If,readFileSync as Rf}from"fs";import{resolve as Wc}from"path";var Uc=e=>e||Wc(process.cwd(),".agentx/wiki");function lx(e){if(e)return e.replace(/\/+$/,"");if(process.env.AGENTX_DAEMON_URL)return process.env.AGENTX_DAEMON_URL.replace(/\/+$/,"");try{let t=Wc(process.cwd(),"agentx.json");if(If(t)){let o=JSON.parse(Rf(t,"utf-8"))?.node?.bind;if(typeof o=="string"&&o.includes(":")){let[n,s]=o.split(":");return`http://${n==="0.0.0.0"?"127.0.0.1":n}:${s}`}}}catch{}return"http://127.0.0.1:18800"}function Qt(e){console.error(Ge.red(` ${e}`)),process.exitCode=1}function Ci(e){return async(...t)=>{try{await e(...t)}catch(o){Qt(o?.message??String(o))}}}function Nf(e){let t=e.command("notes").description("notes agents leave for the wiki observe/sweep run: add, list, handle, config");t.command("add").description("leave a note for the wiki observe/sweep run: what changed, the source, the date").requiredOption("--change <text>","what changed, in a sentence or two").requiredOption("--source <text>",'where you saw it: a system, URL, command, or "owner said"').option("--date <YYYY-MM-DD>","when it changed or when you saw it (default: today)").option("--from <agent>","your agent id",process.env.AGENTX_AGENT_ID).option("--daemon <url>","this node's daemon (default: AGENTX_DAEMON_URL, else node.bind in agentx.json)").option("--dir <path>","write straight into this wiki directory instead of going through the daemon (needs --to)").option("--to <agent>","inbox agent, with --dir").option("--json").action(Ci(async o=>{if(!o.from){Qt("say who you are with --from <agent id>");return}let n={from:o.from,change:o.change,source:o.source,date:o.date},s;if(o.dir){if(!o.to){Qt("--dir needs --to <inbox agent>");return}let{NoteStore:a,validateNote:c}=await import("./notes-WJJEJ4CJ.js"),l=c({...n,to:o.to});if("error"in l){Qt(l.error);return}s={ok:!0,...new a(Uc(o.dir)).add(l.note)}}else{let a=lx(o.daemon),c;try{c=await fetch(`${a}/wiki/notes`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(2e4)})}catch(l){Qt(`could not reach the daemon at ${a}: ${l?.message??l}`);return}if(s=await c.json().catch(()=>({})),!c.ok){Qt(s?.error||`daemon answered ${c.status}`);return}}if(o.json){console.log(JSON.stringify(s,null,2));return}let r=s.note,i=s.peer?` on ${s.peer}`:"";console.log(s.added===!1?Ge.dim(` already in the inbox${i}: ${r?.id} (${r?.status})`):Ge.green(` note ${r?.id} left for ${r?.to}${i}; the next observe/sweep run reads it`))})),t.command("list").description("notes in this node's inbox (waiting ones by default)").option("--status <status>","waiting | open | patched | rejected | deferred | expired | all","waiting").option("--dir <path>","wiki directory").option("--json").action(Ci(async o=>{let{NoteStore:n}=await import("./notes-WJJEJ4CJ.js"),s=["waiting","open","patched","rejected","deferred","expired","all"];if(!s.includes(o.status)){Qt(`--status must be one of ${s.join(", ")}`);return}let r=new n(Uc(o.dir)),i=r.load();if(i.unreadable){Qt(`${r.path} is unreadable (${i.unreadable}); repair or move it aside`);return}let a=r.list(o.status==="all"?void 0:o.status);if(o.json){console.log(JSON.stringify(a,null,2));return}if(a.length===0){console.log(Ge.dim(` no ${o.status==="all"?"":`${o.status} `}notes`));return}for(let c of a){let l=c.status==="open"?Ge.yellow("open"):c.status==="deferred"?Ge.yellow("deferred"):Ge.dim(c.status);console.log(` ${Ge.cyan(c.id)} ${l} \xB7 from ${c.from}${c.fromNode?` on ${c.fromNode}`:""} \xB7 ${c.date}`),console.log(` ${c.change}`),console.log(Ge.dim(` source: ${c.source}`)),c.listedIn?.length&&console.log(Ge.dim(` given to: ${c.listedIn.at(-1)}${c.listedIn.length>1?` (+${c.listedIn.length-1} earlier)`:""}`)),c.handled&&console.log(Ge.dim(` ${c.handled.outcome}${c.deferrals?` (deferred ${c.deferrals}x)`:""} by ${c.handled.by} ${c.handled.at.slice(0,10)}: ${c.handled.reason}`)),c.expired&&console.log(Ge.dim(` expired ${c.expired.at.slice(0,10)} after ${c.expired.after} deferrals; no longer offered to the run`))}})),t.command("handle <id>").description("record what the run did with a note: patched, rejected or deferred, with a reason").requiredOption("--outcome <outcome>","patched | rejected | deferred").requiredOption("--reason <text>","what you patched, why you rejected it, or why it waits").option("--run <id>","the run that used it").option("--by <agent>","who handled it",process.env.AGENTX_AGENT_ID||"operator").option("--dir <path>","wiki directory").action(Ci(async(o,n)=>{let{NoteStore:s}=await import("./notes-WJJEJ4CJ.js"),r=new s(Uc(n.dir)).handle(o,n.outcome,n.reason,n.by,n.run);console.log(Ge.green(` note ${r.id}: ${r.status}`))})),t.command("config").description("show or set the inbox agent, and the schedules and absorb pass that read it").option("--inbox <agent>",'agent that runs the wiki observe/sweep schedule ("" clears it)').option("--cron <ids>",'comma-separated schedule ids that read the inbox ("" for none)').option("--absorb <agent>",'agent whose `wiki absorb` pass reads and answers the notes ("" clears it)').option("--max <n>","most notes one run is given (1-100)").option("--max-deferrals <n>","times a note may be deferred before it expires (1-20)").option("--enable","turn wiki notes on").option("--disable","turn wiki notes off").option("--json").action(Ci(async o=>{let{patchWikiNotes:n,wikiNotesSettings:s}=await import("./notes-settings-VPXI5IIS.js"),r={};if(o.inbox!==void 0&&(r.inbox=o.inbox),o.cron!==void 0&&(r.crons=String(o.cron).split(",")),o.absorb!==void 0&&(r.absorbAgent=o.absorb),o.max!==void 0&&(r.maxNotesPerRun=Number(o.max)),o.maxDeferrals!==void 0&&(r.maxDeferrals=Number(o.maxDeferrals)),o.enable&&o.disable){Qt("pick one of --enable and --disable");return}if(o.enable&&(r.enabled=!0),o.disable&&(r.enabled=!1),Object.keys(r).length>0){let{mutateAgentxConfig:c}=await import("./config-mutate-HXWAXWHC.js"),{summary:l}=c(g=>n(g,r));console.log(Ge.green(` ${l}`))}let i=Wc(process.cwd(),"agentx.json");if(!If(i)){Qt(`agentx.json not found at ${i}`);return}let a=s(JSON.parse(Rf(i,"utf-8"))?.wikiNotes);if(o.json){console.log(JSON.stringify(a,null,2));return}console.log(` wiki notes: ${a.enabled?Ge.green("on"):Ge.dim("off")}`),console.log(` inbox agent: ${a.inbox||Ge.dim("not set")}`),console.log(` schedules that read it: ${a.crons.length?a.crons.join(", "):Ge.dim("none on this node")}`),console.log(` absorb that reads it: ${a.absorbAgent?`wiki absorb for ${a.absorbAgent}`:Ge.dim("none")}`),console.log(` most notes per run: ${a.maxNotesPerRun}`),console.log(` deferrals before a note expires: ${a.maxDeferrals}`)}))}import No from"chalk";import{resolve as dx}from"path";var Bc=e=>e||dx(process.cwd(),".agentx/wiki");function jf(e){let t=e.command("ontology").description("the wiki's pillars, types, typed relations and page lenses (show, init, check)");t.command("init").description("write the default ontology to ontology.yaml in the wiki, to edit").option("--dir <path>","wiki directory (default .agentx/wiki)").action(async o=>{let{writeDefaultOntology:n}=await import("./load-LQ2I2PQI.js");try{let s=n(Bc(o.dir));console.log(No.green(` wrote ${s}`))}catch(s){console.error(No.red(` ${s.message}`)),process.exitCode=1}}),t.command("check").description("report problems in ontology.yaml").option("--dir <path>","wiki directory (default .agentx/wiki)").action(async o=>{let{loadOntology:n}=await import("./load-LQ2I2PQI.js"),{file:s,errors:r}=n(Bc(o.dir));if(!s){console.log(No.dim(" no ontology.yaml: the built-in defaults are in use"));return}if(r.length===0){console.log(No.green(` ${s}: no problems`));return}console.log(No.yellow(` ${s}: ${r.length} problem(s)`));for(let i of r)console.log(` - ${i}`);process.exitCode=1}),t.command("show").description("pages per pillar and type, as the wiki view groups them").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--json","print JSON").action(async o=>{let{loadOntology:n}=await import("./load-LQ2I2PQI.js"),{GraphCache:s}=await import("./graph-ZVKV3JBD.js"),{WikiHub:r}=await import("./hub-XGWCWKMT.js"),i=Bc(o.dir),{loadRoster:a}=await import("./roster-BZGKG2ZA.js"),{ontology:c,errors:l}=n(i),g=new r(i,()=>{}),d=new s().get(g,c,a(i,g.listAgents([]),c.agent_names)),f=new Map;for(let p of d.entities.values())f.set(p.type,(f.get(p.type)??0)+1);if(o.json){console.log(JSON.stringify({entities:d.entities.size,types:Object.fromEntries(f),errors:l},null,2));return}console.log(No.bold(` ${d.entities.size} entities`));for(let p of c.pillars){let u=c.types.filter(y=>y.pillar===p.id),h=u.reduce((y,$)=>y+(f.get($.id)??0),0);console.log(` ${p.label.padEnd(26)} ${String(h).padStart(6)} ${No.dim(u.map(y=>`${y.id} ${f.get(y.id)??0}`).join(" \xB7 "))}`)}l.length&&console.log(No.yellow(` ontology.yaml has ${l.length} problem(s): agentx wiki ontology check`))})}import ze from"chalk";import{resolve as gx}from"path";var Jc=e=>e||gx(process.cwd(),".agentx/wiki"),mx=()=>new Date().toISOString().slice(0,10);async function Gc(e){let{WikiHub:t}=await import("./hub-XGWCWKMT.js"),{GraphCache:o}=await import("./graph-ZVKV3JBD.js"),{loadOntology:n}=await import("./load-LQ2I2PQI.js"),{loadRoster:s}=await import("./roster-BZGKG2ZA.js"),r=new t(e,()=>{}),{ontology:i}=n(e),a=new o().get(r,i,s(e,r.listAgents([]),i.agent_names));return{hub:r,g:a}}function _f(e,t){let o=Number(e);return Number.isInteger(o)&&o>=1?o:(console.error(ze.red(` ${t} must be a whole number, 1 or more`)),process.exitCode=1,null)}function Df(e){let t=e.command("events").description("give each event page an importance level (minor, normal, major) and the pages it is about").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--about <titles...>","only events linked to or naming these pages (a pilot)").option("--max <n>","most events per run","200").option("--batch <n>","events per model call","20").option("--max-cost <usd>","stop before the next call once the run spent this much","1").option("--model <m>","model","haiku").option("--rules-only","use only the importance rules in ontology.yaml; no model call").option("--force","redo events whose level this job set earlier").option("--dry-run","show what would be written, write nothing").option("--json","print the run as JSON").action(async o=>{let{runEvents:n,summariseAbout:s}=await import("./event-levels-NBOMTB23.js"),{claudeCall:r}=await import("./wiki-enrich-JNQ2RPWU.js"),i=_f(o.max,"--max"),a=_f(o.batch,"--batch");if(i===null||a===null)return;let c=Number(o.maxCost);if(!Number.isFinite(c)||c<=0){console.error(ze.red(" --max-cost must be a positive number of dollars")),process.exitCode=1;return}let{hub:l,g}=await Gc(Jc(o.dir)),d=o.about??[],{normName:f}=await import("./graph-ZVKV3JBD.js"),p=d.filter($=>!g.names.has(f($))&&!g.entities.has($));if(p.length){console.error(ze.red(` no page is titled: ${p.join(", ")}`)),process.exitCode=1;return}let u=await n(l,g,r(o.model),{about:d,max:i,batch:a,maxCostUsd:c,dryRun:!!o.dryRun,force:!!o.force,rulesOnly:!!o.rulesOnly,today:mx()}),h=s(g,u,d);if(o.json){console.log(JSON.stringify({...u,about:h},null,2));return}for(let $ of u.outcomes){let b=$.status==="written"?ze.green("\u2713"):$.status==="dry-run"?ze.cyan("~"):ze.yellow("\xB7"),v=$.importance?`${$.importance}${$.proposed?` (proposed ${$.proposed})`:""}`:$.status;console.log(` ${b} ${$.date||"no date "} ${v.padEnd(8)} ${$.title} ${ze.dim(`${$.by??$.status}${$.about.length?` \xB7 about ${$.about.join(", ")}`:""}${$.why?` \xB7 ${$.why}`:""}`)}`);for(let A of $.dropped.slice(0,4))console.log(ze.dim(` dropped: ${A}`))}for(let $ of h)console.log(ze.bold(` ${$.title}`)+ze.dim(` (${$.type}): ${$.before} events in its History before \xB7 after: ${$.after.major} major, ${$.after.normal} normal, ${$.after.minor} minor (folded)`));let y=u.outcomes.filter($=>$.importance).length;u.outcomes.length===0&&console.log(ze.dim(" nothing to do: every event in scope already has a level (--force redoes the ones this job set)")),console.log(ze.dim(` ${y} event${y===1?"":"s"} ${o.dryRun?"would get":"got"} a level \xB7 ${u.left} left \xB7 ${u.calls} model call${u.calls===1?"":"s"} \xB7 spent $${u.costUsd.toFixed(3)} of $${c}${u.capped?" \xB7 stopped at the cap":""}`)),u.outcomes.some($=>$.status==="failed")&&(process.exitCode=1)});t.command("set <title> <level>").description("set an event's importance yourself (minor, normal or major); no later run changes it").option("--dir <path>","wiki directory (default .agentx/wiki)").action(async(o,n,s,r)=>{let{setEventLevel:i}=await import("./event-levels-NBOMTB23.js"),{IMPORTANCE_LEVELS:a}=await import("./types-YZX46RES.js"),c=n.toLowerCase();if(!a.includes(c)){console.error(ze.red(` level must be one of ${a.join(", ")}`)),process.exitCode=1;return}let{hub:l,g}=await Gc(Jc(r.optsWithGlobals().dir)),d=i(l,g,o,c);d.ok?console.log(ze.green(` ${d.title} is now ${c}`)+ze.dim(` (${d.page})`)):(console.error(ze.red(` not set: ${d.reason}`)),process.exitCode=1)}),t.command("proposed").description("list events a run suggests as major, waiting for you to decide").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--json","print as JSON").action(async(o,n)=>{let s=n.optsWithGlobals(),{g:r}=await Gc(Jc(s.dir)),i=[...r.entities.values()].filter(a=>a.type==="event"&&a.importanceProposed&&a.importanceProposed!==a.importance).sort((a,c)=>(c.date||"").localeCompare(a.date||""));if(s.json){console.log(JSON.stringify(i.map(a=>({id:a.id,title:a.title,date:a.date,importance:a.importance,proposed:a.importanceProposed})),null,2));return}for(let a of i)console.log(` ${a.date||"no date "} ${a.title} ${ze.dim(`now ${a.importance}, proposed ${a.importanceProposed}`)}`);console.log(ze.dim(i.length?` ${i.length} waiting. Decide each with: agentx wiki events set "<title>" major (or normal)`:" none waiting"))})}import $t from"chalk";import{resolve as ux}from"path";var px=e=>e||ux(process.cwd(),".agentx/wiki");function Pf(e){e.command("rules [pages...]").description("write one obligation page per rule the wiki states, with deadline, penalty, source and check date").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--words <list>","comma-separated words that mark a page as stating rules (default: deadline, penalty, filing\u2026 in English, French and Arabic)").option("--max <n>","most source pages per run","10").option("--max-cost <usd>","stop before the next call once the run spent this much","1").option("--model <m>","model","sonnet").option("--force","read again pages that did not change").option("--dry-run","show what would be written, write nothing").option("--json","print the run as JSON").action(async(t,o)=>{let{WikiHub:n}=await import("./hub-XGWCWKMT.js"),{GraphCache:s}=await import("./graph-ZVKV3JBD.js"),{loadOntology:r}=await import("./load-LQ2I2PQI.js"),{loadRoster:i}=await import("./roster-BZGKG2ZA.js"),{loadRulesState:a,ruleWordsPattern:c,runRules:l,saveRulesState:g}=await import("./rules-5ZZQZLQA.js"),d=px(o.dir),f=Number(o.max);if(!Number.isInteger(f)||f<1){console.error($t.red(" --max must be a whole number of pages, 1 or more")),process.exitCode=1;return}let p=Number(o.maxCost);if(!Number.isFinite(p)||p<=0){console.error($t.red(" --max-cost must be a positive number of dollars")),process.exitCode=1;return}let u=o.words?.split(",").map(A=>A.trim()).filter(Boolean);if(o.words!==void 0&&!u?.length){console.error($t.red(" --words needs at least one word")),process.exitCode=1;return}let h=new n(d,()=>{}),{ontology:y}=r(d);if(!y.types.some(A=>A.id==="obligation")){console.error($t.red(" ontology.yaml has no `obligation` type; add it back to write rule pages")),process.exitCode=1;return}let $=new s().get(h,y,i(d,h.listAgents([]),y.agent_names)),b=a(d),v=await l(h,$,vm(o.model),{only:t,words:c(u),max:f,maxCostUsd:p,dryRun:!!o.dryRun,force:!!o.force,today:new Date().toISOString().slice(0,10),save:A=>g(d,A)},b);if(o.json){console.log(JSON.stringify(v,null,2));return}for(let A of v.outcomes){let x=A.status==="written"?$t.green("\u2713"):A.status==="dry-run"?$t.cyan("~"):$t.yellow("\xB7");console.log(` ${x} ${A.title} ${$t.dim(`${A.status} \xB7 ${A.page??"no page"} \xB7 ${A.rules.length} rules \xB7 $${A.costUsd.toFixed(3)}`)}`);for(let k of A.rules){let S=[k.deadline?"":"no deadline",k.penalty?"":"no penalty"].filter(Boolean);console.log(` ${k.created?"new":"updated"}: ${k.title} ${$t.dim(`\xB7 ${k.page}${S.length?` \xB7 ${S.join(", ")}`:""}${k.linked.length?` \xB7 linked from ${k.linked.join(", ")}`:""}`)}`),k.preview&&console.log($t.dim(k.preview.split(`
527
527
  `).map(C=>` | ${C}`).join(`
528
528
  `)))}for(let k of A.dropped.slice(0,6))console.log($t.dim(` dropped: ${k}`))}v.outcomes.length===0&&console.log($t.dim(" nothing to do: no page that states rules changed since the last run (--force reads them again)")),console.log($t.dim(` spent $${v.costUsd.toFixed(3)} of $${p}${v.capped?" \xB7 stopped at the cap":""}`))})}import Oi from"chalk";import{resolve as fx}from"path";var hx=e=>e||fx(process.cwd(),".agentx/wiki");function Mf(e){e.command("summarize").description("write the one-line page summaries `wiki query` picks pages from; only new or changed pages are summarised").option("--dir <path>","wiki directory (default .agentx/wiki)").option("--agent <id>","summarise this agent's pages (default: the calling agent)").option("--all","summarise every agent's pages and the shared pages").option("--model <m>","model (default: wiki.summaries.model, haiku)").option("--batch <n>","pages per model call (default: wiki.summaries.batchSize, 20)").option("--workers <n>","model calls running at once","4").option("--limit <n>","most pages to summarise per agent in this run (0 = all)","0").option("--dry-run","show how many pages are due, call no model, write nothing").option("--json","print the run as JSON").action(async t=>{let{WikiHub:o}=await import("./wiki-ISKHNG3P.js"),{summarizeStore:n}=await import("./summaries-BIRSNWGH.js"),{claudeModelCall:s}=await import("./model-call-J7JATTMW.js"),r={model:"haiku",batchSize:20,maxWords:35};try{let{loadDaemonConfig:g}=await import("./config-THFRJMZD.js");r=g().wiki.summaries}catch{}let i=new o(hx(t.dir),void 0,"graph"),a=t.agent||process.env.AGENTX_AGENT_ID;if(!t.all&&!a){console.log(Oi.red(" Name an agent with --agent <id>, or pass --all.")),process.exitCode=1;return}let c=t.all?[...i.sharedScope("").map(g=>({id:g.id,store:g.store,skip:g.skip}))]:[{id:a,store:i.getAgentWiki(a),skip:void 0}],l=[];for(let g of c){let d=await n(g.store,{call:s,model:t.model??r.model,batchSize:t.batch?parseInt(t.batch):r.batchSize,maxWords:r.maxWords,workers:parseInt(t.workers),limit:parseInt(t.limit),dryRun:t.dryRun,skip:g.skip,log:t.json?void 0:f=>console.log(Oi.dim(` ${g.id}: ${f}`))});if(l.push({agent:g.id,...d}),!t.json&&(d.pages>0||d.removed>0)){let f=t.dryRun?`${d.due} due`:`${d.written} written${d.failed?Oi.yellow(`, ${d.failed} failed`):""}${d.removed?`, ${d.removed} removed`:""}`;console.log(` ${Oi.bold(g.id)}: ${d.pages} pages, ${f}`)}}t.json&&console.log(JSON.stringify(l,null,2)),l.some(g=>g.failed>0)&&(process.exitCode=1)})}import{resolve as F,relative as Lf,dirname as Ff}from"path";import{exec as wx,execSync as pn}from"child_process";import{promisify as $x}from"util";import{appendFileSync as bx,statSync as kx,writeFileSync as Ct,mkdirSync as qt,readFileSync as Ot,readdirSync as vx,renameSync as Ti,rmSync as zc,existsSync as Ye}from"fs";var Gf=$x(wx);function we(e,t){return new ta(gt(e),void 0,t||"graph")}async function Hf(e){let t=[];try{let{loadDaemonConfig:n}=await import("./config-THFRJMZD.js");t=(n().mesh?.peers||[]).map(s=>({url:s.url,token:s.token}))}catch{}if(!e?.length)return t;let o=n=>n.replace(/\/$/,"");return e.map(n=>({url:n,token:t.find(s=>o(s.url)===o(n))?.token}))}async function zf(){try{let{loadDaemonConfig:e}=await import("./config-THFRJMZD.js"),t=Object.keys(e().agents||{});return t.length?new Set(t):null}catch{return null}}async function qf(){try{let{loadDaemonConfig:e}=await import("./config-THFRJMZD.js"),t=e().wikiNotes;return!t?.enabled||!t.inbox||!t.absorbAgent?null:{inbox:t.inbox,absorbAgent:t.absorbAgent,max:t.maxNotesPerRun,maxDeferrals:t.maxDeferrals}}catch{return null}}async function xx(){try{let{loadDaemonConfig:e}=await import("./config-THFRJMZD.js");return gm(e().agents||{})}catch{return new Set}}function fn(e,t){let o=e.syncedFrom(t);return o?(console.log(m.yellow(` ${t}'s articles are copied from ${o.node} and read-only here; change them on ${o.node}.`)),process.exitCode=1,!0):!1}async function Uf(){let{sharedQueryEnabled:e}=await import("./query-X4AFOKZ7.js");return e()}async function Yf(e){let{loadQuerySettings:t}=await import("./query-settings-HV2RFQK7.js"),o=await t();if(e.method&&!["auto","summaries","catalog"].includes(e.method))return console.log(m.red(` --method takes auto, summaries or catalog, not "${e.method}".`)),process.exitCode=1,null;let n=e.linked===void 0?o.summaries.linkedPages:Number(e.linked);if(!Number.isInteger(n)||n<0||n>10)return console.log(m.red(` --linked takes a whole number from 0 to 10, not "${e.linked}".`)),process.exitCode=1,null;let s={...o.summaries.live,enabled:o.summaries.live.enabled&&e.live!==!1},r={...o.notes,enabled:o.notes.enabled&&e.notes!==!1};return{...o,method:e.method??o.method,summaries:{...o.summaries,linkedPages:n,live:s},notes:r}}function gt(e){return e||F(process.cwd(),".agentx/wiki")}function Yc(e){return e==="graph"?"Knowledge Graph":e==="flat"?"Karpathy Flat":"Unified"}var J=new yx().name("wiki").description("wiki knowledge base management");Tf(J);Nf(J);jf(J);xm(J);Df(J);Pf(J);Mf(J);J.command("status").description("show wiki status per agent").option("--dir <path>","wiki directory").option("--mode <mode>","graph (default, canonical) | unified | flat (legacy, back-compat)","graph").action(e=>{let t=e.mode,o=we(e.dir,t),n=o.summary(),r=o.getSharedStore().listEntries().length;console.log(),console.log(m.bold(` Wiki Hub Status [${Yc(t)}]`)),console.log(),console.log(` Total raw entries: ${r}`),console.log(` Agents: ${n.length}`),console.log();for(let a of n){let c=a.unabsorbed>0?m.yellow(`${a.unabsorbed} unabsorbed`):m.green("up to date");if(console.log(` ${m.cyan(a.agentId)}`),console.log(` Entries: ${a.totalEntries} Articles: ${a.totalArticles} ${c}`),console.log(m.dim(` Cited by an article: ${a.cited} Read, not cited: ${a.readNotCited}`)),a.articles.length>0){for(let l of a.articles.slice(0,3))console.log(m.dim(` - ${l.title} [${(l.tags||[]).slice(0,3).join(", ")}]`));a.articles.length>3&&console.log(m.dim(` ... and ${a.articles.length-3} more`))}console.log()}let i=n.reduce((a,c)=>a+c.unabsorbed,0);i>0&&(console.log(m.dim(` ${i} raw entries wait for absorb \u2014 run 'agentx wiki absorb'.`)),console.log())});J.command("lint").description("check wiki for issues per agent").option("--dir <path>","wiki directory").option("--mode <mode>","graph (default, canonical) | unified | flat (legacy, back-compat)","graph").option("--agent <id>","lint a specific agent's wiki").action(async e=>{let t=we(e.dir,e.mode),o=e.agent?[e.agent]:t.listAgents(),n=0;console.log();for(let i of o){let c=t.getAgentWiki(i).lint();if(n+=c.length,c.length===0)console.log(` ${m.cyan(i)}: ${m.green("healthy")}`);else{console.log(` ${m.cyan(i)}: ${m.yellow(`${c.length} issues`)}`);for(let l of c){let g=l.type==="broken-link"?"x":l.type==="orphan"?"?":"!";console.log(` [${g}] ${m.dim(l.type)} ${l.article}: ${l.message}`)}}}let{factContradictions:s}=await import("./ledger-P62U3FHT.js"),r=s(gt(e.dir));if(n+=r.length,r.length>0){console.log(` ${m.cyan("facts")}: ${m.yellow(`${r.length} contradiction(s)`)}`);for(let i of r)console.log(` [!] ${m.dim(i.type)} ${i.articles[0]}: ${i.message}`)}console.log(),n===0&&console.log(m.green(" All agent wikis are healthy")),console.log()});J.command("absorb").description("compile unabsorbed entries into typed per-agent wiki articles (Farzapedia-faithful)").option("--dir <path>","wiki directory").option("--mode <mode>","graph (default, canonical) | unified | flat (legacy, back-compat)","graph").option("--agent <id>","absorb only this agent").option("--dry-run","preview without running").option("--no-facts","skip the system-of-record lookups").option("--max <n>","max entries per agent","10").option("--since <date>","only entries dated on or after YYYY-MM-DD").option("--until <date>","only entries dated on or before YYYY-MM-DD").option("--model <model>","compile model (default: AGENTX_WIKI_ABSORB_MODEL, else sonnet)").option("--run-label <label>","tag this run's lines in _absorb-runs.jsonl, for `wiki absorb-runs`").option("--no-notes","do not read the wiki notes inbox, even for wikiNotes.absorbAgent").action(async e=>{let t=e.mode,o;try{o=Fc(e.model)}catch(C){console.log(m.red(` ${C.message}`)),process.exitCode=1;return}let n=we(e.dir,t),s=await zf(),{agents:r,skipped:i}=mm(n.listAgents().filter(C=>!s||s.has(C)),{only:e.agent,off:await xx()}),a=i.length&&e.notes!==!1?(await qf())?.absorbAgent:void 0;for(let C of i)console.log(` ${m.cyan(C)}: ${m.dim(um(C,a))}`);let c=r.filter(C=>{let T=n.syncedFrom(C);return T&&console.log(` ${m.cyan(C)}: ${m.dim(`copied from ${T.node}, read-only here; absorb it there`)}`),!T}),l=parseInt(e.max),g=(()=>{try{let C=F(process.cwd(),".agentx/graph");return Ye(C)?new po({baseDir:C}):null}catch{return null}})(),d=new Map;if(g)try{let C=g.loadIndex();for(let[T,I]of Object.entries(C.entries))d.set(T,I.path)}catch{}let f,p=C=>{let T=C.meta?.intentPath;if(Array.isArray(T)&&T.every(_=>typeof _=="string")&&T.length>0)return T;if(!g||d.size===0)return;let I=String(C.meta?.sender??""),D=g.fingerprint({text:C.content,channel:C.source,sender:I});return d.get(D)},u=(C,T)=>{let I=new Map;for(let _ of C){let W=T.find(qe=>qe.id===_);if(!W)continue;let Y=p(W);if(!Y?.length)continue;let K=Y.join("/"),Z=I.get(K);Z?Z.n++:I.set(K,{path:Y,n:1})}if(I.size===0)return;let D;for(let _ of I.values())(!D||_.n>D.n)&&(D=_);return D?.path},h=0,y=0,$=0,b=F(n.getBaseDir(),"_absorb-runs.jsonl"),v=typeof e.runLabel=="string"&&e.runLabel.trim()?e.runLabel.trim():void 0,A=C=>{if(!e.dryRun)try{bx(b,`${JSON.stringify(C)}
529
529
  `)}catch{}},x=new Date().toISOString(),k=e.notes===!1?null:await qf(),S=k?new rd(n.getBaseDir()):null;for(let C of c){let T=Date.now(),I=typeof e.since=="string"?e.since.trim():"",D=typeof e.until=="string"?e.until.trim():"",_=n.getUnabsorbedEntries(C).filter(re=>!I||(re.date??"")>=I).filter(re=>!D||(re.date??"").slice(0,10)<=D).slice(0,l),W=!!(k&&S&&k.absorbAgent===C),Y=`absorb/${C}/${x.replace(/[:.]/g,"-")}`,K=[];if(W&&e.dryRun?K=S.peekForRun(k.inbox,k.max,k.maxDeferrals):W&&(K=S.takeForRun(k.inbox,Y,k.max,k.maxDeferrals)),_.length===0&&K.length===0){console.log(` ${m.cyan(C)}: ${m.green("all absorbed")}`);continue}console.log(),console.log(m.bold(` ${m.cyan(C)}: ${_.length} entries to absorb`));for(let re of _.slice(0,3))console.log(m.dim(` [${re.date} via ${re.source}] ${re.content.slice(0,80)}...`));if(_.length>3&&console.log(m.dim(` ... and ${_.length-3} more`)),K.length>0&&console.log(m.dim(` Wiki notes: ${K.length} from the ${k.inbox} inbox${e.dryRun?"":` (run ${Y})`}`)),e.dryRun)continue;let Z=n.getAgentWiki(C),qe=Z.rebuildIndex(),Ue=Z.getWorldview()||n.getSharedStore().getWorldview()||"",P=_.map(re=>`--- ENTRY ${re.id} [${re.date} ${re.agentId} via ${re.source}] ---
@@ -757,7 +757,7 @@ Restart the daemon to activate.
757
757
  dist/
758
758
  *.log
759
759
  .env
760
- `}import{Command as uS}from"commander";import Ke from"chalk";import{writeFileSync as pS,mkdirSync as fS,existsSync as Hi,readFileSync as qh,appendFileSync as Uh}from"fs";import{resolve as ps,dirname as Jh}from"path";import{homedir as pl}from"os";var Gh=new uS().name("completion").description("generate a shell completion script for agentx").option("-s, --shell <shell>","shell to generate completion for: zsh|bash|fish","zsh").option("-i, --install","install the completion script to a default path for the shell").option("-o, --output <path>","write the script to this path (overrides default install path)").option("-y, --yes","skip confirmation prompts (non-interactive)").action(async e=>{let{buildProgram:t}=await import("./program-7VHY5RVZ.js"),o=await t(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=wS(o);break;case"bash":s=xS(o);break;case"fish":s=SS(o);break;default:console.error(Ke.red(`unsupported shell: ${n}`)),console.error(Ke.dim("supported: zsh, bash, fish")),process.exit(1)}if(!e.install&&!e.output){process.stdout.write(s);return}let r=e.output?ps(String(e.output)):hS(n);fS(Jh(r),{recursive:!0}),pS(r,s),console.log(Ke.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${r}`),console.log(),yS(n,r,!!e.yes)});function hS(e){let t=pl();switch(e){case"zsh":return ps(t,".zsh","completions","_agentx");case"bash":return ps(t,".bash_completion.d","agentx.bash");case"fish":return ps(t,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function yS(e,t,o){if(e==="zsh"){let n=ps(pl(),".zshrc"),s=Jh(t),r=`fpath=(${s} $fpath)`,i="autoload -U compinit && compinit",a=Hi(n)?qh(n,"utf-8"):"",c=!a.includes(s),l=!/autoload\s+-U\s+compinit/.test(a);if(!c&&!l){console.log(Ke.dim("~/.zshrc already has fpath + compinit wired up. Run `exec zsh` to pick up the new script."));return}if(o&&Hi(n)){let g=["","# agentx completion"];c&&g.push(r),l&&g.push(i),Uh(n,g.join(`
760
+ `}import{Command as uS}from"commander";import Ke from"chalk";import{writeFileSync as pS,mkdirSync as fS,existsSync as Hi,readFileSync as qh,appendFileSync as Uh}from"fs";import{resolve as ps,dirname as Jh}from"path";import{homedir as pl}from"os";var Gh=new uS().name("completion").description("generate a shell completion script for agentx").option("-s, --shell <shell>","shell to generate completion for: zsh|bash|fish","zsh").option("-i, --install","install the completion script to a default path for the shell").option("-o, --output <path>","write the script to this path (overrides default install path)").option("-y, --yes","skip confirmation prompts (non-interactive)").action(async e=>{let{buildProgram:t}=await import("./program-SJT7PIFO.js"),o=await t(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=wS(o);break;case"bash":s=xS(o);break;case"fish":s=SS(o);break;default:console.error(Ke.red(`unsupported shell: ${n}`)),console.error(Ke.dim("supported: zsh, bash, fish")),process.exit(1)}if(!e.install&&!e.output){process.stdout.write(s);return}let r=e.output?ps(String(e.output)):hS(n);fS(Jh(r),{recursive:!0}),pS(r,s),console.log(Ke.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${r}`),console.log(),yS(n,r,!!e.yes)});function hS(e){let t=pl();switch(e){case"zsh":return ps(t,".zsh","completions","_agentx");case"bash":return ps(t,".bash_completion.d","agentx.bash");case"fish":return ps(t,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function yS(e,t,o){if(e==="zsh"){let n=ps(pl(),".zshrc"),s=Jh(t),r=`fpath=(${s} $fpath)`,i="autoload -U compinit && compinit",a=Hi(n)?qh(n,"utf-8"):"",c=!a.includes(s),l=!/autoload\s+-U\s+compinit/.test(a);if(!c&&!l){console.log(Ke.dim("~/.zshrc already has fpath + compinit wired up. Run `exec zsh` to pick up the new script."));return}if(o&&Hi(n)){let g=["","# agentx completion"];c&&g.push(r),l&&g.push(i),Uh(n,g.join(`
761
761
  `)+`
762
762
  `),console.log(Ke.green("\u2713 Patched ~/.zshrc")),console.log(Ke.dim("Reload your shell: exec zsh"));return}console.log(Ke.dim("Add this to ~/.zshrc if not already present:")),c&&console.log(Ke.cyan(` ${r}`)),l&&console.log(Ke.cyan(` ${i}`)),console.log(),console.log(Ke.dim("Then reload: exec zsh")),console.log(Ke.dim("Or rerun with --yes to auto-patch ~/.zshrc"));return}if(e==="bash"){let n=ps(pl(),".bashrc"),s=`[ -f "${t}" ] && source "${t}"`;if((Hi(n)?qh(n,"utf-8"):"").includes(t)){console.log(Ke.dim("~/.bashrc already sources this file. Start a new shell to pick it up."));return}if(o&&Hi(n)){Uh(n,`
763
763
  # agentx completion
@@ -773,4 +773,4 @@ ${AS({...t,category:e.category})}`),g&&a.set(l.id,g)}let c=`https://github.com/$
773
773
  ${o.url}`)}catch(t){console.error(hs.red(` ${t.message}`)),process.exitCode=1}});ar.command("draft <file>").description("turn a draft JSON file ({category, title, fields}) into a pre-filled issue form link; '-' reads stdin").requiredOption("--model <model>","the model that wrote the draft").option("--models <pathOrUrl>","model list to read",hl).action(async(e,t)=>{try{let o=await $l(t.models);if(!yl(t.model,o)){console.log(wl(t.model,o)),process.exitCode=1;return}let n=e==="-"?await OS():await CS(e,"utf8"),s=JSON.parse(n),{version:r}=await yr(),i=Vh({...s,fields:s.fields??{}},{model:t.model,version:r??"unknown"});console.log(i)}catch(o){console.error(hs.red(` ${o.message}`)),process.exitCode=1}});async function OS(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}async function YM(){let e=await yr(),t=new TS().name("agentx").description("self-hosted multi-agent orchestrator \u2014 Telegram, WhatsApp, crons, A2A mesh, wiki knowledge").version(e.version||"1.0.0","-v, --version","display the version number");t.hook("preAction",(o,n)=>{let s=lm(n);dm(s)&&cm("cli",s)});for(let o of[Km,Xm,ts,Dn,zo,It,zg,Yo,Hr,ro,ao,mn,pf,Io,Gr,hh,Eo,Mu,Lu,zu,Us,sp,cp,Du,gp,mp,Tp,jp,_p,Et,un,vh,Is,ko,Gh,ar])t.addCommand(o);for(let o of Kh)t.addCommand(o,{hidden:!0});return t.addHelpText("after",()=>{let o=Kh.map(n=>n.name()).sort();return["",`Advanced (${o.length}, hidden \u2014 run \`agentx <command> --help\` for any of them):`,IS(o,74," "),""].join(`
774
774
  `)}),t}var Kh=[J,ss,lo,Ut,js,Vn,Ve,co,Ro,dn,cs,ls,So,ut,Un,ri,ki,ln,uh,ph,so,xt,Em,Xo,rr,Ga,_o,yt,Fn,Ha,Fi,Zt,go,_h,Dh,bh];function IS(e,t,o){let n=[],s="";for(let r of e)s&&s.length+r.length+2>t&&(n.push(o+s),s=""),s+=(s?", ":"")+r;return s&&n.push(o+s),n.join(`
775
775
  `)}export{YM as buildProgram};
776
- //# sourceMappingURL=program-7VHY5RVZ.js.map
776
+ //# sourceMappingURL=program-SJT7PIFO.js.map