agentix-cli 0.3.0 → 0.5.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.
@@ -1,5 +1,5 @@
1
1
  import{a as c,b as w,d as x}from"./chunk-M7HKBG3V.js";import{z as u}from"zod";var f=["pre:generate","post:generate","pre:file-write","post:file-write","pre:prompt","post:response","pre:command","on:error","pre:tool-call","post:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run","post:cron-run"],$=["pre:generate","pre:file-write","pre:prompt","post:response","pre:command","pre:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run"],S=u.object({name:u.string(),type:u.enum(["command","prompt","script"]),command:u.string().optional(),prompt:u.string().optional(),provider:u.enum(["claude-code","claude","openai","ollama","custom"]).optional(),model:u.string().optional(),script:u.string().optional(),priority:u.number().default(100),enabled:u.boolean().default(!0)});var E={"claude-sonnet":{input:3,output:15},"claude-opus":{input:15,output:75},"claude-haiku":{input:.25,output:1.25}};function O(r){let o=r.toLowerCase();return o.includes("opus")?"claude-opus":o.includes("haiku")?"claude-haiku":"claude-sonnet"}var y=class{steps=[];models=new Map;recordStep(o,e,t,n){let s=O(e),i=E[s]||E["claude-sonnet"],p=t/1e6*i.input+n/1e6*i.output;this.steps.push({step:o,model:e,inputTokens:t,outputTokens:n,cost:p,timestamp:Date.now()});let a=this.models.get(e)||{inputTokens:0,outputTokens:0,cost:0,steps:0};a.inputTokens+=t,a.outputTokens+=n,a.cost+=p,a.steps++,this.models.set(e,a)}getSummary(){let o=0,e=0,t=0;for(let s of this.steps)o+=s.inputTokens,e+=s.outputTokens,t+=s.cost;let n={};for(let[s,i]of this.models)n[s]={...i};return{totalInputTokens:o,totalOutputTokens:e,totalTokens:o+e,totalCost:t,steps:[...this.steps],models:n}}reset(){this.steps=[],this.models.clear()}},D=new y;import l from"chalk";var d=!1;function R(r){d=r}function U(){return d}function k(){return new Date().toISOString().slice(11,23)}var g={log(...r){d&&console.log(l.dim(`[${k()}]`),...r)},step(r,o){d&&console.log(l.dim(`[${k()}]`),l.blue(`[step ${r}]`),o)},hook(r,o,e){d&&console.log(l.dim(`[${k()}]`),l.magenta("[hook]"),`${r} (${o}ms) \u2192 ${e}`)},api(r,o,e){if(!d)return;let t=e?` (${e} tokens)`:"";console.log(l.dim(`[${k()}]`),l.yellow("[api]"),`${r} \u2192 ${o}${t}`)},tokens(r,o,e){d&&console.log(l.dim(`[${k()}]`),l.green("[tokens]"),`in: ${r.toLocaleString()}, out: ${o.toLocaleString()}, cost: $${e.toFixed(4)}`)},context(r,o){d&&console.log(l.dim(`[${k()}]`),l.cyan(`[${r}]`),o)}};function j(r,o){let e=[];if(e.push(`# Session: ${r.id}`),e.push(""),e.push(`- **Created**: ${r.createdAt}`),e.push(`- **Updated**: ${r.updatedAt}`),e.push(`- **CWD**: ${r.cwd}`),e.push(`- **Messages**: ${r.messages.length}`),e.push(`- **Tokens**: ${r.tokensUsed.toLocaleString()}`),e.push(""),r.filesGenerated.length){e.push("## Files Generated"),e.push("");for(let t of r.filesGenerated)e.push(`- \`${t}\``);e.push("")}if(r.messages.length){e.push("## Conversation"),e.push("");for(let t of r.messages){if(t.role==="system")continue;let n=t.role==="user"?"**User**":"**Assistant**";e.push(`### ${n}`),e.push(""),t.role,e.push(t.content),e.push("")}}if(o){if(e.push("## Cost Summary"),e.push(""),e.push(`- **Total tokens**: ${o.totalTokens.toLocaleString()}`),e.push(` - Input: ${o.totalInputTokens.toLocaleString()}`),e.push(` - Output: ${o.totalOutputTokens.toLocaleString()}`),e.push(`- **Total cost**: $${o.totalCost.toFixed(4)}`),e.push(""),Object.keys(o.models).length){e.push("### Per Model"),e.push(""),e.push("| Model | Input | Output | Cost | Steps |"),e.push("|-------|-------|--------|------|-------|");for(let[t,n]of Object.entries(o.models))e.push(`| ${t} | ${n.inputTokens.toLocaleString()} | ${n.outputTokens.toLocaleString()} | $${n.cost.toFixed(4)} | ${n.steps} |`);e.push("")}if(o.steps.length){e.push("### Per Step"),e.push(""),e.push("| Step | Model | Input | Output | Cost |"),e.push("|------|-------|-------|--------|------|");for(let t of o.steps)e.push(`| ${t.step} | ${t.model} | ${t.inputTokens.toLocaleString()} | ${t.outputTokens.toLocaleString()} | $${t.cost.toFixed(4)} |`);e.push("")}}return e.join(`
2
- `)}import{execa as N}from"execa";var h=class{hooks=new Map;register(o,e){if(!e.enabled)return;let t=this.createHandler(e),n={event:o,definition:e,handler:t},s=this.hooks.get(o)||[];s.push(n),s.sort((i,p)=>i.definition.priority-p.definition.priority),this.hooks.set(o,s)}async execute(o,e){let t=this.hooks.get(o);if(!t?.length)return{};let n=$.includes(o),s={};for(let i of t){let p=Date.now();try{let a=await i.handler({...e,...s}),m=Date.now()-p;if(a.modified&&(s={...s,...a.modified}),n&&a.blocked)return g.hook(i.definition.name,m,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${i.definition.name}`,modified:s};g.hook(i.definition.name,m,"ok")}catch(a){let m=Date.now()-p;if(g.hook(i.definition.name,m,`error: ${a.message}`),c.warn(`Hook "${i.definition.name}" failed: ${a.message}`),n)return{blocked:!0,message:`Hook "${i.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(s).length?s:void 0}}has(o){return!!this.hooks.get(o)?.length}clear(){this.hooks.clear()}createHandler(o){switch(o.type){case"command":return this.createCommandHandler(o);case"script":return this.createScriptHandler(o);case"prompt":return this.createPromptHandler(o);default:throw new Error(`Unknown hook type: ${o.type}`)}}createCommandHandler(o){return async e=>{if(!o.command)return{};let t=o.command;t=t.replace(/\{\{(\w+)\}\}/g,(s,i)=>String(e[i]??""));let n=await N("sh",["-c",t],{cwd:e.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return n.exitCode!==0?{blocked:!0,message:n.stderr||n.stdout||`Command hook "${o.name}" failed`}:{}}}createScriptHandler(o){return async e=>{if(!o.script)return{};let n=await import(o.script.startsWith("/")?o.script:`${e.cwd||process.cwd()}/${o.script}`),s=n.default||n.handler||n;return typeof s=="function"?await s(e):{}}}createPromptHandler(o){return async e=>{if(!o.prompt)return{};let t=o.provider||w()?.provider||"claude-code",n=x();if(!n&&t!=="claude-code")return c.warn(`Prompt hook "${o.name}" skipped: no credentials available for provider "${t}"`),{};try{let{createProvider:s}=await import("./providers-Q3U3ONJO.js"),i=s(t,n?.token),p=o.prompt;p=p.replace(/\{\{(\w+)\}\}/g,(A,C)=>String(e[C]??""));let a=`You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).
2
+ `)}import{execa as N}from"execa";var h=class{hooks=new Map;register(o,e){if(!e.enabled)return;let t=this.createHandler(e),n={event:o,definition:e,handler:t},s=this.hooks.get(o)||[];s.push(n),s.sort((i,p)=>i.definition.priority-p.definition.priority),this.hooks.set(o,s)}async execute(o,e){let t=this.hooks.get(o);if(!t?.length)return{};let n=$.includes(o),s={};for(let i of t){let p=Date.now();try{let a=await i.handler({...e,...s}),m=Date.now()-p;if(a.modified&&(s={...s,...a.modified}),n&&a.blocked)return g.hook(i.definition.name,m,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${i.definition.name}`,modified:s};g.hook(i.definition.name,m,"ok")}catch(a){let m=Date.now()-p;if(g.hook(i.definition.name,m,`error: ${a.message}`),c.warn(`Hook "${i.definition.name}" failed: ${a.message}`),n)return{blocked:!0,message:`Hook "${i.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(s).length?s:void 0}}has(o){return!!this.hooks.get(o)?.length}clear(){this.hooks.clear()}createHandler(o){switch(o.type){case"command":return this.createCommandHandler(o);case"script":return this.createScriptHandler(o);case"prompt":return this.createPromptHandler(o);default:throw new Error(`Unknown hook type: ${o.type}`)}}createCommandHandler(o){return async e=>{if(!o.command)return{};let t=o.command;t=t.replace(/\{\{(\w+)\}\}/g,(s,i)=>String(e[i]??""));let n=await N("sh",["-c",t],{cwd:e.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return n.exitCode!==0?{blocked:!0,message:n.stderr||n.stdout||`Command hook "${o.name}" failed`}:{}}}createScriptHandler(o){return async e=>{if(!o.script)return{};let n=await import(o.script.startsWith("/")?o.script:`${e.cwd||process.cwd()}/${o.script}`),s=n.default||n.handler||n;return typeof s=="function"?await s(e):{}}}createPromptHandler(o){return async e=>{if(!o.prompt)return{};let t=o.provider||w()?.provider||"claude-code",n=x();if(!n&&t!=="claude-code")return c.warn(`Prompt hook "${o.name}" skipped: no credentials available for provider "${t}"`),{};try{let{createProvider:s}=await import("./providers-AVYG63KK.js"),i=s(t,n?.token),p=o.prompt;p=p.replace(/\{\{(\w+)\}\}/g,(A,C)=>String(e[C]??""));let a=`You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).
3
3
 
4
4
  Response format:
5
5
  {"action": "allow", "message": "optional explanation"}
@@ -9,4 +9,4 @@ OR
9
9
  {"action": "allow", "message": "optional", "modified": {"key": "new value"}}
10
10
 
11
11
  The "modified" field is optional and can contain updated values to pass forward.`,v=(await i.generate([{role:"system",content:a},{role:"user",content:p}],{model:o.model,maxTokens:1024})).content.trim().match(/\{[\s\S]*\}/);if(!v)return c.warn(`Prompt hook "${o.name}": LLM response was not valid JSON, allowing`),{};let H=JSON.parse(v[0]);return H.action==="block"?{blocked:!0,message:H.message||`Blocked by prompt hook: ${o.name}`}:H.modified?{modified:H.modified}:{}}catch(s){return c.warn(`Prompt hook "${o.name}" failed: ${s.message}`),{}}}}};import{existsSync as T,readFileSync as P,readdirSync as L}from"fs";import b from"path";function M(r,o){_(r,o),I(r,o)}function _(r,o){let e=b.join(r,"agentx.config.json");if(T(e))try{let t=JSON.parse(P(e,"utf8"));if(!t.hooks)return;for(let[n,s]of Object.entries(t.hooks)){if(!f.includes(n)){c.warn(`Unknown hook event in config: ${n}`);continue}let i=n;if(Array.isArray(s))for(let p of s)try{let a=S.parse(p);o.register(i,a)}catch(a){c.warn(`Invalid hook definition for ${i}: ${a.message}`)}}}catch(t){c.warn(`Failed to load hooks from config: ${t.message}`)}}function I(r,o){let e=b.join(r,".agentx","hooks");if(T(e))try{let t=L(e).filter(n=>n.endsWith(".ts")||n.endsWith(".js")||n.endsWith(".mjs"));for(let n of t){let s=n.replace(/\.(ts|js|mjs)$/,"").split(".");if(s.length<2){c.warn(`Hook file "${n}" should be named <event>.<name>.<ext>`);continue}let i=s[0],p=s.slice(1).join("."),a=i.replace(/-/g,":");if(!f.includes(a)){let m=i.replace("-",":");if(!f.includes(m)){c.warn(`Unknown hook event in filename: ${n}`);continue}o.register(m,{name:p,type:"script",script:b.join(e,n),priority:100,enabled:!0});continue}o.register(a,{name:p,type:"script",script:b.join(e,n),priority:100,enabled:!0})}}catch(t){c.warn(`Failed to load hooks from directory: ${t.message}`)}}var le=new h;export{f as a,$ as b,y as c,D as d,R as e,U as f,g,j as h,h as i,M as j,le as k};
12
- //# sourceMappingURL=chunk-PCAYW54Q.js.map
12
+ //# sourceMappingURL=chunk-Z4GC5D6D.js.map
package/dist/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import{d as N,e as H,p as L,q as z}from"./chunk-S74N276K.js";import"./chunk-PCAYW54Q.js";import"./chunk-M7HKBG3V.js";import{a as K}from"./chunk-MDR7SH7F.js";import{Command as ne}from"commander";import{Command as X}from"commander";import c from"chalk";var x=new X().name("daemon").description("manage the agentx daemon \u2014 start, stop, status, logs");x.command("start").description("start the daemon (default if no subcommand)").option("-c, --config <path>","path to agentx.json").option("-d, --detach","run in background (detached)").option("--port <port>","override bind port").action(async e=>{if(e.detach){let{spawn:o}=await import("child_process"),s=["dist/cli.js","daemon","start"];e.config&&s.push("-c",e.config),e.port&&s.push("--port",e.port);let t=o("node",s,{detached:!0,stdio:["ignore","ignore","ignore"],cwd:process.cwd()});t.unref();let{writeFileSync:i}=await import("fs");i("/tmp/agentx-daemon.pid",String(t.pid)),console.log(c.green(`Daemon started in background (PID: ${t.pid})`)),console.log(c.dim(" Logs: tail -f /tmp/agentx-daemon.log")),console.log(c.dim(" Stop: agentx daemon stop"));return}await new L(e.config).start()});x.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:n}=await import("fs"),o="/tmp/agentx-daemon.pid";n(o)||console.log(c.yellow("No daemon PID file found. Trying to find process..."));try{if(n(o)){let t=parseInt(e(o,"utf-8").trim(),10);process.kill(t,"SIGTERM"),console.log(c.green(`Daemon stopped (PID: ${t})`));return}}catch{}let{execSync:s}=await import("child_process");try{s("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(c.green("Daemon stopped"))}catch{console.log(c.yellow("No daemon process found"))}});x.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let n=N(e.config),[o,s]=n.node.bind.split(":"),t=`http://${o||"127.0.0.1"}:${s}/health`,l=await(await fetch(t,{signal:AbortSignal.timeout(3e3)})).json();if(e.json){console.log(JSON.stringify(l,null,2));return}console.log(),console.log(c.bold(` ${l.node.name}`)+c.dim(` (${l.node.id})`)),console.log(c.green(" Status: running")+c.dim(` \u2014 uptime ${Q(l.uptime)}`)),console.log(),console.log(c.bold(" Agents:"));for(let r of l.agents){let f=r.active>0?c.yellow(` [${r.active} active]`):"",v=r.errors>0?c.red(` (${r.errors} errors)`):"";console.log(` ${c.cyan(r.name)} ${c.dim(`(${r.tier})`)}${f}${v}`),console.log(c.dim(` ${r.workspace}`))}let d=l.crons.filter(r=>r.enabled);if(l.crons.length){console.log(),console.log(c.bold(` Crons: ${d.length} enabled / ${l.crons.length} total`));for(let r of l.crons){let f=r.enabled?c.green("\u25CF"):c.dim("\u25CB"),v=r.nextRun?c.dim(` next: ${new Date(r.nextRun).toLocaleTimeString()}`):"";console.log(` ${f} ${r.id}${v}`)}}if(l.mesh?.length){console.log(),console.log(c.bold(" Mesh:"));for(let r of l.mesh){let f=r.healthy?c.green("\u25CF"):c.red("\u25CF"),v=r.skills?.length?c.dim(` (${r.skills.length} agents)`):"";console.log(` ${f} ${r.peer} ${c.dim(r.peerUrl)}${v}`)}}console.log()}catch(n){if(n.cause?.code==="ECONNREFUSED"||n.name==="TimeoutError")console.log(c.red(" Daemon is not running")),console.log(c.dim(" Start with: agentx daemon start"));else try{let o=N(e.config),s=H(o);if(console.log(),console.log(c.bold(` ${o.node.name}`)+c.dim(` (${o.node.id})`)),console.log(c.yellow(" Status: stopped")),console.log(c.dim(` ${Object.keys(o.agents).length} agents, ${Object.keys(o.crons).length} crons configured`)),s.length){console.log();for(let t of s)console.log(c.yellow(` \u26A0 ${t}`))}console.log()}catch(o){console.log(c.red(` ${o.message}`))}}});x.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:n,spawn:o}=await import("child_process"),s="/tmp/agentx-daemon.log",{existsSync:t}=await import("fs");if(!t(s)){console.log(c.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let i=o("tail",["-f","-n",e.lines,s],{stdio:"inherit"});process.on("SIGINT",()=>{i.kill(),process.exit(0)})}else n(`tail -n ${e.lines} ${s}`,{stdio:"inherit"})});x.command("send <agent> <message...>").description("send a task to an agent via the daemon API").option("-c, --config <path>","path to agentx.json").option("--peer <peer>","send to a mesh peer's agent").option("--json","output raw JSON response").action(async(e,n,o)=>{let s=n.join(" ");try{let t=N(o.config),[i,l]=t.node.bind.split(":"),d=`http://${i||"127.0.0.1"}:${l}`,r,f;o.peer?(r=`${d}/mesh/task`,f={peer:o.peer,message:s,agent:e}):(r=`${d}/task`,f={agent:e,message:s}),console.log(c.dim(` Sending to ${o.peer?`${o.peer}/${e}`:e}...`));let $=await(await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)})).json();o.json?console.log(JSON.stringify($,null,2)):$.error?console.log(c.red(` Error: ${$.error}`)):(console.log(),console.log($.content||$.response||"No response"),$.duration&&console.log(c.dim(`
3
- (${($.duration/1e3).toFixed(1)}s)`)))}catch(t){console.log(c.red(` Failed: ${t.message}`)),console.log(c.dim(" Is the daemon running? Try: agentx daemon status"))}});x.command("deploy <host>").description("deploy agentx to a remote server via rsync").option("-i, --identity <key>","SSH identity file").option("-u, --user <user>","SSH user","clawd").option("-p, --path <path>","remote agentx path","~/agentx").option("--restart","restart remote daemon after deploy",!1).action(async(e,n)=>{let{execSync:o}=await import("child_process"),s=n.identity?`-e "ssh -i ${n.identity}"`:"",t=`${n.user}@${e}:${n.path}/dist/`;console.log(c.dim(` Deploying to ${n.user}@${e}:${n.path}...`));try{if(o(`rsync -avz --delete ${s} dist/ ${t}`,{stdio:"inherit",cwd:process.cwd()}),console.log(c.green(" Deploy complete")),n.restart){console.log(c.dim(" Restarting remote daemon..."));let i=n.identity?`ssh -i ${n.identity}`:"ssh";o(`${i} ${n.user}@${e} "pkill -f 'node dist/cli.js daemon' 2>/dev/null; sleep 2; cd ${n.path} && nohup node dist/cli.js daemon start > /tmp/agentx-daemon.log 2>&1 &"`,{stdio:"inherit"}),console.log(c.green(" Remote daemon restarted"))}}catch(i){console.log(c.red(` Deploy failed: ${i.message}`))}});x.action(async e=>{await new L(e.config).start()});function Q(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h ${Math.round(e%3600/60)}m`:`${Math.round(e/86400)}d ${Math.round(e%86400/3600)}h`}import{Command as V}from"commander";import h from"chalk";import{existsSync as I,readFileSync as Z,writeFileSync as _,mkdirSync as G}from"fs";import{resolve as j}from"path";var q=new V().name("init").description("initialize agentx configuration in the current directory").option("--force","overwrite existing config").action(async e=>{let n=process.cwd(),o=j(n,"agentx.json"),s=j(n,".env"),t=j(n,".agentx/sessions");if(console.log(),console.log(h.bold(" agentx init")),console.log(),I(o)&&!e.force){console.log(h.yellow(" agentx.json already exists. Use --force to overwrite.")),console.log();return}let i=[j(n,"agentx.example.json"),j(n,"node_modules/agentix-cli/agentx.example.json")],l;for(let r of i)if(I(r)){l=Z(r,"utf-8");break}l||(l=JSON.stringify({node:{id:K("os").hostname().toLowerCase().replace(/[^a-z0-9-]/g,"-"),name:K("os").hostname(),bind:"127.0.0.1:18800"},providers:{claude:{apiKey:"${ANTHROPIC_API_KEY}"}},agents:{assistant:{name:"Assistant",workspace:n,tier:"claude-code",model:"claude-sonnet-4-6",mentions:["@assistant","assistant"],maxConcurrent:2,systemPrompt:"You are a helpful assistant.",permissionMode:"default"}},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}}},null,2)),_(o,l),console.log(h.green(" \u2713 Created agentx.json")),I(s)||(_(s,["# AgentX environment variables","# ANTHROPIC_API_KEY=sk-ant-...","# TG_BOT_TOKEN=123456:ABC...","# MESH_TOKEN=your-mesh-secret",""].join(`
4
- `)),console.log(h.green(" \u2713 Created .env template"))),I(t)||(G(t,{recursive:!0}),console.log(h.green(" \u2713 Created .agentx/sessions/")));let d=j(n,".claude");I(d)||(G(d,{recursive:!0}),console.log(h.green(" \u2713 Created .claude/"))),console.log(),console.log(h.bold(" Next steps:")),console.log(` 1. Edit ${h.cyan("agentx.json")} \u2014 configure agents, channels, crons`),console.log(` 2. Edit ${h.cyan(".env")} \u2014 add API keys and bot tokens`),console.log(` 3. Run ${h.cyan("agentx daemon start")} \u2014 start the daemon`),console.log(` 4. Run ${h.cyan("agentx daemon status")} \u2014 verify everything`),console.log()});import{Command as S}from"commander";import a from"chalk";import k from"prompts";import{readFileSync as R,writeFileSync as B,existsSync as y,mkdirSync as C,cpSync as W,readdirSync as ee}from"fs";import{resolve as m,join as T}from"path";function p(){let e=m(process.cwd(),"agentx.json");if(!y(e))throw new Error("No agentx.json found. Run: agentx init");return JSON.parse(R(e,"utf-8"))}function w(e){B(m(process.cwd(),"agentx.json"),JSON.stringify(e,null,2))}var P=new S().name("agent").description("manage agents \u2014 add, list, remove");P.command("list").alias("ls").description("list configured agents").action(()=>{let e=p();console.log();for(let[n,o]of Object.entries(e.agents||{})){let s=o.mentions?.join(", ")||"";console.log(` ${a.cyan(n)} \u2014 ${o.name} (${o.tier})`),console.log(a.dim(` workspace: ${o.workspace}`)),s&&console.log(a.dim(` mentions: ${s}`))}console.log()});P.command("add").description("add a new agent interactively").action(async()=>{let e=p(),n=await k([{type:"text",name:"id",message:"Agent ID (kebab-case)",validate:d=>/^[a-z0-9-]+$/.test(d)||"Use lowercase, numbers, hyphens"},{type:"text",name:"name",message:"Display name"},{type:"text",name:"workspace",message:"Workspace path",initial:m(process.cwd(),"agents/")},{type:"select",name:"tier",message:"Execution tier",choices:[{title:"claude-code (subscription, full features)",value:"claude-code"},{title:"sdk (API key, programmatic)",value:"sdk"},{title:"orchestrator (any provider)",value:"orchestrator"}]},{type:"text",name:"model",message:"Model",initial:"claude-sonnet-4-6"},{type:"list",name:"mentions",message:"Mention patterns (comma-separated)",separator:","},{type:"number",name:"maxConcurrent",message:"Max concurrent tasks",initial:2},{type:"text",name:"systemPrompt",message:"System prompt"}]);if(!n.id)return;let o=n.workspace.endsWith(n.id)?n.workspace:T(n.workspace,n.id);C(m(o,".claude/skills"),{recursive:!0});let s=`# ${n.name}
2
+ import{d as j,e as R,p as G,q as z}from"./chunk-WT2UJMBC.js";import"./chunk-Z4GC5D6D.js";import"./chunk-M7HKBG3V.js";import{a as H}from"./chunk-4YCH6IZV.js";import{Command as ne}from"commander";import{Command as V}from"commander";import r from"chalk";var v=new V().name("daemon").description("manage the agentx daemon \u2014 start, stop, status, logs");v.command("start").description("start the daemon (default if no subcommand)").option("-c, --config <path>","path to agentx.json").option("-d, --detach","run in background (detached)").option("--port <port>","override bind port").action(async e=>{if(e.detach){let{spawn:n}=await import("child_process"),a=["dist/cli.js","daemon","start"];e.config&&a.push("-c",e.config),e.port&&a.push("--port",e.port);let t=n("node",a,{detached:!0,stdio:["ignore","ignore","ignore"],cwd:process.cwd()});t.unref();let{writeFileSync:i}=await import("fs");i("/tmp/agentx-daemon.pid",String(t.pid)),console.log(r.green(`Daemon started in background (PID: ${t.pid})`)),console.log(r.dim(" Logs: tail -f /tmp/agentx-daemon.log")),console.log(r.dim(" Stop: agentx daemon stop"));return}await new G(e.config).start()});v.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:o,unlinkSync:n}=await import("fs"),{resolve:a}=await import("path"),t=[a(process.cwd(),".agentx/daemon.pid"),"/tmp/agentx-daemon.pid"];for(let c of t)if(o(c))try{let d=parseInt(e(c,"utf-8").trim(),10);process.kill(d,"SIGTERM"),await new Promise(l=>setTimeout(l,2e3));try{n(c)}catch{}console.log(r.green(`Daemon stopped (PID: ${d})`));return}catch{try{n(c)}catch{}}let{execSync:i}=await import("child_process");try{i("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(r.green("Daemon stopped"))}catch{console.log(r.yellow("No daemon process found"))}});v.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let o=j(e.config),[n,a]=o.node.bind.split(":"),t=`http://${n||"127.0.0.1"}:${a}/health`,c=await(await fetch(t,{signal:AbortSignal.timeout(3e3)})).json();if(e.json){console.log(JSON.stringify(c,null,2));return}console.log(),console.log(r.bold(` ${c.node.name}`)+r.dim(` (${c.node.id})`)),console.log(r.green(" Status: running")+r.dim(` \u2014 uptime ${Z(c.uptime)}`)),console.log(),console.log(r.bold(" Agents:"));for(let l of c.agents){let u=l.active>0?r.yellow(` [${l.active} active]`):"",k=l.errors>0?r.red(` (${l.errors} errors)`):"";console.log(` ${r.cyan(l.name)} ${r.dim(`(${l.tier})`)}${u}${k}`),console.log(r.dim(` ${l.workspace}`))}let d=c.crons.filter(l=>l.enabled);if(c.crons.length){console.log(),console.log(r.bold(` Crons: ${d.length} enabled / ${c.crons.length} total`));for(let l of c.crons){let u=l.enabled?r.green("\u25CF"):r.dim("\u25CB"),k=l.nextRun?r.dim(` next: ${new Date(l.nextRun).toLocaleTimeString()}`):"";console.log(` ${u} ${l.id}${k}`)}}if(c.mesh?.length){console.log(),console.log(r.bold(" Mesh:"));for(let l of c.mesh){let u=l.healthy?r.green("\u25CF"):r.red("\u25CF"),k=l.skills?.length?r.dim(` (${l.skills.length} agents)`):"";console.log(` ${u} ${l.peer} ${r.dim(l.peerUrl)}${k}`)}}console.log()}catch(o){if(o.cause?.code==="ECONNREFUSED"||o.name==="TimeoutError")console.log(r.red(" Daemon is not running")),console.log(r.dim(" Start with: agentx daemon start"));else try{let n=j(e.config),a=R(n);if(console.log(),console.log(r.bold(` ${n.node.name}`)+r.dim(` (${n.node.id})`)),console.log(r.yellow(" Status: stopped")),console.log(r.dim(` ${Object.keys(n.agents).length} agents, ${Object.keys(n.crons).length} crons configured`)),a.length){console.log();for(let t of a)console.log(r.yellow(` \u26A0 ${t}`))}console.log()}catch(n){console.log(r.red(` ${n.message}`))}}});v.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:o,spawn:n}=await import("child_process"),a="/tmp/agentx-daemon.log",{existsSync:t}=await import("fs");if(!t(a)){console.log(r.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let i=n("tail",["-f","-n",e.lines,a],{stdio:"inherit"});process.on("SIGINT",()=>{i.kill(),process.exit(0)})}else o(`tail -n ${e.lines} ${a}`,{stdio:"inherit"})});v.command("send <agent> <message...>").description("send a task to an agent via the daemon API").option("-c, --config <path>","path to agentx.json").option("--peer <peer>","send to a mesh peer's agent").option("--json","output raw JSON response").action(async(e,o,n)=>{let a=o.join(" ");try{let t=j(n.config),[i,c]=t.node.bind.split(":"),d=`http://${i||"127.0.0.1"}:${c}`,l,u;n.peer?(l=`${d}/mesh/task`,u={peer:n.peer,message:a,agent:e}):(l=`${d}/task`,u={agent:e,message:a}),console.log(r.dim(` Sending to ${n.peer?`${n.peer}/${e}`:e}...`));let y=await(await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)})).json();n.json?console.log(JSON.stringify(y,null,2)):y.error?console.log(r.red(` Error: ${y.error}`)):(console.log(),console.log(y.content||y.response||"No response"),y.duration&&console.log(r.dim(`
3
+ (${(y.duration/1e3).toFixed(1)}s)`)))}catch(t){console.log(r.red(` Failed: ${t.message}`)),console.log(r.dim(" Is the daemon running? Try: agentx daemon status"))}});v.command("deploy <host>").description("deploy agentx to a remote server via rsync").option("-i, --identity <key>","SSH identity file").option("-u, --user <user>","SSH user","clawd").option("-p, --path <path>","remote agentx path","~/agentx").option("--restart","restart remote daemon after deploy",!1).option("--skip-checks","skip build and test before deploy",!1).action(async(e,o)=>{let{execSync:n}=await import("child_process"),a=o.identity?`-e "ssh -i ${o.identity}"`:"",t=`${o.user}@${e}:${o.path}/dist/`;if(!o.skipChecks){try{console.log(r.dim(" Running tests...")),n("npx vitest run --reporter=dot",{stdio:"pipe",cwd:process.cwd()}),console.log(r.green(" \u2713 Tests passed"))}catch{console.log(r.red(" \u2717 Tests failed \u2014 aborting deploy")),console.log(r.dim(" Use --skip-checks to deploy anyway"));return}let{existsSync:i,statSync:c}=await import("fs"),{resolve:d}=await import("path"),l=d(process.cwd(),"dist/cli.js");if(!i(l)){console.log(r.red(" \u2717 dist/ not found \u2014 run build first"));return}Date.now()-c(l).mtimeMs>3e5&&(console.log(r.yellow(" \u26A0 dist/ is older than 5 minutes \u2014 rebuilding...")),n("npx tsup --no-dts",{stdio:"pipe",cwd:process.cwd()}),console.log(r.green(" \u2713 Build complete")))}console.log(r.dim(` Deploying to ${o.user}@${e}:${o.path}...`));try{if(n(`rsync -avzL --delete ${a} dist/ ${t}`,{stdio:"inherit",cwd:process.cwd()}),console.log(r.green(" \u2713 Deploy complete")),o.restart){console.log(r.dim(" Restarting remote daemon..."));let i=o.identity?`ssh -i ${o.identity}`:"ssh";n(`${i} ${o.user}@${e} "pkill -f 'node dist/cli.js daemon' 2>/dev/null; sleep 2; cd ${o.path} && nohup node dist/cli.js daemon start > /tmp/agentx-daemon.log 2>&1 &"`,{stdio:"inherit"}),console.log(r.green(" Remote daemon restarted"))}}catch(i){console.log(r.red(` Deploy failed: ${i.message}`))}});v.action(async e=>{await new G(e.config).start()});function Z(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h ${Math.round(e%3600/60)}m`:`${Math.round(e/86400)}d ${Math.round(e%86400/3600)}h`}import{Command as ee}from"commander";import $ from"chalk";import{existsSync as O,readFileSync as oe,writeFileSync as _,mkdirSync as q}from"fs";import{resolve as C}from"path";var X=new ee().name("init").description("initialize agentx configuration in the current directory").option("--force","overwrite existing config").action(async e=>{let o=process.cwd(),n=C(o,"agentx.json"),a=C(o,".env"),t=C(o,".agentx/sessions");if(console.log(),console.log($.bold(" agentx init")),console.log(),O(n)&&!e.force){console.log($.yellow(" agentx.json already exists. Use --force to overwrite.")),console.log();return}let i=[C(o,"agentx.example.json"),C(o,"node_modules/agentix-cli/agentx.example.json")],c;for(let l of i)if(O(l)){c=oe(l,"utf-8");break}c||(c=JSON.stringify({node:{id:H("os").hostname().toLowerCase().replace(/[^a-z0-9-]/g,"-"),name:H("os").hostname(),bind:"127.0.0.1:18800"},providers:{claude:{apiKey:"${ANTHROPIC_API_KEY}"}},agents:{assistant:{name:"Assistant",workspace:o,tier:"claude-code",model:"claude-sonnet-4-6",mentions:["@assistant","assistant"],maxConcurrent:2,systemPrompt:"You are a helpful assistant.",permissionMode:"default"}},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}}},null,2)),_(n,c),console.log($.green(" \u2713 Created agentx.json")),O(a)||(_(a,["# AgentX environment variables","# ANTHROPIC_API_KEY=sk-ant-...","# TG_BOT_TOKEN=123456:ABC...","# MESH_TOKEN=your-mesh-secret",""].join(`
4
+ `)),console.log($.green(" \u2713 Created .env template"))),O(t)||(q(t,{recursive:!0}),console.log($.green(" \u2713 Created .agentx/sessions/")));let d=C(o,".claude");O(d)||(q(d,{recursive:!0}),console.log($.green(" \u2713 Created .claude/"))),console.log(),console.log($.bold(" Next steps:")),console.log(` 1. Edit ${$.cyan("agentx.json")} \u2014 configure agents, channels, crons`),console.log(` 2. Edit ${$.cyan(".env")} \u2014 add API keys and bot tokens`),console.log(` 3. Run ${$.cyan("agentx daemon start")} \u2014 start the daemon`),console.log(` 4. Run ${$.cyan("agentx daemon status")} \u2014 verify everything`),console.log()});import{Command as S}from"commander";import s from"chalk";import w from"prompts";import{readFileSync as M,writeFileSync as E,existsSync as h,mkdirSync as A,cpSync as F,readdirSync as Y}from"fs";import{resolve as g,join as L}from"path";function p(){let e=g(process.cwd(),"agentx.json");if(!h(e))throw new Error("No agentx.json found. Run: agentx init");return JSON.parse(M(e,"utf-8"))}function b(e){E(g(process.cwd(),"agentx.json"),JSON.stringify(e,null,2))}var I=new S().name("agent").description("manage agents \u2014 add, list, remove");I.command("list").alias("ls").description("list configured agents").action(()=>{let e=p();console.log();for(let[o,n]of Object.entries(e.agents||{})){let a=n.mentions?.join(", ")||"";console.log(` ${s.cyan(o)} \u2014 ${n.name} (${n.tier})`),console.log(s.dim(` workspace: ${n.workspace}`)),a&&console.log(s.dim(` mentions: ${a}`))}console.log()});I.command("add").description("add a new agent interactively").action(async()=>{let e=p(),o=await w([{type:"text",name:"id",message:"Agent ID (kebab-case)",validate:d=>/^[a-z0-9-]+$/.test(d)||"Use lowercase, numbers, hyphens"},{type:"text",name:"name",message:"Display name"},{type:"text",name:"workspace",message:"Workspace path",initial:g(process.cwd(),"agents/")},{type:"select",name:"tier",message:"Execution tier",choices:[{title:"claude-code (subscription, full features)",value:"claude-code"},{title:"sdk (API key, programmatic)",value:"sdk"},{title:"orchestrator (any provider)",value:"orchestrator"}]},{type:"text",name:"model",message:"Model",initial:"claude-sonnet-4-6"},{type:"list",name:"mentions",message:"Mention patterns (comma-separated)",separator:","},{type:"number",name:"maxConcurrent",message:"Max concurrent tasks",initial:2},{type:"text",name:"systemPrompt",message:"System prompt"}]);if(!o.id)return;let n=o.workspace.endsWith(o.id)?o.workspace:L(o.workspace,o.id);A(g(n,".claude/skills"),{recursive:!0});let a=`# ${o.name}
5
5
 
6
- ${n.systemPrompt}
7
- `;B(m(o,"CLAUDE.md"),s),B(m(o,".claude/settings.json"),JSON.stringify({permissions:{allow:["Bash(git *)","Bash(curl *)","Bash(node *)","Read","Write","Edit","Glob","Grep","WebFetch","WebSearch"]}},null,2));let t=m(process.cwd(),"src/wiki/SKILL.md"),i=m(__dirname,"../wiki/SKILL.md"),l=y(t)?t:i;y(l)&&(C(m(o,".claude/skills/wiki"),{recursive:!0}),W(l,m(o,".claude/skills/wiki/SKILL.md"))),e.agents=e.agents||{},e.agents[n.id]={name:n.name,workspace:o,tier:n.tier,model:n.model,mentions:n.mentions?.map(d=>d.trim()).filter(Boolean)||[],maxConcurrent:n.maxConcurrent,systemPrompt:n.systemPrompt,permissionMode:"default"},w(e),console.log(a.green(`
8
- Agent "${n.id}" added`)),console.log(a.dim(` Workspace: ${o}`)),console.log(a.dim(" Wiki skill installed")),console.log(a.dim(" CLAUDE.md + settings.json created")),console.log()});P.command("remove <id>").alias("rm").description("remove an agent from config (keeps workspace)").action(e=>{let n=p();if(!n.agents?.[e]){console.log(a.red(` Agent "${e}" not found`));return}delete n.agents[e],w(n),console.log(a.green(` Agent "${e}" removed from config (workspace preserved)`))});var M=new S().name("channel").description("manage channels \u2014 add telegram/whatsapp/discord, list");M.command("list").alias("ls").description("list configured channels and bindings").action(()=>{let e=p();console.log();let n=e.channels?.telegram;if(n?.enabled){console.log(a.bold(" Telegram:"));for(let[t,i]of Object.entries(n.accounts||{}))console.log(` ${a.cyan(t)} -> agent: ${i.agentBinding}`)}else console.log(a.dim(" Telegram: disabled"));let o=e.channels?.whatsapp;if(o?.enabled){console.log(a.bold(" WhatsApp:")),console.log(` default agent: ${o.defaultAgent||"(none)"}`),console.log(` session: ${o.sessionDir||".agentx/whatsapp-sessions"}`);for(let t of o.routes||[]){let i=t.contact?`contact ${t.contact}`:`group "${t.group}"`;console.log(` ${i} -> agent: ${t.agent}`)}}else console.log(a.dim(" WhatsApp: disabled"));let s=e.channels?.discord;s?.enabled?(console.log(a.bold(" Discord:")),console.log(` agent: ${s.agentBinding||"(none)"}`)):console.log(a.dim(" Discord: disabled")),console.log()});M.command("add").description("add a channel (telegram, whatsapp, or discord)").action(async()=>{let e=p(),n=Object.keys(e.agents||{});if(!n.length){console.log(a.red(" No agents configured. Run: agentx agent add"));return}let o=n.map(t=>({title:`${t} (${e.agents[t].name})`,value:t})),{channelType:s}=await k({type:"select",name:"channelType",message:"Channel type",choices:[{title:"Telegram \u2014 bot via BotFather token",value:"telegram"},{title:"WhatsApp \u2014 link via QR code (self-chat or contacts)",value:"whatsapp"},{title:"Discord \u2014 bot via Discord developer portal",value:"discord"}]});if(s){if(e.channels=e.channels||{},s==="telegram"){let t=await k([{type:"text",name:"accountName",message:"Account name (e.g. 'default', 'devops')"},{type:"text",name:"token",message:"Bot token (from @BotFather)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:o}]);if(!t.accountName||!t.token)return;try{let l=await(await fetch(`https://api.telegram.org/bot${t.token}/getMe`)).json();if(!l.ok)throw new Error(l.description);console.log(a.green(` Bot verified: @${l.result.username}`));let d=`@${l.result.username}`,r=e.agents[t.agentBinding].mentions||[];r.includes(d)||(r.push(d,l.result.username),e.agents[t.agentBinding].mentions=r)}catch(i){console.log(a.red(` Invalid token: ${i.message}`));return}e.channels.telegram=e.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},e.channels.telegram.enabled=!0,e.channels.telegram.accounts[t.accountName]={token:t.token,agentBinding:t.agentBinding},w(e),console.log(a.green(` Telegram "${t.accountName}" added -> ${t.agentBinding}`))}if(s==="whatsapp"){let t=await k([{type:"select",name:"defaultAgent",message:"Default agent for WhatsApp messages",choices:o},{type:"text",name:"sessionDir",message:"Session directory",initial:".agentx/whatsapp-sessions"},{type:"confirm",name:"addRoute",message:"Add a contact/group route?",initial:!0}]);if(!t.defaultAgent)return;let i=[],l=t.addRoute;for(;l;){let d=await k([{type:"select",name:"type",message:"Route type",choices:[{title:"Contact (phone number)",value:"contact"},{title:"Group (name match)",value:"group"}]},{type:"text",name:"value",message:r=>r==="contact"?"Phone number (e.g. +21624309128)":"Group name (partial match)"},{type:"select",name:"agent",message:"Route to agent",choices:o},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);d.value&&d.agent&&i.push({[d.type]:d.value,agent:d.agent}),l=d.more}e.channels.whatsapp={enabled:!0,sessionDir:t.sessionDir,defaultAgent:t.defaultAgent,routes:i},w(e),C(m(process.cwd(),t.sessionDir),{recursive:!0}),console.log(a.green(` WhatsApp enabled (${i.length} routes, default: ${t.defaultAgent})`)),console.log(a.dim(" Start daemon to scan QR code: agentx daemon start"))}if(s==="discord"){let t=await k([{type:"text",name:"token",message:"Discord bot token (from developer portal)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:o}]);if(!t.token)return;e.channels.discord={enabled:!0,token:t.token,agentBinding:t.agentBinding},w(e),console.log(a.green(` Discord added -> ${t.agentBinding}`))}console.log(a.dim(" Restart daemon to apply: agentx daemon stop && agentx daemon start")),console.log()}});var A=new S().name("cron").description("manage cron jobs \u2014 add, list, enable, disable");A.command("list").alias("ls").description("list cron jobs").action(()=>{let e=p();console.log();for(let[n,o]of Object.entries(e.crons||{})){let s=o.enabled?a.green("\u25CF"):a.dim("\u25CB");console.log(` ${s} ${a.cyan(n)} \u2014 ${o.schedule} (${o.timezone})`),console.log(a.dim(` agent: ${o.agent} | timeout: ${o.timeout}s`))}Object.keys(e.crons||{}).length||console.log(a.dim(" No cron jobs configured")),console.log()});A.command("add").description("add a cron job").action(async()=>{let e=p(),n=Object.keys(e.agents||{}),o=await k([{type:"text",name:"id",message:"Job ID (kebab-case)"},{type:"text",name:"schedule",message:"Cron expression (e.g. '0 9 * * *')"},{type:"text",name:"timezone",message:"Timezone",initial:"UTC"},{type:"select",name:"agent",message:"Agent",choices:n.map(s=>({title:s,value:s}))},{type:"text",name:"prompt",message:"Task prompt"},{type:"number",name:"timeout",message:"Timeout (seconds)",initial:600},{type:"confirm",name:"enabled",message:"Enable now?",initial:!1}]);!o.id||!o.schedule||(e.crons=e.crons||{},e.crons[o.id]={enabled:o.enabled,schedule:o.schedule,timezone:o.timezone,agent:o.agent,prompt:o.prompt,timeout:o.timeout,onError:"log"},w(e),console.log(a.green(` Cron "${o.id}" added (${o.enabled?"enabled":"disabled"})`)),console.log())});A.command("enable <id>").description("enable a cron job").action(e=>{let n=p();if(!n.crons?.[e]){console.log(a.red(` Cron "${e}" not found`));return}n.crons[e].enabled=!0,w(n),console.log(a.green(` Cron "${e}" enabled`))});A.command("disable <id>").description("disable a cron job").action(e=>{let n=p();if(!n.crons?.[e]){console.log(a.red(` Cron "${e}" not found`));return}n.crons[e].enabled=!1,w(n),console.log(a.green(` Cron "${e}" disabled`))});var O=new S().name("mesh").description("manage mesh peers \u2014 add, list, remove");O.command("list").alias("ls").description("list mesh peers").action(async()=>{let e=p();if(console.log(),!e.mesh?.enabled)console.log(a.dim(" Mesh: disabled"));else{console.log(a.bold(" Mesh peers:"));for(let n of e.mesh.peers||[]){let o=a.red("unreachable");try{let t=await(await fetch(`${n.url}/health`,{signal:AbortSignal.timeout(3e3)})).json();o=a.green(`healthy \u2014 ${t.agents?.length||0} agents`)}catch{}console.log(` ${a.cyan(n.name)} ${a.dim(n.url)} ${o}`)}}console.log()});O.command("add").description("add a mesh peer (another agentx server)").action(async()=>{let e=p(),n=await k([{type:"text",name:"name",message:"Peer name (e.g. 'server-2')"},{type:"text",name:"url",message:"Peer URL (e.g. 'http://100.67.108.119:18800')"},{type:"text",name:"token",message:"Auth token (optional, press enter to skip)"}]);if(!(!n.name||!n.url)){try{let s=await(await fetch(`${n.url}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)})).json();console.log(a.green(` Connected: ${s.name} (${s.skills?.length||0} agents)`))}catch{console.log(a.yellow(" Could not reach peer (adding anyway)"))}e.mesh=e.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},e.mesh.enabled=!0,e.mesh.peers=e.mesh.peers||[],e.mesh.peers.push({url:n.url,name:n.name,...n.token?{token:n.token}:{}}),w(e),console.log(a.green(` Peer "${n.name}" added`)),console.log()}});O.command("remove <name>").alias("rm").description("remove a mesh peer").action(e=>{let n=p();n.mesh?.peers&&(n.mesh.peers=n.mesh.peers.filter(o=>o.name!==e),n.mesh.peers.length===0&&(n.mesh.enabled=!1),w(n),console.log(a.green(` Peer "${e}" removed`)))});var E=new S().name("skill").description("manage skills \u2014 add to agent(s), list");E.command("add <skillPath>").description("add a skill to agent(s)").option("-a, --agent <agents...>","target agent ID(s)").option("--all","add to all agents").action(async(e,n)=>{let o=p(),s=m(e);if(!y(s)){console.log(a.red(` Skill not found: ${s}`));return}let t=y(T(s,"SKILL.md"))?s.split("/").pop():s.replace(/\/SKILL\.md$/,"").split("/").pop(),i;if(n.all)i=Object.keys(o.agents||{});else if(n.agent)i=n.agent;else{let l=Object.keys(o.agents||{});i=(await k({type:"multiselect",name:"agents",message:"Install to which agents?",choices:l.map(r=>({title:`${r} (${o.agents[r].name})`,value:r}))})).agents||[]}for(let l of i){let d=o.agents[l];if(!d){console.log(a.yellow(` Agent "${l}" not found, skipping`));continue}let r=m(d.workspace,".claude/skills",t);C(r,{recursive:!0}),y(T(s,"SKILL.md"))?W(s,r,{recursive:!0}):s.endsWith(".md")&&W(s,T(r,"SKILL.md")),console.log(a.green(` ${t} -> ${l} (${d.workspace})`))}console.log()});E.command("list").alias("ls").description("list skills per agent").action(()=>{let e=p();console.log();for(let[n,o]of Object.entries(e.agents||{})){let s=m(o.workspace,".claude/skills"),t=y(s)?ee(s).filter(i=>!i.startsWith(".")):[];console.log(` ${a.cyan(n)}: ${t.length?t.join(", "):a.dim("(none)")}`)}console.log()});var U=new S().name("hook").description("manage hooks \u2014 add to agent workspace");U.command("add <agent>").description("add a hook to an agent's workspace settings").action(async e=>{let o=p().agents?.[e];if(!o){console.log(a.red(` Agent "${e}" not found`));return}let s=m(o.workspace,".claude/settings.json"),t=y(s)?JSON.parse(R(s,"utf-8")):{},i=await k([{type:"select",name:"event",message:"Hook event",choices:[{title:"PreToolUse \u2014 before any tool runs",value:"PreToolUse"},{title:"PostToolUse \u2014 after any tool runs",value:"PostToolUse"},{title:"SessionStart \u2014 when session begins",value:"SessionStart"},{title:"Notification \u2014 on notifications",value:"Notification"},{title:"Stop \u2014 before session stops",value:"Stop"}]},{type:"select",name:"type",message:"Hook type",choices:[{title:"command \u2014 run a shell command",value:"command"},{title:"http \u2014 POST to a URL",value:"http"}]},{type:"text",name:"value",message:r=>r==="command"?"Shell command":"URL"},{type:"text",name:"matcher",message:"Matcher regex (optional, e.g. 'Bash' to match tool)"}]);if(!i.event||!i.value)return;t.hooks=t.hooks||{},t.hooks[i.event]=t.hooks[i.event]||[];let d={hooks:[{type:i.type,...i.type==="command"?{command:i.value}:{url:i.value}}]};i.matcher&&(d.matcher=i.matcher),t.hooks[i.event].push(d),C(m(o.workspace,".claude"),{recursive:!0}),B(s,JSON.stringify(t,null,2)),console.log(a.green(` Hook added to ${e}: ${i.event} -> ${i.type}`)),console.log()});var F=new S().name("migrate").description("import configuration from OpenClaw or other tools");F.command("openclaw [configPath]").description("import agents, channels, and crons from OpenClaw config").option("--dry-run","show what would be imported without writing").action(async(e,n)=>{let o=[e,m(process.env.HOME||"",".openclaw/openclaw.json"),m(process.env.HOME||"",".openclaw/clawdbot.json")].filter(Boolean),s;for(let g of o)if(g&&y(g)){s=g;break}if(!s){console.log(a.red(" OpenClaw config not found. Pass the path: agentx migrate openclaw /path/to/config.json"));return}console.log(a.dim(` Reading: ${s}`));let t=JSON.parse(R(s,"utf-8")),i=y(m(process.cwd(),"agentx.json"))?p():{node:{id:"imported",name:"Imported",bind:"127.0.0.1:18800"},providers:{},agents:{},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[]}},l=t.agents?.list||[],d=t.bindings||[],r={};for(let g of d)g.match?.channel==="telegram"&&(r[g.match.accountId]=g.agentId);l.find(g=>g.id==="main"||g.default)&&(r.default="main");let f=0;for(let g of l){if(g.workspace?.startsWith("/data"))continue;let b=g.id.replace(/-agent$/,"").replace(/^main$/,"atlas"),u=g.groupChat?.mentionPatterns||[];u.some(D=>D===b)||u.push(b),i.agents[b]={name:g.name,workspace:g.workspace,tier:"claude-code",model:"claude-sonnet-4-6",mentions:u,maxConcurrent:g.id==="main"?2:1,systemPrompt:`You are ${g.name} on AgentX.`,permissionMode:"bypassPermissions"},f++,n.dryRun||C(m(g.workspace,".claude/skills"),{recursive:!0})}console.log(` ${a.green(f)} agents imported`);let v=t.channels?.telegram?.accounts||{},$=0;for(let[g,b]of Object.entries(v)){if(!b.botToken)continue;let D=r[g]?.replace(/-agent$/,"").replace(/^main$/,"atlas")||"atlas";i.channels.telegram.accounts[g]={token:b.botToken,agentBinding:D},i.channels.telegram.enabled=!0,$++}console.log(` ${a.green($)} Telegram accounts imported`);let J=m(s,"../cron/jobs.json");if(y(J)){let g=JSON.parse(R(J,"utf-8")),b=0;for(let u of g.jobs||[]){let D=u.name||u.id,Y=u.agentId?.replace(/-agent$/,"").replace(/^main$/,"atlas")||"atlas";i.crons[D]={enabled:u.enabled||!1,schedule:u.schedule?.expr||"0 9 * * *",timezone:u.schedule?.tz||"UTC",agent:Y,prompt:u.payload?.message||"",timeout:u.payload?.timeoutSeconds||600,onError:"log"},b++}console.log(` ${a.green(b)} cron jobs imported`)}n.dryRun?(console.log(a.yellow(`
9
- Dry run \u2014 nothing written`)),console.log(JSON.stringify(i,null,2))):(w(i),console.log(a.green(`
10
- Migration complete! Review agentx.json and run: agentx daemon start`))),console.log()});process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function oe(){let e=await z(),n=new ne().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");if(n.addCommand(x).addCommand(q).addCommand(P).addCommand(M).addCommand(A).addCommand(O).addCommand(E).addCommand(U).addCommand(F),process.argv.slice(2).length===0){n.outputHelp();return}n.parse()}oe();
6
+ ${o.systemPrompt}
7
+ `;E(g(n,"CLAUDE.md"),a),E(g(n,".claude/settings.json"),JSON.stringify({permissions:{allow:["Bash(git *)","Bash(curl *)","Bash(node *)","Read","Write","Edit","Glob","Grep","WebFetch","WebSearch"]}},null,2));let t=g(process.cwd(),"src/wiki/SKILL.md"),i=g(__dirname,"../wiki/SKILL.md"),c=h(t)?t:i;h(c)&&(A(g(n,".claude/skills/wiki"),{recursive:!0}),F(c,g(n,".claude/skills/wiki/SKILL.md"))),e.agents=e.agents||{},e.agents[o.id]={name:o.name,workspace:n,tier:o.tier,model:o.model,mentions:o.mentions?.map(d=>d.trim()).filter(Boolean)||[],maxConcurrent:o.maxConcurrent,systemPrompt:o.systemPrompt,permissionMode:"default"},b(e),console.log(s.green(`
8
+ Agent "${o.id}" added`)),console.log(s.dim(` Workspace: ${n}`)),console.log(s.dim(" Wiki skill installed")),console.log(s.dim(" CLAUDE.md + settings.json created")),console.log()});I.command("remove <id>").alias("rm").description("remove an agent from config (keeps workspace)").action(e=>{let o=p();if(!o.agents?.[e]){console.log(s.red(` Agent "${e}" not found`));return}delete o.agents[e],b(o),console.log(s.green(` Agent "${e}" removed from config (workspace preserved)`))});var B=new S().name("channel").description("manage channels \u2014 add telegram/whatsapp/discord, list");B.command("list").alias("ls").description("list configured channels and bindings").action(()=>{let e=p();console.log();let o=e.channels?.telegram;if(o?.enabled){console.log(s.bold(" Telegram:"));for(let[i,c]of Object.entries(o.accounts||{}))console.log(` ${s.cyan(i)} -> agent: ${c.agentBinding}`)}else console.log(s.dim(" Telegram: disabled"));let n=e.channels?.whatsapp;if(n?.enabled){console.log(s.bold(" WhatsApp:")),console.log(` default agent: ${n.defaultAgent||"(none)"}`),console.log(` session: ${n.sessionDir||".agentx/whatsapp-sessions"}`);for(let i of n.routes||[]){let c=i.contact?`contact ${i.contact}`:`group "${i.group}"`;console.log(` ${c} -> agent: ${i.agent}`)}}else console.log(s.dim(" WhatsApp: disabled"));let a=e.channels?.discord;a?.enabled?(console.log(s.bold(" Discord:")),console.log(` agent: ${a.agentBinding||"(none)"}`)):console.log(s.dim(" Discord: disabled"));let t=e.channels?.gitlab;if(t?.enabled){console.log(s.bold(" GitLab:")),console.log(` host: ${t.host}`),console.log(` webhook: :${t.webhookPort}`);for(let i of t.routes||[])console.log(` ${i.project} -> agent: ${i.agent}`)}else console.log(s.dim(" GitLab: disabled"));console.log()});B.command("add").description("add a channel (telegram, whatsapp, or discord)").action(async()=>{let e=p(),o=Object.keys(e.agents||{});if(!o.length){console.log(s.red(" No agents configured. Run: agentx agent add"));return}let n=o.map(t=>({title:`${t} (${e.agents[t].name})`,value:t})),{channelType:a}=await w({type:"select",name:"channelType",message:"Channel type",choices:[{title:"Telegram \u2014 bot via BotFather token",value:"telegram"},{title:"WhatsApp \u2014 link via QR code (self-chat or contacts)",value:"whatsapp"},{title:"Discord \u2014 bot via Discord developer portal",value:"discord"},{title:"GitLab \u2014 webhook for issues, MRs, comments, pipelines",value:"gitlab"}]});if(a){if(e.channels=e.channels||{},a==="telegram"){let t=await w([{type:"text",name:"accountName",message:"Account name (e.g. 'default', 'devops')"},{type:"text",name:"token",message:"Bot token (from @BotFather)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:n}]);if(!t.accountName||!t.token)return;try{let c=await(await fetch(`https://api.telegram.org/bot${t.token}/getMe`)).json();if(!c.ok)throw new Error(c.description);console.log(s.green(` Bot verified: @${c.result.username}`));let d=`@${c.result.username}`,l=e.agents[t.agentBinding].mentions||[];l.includes(d)||(l.push(d,c.result.username),e.agents[t.agentBinding].mentions=l)}catch(i){console.log(s.red(` Invalid token: ${i.message}`));return}e.channels.telegram=e.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},e.channels.telegram.enabled=!0,e.channels.telegram.accounts[t.accountName]={token:t.token,agentBinding:t.agentBinding},b(e),console.log(s.green(` Telegram "${t.accountName}" added -> ${t.agentBinding}`))}if(a==="whatsapp"){let t=await w([{type:"select",name:"defaultAgent",message:"Default agent for WhatsApp messages",choices:n},{type:"text",name:"sessionDir",message:"Session directory",initial:".agentx/whatsapp-sessions"},{type:"confirm",name:"addRoute",message:"Add a contact/group route?",initial:!0}]);if(!t.defaultAgent)return;let i=[],c=t.addRoute;for(;c;){let d=await w([{type:"select",name:"type",message:"Route type",choices:[{title:"Contact (phone number)",value:"contact"},{title:"Group (name match)",value:"group"}]},{type:"text",name:"value",message:l=>l==="contact"?"Phone number (e.g. +21624309128)":"Group name (partial match)"},{type:"select",name:"agent",message:"Route to agent",choices:n},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);d.value&&d.agent&&i.push({[d.type]:d.value,agent:d.agent}),c=d.more}e.channels.whatsapp={enabled:!0,sessionDir:t.sessionDir,defaultAgent:t.defaultAgent,routes:i},b(e),A(g(process.cwd(),t.sessionDir),{recursive:!0}),console.log(s.green(` WhatsApp enabled (${i.length} routes, default: ${t.defaultAgent})`)),console.log(s.dim(" Start daemon to scan QR code: agentx daemon start"))}if(a==="discord"){let t=await w([{type:"text",name:"token",message:"Discord bot token (from developer portal)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:n}]);if(!t.token)return;e.channels.discord={enabled:!0,token:t.token,agentBinding:t.agentBinding},b(e),console.log(s.green(` Discord added -> ${t.agentBinding}`))}if(a==="gitlab"){let t=await w([{type:"text",name:"host",message:"GitLab instance URL",initial:"https://gitlab.noqta.tn"},{type:"text",name:"token",message:"GitLab API token (PRIVATE-TOKEN)"},{type:"number",name:"webhookPort",message:"Webhook listen port",initial:18810},{type:"text",name:"webhookSecret",message:"Webhook secret (X-Gitlab-Token, optional)"},{type:"confirm",name:"addRoute",message:"Add a project route?",initial:!0}]);if(!t.token)return;let i=[],c=t.addRoute;for(;c;){let d=await w([{type:"text",name:"project",message:"GitLab project path (e.g. noqta/mtgl-v2, or * for default)"},{type:"select",name:"agent",message:"Route to agent",choices:n},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);d.project&&d.agent&&i.push({project:d.project,agent:d.agent}),c=d.more}e.channels.gitlab={enabled:!0,host:t.host,token:t.token,webhookPort:t.webhookPort,webhookSecret:t.webhookSecret||void 0,routes:i},b(e),console.log(s.green(` GitLab enabled (${i.length} routes, webhook :${t.webhookPort})`)),console.log(s.dim(` Add webhook in GitLab: ${t.host}/<project>/-/hooks`)),console.log(s.dim(` URL: http://your-server:${t.webhookPort}/`)),t.webhookSecret&&console.log(s.dim(` Secret token: ${t.webhookSecret}`)),console.log(s.dim(" Events: Comments, Issues, Merge requests, Pipeline"))}console.log(s.dim(" Restart daemon to apply: agentx daemon stop && agentx daemon start")),console.log()}});var P=new S().name("cron").description("manage cron jobs \u2014 add, list, enable, disable");P.command("list").alias("ls").description("list cron jobs").action(()=>{let e=p();console.log();for(let[o,n]of Object.entries(e.crons||{})){let a=n.enabled?s.green("\u25CF"):s.dim("\u25CB");console.log(` ${a} ${s.cyan(o)} \u2014 ${n.schedule} (${n.timezone})`),console.log(s.dim(` agent: ${n.agent} | timeout: ${n.timeout}s`))}Object.keys(e.crons||{}).length||console.log(s.dim(" No cron jobs configured")),console.log()});P.command("add").description("add a cron job").action(async()=>{let e=p(),o=Object.keys(e.agents||{}),n=await w([{type:"text",name:"id",message:"Job ID (kebab-case)"},{type:"text",name:"schedule",message:"Cron expression (e.g. '0 9 * * *')"},{type:"text",name:"timezone",message:"Timezone",initial:"UTC"},{type:"select",name:"agent",message:"Agent",choices:o.map(a=>({title:a,value:a}))},{type:"text",name:"prompt",message:"Task prompt"},{type:"number",name:"timeout",message:"Timeout (seconds)",initial:600},{type:"confirm",name:"enabled",message:"Enable now?",initial:!1}]);!n.id||!n.schedule||(e.crons=e.crons||{},e.crons[n.id]={enabled:n.enabled,schedule:n.schedule,timezone:n.timezone,agent:n.agent,prompt:n.prompt,timeout:n.timeout,onError:"log"},b(e),console.log(s.green(` Cron "${n.id}" added (${n.enabled?"enabled":"disabled"})`)),console.log())});P.command("enable <id>").description("enable a cron job").action(e=>{let o=p();if(!o.crons?.[e]){console.log(s.red(` Cron "${e}" not found`));return}o.crons[e].enabled=!0,b(o),console.log(s.green(` Cron "${e}" enabled`))});P.command("disable <id>").description("disable a cron job").action(e=>{let o=p();if(!o.crons?.[e]){console.log(s.red(` Cron "${e}" not found`));return}o.crons[e].enabled=!1,b(o),console.log(s.green(` Cron "${e}" disabled`))});var T=new S().name("mesh").description("manage mesh peers \u2014 add, list, remove");T.command("list").alias("ls").description("list mesh peers").action(async()=>{let e=p();if(console.log(),!e.mesh?.enabled)console.log(s.dim(" Mesh: disabled"));else{console.log(s.bold(" Mesh peers:"));for(let o of e.mesh.peers||[]){let n=s.red("unreachable");try{let t=await(await fetch(`${o.url}/health`,{signal:AbortSignal.timeout(3e3)})).json();n=s.green(`healthy \u2014 ${t.agents?.length||0} agents`)}catch{}console.log(` ${s.cyan(o.name)} ${s.dim(o.url)} ${n}`)}}console.log()});T.command("add").description("add a mesh peer (another agentx server)").action(async()=>{let e=p(),o=await w([{type:"text",name:"name",message:"Peer name (e.g. 'server-2')"},{type:"text",name:"url",message:"Peer URL (e.g. 'http://100.67.108.119:18800')"},{type:"text",name:"token",message:"Auth token (optional, press enter to skip)"}]);if(!(!o.name||!o.url)){try{let a=await(await fetch(`${o.url}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)})).json();console.log(s.green(` Connected: ${a.name} (${a.skills?.length||0} agents)`))}catch{console.log(s.yellow(" Could not reach peer (adding anyway)"))}e.mesh=e.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},e.mesh.enabled=!0,e.mesh.peers=e.mesh.peers||[],e.mesh.peers.push({url:o.url,name:o.name,...o.token?{token:o.token}:{}}),b(e),console.log(s.green(` Peer "${o.name}" added`)),console.log()}});T.command("remove <name>").alias("rm").description("remove a mesh peer").action(e=>{let o=p();o.mesh?.peers&&(o.mesh.peers=o.mesh.peers.filter(n=>n.name!==e),o.mesh.peers.length===0&&(o.mesh.enabled=!1),b(o),console.log(s.green(` Peer "${e}" removed`)))});var W=new S().name("skill").description("manage skills \u2014 add to agent(s), list");W.command("add <skillPath>").description("add a skill to agent(s)").option("-a, --agent <agents...>","target agent ID(s)").option("--all","add to all agents").action(async(e,o)=>{let n=p(),a=g(e);if(!h(a)){console.log(s.red(` Skill not found: ${a}`));return}let t=h(L(a,"SKILL.md"))?a.split("/").pop():a.replace(/\/SKILL\.md$/,"").split("/").pop(),i;if(o.all)i=Object.keys(n.agents||{});else if(o.agent)i=o.agent;else{let c=Object.keys(n.agents||{});i=(await w({type:"multiselect",name:"agents",message:"Install to which agents?",choices:c.map(l=>({title:`${l} (${n.agents[l].name})`,value:l}))})).agents||[]}for(let c of i){let d=n.agents[c];if(!d){console.log(s.yellow(` Agent "${c}" not found, skipping`));continue}let l=g(d.workspace,".claude/skills",t);A(l,{recursive:!0}),h(L(a,"SKILL.md"))?F(a,l,{recursive:!0}):a.endsWith(".md")&&F(a,L(l,"SKILL.md")),console.log(s.green(` ${t} -> ${c} (${d.workspace})`))}console.log()});W.command("list").alias("ls").description("list skills per agent").action(()=>{let e=p();console.log();for(let[o,n]of Object.entries(e.agents||{})){let a=g(n.workspace,".claude/skills"),t=h(a)?Y(a).filter(i=>!i.startsWith(".")):[];console.log(` ${s.cyan(o)}: ${t.length?t.join(", "):s.dim("(none)")}`)}console.log()});var J=new S().name("hook").description("manage hooks \u2014 add to agent workspace");J.command("add <agent>").description("add a hook to an agent's workspace settings").action(async e=>{let n=p().agents?.[e];if(!n){console.log(s.red(` Agent "${e}" not found`));return}let a=g(n.workspace,".claude/settings.json"),t=h(a)?JSON.parse(M(a,"utf-8")):{},i=await w([{type:"select",name:"event",message:"Hook event",choices:[{title:"PreToolUse \u2014 before any tool runs",value:"PreToolUse"},{title:"PostToolUse \u2014 after any tool runs",value:"PostToolUse"},{title:"SessionStart \u2014 when session begins",value:"SessionStart"},{title:"Notification \u2014 on notifications",value:"Notification"},{title:"Stop \u2014 before session stops",value:"Stop"}]},{type:"select",name:"type",message:"Hook type",choices:[{title:"command \u2014 run a shell command",value:"command"},{title:"http \u2014 POST to a URL",value:"http"}]},{type:"text",name:"value",message:l=>l==="command"?"Shell command":"URL"},{type:"text",name:"matcher",message:"Matcher regex (optional, e.g. 'Bash' to match tool)"}]);if(!i.event||!i.value)return;t.hooks=t.hooks||{},t.hooks[i.event]=t.hooks[i.event]||[];let d={hooks:[{type:i.type,...i.type==="command"?{command:i.value}:{url:i.value}}]};i.matcher&&(d.matcher=i.matcher),t.hooks[i.event].push(d),A(g(n.workspace,".claude"),{recursive:!0}),E(a,JSON.stringify(t,null,2)),console.log(s.green(` Hook added to ${e}: ${i.event} -> ${i.type}`)),console.log()});var K=new S().name("migrate").description("import configuration from OpenClaw or other tools");K.command("openclaw [configPath]").description("import agents, channels, and crons from OpenClaw config").option("--dry-run","show what would be imported without writing").action(async(e,o)=>{let n=[e,g(process.env.HOME||"",".openclaw/openclaw.json"),g(process.env.HOME||"",".openclaw/clawdbot.json")].filter(Boolean),a;for(let m of n)if(m&&h(m)){a=m;break}if(!a){console.log(s.red(" OpenClaw config not found. Pass the path: agentx migrate openclaw /path/to/config.json"));return}console.log(s.dim(` Reading: ${a}`));let t=JSON.parse(M(a,"utf-8")),i=h(g(process.cwd(),"agentx.json"))?p():{node:{id:"imported",name:"Imported",bind:"127.0.0.1:18800"},providers:{},agents:{},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[]}},c=t.agents?.list||[],d=t.bindings||[],l={};for(let m of d)m.match?.channel==="telegram"&&(l[m.match.accountId]=m.agentId);c.find(m=>m.id==="main"||m.default)&&(l.default="main");let u=0;for(let m of c){if(m.workspace?.startsWith("/data"))continue;let x=m.id.replace(/-agent$/,"").replace(/^main$/,"atlas"),f=m.groupChat?.mentionPatterns||[];f.some(D=>D===x)||f.push(x),i.agents[x]={name:m.name,workspace:m.workspace,tier:"claude-code",model:"claude-sonnet-4-6",mentions:f,maxConcurrent:m.id==="main"?2:1,systemPrompt:`You are ${m.name} on AgentX.`,permissionMode:"bypassPermissions"},u++,o.dryRun||A(g(m.workspace,".claude/skills"),{recursive:!0})}console.log(` ${s.green(u)} agents imported`);let k=t.channels?.telegram?.accounts||{},y=0;for(let[m,x]of Object.entries(k)){if(!x.botToken)continue;let D=l[m]?.replace(/-agent$/,"").replace(/^main$/,"atlas")||"atlas";i.channels.telegram.accounts[m]={token:x.botToken,agentBinding:D},i.channels.telegram.enabled=!0,y++}console.log(` ${s.green(y)} Telegram accounts imported`);let N=g(a,"../cron/jobs.json");if(h(N)){let m=JSON.parse(M(N,"utf-8")),x=0;for(let f of m.jobs||[]){let D=f.name||f.id,Q=f.agentId?.replace(/-agent$/,"").replace(/^main$/,"atlas")||"atlas";i.crons[D]={enabled:f.enabled||!1,schedule:f.schedule?.expr||"0 9 * * *",timezone:f.schedule?.tz||"UTC",agent:Q,prompt:f.payload?.message||"",timeout:f.payload?.timeoutSeconds||600,onError:"log"},x++}console.log(` ${s.green(x)} cron jobs imported`)}o.dryRun?(console.log(s.yellow(`
9
+ Dry run \u2014 nothing written`)),console.log(JSON.stringify(i,null,2))):(b(i),console.log(s.green(`
10
+ Migration complete! Review agentx.json and run: agentx daemon start`))),console.log()});var U=new S().name("config").description("validate and inspect configuration");U.command("check").description("validate agentx.json and check all workspaces").option("-c, --config <path>","path to agentx.json").action(async e=>{console.log();try{let o=j(e.config);console.log(s.green(" \u2713 Config valid")),console.log(s.dim(` Node: ${o.node.name} (${o.node.id})`)),console.log(s.dim(` Bind: ${o.node.bind}`)),console.log(s.dim(` Agents: ${Object.keys(o.agents).length}`)),console.log(s.dim(` Crons: ${Object.keys(o.crons).length}`)),console.log(s.dim(` Mesh peers: ${o.mesh.peers.length}`));let n=Object.keys(o.channels.telegram.accounts).length;console.log(s.dim(` Telegram: ${o.channels.telegram.enabled?`${n} accounts`:"disabled"}`)),console.log(s.dim(` WhatsApp: ${o.channels.whatsapp.enabled?`${o.channels.whatsapp.routes.length} routes`:"disabled"}`)),console.log(s.dim(` Discord: ${o.channels.discord?.enabled?"enabled":"disabled"}`));let a=R(o);if(a.length){console.log(),console.log(s.yellow(" Warnings:"));for(let t of a)console.log(s.yellow(` \u26A0 ${t}`))}else console.log(s.green(" \u2713 All workspaces valid"));console.log();for(let[t,i]of Object.entries(o.agents)){let c=i.workspace,d=h(g(c,".claude")),l=h(g(c,"CLAUDE.md")),u=h(g(c,".claude/settings.json")),k=h(g(c,".claude/skills"))?Y(g(c,".claude/skills")).filter(N=>!N.startsWith(".")).length:0,y=[d?s.green("\u2713"):s.red("\u2717"),".claude",l?s.green("\u2713"):s.yellow("\u25CB"),"CLAUDE.md",u?s.green("\u2713"):s.yellow("\u25CB"),"settings",`${k} skills`];console.log(` ${s.cyan(t)}: ${y.join(" ")}`)}}catch(o){console.log(s.red(` \u2717 ${o.message}`))}console.log()});U.command("show").description("print the resolved configuration").option("-c, --config <path>","path to agentx.json").action(e=>{try{let o=j(e.config);console.log(JSON.stringify(o,null,2))}catch(o){console.log(s.red(o.message))}});process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function te(){let e=await z(),o=new ne().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");if(o.addCommand(v).addCommand(X).addCommand(I).addCommand(B).addCommand(P).addCommand(T).addCommand(W).addCommand(J).addCommand(K).addCommand(U),process.argv.slice(2).length===0){o.outputHelp();return}o.parse()}te();
11
11
  //# sourceMappingURL=cli.js.map