agentix-cli 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{board-dashboard-R7FWWFFK.js → board-dashboard-HLTVSSGW.js} +128 -97
- package/dist/board-dashboard-HLTVSSGW.js.map +1 -0
- package/dist/{chunk-L2RUE6T4.js → chunk-FZ3ZDG6T.js} +113 -113
- package/dist/{chunk-L2RUE6T4.js.map → chunk-FZ3ZDG6T.js.map} +1 -1
- package/dist/{chunk-R3VXG2Q5.js → chunk-ITIMNSFR.js} +4 -4
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-E6AXVO5W.js → program-FJLMTESZ.js} +2 -2
- package/package.json +1 -1
- package/dist/board-dashboard-R7FWWFFK.js.map +0 -1
- /package/dist/{chunk-R3VXG2Q5.js.map → chunk-ITIMNSFR.js.map} +0 -0
- /package/dist/{program-E6AXVO5W.js.map → program-FJLMTESZ.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as Gr,b as hn,g as zr}from"./chunk-SJPLXXCI.js";import{b as qr}from"./chunk-B5HKRYCU.js";import{a as Zo,b as Fr,f as fn,j as Hr}from"./chunk-REPZID5M.js";import{a as Wr,c as Br,d as Jr}from"./chunk-2TJ5L7CB.js";import{a as Xo}from"./chunk-GV7S5BAX.js";import{e as Wi}from"./chunk-GSX4NK2N.js";import{c as Bi}from"./chunk-SZDACK6O.js";import{$ as Ct,A as ds,B as ln,C as br,D as Qo,E as uo,F as $r,G as gs,H as ms,I as kr,J as vr,K as It,L as dn,M as xr,N as Sr,O as Er,P as gn,Q as Ar,R as Or,S as ps,T as mn,U as pn,V as jr,W as Ir,X as Cr,Y as Tr,Z as Ee,_ as un,a as Qi,aa as us,b as Zi,ba as Nr,ca as Rr,da as _r,ea as Lr,fa as ys,ga as ws,h as nr,ha as Mr,i as sr,ia as Ur,j as Ot,k as cn,l as ir,m as rr,n as ar,o as cr,p as lr,q as dr,r as gr,s as mr,t as pr,u as ur,v as fr,w as hr,x as yr,y as wr,z as jt}from"./chunk-
|
|
1
|
+
import{a as Gr,b as hn,g as zr}from"./chunk-SJPLXXCI.js";import{b as qr}from"./chunk-B5HKRYCU.js";import{a as Zo,b as Fr,f as fn,j as Hr}from"./chunk-REPZID5M.js";import{a as Wr,c as Br,d as Jr}from"./chunk-2TJ5L7CB.js";import{a as Xo}from"./chunk-GV7S5BAX.js";import{e as Wi}from"./chunk-GSX4NK2N.js";import{c as Bi}from"./chunk-SZDACK6O.js";import{$ as Ct,A as ds,B as ln,C as br,D as Qo,E as uo,F as $r,G as gs,H as ms,I as kr,J as vr,K as It,L as dn,M as xr,N as Sr,O as Er,P as gn,Q as Ar,R as Or,S as ps,T as mn,U as pn,V as jr,W as Ir,X as Cr,Y as Tr,Z as Ee,_ as un,a as Qi,aa as us,b as Zi,ba as Nr,ca as Rr,da as _r,ea as Lr,fa as ys,ga as ws,h as nr,ha as Mr,i as sr,ia as Ur,j as Ot,k as cn,l as ir,m as rr,n as ar,o as cr,p as lr,q as dr,r as gr,s as mr,t as pr,u as ur,v as fr,w as hr,x as yr,y as wr,z as jt}from"./chunk-FZ3ZDG6T.js";import{i as Dr,j as fs,k as Pr,l as hs}from"./chunk-F6CNF7V3.js";import{a as er,d as or,e as tr}from"./chunk-FAJEBVZE.js";import{J as Xi,m as Mi,o as Yo,q as as,r as Fi,t as po,z as Ki}from"./chunk-DIKZWTL5.js";import{b as Vo,c as rn,d as an,e as Ko,f as qi,g as Co,h as At}from"./chunk-P7LNYB53.js";import{d as ls,f as Yi}from"./chunk-VMDA2SX2.js";import{a as zi}from"./chunk-QLTM3F7M.js";import{a as Ui,e as Gi}from"./chunk-NZ6AQIKJ.js";import{f as Ji,g as Hi,h as cs}from"./chunk-76Z4VHDX.js";import{a as de,b as be,c as To,d as Vi}from"./chunk-B32HVIDN.js";import{h as Li}from"./chunk-DWADWDMU.js";import{b as mo,d as sn,f as rs}from"./chunk-RCVGIKC2.js";import{b as zo,d as Pi}from"./chunk-2GIDVZ4H.js";import{a as is,b as Si,c as wl,d as tn,e as Ei,f as Ci,g as $l,h as Ti,i as kl,m as Go,n as Ri,o as _i,s as Di,v as Xe,w as Et}from"./chunk-H4MIYENA.js";import{a as Ni,b as vl}from"./chunk-AJONZWLT.js";import{a as io,b as Ho,e as Oi,f as St}from"./chunk-F4HZTZHW.js";import{a as so,b as yl}from"./chunk-L2WSPY6S.js";import{f as Ai,g as D,h as nn,j as we}from"./chunk-IAG6FI3Q.js";import{g as ji,k as Ii,l as bl}from"./chunk-BH3GTCZ6.js";import{a as hl}from"./chunk-FIOB3MEX.js";import{Command as xl}from"commander";var Yr=new xl().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 Zi({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()});we();import{Command as Sl}from"commander";import{execFileSync as ro}from"node:child_process";import{cpSync as Vr,existsSync as ks,mkdirSync as bs,mkdtempSync as El,readFileSync as Al,rmSync as Ol,writeFileSync as Kr}from"node:fs";import{dirname as $s,join as Ie,resolve as Xr}from"node:path";import{homedir as yn,release as jl,tmpdir as Il}from"node:os";import{fileURLToPath as Cl}from"node:url";import{setTimeout as Tl}from"node:timers/promises";function wn(){let e=jr(process.platform,process.arch,jl());if(e)throw new Error(e)}function Tt(){return`gui/${process.getuid()}/${ps}`}function et(){return Ie(yn(),"Library/LaunchAgents",`${ps}.plist`)}async function Qr(){try{ro("launchctl",["bootout",Tt()],{stdio:"pipe"})}catch{}for(let e=0;e<30;e++){try{ro("launchctl",["print",Tt()],{stdio:"pipe"})}catch{return}await Tl(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function Zr(){if(!ks(et()))throw new Error("Run agentx desktop install first.");let e=!0;try{ro("launchctl",["print",Tt()],{stdio:"pipe"})}catch{e=!1}e||ro("launchctl",["bootstrap",`gui/${process.getuid()}`,et()],{stdio:"pipe"}),ro("launchctl",["kickstart",Tt()],{stdio:"pipe"})}function Nl(){let e=$s(Cl(import.meta.url));for(let o of[Xr(e,".."),Xr(e,"../.."),process.cwd()])try{if(JSON.parse(Al(Ie(o,"package.json"),"utf8")).name==="agentix-cli"&&ks(Ie(o,"apps/mac-voice/build.sh")))return o}catch{}throw new Error("Desktop sources are missing from this installation. Update AgentX to a release containing apps/mac-voice and apps/mac-helper.")}var ot=new Sl("desktop").description("install and control the macOS desktop assistant");ot.command("install").description("build, install, and start voice and computer-use helpers at login").option("--agent <id>","agent to use (defaults to the first configured agent)").option("--dry-run","show the installation plan without building or changing login items").action(async e=>{wn();let o=D(),t=Ir(o.agents,e.agent),n=o.dashboard?.daemonUrl||`http://${o.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:")}`,s=Nl(),i=Ie(yn(),"Applications");if(console.log(`Desktop assistant \u2192 ${Ie(i,mn)}
|
|
2
2
|
Computer-use helper \u2192 ${Ie(i,pn)}
|
|
3
3
|
Agent \u2192 ${t}
|
|
4
4
|
Daemon \u2192 ${n}
|
|
@@ -318,7 +318,7 @@ ${n}`:n,a=await fetch(`${jg}/send`,{method:"POST",headers:{"Content-Type":"appli
|
|
|
318
318
|
settings \u2014 without this an attached production identity would be less
|
|
319
319
|
guarded than a spawned one.)`))):console.log(M.yellow(" ! Guard hook skipped. An attached production identity will run unguarded.")),console.log(),console.log(`Next: ${M.cyan("agentx attach <agent>")} inside a Claude Code session.`)}catch(o){console.error(M.red(`Install failed: ${o?.message??o}`)),process.exit(1)}});Uo.command("uninstall").description("remove the attach hooks from ~/.claude/settings.json").option("--path <file>","settings file to patch (default: ~/.claude/settings.json)").option("--remove-guard","also remove the PreToolUse guard hook").action(e=>{try{let o=sa({path:e.path,keepGuard:!e.removeGuard});console.log(o.changed?`${M.green("\u2713")} Removed attach hooks from ${M.gray(o.path)} (${o.events.join(", ")})`:`${M.gray("Nothing to remove.")}`),e.removeGuard||console.log(M.gray(" PreToolUse guard left in place \u2014 pass --remove-guard to drop it too."))}catch(o){console.error(M.red(`Uninstall failed: ${o?.message??o}`)),process.exit(1)}});we();import{Command as dm}from"commander";import pe from"chalk";var Ln=new dm().name("process").description("inspect / rotate persistent claude processes (--persistentProcess agents)");function ac(e){let o=typeof e.node=="string"?e.node:"",t=typeof e.token=="string"?e.token:"";if(!o||!t)try{let n=D(e.config);o||(o=n.dashboard?.daemonUrl||""),t||(t=n.dashboard?.token||"")}catch{}return o||(o="http://localhost:18800"),{baseUrl:o.replace(/\/+$/,""),token:t}}function cc(e,o){let t={};return e&&(t.Authorization=`Bearer ${e}`),o&&(t["Content-Type"]=o),t}function rc(e){let o=Math.round((Date.now()-e)/1e3);return o<60?`${o}s`:o<3600?`${Math.round(o/60)}m`:o<86400?`${Math.round(o/3600)}h`:`${Math.round(o/86400)}d`}function gm(e){return e==="busy"?pe.magenta:e==="warm-hot"?pe.green:e==="warm-cold"?pe.cyan:e==="idle"?pe.yellow:e==="dead"?pe.red:pe.dim}Ln.command("list").description("list every live persistent claude process").option("-c, --config <path>","daemon config file").option("--node <url>","daemon URL (defaults to dashboard.daemonUrl)").option("--token <token>","bearer token (defaults to dashboard.token)").option("--json","emit JSON").action(async e=>{let{baseUrl:o,token:t}=ac(e),n;try{n=await fetch(`${o}/api/processes`,{headers:cc(t)})}catch(r){console.log(pe.red(` could not reach daemon at ${o}: ${r.message||r}`)),process.exit(1)}if(n.status===503){console.log(pe.dim(` daemon at ${o} has no agents with persistentProcess: true`));return}n.ok||(console.log(pe.red(` HTTP ${n.status} from ${o}/processes`)),process.exit(1));let i=(await n.json()).processes??[];if(e.json){console.log(JSON.stringify(i,null,2));return}if(i.length===0){console.log(pe.dim(" (no processes)"));return}for(let r of i){let a=gm(r.state)(r.state.padEnd(9)),c=rc(r.spawnedAt),d=r.lastTurnAt?rc(r.lastTurnAt)+" ago":"\u2014",g=r.lastInputTokens?pe.dim(`last_in=${r.lastInputTokens} tok`):"",l=r.claudeSessionId?pe.dim(`sess=${r.claudeSessionId.slice(0,8)}\u2026`):pe.dim("sess=\u2014"),p=r.pendingTaskId?pe.cyan(`task=${String(r.pendingTaskId).slice(0,12)}`):"";console.log(`${a} ${pe.bold(r.key.agentId)}${pe.dim(":"+r.key.channel+":"+r.key.chatId)} ${pe.dim("\xB7")} pid=${r.pid??"?"} age=${c} turn#${r.turnCount} last=${d} ${l} ${g} ${p}`),r.deadReason&&console.log(` ${pe.red("dead:")} ${r.deadReason}`)}});Ln.command("kill <agentId> <channel> <chatId>").description("force-kill one persistent process (the next dispatch will spawn fresh)").option("-c, --config <path>","daemon config file").option("--node <url>","daemon URL (defaults to dashboard.daemonUrl)").option("--token <token>","bearer token (defaults to dashboard.token)").option("-r, --reason <reason>","kill reason (recorded on the dead-process snapshot)","operator-cli").action(async(e,o,t,n)=>{let{baseUrl:s,token:i}=ac(n),r;try{r=await fetch(`${s}/api/processes/kill`,{method:"POST",headers:cc(i,"application/json"),body:JSON.stringify({agentId:e,channel:o,chatId:t,reason:n.reason})})}catch(a){console.log(pe.red(` could not reach daemon at ${s}: ${a.message||a}`)),process.exit(1)}if(r.status===503){console.log(pe.dim(" daemon has no persistent-process registry"));return}if(!r.ok){let a=`HTTP ${r.status}`;try{let c=await r.json();c.error&&(a+=` \u2014 ${c.error}`)}catch{}console.log(pe.red(` ${a}`)),process.exit(1)}console.log(pe.green(` killed ${e}:${o}:${t}`))});import{Command as mm}from"commander";import Te from"chalk";import{existsSync as Gs,rmSync as pm}from"fs";import{resolve as zs}from"path";var lt=new mm().name("rag").description("manage per-agent lexical (BM25) RAG indexes (improvement plan #7)");lt.command("add <agentId>").description("build or refresh an agent's lexical index from one or more globs").argument("<globs...>","glob patterns relative to cwd (e.g. './docs/**/*.md')").option("-v, --verbose","log each indexed file").action(async(e,o,t)=>{o.length===0&&(console.log(Te.red(` No globs provided. Example: agentx rag add ${e} './docs/**/*.md'`)),process.exit(1));let n=!!t.verbose,s=Date.now(),i=await Ji(e,o,{verbose:n}),r=Date.now()-s;console.log(Te.green(` \u2713 indexed ${i.docs} doc(s) for ${Te.bold(e)} in ${r}ms`)),console.log(Te.dim(` \u2192 ${i.path}`))});lt.command("list").description("list every agent's index, sizes, paths").option("-c, --cwd <path>","search root",process.cwd()).action(async e=>{let o=zs(e.cwd,".agentx","rag");if(!Gs(o)){console.log(Te.dim(" (no indexes yet \u2014 try `agentx rag add <agentId> <glob>`)"));return}let{readdirSync:t}=await import("fs"),n=t(o).filter(s=>Gs(zs(o,s,"index.json")));if(n.length===0){console.log(Te.dim(" (no indexes)"));return}for(let s of n.sort()){let i=cs(s);console.log(` ${Te.bold(s)} ${i.docs} doc(s) ${Te.dim(i.path)}`)}});lt.command("search <agentId> <query>").description("query an agent's index \u2014 useful for debugging recall before the agent calls rag.lexical").option("-k, --k <n>","top-k results","5").option("--json","emit JSON").action((e,o,t)=>{let n=parseInt(t.k,10)||5,s=Hi(e,o,{k:n});if(t.json){console.log(JSON.stringify(s,null,2));return}if(s.length===0){let i=cs(e);i.exists?console.log(Te.dim(` (no hits in ${i.docs} indexed docs)`)):console.log(Te.red(` no index for ${e} \u2014 run \`agentx rag add ${e} <glob>\` first`));return}for(let i of s)console.log(` ${Te.bold(i.title)} ${Te.dim(`(${i.score.toFixed(2)})`)}`),console.log(` ${Te.dim(i.path)}`),console.log(` ${Te.dim(i.snippet.slice(0,200))}`)});lt.command("clear <agentId>").description("delete an agent's index").action(e=>{let o=zs(process.cwd(),".agentx","rag",e);if(!Gs(o)){console.log(Te.dim(` no index for ${e} \u2014 nothing to clear`));return}pm(o,{recursive:!0,force:!0}),console.log(Te.green(` \u2713 cleared index for ${e}`))});we();import{Command as um}from"commander";import K from"chalk";import dt from"prompts";var Fo=new um().name("backlog").description("manage the local backlog used by business workSource=backlog");function Bt(e){let o=D(e),t=o.business?.workSource,n=t?.type==="backlog"?t.path:".agentx/backlog.md";return{config:o,storePath:n,store:new Dr(n)}}function fm(e){return e?K.cyan(`${e.type}:${e.project}#${e.iid}`):K.dim("manual")}function hm(e){return{todo:K.gray("todo"),doing:K.yellow("doing"),blocked:K.red("blocked"),done:K.green("done")}[e]}Fo.command("list",{isDefault:!0}).description("list backlog items").option("--status <status>","filter by status (todo|doing|blocked|done)").option("--assignee <agent>","filter by assignee").option("--source <type>","filter by source.type (gitlab|github|manual)").option("-c, --config <path>","config path").action(async e=>{let{store:o}=Bt(e.config),t=o.list();if(e.status&&(t=t.filter(n=>n.status===e.status)),e.assignee&&(t=t.filter(n=>n.assignee===e.assignee)),e.source&&(t=t.filter(n=>e.source==="manual"?!n.source:n.source?.type===e.source)),!t.length){console.log(K.dim(" (no items)"));return}console.log();for(let n of t){let s=n.assignee?K.magenta(`@${n.assignee}`):K.dim("unassigned");console.log(` ${hm(n.status).padEnd(7)} ${fm(n.source)} ${s} ${n.title}`),n.source?.url&&console.log(K.dim(` ${n.source.url}`))}console.log(),console.log(K.dim(` ${t.length} item${t.length===1?"":"s"} \u2014 ${o.jsonPath()}`))});Fo.command("claim <id> <agent>").description("assign an item to an agent and set status=doing").option("-c, --config <path>","config path").action(async(e,o,t)=>{let n=Bt(t.config);n.store.findById(e)||(console.error(K.red(` item ${e} not found`)),process.exit(1));let i=n.store.update(e,{assignee:o,status:"doing"});if(console.log(K.green(` claimed: ${i.title} -> ${o}`)),i.source){let r=Pr([o],i.source,n.config),a=await hs(i,{assigneeUsernames:r,addLabels:["Doing"],removeLabels:["To Do"]},n.config,(...c)=>console.log(K.dim(" sync:"),...c));console.log(a.ok?K.dim(` synced -> ${a.url??i.source.type}`):K.yellow(` sync failed: ${a.error}`))}});Fo.command("done <id>").description("mark an item as done; closes the upstream issue if linked").option("--note <text>","comment to post upstream").option("--close","also close the upstream issue (default: only labels change)",!1).option("-c, --config <path>","config path").action(async(e,o)=>{let t=Bt(o.config);t.store.findById(e)||(console.error(K.red(` item ${e} not found`)),process.exit(1));let s=t.store.update(e,{status:"done"});if(console.log(K.green(` done: ${s.title}`)),s.source){let i=await hs(s,{addLabels:["Done"],removeLabels:["Doing"],state:o.close?"closed":void 0,note:o.note},t.config,(...r)=>console.log(K.dim(" sync:"),...r));console.log(i.ok?K.dim(` synced -> ${i.url??s.source.type}`):K.yellow(` sync failed: ${i.error}`))}});Fo.command("remove <id>").description("remove an item from the local backlog (does NOT touch upstream)").option("-c, --config <path>","config path").action(async(e,o)=>{let{store:t}=Bt(o.config);t.remove(e)||(console.error(K.red(` item ${e} not found`)),process.exit(1)),console.log(K.green(` removed ${e}`))});Fo.command("import").description("import open issues from gitlab/github into the backlog (interactive)").option("--source <type>","source type (gitlab|github)").option("--project <id>","project id (group/repo for gitlab, owner/repo for github)").option("--assignee <agent>","assign all imported items to this agentId").option("-c, --config <path>","config path").action(async e=>{let o=Bt(e.config),t=!!o.config.channels.gitlab?.token,n=!!o.config.channels.github?.token;!t&&!n&&(console.error(K.red(" no source configured \u2014 set channels.gitlab.token or channels.github.token in agentx.json")),process.exit(1));let s=e.source;if(!s){let y=[t&&{title:"GitLab",value:"gitlab"},n&&{title:"GitHub",value:"github"}].filter(Boolean);if(s=(await dt({type:"select",name:"source",message:"Source",choices:y})).source,!s)return}s==="gitlab"&&!t&&(console.error(K.red(" channels.gitlab.token not configured")),process.exit(1)),s==="github"&&!n&&(console.error(K.red(" channels.github.token not configured")),process.exit(1));let i=e.project;if(!i){let y=s==="gitlab"?wm(o.config):bm(o.config);y.length?(i=(await dt({type:"autocomplete",name:"project",message:"Project (type to filter, or pick + then Enter for custom)",choices:[...y.map(b=>({title:b,value:b})),{title:"(custom \u2014 type below)",value:"__CUSTOM__"}]})).project,i==="__CUSTOM__"&&(i=(await dt({type:"text",name:"p",message:s==="gitlab"?"Group/path":"owner/repo"})).p)):i=(await dt({type:"text",name:"p",message:s==="gitlab"?"Group/path":"owner/repo"})).p}if(!i)return;let a=((await dt({type:"text",name:"search",message:"Search filter (optional \u2014 leave empty for all open)"})).search||"").trim();console.log(K.dim(` fetching open issues from ${s}:${i}${a?` (search: ${a})`:""}\u2026`));let c=s==="gitlab"?await $m(o.config,i,a):await km(o.config,i,a);if(!c.length){console.log(K.yellow(" no open issues matched"));return}console.log(K.dim(` ${c.length} open issue${c.length===1?"":"s"}`));let d=i,g=new Set(o.store.list().map(y=>y.id)),l=c.map(y=>{let $=fs({type:s,project:d,iid:y.iid,url:y.url}),b=g.has($),v=y.labels.length?` [${y.labels.slice(0,3).join(",")}]`:"";return{title:`#${y.iid} ${y.title}${v}${b?K.dim(" (already imported)"):""}`,value:y,disabled:b}}),f=(await dt({type:"autocompleteMultiselect",name:"selected",message:"Pick issues to import (space to toggle, Enter to confirm)",instructions:!1,choices:l,min:1})).selected||[];if(!f.length){console.log(K.dim(" nothing selected"));return}let u=f.map(y=>{let $={type:s,host:s==="gitlab"?ym(o.config):void 0,project:d,iid:y.iid,url:y.url};return{id:fs($),title:y.title,description:y.description,assignee:e.assignee||y.assignee,labels:y.labels,milestone:y.milestone,status:"todo",source:$,importedAt:new Date().toISOString()}}),w=o.store.addMany(u);console.log(K.green(` imported ${w.length} item${w.length===1?"":"s"}`));for(let y of w)console.log(K.dim(` ${y.id} \u2014 ${y.title}`))});function ym(e){let o=e.channels.gitlab?.host;if(o)return o.replace(/^https?:\/\//,"").replace(/\/+$/,"")}function wm(e){let o=new Set;for(let n of e.channels.gitlab?.routes??[])n.project&&n.project!=="*"&&o.add(n.project);let t=e.business?.workSource;if(t?.type==="gitlab")for(let n of t.projects??[])o.add(n);for(let n of e.business?.projects??[])n?.id&&n.id.includes("/")&&o.add(n.id);return[...o].sort()}function bm(e){let o=new Set;for(let t of e.channels.github?.routes??[])t.repo&&t.repo!=="*"&&o.add(t.repo);return[...o].sort()}async function $m(e,o,t){let n=e.channels.gitlab,s=new URLSearchParams({state:"opened",scope:"all",per_page:"100",order_by:"updated_at",sort:"desc"});t&&s.set("search",t);let i=await fetch(`${n.host}/api/v4/projects/${encodeURIComponent(o)}/issues?${s}`,{headers:{"PRIVATE-TOKEN":n.token}});if(!i.ok)throw new Error(`GitLab ${i.status}: ${await i.text().catch(()=>"")}`);let r=await i.json();return Array.isArray(r)?r.map(a=>({iid:a.iid,title:a.title,description:a.description||void 0,labels:Array.isArray(a.labels)?a.labels.map(c=>typeof c=="string"?c:c.name):[],milestone:a.milestone?.title||void 0,assignee:a.assignee?.username||a.assignees?.[0]?.username||void 0,url:a.web_url})):[]}async function km(e,o,t){let s={Authorization:`Bearer ${e.channels.github.token}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28"},i;if(t){let c=`repo:${o} is:issue is:open ${t}`;i=`https://api.github.com/search/issues?q=${encodeURIComponent(c)}&per_page=100&sort=updated&order=desc`;let d=await fetch(i,{headers:s});if(!d.ok)throw new Error(`GitHub ${d.status}: ${await d.text().catch(()=>"")}`);return((await d.json()).items??[]).map(lc)}i=`https://api.github.com/repos/${o}/issues?state=open&per_page=100&sort=updated&direction=desc`;let r=await fetch(i,{headers:s});if(!r.ok)throw new Error(`GitHub ${r.status}: ${await r.text().catch(()=>"")}`);let a=await r.json();return Array.isArray(a)?a.filter(c=>!c.pull_request).map(lc):[]}function lc(e){return{iid:e.number,title:e.title,description:e.body||void 0,labels:Array.isArray(e.labels)?e.labels.map(o=>typeof o=="string"?o:o.name):[],milestone:e.milestone?.title||void 0,assignee:e.assignee?.login||e.assignees?.[0]?.login||void 0,url:e.html_url}}import{Command as Sm}from"commander";import z from"chalk";import{existsSync as Em,readFileSync as Am}from"fs";import{resolve as Om}from"path";import jm from"prompts";we();import vm from"cronstrue";var Ys={sun:0,sunday:0,mon:1,monday:1,tue:2,tuesday:2,tues:2,wed:3,wednesday:3,thu:4,thursday:4,thurs:4,fri:5,friday:5,sat:6,saturday:6},Mn={morning:{h:9,m:0},afternoon:{h:14,m:0},evening:{h:18,m:0},night:{h:22,m:0},noon:{h:12,m:0},midnight:{h:0,m:0}};function no(e){try{return vm.toString(e,{use24HourTimeFormat:!1})}catch{return e}}function xm(e){if(/\b(noon|midday)\b/.test(e))return Mn.noon;if(/\bmidnight\b/.test(e))return Mn.midnight;let o=e.match(/\b(?:at|by|@)\s*(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\b/);if(o){let t=parseInt(o[1],10),n=o[2]?parseInt(o[2],10):0,s=o[3];return s==="pm"&&t<12&&(t+=12),s==="am"&&t===12&&(t=0),t>23||n>59?null:{h:t,m:n}}return null}function Vs(e){let o=e.trim().toLowerCase();if(!o)return null;let t;if(t=o.match(/\bevery\s+(\d+)\s*(minutes|mins|m)\b/)){let l=parseInt(t[1],10);return l<1||l>59?null:{cron:`*/${l} * * * *`,human:no(`*/${l} * * * *`),matched:t[0]}}if(/\bevery\s+minute\b/.test(o))return{cron:"* * * * *",human:no("* * * * *"),matched:"every minute"};if(t=o.match(/\bevery\s+(\d+)\s*(hours|hrs|h)\b/)){let l=parseInt(t[1],10);return l<1||l>23?null:{cron:`0 */${l} * * *`,human:no(`0 */${l} * * *`),matched:t[0]}}if(/\b(every hour|hourly)\b/.test(o))return{cron:"0 * * * *",human:no("0 * * * *"),matched:"every hour"};let n=xm(o),s=null;for(let[l,p]of Object.entries(Mn))if(!(l==="noon"||l==="midnight")&&new RegExp(`\\b(every\\s+)?${l}s?\\b`).test(o)){s=p;break}let i=n||s,r=o.match(/\b(first|1st|2nd|3rd|last|(\d+)(?:st|nd|rd|th)?)\s+(day\s+)?of\s+(every|each|the)\s+month\b/);if(r){let l=r[1],p=1;if(l==="last"||(/^\d+(st|nd|rd|th)?$/.test(l)?p=parseInt(l,10):l==="first"||l==="1st"?p=1:l==="2nd"?p=2:l==="3rd"&&(p=3),p<1||p>31))return null;let f=i||{h:9,m:0},u=`${f.m} ${f.h} ${p} * *`;return{cron:u,human:no(u),matched:r[0]}}let a=[],c=Object.keys(Ys).join("|"),d=new RegExp(`\\b(?:every|on|each|by)\\s+((?:${c})s?(?:\\s*(?:,|and|&)\\s*(?:${c})s?)*)\\b`),g=o.match(d);if(g){let l=g[1];for(let p of Object.keys(Ys))if(new RegExp(`\\b${p}s?\\b`).test(l)){let f=Ys[p];a.includes(f)||a.push(f)}}if(a.length){let l=i||{h:9,m:0};a.sort((u,w)=>u-w);let p=a.join(","),f=`${l.m} ${l.h} * * ${p}`;return{cron:f,human:no(f),matched:`on ${p}`}}if(/\b(weekday|workday|business day)s?\b/.test(o)){let l=i||{h:9,m:0},p=`${l.m} ${l.h} * * 1-5`;return{cron:p,human:no(p),matched:"weekdays"}}if(/\bweekends?\b/.test(o)){let l=i||{h:9,m:0},p=`${l.m} ${l.h} * * 0,6`;return{cron:p,human:no(p),matched:"weekends"}}if(/\b(every day|daily|each day)\b/.test(o)||s){let l=i||{h:9,m:0},p=`${l.m} ${l.h} * * *`;return{cron:p,human:no(p),matched:s&&Object.entries(Mn).find(([,f])=>f===s)?.[0]||"daily"}}if(n){let l=`${n.m} ${n.h} * * *`;return{cron:l,human:no(l),matched:`at ${n.h}:${String(n.m).padStart(2,"0")}`}}return null}function dc(e,o){return`${e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)||"job"}-${o}`}function gc(e){let o=e||Om(process.cwd(),"agentx.json");return Em(o)||(console.log(z.red(` No config at ${o}. Run: agentx init`)),process.exit(1)),JSON.parse(Am(o,"utf-8"))}function Im(e){return e?e.split(",").map(o=>o.trim().toLowerCase()).filter(o=>o==="log"||o==="notify"||o==="disable"):["log"]}async function Cm(e,o){if(!e)return;if(e==="me"){let n=o?.notifications?.destination;if(n?.channel&&n?.chatId)return{channel:n.channel,chatId:n.chatId,accountId:n.accountId};console.log(z.yellow(" --notify me: no notifications.destination set yet."));let{channel:s,chatId:i,accountId:r}=await jm([{type:"text",name:"channel",message:"Destination channel (telegram/whatsapp):"},{type:"text",name:"chatId",message:"Destination chatId:"},{type:"text",name:"accountId",message:"Account id (optional):"}]);return!s||!i?void 0:{channel:s,chatId:i,accountId:r||void 0}}let t=e.split(":");if(t.length>=2)return{channel:t[0],chatId:t[1],accountId:t[2]};console.log(z.red(` Unrecognized --notify value: ${e} (use "me" or "channel:chatId[:account]")`))}var xo=new Sm().name("schedule").description('schedule agents with natural-language cron: "every morning at 9" --agent devops --do "Post standup"');xo.argument("[when]",'natural-language schedule, e.g. "every morning at 9"').option("--agent <id>","agent to run").option("--do <prompt>","prompt to run at each tick (required unless --id exists)").option("--id <name>","explicit cron id (default: auto-slug of <when>-<agent>)").option("--notify <target>",'"me" (use notifications.destination) or "channel:chatId[:accountId]"').option("--on-error <modes>",'comma list of "log|notify|disable" (default: log; notify implies "notify")').option("--timezone <tz>","IANA timezone (default: Africa/Tunis)","Africa/Tunis").option("--timeout <seconds>","max run time","600").option("--model <model>","override model").option("--disabled","create but leave disabled").option("--dry-run","print what would be written without writing").action(async(e,o)=>{if(!e){xo.help();return}o.agent||(console.log(z.red(' --agent is required. Try: agentx schedule "every morning at 9" --agent devops --do "..."')),process.exit(1)),!o.do&&!o.id&&(console.log(z.red(' --do "<prompt>" is required')),process.exit(1));let t=Vs(e);t||(console.log(z.red(` Couldn't parse: "${e}"`)),console.log(z.dim(' Try: "every morning at 9", "weekdays at 6pm", "every 15 minutes",')),console.log(z.dim(' "every monday at 10am", "1st of every month at noon",')),console.log(z.dim(' "daily at 9:30am", "every hour", "hourly"')),process.exit(1));let n=gc(o.config),s=Ai(n);n.agents?.[o.agent]||(console.log(z.red(` Agent "${o.agent}" not found in agentx.json`)),console.log(z.dim(` Available: ${Object.keys(n.agents||{}).join(", ")||"(none)"}`)),process.exit(1));let i=Im(o.onError),r=await Cm(o.notify,s);r&&!i.includes("notify")&&i.push("notify");let a=o.id||dc(t.matched,o.agent),c={enabled:!o.disabled,schedule:t.cron,timezone:o.timezone,agent:o.agent,prompt:o.do,timeout:parseInt(o.timeout,10),onError:i};o.model&&(c.model=o.model),r&&(c.notify=r);let d=await de(l=>be(l,`crons.${a}`,c),{configPath:o.config,dryRun:!!o.dryRun});d.success||(console.log(z.red(` \u2717 ${d.error}`)),process.exit(1));let g=o.dryRun?"would add":"Added";console.log(z.green(` \u2713 ${g} cron ${z.cyan(a)}`)),console.log(z.dim(` Schedule: ${t.cron} (${t.human}, ${o.timezone})`)),console.log(z.dim(` Agent: ${o.agent}`)),r&&console.log(z.dim(` Notify: ${r.channel} ${r.chatId}`)),i.length&&console.log(z.dim(` On error: ${i.join(", ")}`)),!o.dryRun&&d.reloaded&&console.log(z.dim(" Daemon hot-reloaded."))});xo.command("list").alias("ls").description("list all scheduled jobs with human-readable descriptions").option("-c, --config <path>","path to agentx.json").action(async e=>{let t=gc(e.config).crons||{},n=Object.entries(t);if(!n.length){console.log(z.dim(" No scheduled jobs"));return}console.log();for(let[s,i]of n){let r=i.enabled?z.green("\u25CF"):z.dim("\u25CB"),a=i.schedule;try{a=(await import("cronstrue")).default.toString(i.schedule,{use24HourTimeFormat:!1})}catch{}console.log(` ${r} ${z.cyan(s.padEnd(32))} ${z.dim(i.schedule.padEnd(14))} ${z.dim("\u2192")} ${i.agent}`),console.log(z.dim(` ${a} (${i.timezone||"UTC"})`)),i.notify&&console.log(z.dim(` notify: ${i.notify.channel} ${i.notify.chatId}`))}console.log()});for(let[e,o]of[["on",!0],["off",!1]])xo.command(`${e} <id>`).description(`${o?"enable":"disable"} a scheduled job`).action(async t=>{let n=await de(s=>{if(!To(s,`crons.${t}`))throw new Error(`cron "${t}" not found`);be(s,`crons.${t}.enabled`,o)});n.success||(console.log(z.red(` \u2717 ${n.error}`)),process.exit(1)),console.log(z.green(` \u2713 ${t} ${o?"enabled":"disabled"}`)),n.reloaded&&console.log(z.dim(" Daemon hot-reloaded."))});xo.command("remove <id>").alias("rm").description("remove a scheduled job").action(async e=>{let o=await de(t=>{if(!To(t,`crons.${e}`))throw new Error(`cron "${e}" not found`);Vi(t,`crons.${e}`)});o.success||(console.log(z.red(` \u2717 ${o.error}`)),process.exit(1)),console.log(z.green(` \u2713 ${e} removed`)),o.reloaded&&console.log(z.dim(" Daemon hot-reloaded."))});xo.command("parse <when...>").description("preview a natural-language parse without writing anything").action(e=>{let o=e.join(" "),t=Vs(o);t||(console.log(z.red(` \u2717 could not parse: "${o}"`)),process.exit(1)),console.log(z.green(` "${o}"`)),console.log(z.dim(` \u2192 ${t.cron}`)),console.log(z.dim(` \u2192 ${t.human}`))});import{Command as Zm}from"commander";import gt from"chalk";import Z from"chalk";import Ht from"prompts";import{readFileSync as Tm,writeFileSync as Nm,existsSync as Rm}from"fs";import{resolve as mc}from"path";var _m=/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;function Dm(e){let o=e.trim();return o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'")?o.slice(1,-1):o}function Ks(e){return/[\s#"'\\]/.test(e)||e===""?JSON.stringify(e):e}function pc(e=".env"){let o=mc(e);if(!Rm(o))return[];let t=Tm(o,"utf-8"),n=[];for(let s of t.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 i=s.match(_m);i?n.push({kind:"kv",key:i[1],value:Dm(i[2]),raw:s}):n.push({kind:"comment",raw:s})}return n.length&&n[n.length-1].kind==="blank"&&n.pop(),n}function Pm(e){return e.map(o=>o.kind==="kv"?`${o.key}=${Ks(o.value)}`:o.raw).join(`
|
|
320
320
|
`)+`
|
|
321
|
-
`}function Jt(e,o,t=".env"){let n=mc(t),s=pc(n),i=s.findIndex(r=>r.kind==="kv"&&r.key===e);i>=0?s[i]={kind:"kv",key:e,value:o,raw:`${e}=${Ks(o)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:o,raw:`${e}=${Ks(o)}`})),Nm(n,Pm(s))}function Xs(e,o=".env"){return pc(o).find(s=>s.kind==="kv"&&s.key===e)?.value}var uc="https://t.me/BotFather";async function Lm(e){try{let o=await fetch(`https://api.telegram.org/bot${e}/getMe`,{signal:AbortSignal.timeout(8e3)});if(!o.ok)return null;let t=await o.json();return t?.ok?t.result:null}catch{return null}}async function Mm(e,o){let t=Date.now()+o,n=0;try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=-1&timeout=0`,{signal:AbortSignal.timeout(5e3)})).json();i?.result?.length&&(n=i.result[0].update_id+1)}catch{}for(;Date.now()<t;)try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=${n}&timeout=10`,{signal:AbortSignal.timeout(15e3)})).json();for(let r of i?.result||[]){n=Math.max(n,r.update_id+1);let a=r.message||r.edited_message||r.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 fc(e={}){console.log(),console.log(Z.bold(" Connect Telegram")),console.log(),console.log(Z.dim(` 1. Open ${uc}`)),console.log(Z.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(Z.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{openBrowser:o}=await Ht({type:"confirm",name:"openBrowser",message:"Open BotFather in your browser?",initial:!0});if(o)try{let{spawn:b}=await import("child_process"),v=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";b(v,[uc],{stdio:"ignore",detached:!0}).unref()}catch{}let{token:t}=await Ht({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"});t||(console.log(Z.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await Lm(t.trim());n||(console.log(Z.red("\u2717 invalid or revoked")),process.exit(1)),console.log(Z.green(`\u2713 ${n.first_name} (@${n.username})`));let{readFileSync:s,existsSync:i}=await import("fs"),{resolve:r}=await import("path"),a=e.configPath||r(process.cwd(),"agentx.json");i(a)||(console.log(Z.red(` No agentx.json at ${a}. Run: agentx init`)),process.exit(1));let c=JSON.parse(s(a,"utf-8")),d=Object.keys(c.agents||{});d.length===0&&(console.log(Z.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await Ht({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:d.map(v=>({title:v,value:v})),initial:0})).agent),g||(console.log(Z.red(" Aborted")),process.exit(1));let l=c.channels?.telegram?.accounts||{},p=e.account||g;l[p]&&l[p].agentBinding!==g&&(p=(await Ht({type:"text",name:"account",message:`Account "${p}" 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),p||(console.log(Z.red(" Aborted")),process.exit(1));let f=`TG_${p.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Jt(f,t.trim()),process.env[f]=t.trim();let u=await de(b=>{be(b,"channels.telegram.enabled",!0),be(b,`channels.telegram.accounts.${p}`,{token:`\${${f}}`,agentBinding:g});let v=To(b,`agents.${g}.mentions`)||[],A=`@${n.username}`;v.includes(A)||(v.push(A),be(b,`agents.${g}.mentions`,v))},{configPath:e.configPath});if(u.success||(console.log(Z.red(` \u2717 ${u.error}`)),process.exit(1)),console.log(),console.log(Z.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(Z.dim(` Token stored in .env as ${f}`)),console.log(Z.dim(` Mentions updated to include @${n.username}`)),u.reloaded?console.log(Z.dim(" Daemon hot-reloaded.")):console.log(Z.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:w}=await Ht({type:"confirm",name:"capture",message:"Listen for a message so we can set this as your default --notify target?",initial:!0});if(!w)return;console.log(),console.log(Z.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(Z.dim(" Waiting up to 90s..."));let y=await Mm(t.trim(),9e4);if(!y){console.log(Z.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(Z.dim(" agentx config set notifications.destination.channel telegram")),console.log(Z.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(Z.dim(` agentx config set notifications.destination.accountId ${p}`));return}let $=await de(b=>{be(b,"notifications.destination",{channel:"telegram",chatId:String(y.chatId),accountId:p})},{configPath:e.configPath});if(!$.success){console.log(Z.red(` \u2717 failed to save destination: ${$.error}`));return}console.log(Z.green(" \u2713 Default --notify target set")),console.log(Z.dim(` Chat: ${y.chatTitle||y.chatId} (from ${y.from})`)),console.log(Z.dim(" From now on, --notify me resolves to this chat.")),$.reloaded&&console.log(Z.dim(" Daemon hot-reloaded."))}import ue from"chalk";import Qs from"prompts";import{existsSync as ei,mkdirSync as Um,readdirSync as Fm,readFileSync as hc}from"fs";import{resolve as Zs}from"path";var qm=".agentx/whatsapp-sessions";function Wm(){let e=Zs(process.cwd(),".agentx/daemon.pid");if(!ei(e))return!1;try{let o=parseInt(hc(e,"utf-8").trim(),10);return o?(process.kill(o,0),!0):!1}catch{return!1}}function Bm(e){if(!ei(e))return!1;try{return Fm(e).some(o=>o.includes("creds")||o.endsWith(".json"))}catch{return!1}}async function Jm(e,o){let t;try{t=await import("@whiskeysockets/baileys")}catch{return o(ue.red(" WhatsApp pairing needs @whiskeysockets/baileys.")),o(ue.red(" Install with: pnpm add @whiskeysockets/baileys (or npm install)")),!1}let{makeWASocket:n,useMultiFileAuthState:s}=t.default||t;Um(e,{recursive:!0});let{state:i,saveCreds:r}=await s(e),a;try{a=(await t.fetchLatestBaileysVersion()).version}catch{}let c={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:()=>{},child:()=>c},d=n({auth:{creds:i.creds,keys:t.makeCacheableSignalKeyStore?t.makeCacheableSignalKeyStore(i.keys,c):i.keys},...a?{version:a}:{},logger:c,printQRInTerminal:!1,browser:["agentx-connect","pairing","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1});return d.ev.on("creds.update",r),await new Promise(g=>{let p=setTimeout(()=>{o(ue.yellow(" Timed out waiting for scan (2min)."));try{d.end(void 0)}catch{}g(!1)},12e4);d.ev.on("connection.update",async f=>{if(f.qr){o(ue.dim(" Scan this QR with WhatsApp \u2192 Linked devices \u2192 Link a device:")),o("");try{let{default:u}=await import("qrcode-terminal");u.generate(f.qr,{small:!0})}catch{o(` QR: ${f.qr}`)}o("")}if(f.connection==="open"){clearTimeout(p),o(ue.green(" \u2713 Paired"));try{d.end(void 0)}catch{}g(!0)}f.connection==="close"&&!f.qr&&f.lastDisconnect?.error?.output?.statusCode===401&&(clearTimeout(p),o(ue.red(" \u2717 Authorization failed \u2014 rescan required")),g(!1))})})}async function yc(e={}){if(console.log(),console.log(ue.bold(" Connect WhatsApp")),console.log(),Wm()){console.log(ue.yellow(" \u26A0 The daemon is running. Stop it first so pairing can open a fresh Baileys session:")),console.log(ue.dim(" agentx daemon stop")),console.log();let{cont:d}=await Qs({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});d||(console.log(ue.red(" Aborted")),process.exit(1))}let o=e.configPath||Zs(process.cwd(),"agentx.json");ei(o)||(console.log(ue.red(` No agentx.json at ${o}. Run: agentx init`)),process.exit(1));let t=JSON.parse(hc(o,"utf-8")),n=e.sessionDir||t.channels?.whatsapp?.sessionDir||qm,s=Zs(process.cwd(),n),i=Object.keys(t.agents||{});i.length===0&&(console.log(ue.red(" No agents configured. Run: agentx agent add")),process.exit(1));let r=e.agent;r||(r=(await Qs({type:"select",name:"agent",message:"Default agent for incoming messages:",choices:i.map(g=>({title:g,value:g})),initial:0})).agent),r||(console.log(ue.red(" Aborted")),process.exit(1));let a=!e.skipPair;if(Bm(s)&&a){let{keep:d}=await Qs({type:"confirm",name:"keep",message:`An existing session was found at ${n}. Keep it (recommended), or pair again?`,initial:!0});a=!d,d&&console.log(ue.dim(" Keeping existing session \u2014 skipping QR pair."))}a&&(await Jm(s,g=>console.log(g))||(console.log(ue.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await de(d=>{be(d,"channels.whatsapp.enabled",!0),be(d,"channels.whatsapp.sessionDir",n),be(d,"channels.whatsapp.defaultAgent",r)},{configPath:e.configPath});c.success||(console.log(ue.red(` \u2717 ${c.error}`)),process.exit(1)),console.log(),console.log(ue.green(` \u2713 WhatsApp bound to agent "${r}"`)),console.log(ue.dim(` Session: ${n}`)),console.log(ue.dim(" Start the daemon to begin receiving:")),console.log(ue.dim(" agentx daemon start")),console.log(ue.dim(" Add routes later with:")),console.log(ue.dim(` agentx config set channels.whatsapp.routes '[{"contact":"+1234567890","agent":"${r}"}]'`)),console.log()}import{randomBytes as Hm}from"crypto";import $e from"chalk";import wc from"prompts";var Un="agentx-mesh:",Fn="//join/";function Gm(e){return Buffer.from(e,"utf-8").toString("base64url")}function zm(e){return Buffer.from(e,"base64url").toString("utf-8")}function Ym(e){return`${Un}${Fn}${Gm(JSON.stringify(e))}`}function Vm(e){if(!e.startsWith(`${Un}${Fn}`))throw new Error(`Not a mesh invite link \u2014 expected ${Un}${Fn}\u2026`);let o=e.slice(Un.length+Fn.length),t=JSON.parse(zm(o));if(t.version!==1)throw new Error(`Unsupported invite version: ${t.version}`);if(typeof t.url!="string"||typeof t.token!="string"||typeof t.name!="string")throw new Error("Invite payload missing required fields (url, token, name)");return t}function Km(){return Hm(32).toString("hex")}function Xm(e){let o=e?.node?.bind||"127.0.0.1:18800",[t,n]=o.split(":");return`http://${t}:${n}`}function Qm(e){return e?.node?.name||e?.node?.id||"node"}async function bc(e){let{readFileSync:o,existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=e.configPath||n(process.cwd(),"agentx.json");t(s)||(console.log($e.red(` No agentx.json at ${s}. Run: agentx init`)),process.exit(1));let i=JSON.parse(o(s,"utf-8")),r=Xs("MESH_TOKEN");r||(r=Km(),Jt("MESH_TOKEN",r),console.log($e.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||Xm(i);if((a.includes("0.0.0.0")||a.includes("127.0.0.1")||a.includes("localhost"))&&!e.url){let{url:l}=await wc({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:p=>/^https?:\/\//.test(p)||"must start with http:// or https://"});l||(console.log($e.red(" Aborted")),process.exit(1)),a=l}let d=await de(l=>{be(l,"mesh.enabled",!0)},{configPath:e.configPath});d.success||(console.log($e.red(` \u2717 ${d.error}`)),process.exit(1));let g=Ym({url:a,token:r,name:Qm(i),version:1});console.log(),console.log($e.bold(" Mesh invite")),console.log(),console.log(` ${$e.cyan(g)}`),console.log(),console.log($e.dim(" Run on the other node:")),console.log($e.dim(` agentx connect mesh join "${g}"`)),console.log(),console.log($e.yellow(" Share over a trusted channel only \u2014 whoever holds this link can join your mesh.")),console.log()}async function $c(e,o={}){let t;try{t=Vm(e)}catch(i){console.log($e.red(` \u2717 ${i.message}`)),process.exit(1)}let n=Xs("MESH_TOKEN");if(n&&n!==t.token){let{overwrite:i}=await wc({type:"confirm",name:"overwrite",message:"A different MESH_TOKEN already exists in .env. Overwrite with the invite's token?",initial:!1});i||(console.log($e.red(" Aborted (keeping existing .env)")),process.exit(1))}Jt("MESH_TOKEN",t.token);let s=await de(i=>{be(i,"mesh.enabled",!0);let r=To(i,"mesh.peers")||[],a=r.findIndex(d=>d.name===t.name),c={name:t.name,url:t.url,token:"${MESH_TOKEN}"};a>=0?r[a]=c:r.push(c),be(i,"mesh.peers",r)},{configPath:o.configPath});s.success||(console.log($e.red(` \u2717 ${s.error}`)),process.exit(1)),console.log($e.green(" \u2713 Joined mesh")),console.log($e.dim(` Peer: ${t.name} @ ${t.url}`)),console.log($e.dim(" Shared token stored in .env as MESH_TOKEN")),s.reloaded?console.log($e.dim(" Daemon hot-reloaded.")):console.log($e.dim(" Restart the daemon to start the mesh (agentx daemon start).")),console.log();try{let i=await fetch(`${t.url.replace(/\/$/,"")}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)});if(i.ok){let r=await i.json(),a=Array.isArray(r.agents)?r.agents.length:"?";console.log($e.dim(` Reachable \u2014 ${t.name} exposes ${a} agents`))}else console.log($e.yellow(` Peer returned HTTP ${i.status} \u2014 double-check the URL`))}catch(i){console.log($e.yellow(` Could not reach ${t.url} right now (${i?.cause?.code||i.message}) \u2014 verify VPN / Tailscale when the peer daemon is up`))}}var mt=new Zm().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");mt.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 fc({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});mt.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 yc({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var kc=mt.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");kc.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 bc({url:e.url,configPath:e.config})});kc.command("join <link>").description("accept an invite link from another AgentX node").option("-c, --config <path>","path to agentx.json").action(async(e,o)=>{await $c(e,{configPath:o.config})});mt.action(()=>{console.log(),console.log(gt.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${gt.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${gt.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${gt.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${gt.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(gt.dim(" GitLab connect is the next slice.")),console.log()});we();import{Command as ep}from"commander";import le from"chalk";var Gt=new ep().name("usage").description("token usage analysis and reporting");Gt.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=D(),[o,t]=e.node.bind.split(":"),s=await(await fetch(`http://${o||"127.0.0.1"}:${t}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(le.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(le.dim(" No tasks recorded yet")),console.log();return}let i=a=>a.toLocaleString();console.log(` Total: ${le.bold(i(s.totalTokens))} tokens across ${s.totalTasks} tasks`),console.log(` Input: ${i(s.totalInput)}`),console.log(` Output: ${i(s.totalOutput)}`),console.log(` Cache read: ${i(s.totalCacheRead)}`),console.log(` Cache create: ${i(s.totalCacheCreate)}`),s.cacheHitRatio>0&&console.log(` Cache hit: ${(s.cacheHitRatio*100).toFixed(1)}%`),s.totalErrors>0&&console.log(` Errors: ${le.red(String(s.totalErrors))}`),console.log(),console.log(le.bold(" By Agent:"));let r=Object.entries(s.byAgent||{});r.sort((a,c)=>c[1].total-a[1].total);for(let[a,c]of r){let d=i(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${le.cyan(a)}: ${d} tokens (${c.tasks} tasks) ${le.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(le.red(" Daemon not running. Start with: agentx daemon start")):console.log(le.red(` ${e.message}`))}});Gt.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:o}=await import("child_process"),{existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=n(process.cwd(),"scripts/token-report.py");if(!t(s)){console.log(le.red(` Script not found: ${s}`)),console.log(le.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(le.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(le.red(" Analysis failed. Is Python 3 installed?"))}});Gt.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:o}=await import("./surface-usage-UREILT2E.js"),t=e.kind==="cli"||e.kind==="page"?e.kind:void 0,n=o({kind:t,sinceDays:Number(e.days)||30});if(e.unused){let{buildProgram:i}=await import("./program-E6AXVO5W.js"),r=await i(),a=new Set(n.filter(l=>l.kind==="cli").map(l=>l.name)),c=[],d=(l,p)=>{for(let f of l.commands??[]){let u=p?`${p} ${f.name()}`:f.name();c.push(u),d(f,u)}};d(r,"");let g=c.filter(l=>!a.has(l)).sort();if(e.json){console.log(JSON.stringify({windowDays:Number(e.days)||30,unused:g},null,2));return}console.log(),console.log(le.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let l of g)console.log(` ${le.dim("\xB7")} ${l}`);console.log(),console.log(le.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(le.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(le.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(le.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(le.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let i of n){i.kind!==s&&(console.log(le.dim(` ${i.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=i.kind);let r=String(i.count).padStart(6),a=le.dim(`${i.days}d`);console.log(` ${le.cyan(r)} ${i.name.padEnd(28)} ${a}`)}console.log(),console.log(le.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as op}from"commander";import fe from"chalk";import{resolve as tp}from"path";we();var So=new op().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");So.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{Pi(tp(process.cwd(),".env"))}catch{}let o=np(e.port,e.bind),{startBoardDashboard:t}=await import("./board-dashboard-R7FWWFFK.js");t(o)}catch(o){console.log(fe.red(` ${o.message}`)),process.env.DEBUG&&o.stack&&console.log(fe.dim(o.stack)),process.exit(1)}});function np(e,o){try{let t=D();return e&&(t.dashboard.port=parseInt(e,10)),o&&(t.dashboard.bind=o),t}catch{return console.log(fe.yellow(" No agentx.json found \u2014 starting dashboard in setup-only mode.")),console.log(fe.dim(" Visit http://127.0.0.1:"+(e||"4202")+` to run the wizard.
|
|
321
|
+
`}function Jt(e,o,t=".env"){let n=mc(t),s=pc(n),i=s.findIndex(r=>r.kind==="kv"&&r.key===e);i>=0?s[i]={kind:"kv",key:e,value:o,raw:`${e}=${Ks(o)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:o,raw:`${e}=${Ks(o)}`})),Nm(n,Pm(s))}function Xs(e,o=".env"){return pc(o).find(s=>s.kind==="kv"&&s.key===e)?.value}var uc="https://t.me/BotFather";async function Lm(e){try{let o=await fetch(`https://api.telegram.org/bot${e}/getMe`,{signal:AbortSignal.timeout(8e3)});if(!o.ok)return null;let t=await o.json();return t?.ok?t.result:null}catch{return null}}async function Mm(e,o){let t=Date.now()+o,n=0;try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=-1&timeout=0`,{signal:AbortSignal.timeout(5e3)})).json();i?.result?.length&&(n=i.result[0].update_id+1)}catch{}for(;Date.now()<t;)try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=${n}&timeout=10`,{signal:AbortSignal.timeout(15e3)})).json();for(let r of i?.result||[]){n=Math.max(n,r.update_id+1);let a=r.message||r.edited_message||r.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 fc(e={}){console.log(),console.log(Z.bold(" Connect Telegram")),console.log(),console.log(Z.dim(` 1. Open ${uc}`)),console.log(Z.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(Z.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{openBrowser:o}=await Ht({type:"confirm",name:"openBrowser",message:"Open BotFather in your browser?",initial:!0});if(o)try{let{spawn:b}=await import("child_process"),v=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";b(v,[uc],{stdio:"ignore",detached:!0}).unref()}catch{}let{token:t}=await Ht({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"});t||(console.log(Z.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await Lm(t.trim());n||(console.log(Z.red("\u2717 invalid or revoked")),process.exit(1)),console.log(Z.green(`\u2713 ${n.first_name} (@${n.username})`));let{readFileSync:s,existsSync:i}=await import("fs"),{resolve:r}=await import("path"),a=e.configPath||r(process.cwd(),"agentx.json");i(a)||(console.log(Z.red(` No agentx.json at ${a}. Run: agentx init`)),process.exit(1));let c=JSON.parse(s(a,"utf-8")),d=Object.keys(c.agents||{});d.length===0&&(console.log(Z.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await Ht({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:d.map(v=>({title:v,value:v})),initial:0})).agent),g||(console.log(Z.red(" Aborted")),process.exit(1));let l=c.channels?.telegram?.accounts||{},p=e.account||g;l[p]&&l[p].agentBinding!==g&&(p=(await Ht({type:"text",name:"account",message:`Account "${p}" 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),p||(console.log(Z.red(" Aborted")),process.exit(1));let f=`TG_${p.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Jt(f,t.trim()),process.env[f]=t.trim();let u=await de(b=>{be(b,"channels.telegram.enabled",!0),be(b,`channels.telegram.accounts.${p}`,{token:`\${${f}}`,agentBinding:g});let v=To(b,`agents.${g}.mentions`)||[],A=`@${n.username}`;v.includes(A)||(v.push(A),be(b,`agents.${g}.mentions`,v))},{configPath:e.configPath});if(u.success||(console.log(Z.red(` \u2717 ${u.error}`)),process.exit(1)),console.log(),console.log(Z.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(Z.dim(` Token stored in .env as ${f}`)),console.log(Z.dim(` Mentions updated to include @${n.username}`)),u.reloaded?console.log(Z.dim(" Daemon hot-reloaded.")):console.log(Z.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:w}=await Ht({type:"confirm",name:"capture",message:"Listen for a message so we can set this as your default --notify target?",initial:!0});if(!w)return;console.log(),console.log(Z.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(Z.dim(" Waiting up to 90s..."));let y=await Mm(t.trim(),9e4);if(!y){console.log(Z.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(Z.dim(" agentx config set notifications.destination.channel telegram")),console.log(Z.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(Z.dim(` agentx config set notifications.destination.accountId ${p}`));return}let $=await de(b=>{be(b,"notifications.destination",{channel:"telegram",chatId:String(y.chatId),accountId:p})},{configPath:e.configPath});if(!$.success){console.log(Z.red(` \u2717 failed to save destination: ${$.error}`));return}console.log(Z.green(" \u2713 Default --notify target set")),console.log(Z.dim(` Chat: ${y.chatTitle||y.chatId} (from ${y.from})`)),console.log(Z.dim(" From now on, --notify me resolves to this chat.")),$.reloaded&&console.log(Z.dim(" Daemon hot-reloaded."))}import ue from"chalk";import Qs from"prompts";import{existsSync as ei,mkdirSync as Um,readdirSync as Fm,readFileSync as hc}from"fs";import{resolve as Zs}from"path";var qm=".agentx/whatsapp-sessions";function Wm(){let e=Zs(process.cwd(),".agentx/daemon.pid");if(!ei(e))return!1;try{let o=parseInt(hc(e,"utf-8").trim(),10);return o?(process.kill(o,0),!0):!1}catch{return!1}}function Bm(e){if(!ei(e))return!1;try{return Fm(e).some(o=>o.includes("creds")||o.endsWith(".json"))}catch{return!1}}async function Jm(e,o){let t;try{t=await import("@whiskeysockets/baileys")}catch{return o(ue.red(" WhatsApp pairing needs @whiskeysockets/baileys.")),o(ue.red(" Install with: pnpm add @whiskeysockets/baileys (or npm install)")),!1}let{makeWASocket:n,useMultiFileAuthState:s}=t.default||t;Um(e,{recursive:!0});let{state:i,saveCreds:r}=await s(e),a;try{a=(await t.fetchLatestBaileysVersion()).version}catch{}let c={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:()=>{},child:()=>c},d=n({auth:{creds:i.creds,keys:t.makeCacheableSignalKeyStore?t.makeCacheableSignalKeyStore(i.keys,c):i.keys},...a?{version:a}:{},logger:c,printQRInTerminal:!1,browser:["agentx-connect","pairing","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1});return d.ev.on("creds.update",r),await new Promise(g=>{let p=setTimeout(()=>{o(ue.yellow(" Timed out waiting for scan (2min)."));try{d.end(void 0)}catch{}g(!1)},12e4);d.ev.on("connection.update",async f=>{if(f.qr){o(ue.dim(" Scan this QR with WhatsApp \u2192 Linked devices \u2192 Link a device:")),o("");try{let{default:u}=await import("qrcode-terminal");u.generate(f.qr,{small:!0})}catch{o(` QR: ${f.qr}`)}o("")}if(f.connection==="open"){clearTimeout(p),o(ue.green(" \u2713 Paired"));try{d.end(void 0)}catch{}g(!0)}f.connection==="close"&&!f.qr&&f.lastDisconnect?.error?.output?.statusCode===401&&(clearTimeout(p),o(ue.red(" \u2717 Authorization failed \u2014 rescan required")),g(!1))})})}async function yc(e={}){if(console.log(),console.log(ue.bold(" Connect WhatsApp")),console.log(),Wm()){console.log(ue.yellow(" \u26A0 The daemon is running. Stop it first so pairing can open a fresh Baileys session:")),console.log(ue.dim(" agentx daemon stop")),console.log();let{cont:d}=await Qs({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});d||(console.log(ue.red(" Aborted")),process.exit(1))}let o=e.configPath||Zs(process.cwd(),"agentx.json");ei(o)||(console.log(ue.red(` No agentx.json at ${o}. Run: agentx init`)),process.exit(1));let t=JSON.parse(hc(o,"utf-8")),n=e.sessionDir||t.channels?.whatsapp?.sessionDir||qm,s=Zs(process.cwd(),n),i=Object.keys(t.agents||{});i.length===0&&(console.log(ue.red(" No agents configured. Run: agentx agent add")),process.exit(1));let r=e.agent;r||(r=(await Qs({type:"select",name:"agent",message:"Default agent for incoming messages:",choices:i.map(g=>({title:g,value:g})),initial:0})).agent),r||(console.log(ue.red(" Aborted")),process.exit(1));let a=!e.skipPair;if(Bm(s)&&a){let{keep:d}=await Qs({type:"confirm",name:"keep",message:`An existing session was found at ${n}. Keep it (recommended), or pair again?`,initial:!0});a=!d,d&&console.log(ue.dim(" Keeping existing session \u2014 skipping QR pair."))}a&&(await Jm(s,g=>console.log(g))||(console.log(ue.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await de(d=>{be(d,"channels.whatsapp.enabled",!0),be(d,"channels.whatsapp.sessionDir",n),be(d,"channels.whatsapp.defaultAgent",r)},{configPath:e.configPath});c.success||(console.log(ue.red(` \u2717 ${c.error}`)),process.exit(1)),console.log(),console.log(ue.green(` \u2713 WhatsApp bound to agent "${r}"`)),console.log(ue.dim(` Session: ${n}`)),console.log(ue.dim(" Start the daemon to begin receiving:")),console.log(ue.dim(" agentx daemon start")),console.log(ue.dim(" Add routes later with:")),console.log(ue.dim(` agentx config set channels.whatsapp.routes '[{"contact":"+1234567890","agent":"${r}"}]'`)),console.log()}import{randomBytes as Hm}from"crypto";import $e from"chalk";import wc from"prompts";var Un="agentx-mesh:",Fn="//join/";function Gm(e){return Buffer.from(e,"utf-8").toString("base64url")}function zm(e){return Buffer.from(e,"base64url").toString("utf-8")}function Ym(e){return`${Un}${Fn}${Gm(JSON.stringify(e))}`}function Vm(e){if(!e.startsWith(`${Un}${Fn}`))throw new Error(`Not a mesh invite link \u2014 expected ${Un}${Fn}\u2026`);let o=e.slice(Un.length+Fn.length),t=JSON.parse(zm(o));if(t.version!==1)throw new Error(`Unsupported invite version: ${t.version}`);if(typeof t.url!="string"||typeof t.token!="string"||typeof t.name!="string")throw new Error("Invite payload missing required fields (url, token, name)");return t}function Km(){return Hm(32).toString("hex")}function Xm(e){let o=e?.node?.bind||"127.0.0.1:18800",[t,n]=o.split(":");return`http://${t}:${n}`}function Qm(e){return e?.node?.name||e?.node?.id||"node"}async function bc(e){let{readFileSync:o,existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=e.configPath||n(process.cwd(),"agentx.json");t(s)||(console.log($e.red(` No agentx.json at ${s}. Run: agentx init`)),process.exit(1));let i=JSON.parse(o(s,"utf-8")),r=Xs("MESH_TOKEN");r||(r=Km(),Jt("MESH_TOKEN",r),console.log($e.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||Xm(i);if((a.includes("0.0.0.0")||a.includes("127.0.0.1")||a.includes("localhost"))&&!e.url){let{url:l}=await wc({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:p=>/^https?:\/\//.test(p)||"must start with http:// or https://"});l||(console.log($e.red(" Aborted")),process.exit(1)),a=l}let d=await de(l=>{be(l,"mesh.enabled",!0)},{configPath:e.configPath});d.success||(console.log($e.red(` \u2717 ${d.error}`)),process.exit(1));let g=Ym({url:a,token:r,name:Qm(i),version:1});console.log(),console.log($e.bold(" Mesh invite")),console.log(),console.log(` ${$e.cyan(g)}`),console.log(),console.log($e.dim(" Run on the other node:")),console.log($e.dim(` agentx connect mesh join "${g}"`)),console.log(),console.log($e.yellow(" Share over a trusted channel only \u2014 whoever holds this link can join your mesh.")),console.log()}async function $c(e,o={}){let t;try{t=Vm(e)}catch(i){console.log($e.red(` \u2717 ${i.message}`)),process.exit(1)}let n=Xs("MESH_TOKEN");if(n&&n!==t.token){let{overwrite:i}=await wc({type:"confirm",name:"overwrite",message:"A different MESH_TOKEN already exists in .env. Overwrite with the invite's token?",initial:!1});i||(console.log($e.red(" Aborted (keeping existing .env)")),process.exit(1))}Jt("MESH_TOKEN",t.token);let s=await de(i=>{be(i,"mesh.enabled",!0);let r=To(i,"mesh.peers")||[],a=r.findIndex(d=>d.name===t.name),c={name:t.name,url:t.url,token:"${MESH_TOKEN}"};a>=0?r[a]=c:r.push(c),be(i,"mesh.peers",r)},{configPath:o.configPath});s.success||(console.log($e.red(` \u2717 ${s.error}`)),process.exit(1)),console.log($e.green(" \u2713 Joined mesh")),console.log($e.dim(` Peer: ${t.name} @ ${t.url}`)),console.log($e.dim(" Shared token stored in .env as MESH_TOKEN")),s.reloaded?console.log($e.dim(" Daemon hot-reloaded.")):console.log($e.dim(" Restart the daemon to start the mesh (agentx daemon start).")),console.log();try{let i=await fetch(`${t.url.replace(/\/$/,"")}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)});if(i.ok){let r=await i.json(),a=Array.isArray(r.agents)?r.agents.length:"?";console.log($e.dim(` Reachable \u2014 ${t.name} exposes ${a} agents`))}else console.log($e.yellow(` Peer returned HTTP ${i.status} \u2014 double-check the URL`))}catch(i){console.log($e.yellow(` Could not reach ${t.url} right now (${i?.cause?.code||i.message}) \u2014 verify VPN / Tailscale when the peer daemon is up`))}}var mt=new Zm().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");mt.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 fc({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});mt.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 yc({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var kc=mt.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");kc.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 bc({url:e.url,configPath:e.config})});kc.command("join <link>").description("accept an invite link from another AgentX node").option("-c, --config <path>","path to agentx.json").action(async(e,o)=>{await $c(e,{configPath:o.config})});mt.action(()=>{console.log(),console.log(gt.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${gt.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${gt.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${gt.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${gt.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(gt.dim(" GitLab connect is the next slice.")),console.log()});we();import{Command as ep}from"commander";import le from"chalk";var Gt=new ep().name("usage").description("token usage analysis and reporting");Gt.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=D(),[o,t]=e.node.bind.split(":"),s=await(await fetch(`http://${o||"127.0.0.1"}:${t}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(le.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(le.dim(" No tasks recorded yet")),console.log();return}let i=a=>a.toLocaleString();console.log(` Total: ${le.bold(i(s.totalTokens))} tokens across ${s.totalTasks} tasks`),console.log(` Input: ${i(s.totalInput)}`),console.log(` Output: ${i(s.totalOutput)}`),console.log(` Cache read: ${i(s.totalCacheRead)}`),console.log(` Cache create: ${i(s.totalCacheCreate)}`),s.cacheHitRatio>0&&console.log(` Cache hit: ${(s.cacheHitRatio*100).toFixed(1)}%`),s.totalErrors>0&&console.log(` Errors: ${le.red(String(s.totalErrors))}`),console.log(),console.log(le.bold(" By Agent:"));let r=Object.entries(s.byAgent||{});r.sort((a,c)=>c[1].total-a[1].total);for(let[a,c]of r){let d=i(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${le.cyan(a)}: ${d} tokens (${c.tasks} tasks) ${le.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(le.red(" Daemon not running. Start with: agentx daemon start")):console.log(le.red(` ${e.message}`))}});Gt.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:o}=await import("child_process"),{existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=n(process.cwd(),"scripts/token-report.py");if(!t(s)){console.log(le.red(` Script not found: ${s}`)),console.log(le.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(le.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(le.red(" Analysis failed. Is Python 3 installed?"))}});Gt.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:o}=await import("./surface-usage-UREILT2E.js"),t=e.kind==="cli"||e.kind==="page"?e.kind:void 0,n=o({kind:t,sinceDays:Number(e.days)||30});if(e.unused){let{buildProgram:i}=await import("./program-FJLMTESZ.js"),r=await i(),a=new Set(n.filter(l=>l.kind==="cli").map(l=>l.name)),c=[],d=(l,p)=>{for(let f of l.commands??[]){let u=p?`${p} ${f.name()}`:f.name();c.push(u),d(f,u)}};d(r,"");let g=c.filter(l=>!a.has(l)).sort();if(e.json){console.log(JSON.stringify({windowDays:Number(e.days)||30,unused:g},null,2));return}console.log(),console.log(le.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let l of g)console.log(` ${le.dim("\xB7")} ${l}`);console.log(),console.log(le.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(le.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(le.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(le.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(le.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let i of n){i.kind!==s&&(console.log(le.dim(` ${i.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=i.kind);let r=String(i.count).padStart(6),a=le.dim(`${i.days}d`);console.log(` ${le.cyan(r)} ${i.name.padEnd(28)} ${a}`)}console.log(),console.log(le.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as op}from"commander";import fe from"chalk";import{resolve as tp}from"path";we();var So=new op().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");So.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{Pi(tp(process.cwd(),".env"))}catch{}let o=np(e.port,e.bind),{startBoardDashboard:t}=await import("./board-dashboard-HLTVSSGW.js");t(o)}catch(o){console.log(fe.red(` ${o.message}`)),process.env.DEBUG&&o.stack&&console.log(fe.dim(o.stack)),process.exit(1)}});function np(e,o){try{let t=D();return e&&(t.dashboard.port=parseInt(e,10)),o&&(t.dashboard.bind=o),t}catch{return console.log(fe.yellow(" No agentx.json found \u2014 starting dashboard in setup-only mode.")),console.log(fe.dim(" Visit http://127.0.0.1:"+(e||"4202")+` to run the wizard.
|
|
322
322
|
`)),{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:o||"127.0.0.1",daemonUrl:"http://localhost:18800",daemons:[]},business:void 0,session:{staleMinutes:120}}}}So.command("list").description("list configured boards").action(()=>{try{let e=D();if(!e.boards?.length){console.log(fe.dim(`
|
|
323
323
|
No boards configured.
|
|
324
324
|
`));return}console.log();for(let o of e.boards){console.log(` ${fe.cyan(o.id)} \u2014 ${o.name}`);let t=o.source;console.log(fe.dim(` source: ${t.type}${t.projects?" ("+t.projects.join(", ")+")":""}`)),o.primaryToolLabel&&console.log(fe.dim(` primary label: ${o.primaryToolLabel}`)),console.log(fe.dim(` window: ${o.timeRangeDays} days`))}console.log()}catch(e){console.log(fe.red(` ${e.message}`)),process.exit(1)}});So.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,o)=>{try{zt(t=>{if(Array.isArray(t.boards)||(t.boards=[]),t.boards.find(i=>i.id===e))throw new Error(`board "${e}" already exists`);let n=String(o.projects).split(",").map(i=>i.trim()).filter(Boolean);if(n.length===0)throw new Error("--projects must include at least one path");let s={id:e,name:o.name,source:{type:"gitlab",projects:n},timeRangeDays:parseInt(o.days,10)||30,closedWindowDays:parseInt(o.closedDays,10)||30};return o.label&&(s.primaryToolLabel=o.label),t.boards.push(s),`added board "${e}" (${n.join(", ")})`})}catch(t){console.log(fe.red(` ${t.message}`)),process.exit(1)}});So.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,o)=>{try{zt(t=>{let s=(Array.isArray(t.boards)?t.boards:[]).find(r=>r.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=[];if(o.name&&(s.name=o.name,i.push(`name="${o.name}"`)),o.projects){let r=String(o.projects).split(",").map(a=>a.trim()).filter(Boolean);if(r.length===0)throw new Error("--projects must include at least one path");s.source={...s.source||{type:"gitlab"},type:"gitlab",projects:r},i.push(`projects=${r.length}`)}if(o.label!==void 0&&(o.label==="-"?(delete s.primaryToolLabel,i.push("label cleared")):(s.primaryToolLabel=o.label,i.push(`label="${o.label}"`))),o.days&&(s.timeRangeDays=parseInt(o.days,10)||s.timeRangeDays,i.push(`days=${s.timeRangeDays}`)),o.closedDays&&(s.closedWindowDays=parseInt(o.closedDays,10)||s.closedWindowDays,i.push(`closed-days=${s.closedWindowDays}`)),i.length===0)throw new Error("no changes \u2014 pass at least one option");return`board "${e}" updated (${i.join(", ")})`})}catch(t){console.log(fe.red(` ${t.message}`)),process.exit(1)}});var oi=So.command("column").description("manage a board's columns (add / remove / edit / list)");oi.command("list <boardId>").description("list columns on a board, in order").action(e=>{try{let t=(JSON.parse(hl("fs").readFileSync("agentx.json","utf-8")).boards||[]).find(s=>s.id===e);if(!t)throw new Error(`board "${e}" not found`);let n=t.columns||[];if(n.length===0){console.log(fe.dim(" no columns (board falls back to GitLab default flow)"));return}for(let s of n){let i=s.kind==="scoped-label"?`scoped="${s.scopedLabel}"`:s.kind==="label"?`label="${s.mapsToLabel||""}"`:s.kind==="open-backlog"?`prefix="${s.scopedPrefix}"`:s.kind;console.log(` ${fe.cyan(s.id.padEnd(12))} ${s.title.padEnd(14)} ${fe.dim(i)}`)}}catch(o){console.log(fe.red(` ${o.message}`)),process.exit(1)}});oi.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,o,t)=>{try{zt(n=>{let i=(Array.isArray(n.boards)?n.boards:[]).find(a=>a.id===e);if(!i)throw new Error(`board "${e}" not found`);if(i.columns=i.columns||[],i.columns.find(a=>a.id===o))throw new Error(`column "${o}" already exists on board "${e}"`);let r={id:o,title:t.title,kind:t.kind,scopedPrefix:t.scopedPrefix};if(t.kind==="scoped-label"){if(!t.scoped)throw new Error("--scoped required for kind=scoped-label");r.scopedLabel=t.scoped}if(t.kind==="label"){if(!t.label)throw new Error("--label required for kind=label");r.mapsToLabel=t.label}return t.accent&&(r.accent=t.accent),i.columns.push(r),`column "${o}" added to board "${e}"`})}catch(n){console.log(fe.red(` ${n.message}`)),process.exit(1)}});oi.command("remove <boardId> <columnId>").alias("rm").description("remove a column from a board").action((e,o)=>{try{zt(t=>{let s=(Array.isArray(t.boards)?t.boards:[]).find(r=>r.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(r=>r.id!==o),s.columns.length===i)throw new Error(`column "${o}" not found`);return`column "${o}" removed from board "${e}"`})}catch(t){console.log(fe.red(` ${t.message}`)),process.exit(1)}});So.command("remove <id>").alias("rm").description("remove a board from agentx.json").action(e=>{try{zt(o=>{if(!Array.isArray(o.boards)||o.boards.length===0)throw new Error("no boards configured");let t=o.boards.length;if(o.boards=o.boards.filter(n=>n.id!==e),o.boards.length===t)throw new Error(`board "${e}" not found`);return`removed board "${e}"`})}catch(o){console.log(fe.red(` ${o.message}`)),process.exit(1)}});function zt(e){let{summary:o,backupPath:t}=Zo(n=>e(n));console.log(fe.green(`
|
|
@@ -536,7 +536,7 @@ Restart the daemon to activate.
|
|
|
536
536
|
dist/
|
|
537
537
|
*.log
|
|
538
538
|
.env
|
|
539
|
-
`}import{Command as Cu}from"commander";import Oe from"chalk";import{writeFileSync as Tu,mkdirSync as Nu,existsSync as ts,readFileSync as cl,appendFileSync as ll}from"fs";import{resolve as vt,dirname as ml}from"path";import{homedir as vi}from"os";var pl=new Cu().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:o}=await import("./program-
|
|
539
|
+
`}import{Command as Cu}from"commander";import Oe from"chalk";import{writeFileSync as Tu,mkdirSync as Nu,existsSync as ts,readFileSync as cl,appendFileSync as ll}from"fs";import{resolve as vt,dirname as ml}from"path";import{homedir as vi}from"os";var pl=new Cu().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:o}=await import("./program-FJLMTESZ.js"),t=await o(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=Du(t);break;case"bash":s=Fu(t);break;case"fish":s=qu(t);break;default:console.error(Oe.red(`unsupported shell: ${n}`)),console.error(Oe.dim("supported: zsh, bash, fish")),process.exit(1)}if(!e.install&&!e.output){process.stdout.write(s);return}let i=e.output?vt(String(e.output)):Ru(n);Nu(ml(i),{recursive:!0}),Tu(i,s),console.log(Oe.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${i}`),console.log(),_u(n,i,!!e.yes)});function Ru(e){let o=vi();switch(e){case"zsh":return vt(o,".zsh","completions","_agentx");case"bash":return vt(o,".bash_completion.d","agentx.bash");case"fish":return vt(o,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function _u(e,o,t){if(e==="zsh"){let n=vt(vi(),".zshrc"),s=ml(o),i=`fpath=(${s} $fpath)`,r="autoload -U compinit && compinit",a=ts(n)?cl(n,"utf-8"):"",c=!a.includes(s),d=!/autoload\s+-U\s+compinit/.test(a);if(!c&&!d){console.log(Oe.dim("~/.zshrc already has fpath + compinit wired up. Run `exec zsh` to pick up the new script."));return}if(t&&ts(n)){let g=["","# agentx completion"];c&&g.push(i),d&&g.push(r),ll(n,g.join(`
|
|
540
540
|
`)+`
|
|
541
541
|
`),console.log(Oe.green("\u2713 Patched ~/.zshrc")),console.log(Oe.dim("Reload your shell: exec zsh"));return}console.log(Oe.dim("Add this to ~/.zshrc if not already present:")),c&&console.log(Oe.cyan(` ${i}`)),d&&console.log(Oe.cyan(` ${r}`)),console.log(),console.log(Oe.dim("Then reload: exec zsh")),console.log(Oe.dim("Or rerun with --yes to auto-patch ~/.zshrc"));return}if(e==="bash"){let n=vt(vi(),".bashrc"),s=`[ -f "${o}" ] && source "${o}"`;if((ts(n)?cl(n,"utf-8"):"").includes(o)){console.log(Oe.dim("~/.bashrc already sources this file. Start a new shell to pick it up."));return}if(t&&ts(n)){ll(n,`
|
|
542
542
|
# agentx completion
|
|
@@ -547,4 +547,4 @@ ${s}
|
|
|
547
547
|
`)}function xi(e){return String(e||"").replace(/\r?\n/g," ").replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function ki(e,o){let t=e.short?e.short.replace(/^-/,""):"",n=e.long?e.long.replace(/^--/,""):"";if(!t&&!n)return null;let s=xi(e.description||""),r=["complete -c agentx",o.map(a=>`-n "${a}"`).join(" ")];return t&&r.push(`-s ${t}`),n&&r.push(`-l ${n}`),r.push(`-d "${s}"`),r.join(" ")}async function Kx(){let e=await Ur(),o=new Wu().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");o.hook("preAction",(t,n)=>{let s=Br(n);Jr(s)&&Wr("cli",s)});for(let t of[pa,da,mt,ot,Qe,qr,Ro,En,xo,Uo,Sn,zc,ko,Sa,Ra,Ba,Ga,za,Qa,tc,nc,Pn,Gt,Qc,Dt,yo,pl])o.addCommand(t);for(let t of fl)o.addCommand(t,{hidden:!0});return o.addHelpText("after",()=>{let t=fl.map(n=>n.name()).sort();return["",`Advanced (${t.length}, hidden \u2014 run \`agentx <command> --help\` for any of them):`,Bu(t,74," "),""].join(`
|
|
548
548
|
`)}),o}var fl=[ee,pt,Jo,Ke,Lt,lt,Ue,lo,So,Fo,yt,wt,$o,Pe,Mt,Ln,Hc,ao,it,Yr,_o,en,Os,Ao,st,js,Vn,bt,Oo,nl,il,Xc];function Bu(e,o,t){let n=[],s="";for(let i of e)s&&s.length+i.length+2>o&&(n.push(t+s),s=""),s+=(s?", ":"")+i;return s&&n.push(t+s),n.join(`
|
|
549
549
|
`)}export{Kx as a};
|
|
550
|
-
//# sourceMappingURL=chunk-
|
|
550
|
+
//# sourceMappingURL=chunk-ITIMNSFR.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as s}from"./chunk-
|
|
2
|
+
import{a as s}from"./chunk-ITIMNSFR.js";import"./chunk-SJPLXXCI.js";import"./chunk-B5HKRYCU.js";import"./chunk-REPZID5M.js";import"./chunk-2TJ5L7CB.js";import"./chunk-7CVJ4JOE.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-SZDACK6O.js";import"./chunk-FZ3ZDG6T.js";import"./chunk-F6CNF7V3.js";import"./chunk-FAJEBVZE.js";import"./chunk-V7FYSZSV.js";import"./chunk-ZVP6GB4G.js";import"./chunk-DIKZWTL5.js";import"./chunk-P7LNYB53.js";import"./chunk-VMDA2SX2.js";import"./chunk-QLTM3F7M.js";import"./chunk-NZ6AQIKJ.js";import"./chunk-WBGROLOX.js";import"./chunk-SFQUP3BP.js";import"./chunk-3SCPRYJB.js";import"./chunk-WPMX3VGI.js";import"./chunk-K33GIBSE.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-B32HVIDN.js";import"./chunk-X763UOES.js";import"./chunk-DWADWDMU.js";import"./chunk-77OV7346.js";import"./chunk-VWTBHLMX.js";import"./chunk-RCVGIKC2.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-RQKUQOFC.js";import"./chunk-AJ5RMU7X.js";import"./chunk-2GIDVZ4H.js";import"./chunk-H4MIYENA.js";import"./chunk-ZTEU5JVQ.js";import"./chunk-AJONZWLT.js";import"./chunk-F4HZTZHW.js";import"./chunk-QOYAX2FT.js";import"./chunk-LCIREYTD.js";import"./chunk-L2WSPY6S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-IAG6FI3Q.js";import"./chunk-BH3GTCZ6.js";import"./chunk-FIOB3MEX.js";process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function o(){let r=await s();if(process.argv.slice(2).length===0){r.outputHelp();return}r.parse()}o();
|
|
3
3
|
//# sourceMappingURL=cli.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as L}from"./chunk-W5C2GDNC.js";import{a as St,b as kt,c as vt,d as xt,e as $t,f as Ct,g as Pt,ga as bt,ha as Tt,ia as Mt}from"./chunk-
|
|
1
|
+
import{a as L}from"./chunk-W5C2GDNC.js";import{a as St,b as kt,c as vt,d as xt,e as $t,f as Ct,g as Pt,ga as bt,ha as Tt,ia as Mt}from"./chunk-FZ3ZDG6T.js";import"./chunk-F6CNF7V3.js";import"./chunk-FAJEBVZE.js";import"./chunk-V7FYSZSV.js";import"./chunk-ZVP6GB4G.js";import{J as yt,h as lt,i as ct,j as dt,k as mt,l as pt}from"./chunk-DIKZWTL5.js";import"./chunk-P7LNYB53.js";import"./chunk-VMDA2SX2.js";import"./chunk-QLTM3F7M.js";import{h as ut}from"./chunk-NZ6AQIKJ.js";import{A as D,B as z,C as V,a as ye,b as we,c as Se,d as Ae,e as Ie,f as Oe,g as Ne,h as He,i as je,j as Ue,k as _e,l as I,m as q,n as Be,o as qe,p as Ye,q as O,r as ze,s as Ve,t as Xe,u as x,v as Y,w as Qe,x as Ze,y as et,z as wt}from"./chunk-WBGROLOX.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-3SCPRYJB.js";import"./chunk-WPMX3VGI.js";import"./chunk-K33GIBSE.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-B32HVIDN.js";import"./chunk-X763UOES.js";import"./chunk-DWADWDMU.js";import"./chunk-77OV7346.js";import"./chunk-VWTBHLMX.js";import{a as gt,b as ft,e as ht}from"./chunk-RCVGIKC2.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-RQKUQOFC.js";import"./chunk-AJ5RMU7X.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-H4MIYENA.js";import"./chunk-ZTEU5JVQ.js";import"./chunk-AJONZWLT.js";import"./chunk-F4HZTZHW.js";import"./chunk-QOYAX2FT.js";import{a as ke,b as ve,c as xe,d as $e,e as Ce,f as Pe,g as be,h as Te,i as Me,j as Re,l as Ee,m as Ge,o as T,p as W}from"./chunk-LCIREYTD.js";import{a as m,b as G}from"./chunk-L2WSPY6S.js";import{a as Fe,b as Le,c as A,d as De}from"./chunk-VDMYBPYB.js";import{a as Ke,b as Je,e as We}from"./chunk-DSYKYZMT.js";import{e as tt,g as st,h as ot,j as nt}from"./chunk-IAG6FI3Q.js";import"./chunk-BH3GTCZ6.js";import"./chunk-FIOB3MEX.js";W();G();import{execa as Rt}from"execa";import{existsSync as se,promises as X}from"fs";import S from"path";import ie from"node-fetch";async function Et(o,e){let t=o.split("/");if(t.length<2)throw new Error(`Invalid skill package ID: ${o}. Expected format: owner/repo`);let s=t[0],i=t[1],n=t[2];try{let a=n?`${s}/${i}/${n}`:`${s}/${i}`;await Rt("npx",["-y","skills","add",a],{cwd:e,stdio:"pipe"}),m.success(`Installed skill package: ${o}`);let r=S.resolve(e,".skills",`${s}_${i}`);if(se(r))return await ne(r,o);let d=S.resolve(e,".skills");return se(d)?await ne(d,o):[]}catch{return m.info(`Fetching skills directly from GitHub: ${s}/${i}`),await Gt(s,i,n,e)}}async function Gt(o,e,t,s){let i=[];try{let n=`https://api.github.com/repos/${o}/${e}/git/trees/main?recursive=1`,a=await ie(n);if(!a.ok)throw new Error(`GitHub API error: ${a.status}`);let d=(await a.json()).tree.filter(p=>p.type==="blob"&&p.path.endsWith("SKILL.md"));if(t){let p=d.find(f=>f.path.includes(`/${t}/`)||f.path===`${t}/SKILL.md`);if(p){let f=await oe(o,e,p.path,s);f&&i.push(f)}}else for(let p of d){let f=await oe(o,e,p.path,s);f&&i.push(f)}}catch(n){m.error(`Failed to fetch skills from GitHub: ${n.message}`)}return i}async function oe(o,e,t,s){try{let i=`https://raw.githubusercontent.com/${o}/${e}/main/${t}`,n=await ie(i);if(!n.ok)return null;let a=await n.text(),r=A(a);if(r){r.source="remote",r.packageId=`${o}/${e}`;let d=S.dirname(t),p=S.resolve(s,".skills",`${o}_${e}`,d);await X.mkdir(p,{recursive:!0}),await X.writeFile(S.resolve(p,"SKILL.md"),a),r.path=S.resolve(p,"SKILL.md")}return r}catch{return null}}async function ne(o,e){let t=[],{default:s}=await import("fast-glob"),i=await s.glob("**/SKILL.md",{cwd:o,deep:5});for(let n of i)try{let a=S.resolve(o,n),r=await X.readFile(a,"utf8"),d=A(r);d&&(d.source="remote",d.path=a,d.packageId=e,t.push(d))}catch{}return t}async function At(o,e,t,s,i){let n=["---",`name: ${o}`,`description: ${e}`];if(s?.length){n.push("tags:");for(let a of s)n.push(` - ${a}`)}if(i?.length){n.push("globs:");for(let a of i)n.push(` - ${a}`)}return n.push("---"),`${n.join(`
|
|
2
2
|
`)}
|
|
3
3
|
|
|
4
4
|
${t}`}async function It(o){let{loadLocalSkills:e}=await import("./loader-BOKE5M5S.js");return e(o)}async function Ot(o,e,t,s,i){let a=[{role:"system",content:`You are a skill author for the Agent Skills ecosystem (skills.sh).
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=program-
|
|
1
|
+
import{a}from"./chunk-ITIMNSFR.js";import"./chunk-SJPLXXCI.js";import"./chunk-B5HKRYCU.js";import"./chunk-REPZID5M.js";import"./chunk-2TJ5L7CB.js";import"./chunk-7CVJ4JOE.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-SZDACK6O.js";import"./chunk-FZ3ZDG6T.js";import"./chunk-F6CNF7V3.js";import"./chunk-FAJEBVZE.js";import"./chunk-V7FYSZSV.js";import"./chunk-ZVP6GB4G.js";import"./chunk-DIKZWTL5.js";import"./chunk-P7LNYB53.js";import"./chunk-VMDA2SX2.js";import"./chunk-QLTM3F7M.js";import"./chunk-NZ6AQIKJ.js";import"./chunk-WBGROLOX.js";import"./chunk-SFQUP3BP.js";import"./chunk-3SCPRYJB.js";import"./chunk-WPMX3VGI.js";import"./chunk-K33GIBSE.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-B32HVIDN.js";import"./chunk-X763UOES.js";import"./chunk-DWADWDMU.js";import"./chunk-77OV7346.js";import"./chunk-VWTBHLMX.js";import"./chunk-RCVGIKC2.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-RQKUQOFC.js";import"./chunk-AJ5RMU7X.js";import"./chunk-2GIDVZ4H.js";import"./chunk-H4MIYENA.js";import"./chunk-ZTEU5JVQ.js";import"./chunk-AJONZWLT.js";import"./chunk-F4HZTZHW.js";import"./chunk-QOYAX2FT.js";import"./chunk-LCIREYTD.js";import"./chunk-L2WSPY6S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-IAG6FI3Q.js";import"./chunk-BH3GTCZ6.js";import"./chunk-FIOB3MEX.js";export{a as buildProgram};
|
|
2
|
+
//# sourceMappingURL=program-FJLMTESZ.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentix-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "AI operations layer for small and medium businesses. Routes Telegram, WhatsApp, GitLab, GitHub, crons, webhooks, and mesh tasks to AI agents. Web wizard for operators, CLI for engineers. Self-hosted.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|