agentix-cli 0.8.0 → 0.9.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/README.md +337 -116
- package/dist/agent-QYQVGKLM.js +2 -0
- package/dist/chunk-34UAFPK4.js +10 -0
- package/dist/chunk-34UAFPK4.js.map +1 -0
- package/dist/{chunk-X7UN6JAA.js → chunk-6MKAXEE5.js} +2 -2
- package/dist/chunk-BAIQJHQF.js +64 -0
- package/dist/chunk-BAIQJHQF.js.map +1 -0
- package/dist/chunk-BHDLKX3G.js +6 -0
- package/dist/chunk-BHDLKX3G.js.map +1 -0
- package/dist/chunk-CJ45Y2IR.js +12 -0
- package/dist/chunk-CJ45Y2IR.js.map +1 -0
- package/dist/chunk-DSYKYZMT.js +2 -0
- package/dist/chunk-DSYKYZMT.js.map +1 -0
- package/dist/chunk-IVVVYXPH.js +136 -0
- package/dist/chunk-IVVVYXPH.js.map +1 -0
- package/dist/{chunk-MGMZNJCE.js → chunk-KXZMYLHQ.js} +27 -27
- package/dist/chunk-KXZMYLHQ.js.map +1 -0
- package/dist/chunk-SBUX74OU.js +108 -0
- package/dist/chunk-SBUX74OU.js.map +1 -0
- package/dist/chunk-X32247GM.js +2 -0
- package/dist/chunk-X32247GM.js.map +1 -0
- package/dist/chunk-ZRYBSI5G.js +23 -0
- package/dist/chunk-ZRYBSI5G.js.map +1 -0
- package/dist/cli.js +280 -36
- package/dist/cli.js.map +1 -1
- package/dist/compaction-E3MQRLTL.js +28 -0
- package/dist/compaction-E3MQRLTL.js.map +1 -0
- package/dist/config-MSWKC466.js +2 -0
- package/dist/debug-N3B5NVJU.js +2 -0
- package/dist/heal-OTGT5HHJ.js +2 -0
- package/dist/heal-OTGT5HHJ.js.map +1 -0
- package/dist/index.d.ts +712 -239
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/memory-extract-RGPUPMKU.js +2 -0
- package/dist/memory-extract-RGPUPMKU.js.map +1 -0
- package/dist/{providers-AVYG63KK.js → providers-G3WZ4RVJ.js} +2 -2
- package/dist/providers-G3WZ4RVJ.js.map +1 -0
- package/dist/registry-FP6FUOXF.js +2 -0
- package/dist/registry-FP6FUOXF.js.map +1 -0
- package/dist/subagent-WV7QKQ3L.js +3 -0
- package/dist/subagent-WV7QKQ3L.js.map +1 -0
- package/dist/usage-dashboard-2TJQBFSH.js +404 -0
- package/dist/usage-dashboard-2TJQBFSH.js.map +1 -0
- package/package.json +4 -1
- package/dist/agent-K2YOEOJ5.js +0 -2
- package/dist/chunk-F73GPYCO.js +0 -106
- package/dist/chunk-F73GPYCO.js.map +0 -1
- package/dist/chunk-MGMZNJCE.js.map +0 -1
- package/dist/chunk-NGKOM4ZZ.js +0 -137
- package/dist/chunk-NGKOM4ZZ.js.map +0 -1
- package/dist/chunk-Z4GC5D6D.js +0 -12
- package/dist/chunk-Z4GC5D6D.js.map +0 -1
- package/dist/heal-UV5A6B5T.js +0 -2
- /package/dist/{agent-K2YOEOJ5.js.map → agent-QYQVGKLM.js.map} +0 -0
- /package/dist/{chunk-X7UN6JAA.js.map → chunk-6MKAXEE5.js.map} +0 -0
- /package/dist/{heal-UV5A6B5T.js.map → config-MSWKC466.js.map} +0 -0
- /package/dist/{providers-AVYG63KK.js.map → debug-N3B5NVJU.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,47 +1,291 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
|
|
4
|
-
`)
|
|
5
|
-
|
|
6
|
-
${o.systemPrompt}
|
|
7
|
-
|
|
8
|
-
Agent "${o.id}" added`)),console.log(a.dim(` Workspace: ${n}`)),console.log(a.dim(" Wiki skill installed")),console.log(a.dim(" CLAUDE.md + settings.json created")),console.log()});E.command("remove <id>").alias("rm").description("remove an agent from config (keeps workspace)").action(e=>{let o=b();if(!o.agents?.[e]){console.log(a.red(` Agent "${e}" not found`));return}delete o.agents[e],v(o),console.log(a.green(` Agent "${e}" removed from config (workspace preserved)`))});var F=new I().name("channel").description("manage channels \u2014 add telegram/whatsapp/discord, list");F.command("list").alias("ls").description("list configured channels and bindings").action(()=>{let e=b();console.log();let o=e.channels?.telegram;if(o?.enabled){console.log(a.bold(" Telegram:"));for(let[i,r]of Object.entries(o.accounts||{}))console.log(` ${a.cyan(i)} -> agent: ${r.agentBinding}`)}else console.log(a.dim(" Telegram: disabled"));let n=e.channels?.whatsapp;if(n?.enabled){console.log(a.bold(" WhatsApp:")),console.log(` default agent: ${n.defaultAgent||"(none)"}`),console.log(` session: ${n.sessionDir||".agentx/whatsapp-sessions"}`);for(let i of n.routes||[]){let r=i.contact?`contact ${i.contact}`:`group "${i.group}"`;console.log(` ${r} -> agent: ${i.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"));let t=e.channels?.gitlab;if(t?.enabled){console.log(a.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(a.dim(" GitLab: disabled"));console.log()});F.command("add").description("add a channel (telegram, whatsapp, or discord)").action(async()=>{let e=b(),o=Object.keys(e.agents||{});if(!o.length){console.log(a.red(" No agents configured. Run: agentx agent add"));return}let n=o.map(t=>({title:`${t} (${e.agents[t].name})`,value:t})),{channelType:s}=await x({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(s){if(e.channels=e.channels||{},s==="telegram"){let t=await x([{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 r=await(await fetch(`https://api.telegram.org/bot${t.token}/getMe`)).json();if(!r.ok)throw new Error(r.description);console.log(a.green(` Bot verified: @${r.result.username}`));let l=`@${r.result.username}`,c=e.agents[t.agentBinding].mentions||[];c.includes(l)||(c.push(l,r.result.username),e.agents[t.agentBinding].mentions=c)}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},v(e),console.log(a.green(` Telegram "${t.accountName}" added -> ${t.agentBinding}`))}if(s==="whatsapp"){let t=await x([{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=[],r=t.addRoute;for(;r;){let l=await x([{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:c=>c==="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}]);l.value&&l.agent&&i.push({[l.type]:l.value,agent:l.agent}),r=l.more}e.channels.whatsapp={enabled:!0,sessionDir:t.sessionDir,defaultAgent:t.defaultAgent,routes:i},v(e),N(u(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 x([{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},v(e),console.log(a.green(` Discord added -> ${t.agentBinding}`))}if(s==="gitlab"){let t=await x([{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=[],r=t.addRoute;for(;r;){let l=await x([{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}]);l.project&&l.agent&&i.push({project:l.project,agent:l.agent}),r=l.more}e.channels.gitlab={enabled:!0,host:t.host,token:t.token,webhookPort:t.webhookPort,webhookSecret:t.webhookSecret||void 0,routes:i},v(e),console.log(a.green(` GitLab enabled (${i.length} routes, webhook :${t.webhookPort})`)),console.log(a.dim(` Add webhook in GitLab: ${t.host}/<project>/-/hooks`)),console.log(a.dim(` URL: http://your-server:${t.webhookPort}/`)),t.webhookSecret&&console.log(a.dim(` Secret token: ${t.webhookSecret}`)),console.log(a.dim(" Events: Comments, Issues, Merge requests, Pipeline"))}console.log(a.dim(" Restart daemon to apply: agentx daemon stop && agentx daemon start")),console.log()}});var P=new I().name("cron").description("manage cron jobs \u2014 add, list, enable, disable");P.command("list").alias("ls").description("list cron jobs").action(()=>{let e=b();console.log();for(let[o,n]of Object.entries(e.crons||{})){let s=n.enabled?a.green("\u25CF"):a.dim("\u25CB");console.log(` ${s} ${a.cyan(o)} \u2014 ${n.schedule} (${n.timezone})`),console.log(a.dim(` agent: ${n.agent} | timeout: ${n.timeout}s`))}Object.keys(e.crons||{}).length||console.log(a.dim(" No cron jobs configured")),console.log()});P.command("add").description("add a cron job").action(async()=>{let e=b(),o=Object.keys(e.agents||{}),n=await x([{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(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}]);!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"},v(e),console.log(a.green(` Cron "${n.id}" added (${n.enabled?"enabled":"disabled"})`)),console.log())});P.command("enable <id>").description("enable a cron job").action(e=>{let o=b();if(!o.crons?.[e]){console.log(a.red(` Cron "${e}" not found`));return}o.crons[e].enabled=!0,v(o),console.log(a.green(` Cron "${e}" enabled`))});P.command("disable <id>").description("disable a cron job").action(e=>{let o=b();if(!o.crons?.[e]){console.log(a.red(` Cron "${e}" not found`));return}o.crons[e].enabled=!1,v(o),console.log(a.green(` Cron "${e}" disabled`))});var L=new I().name("mesh").description("manage mesh peers \u2014 add, list, remove");L.command("list").alias("ls").description("list mesh peers").action(async()=>{let e=b();if(console.log(),!e.mesh?.enabled)console.log(a.dim(" Mesh: disabled"));else{console.log(a.bold(" Mesh peers:"));for(let o of e.mesh.peers||[]){let n=a.red("unreachable");try{let t=await(await fetch(`${o.url}/health`,{signal:AbortSignal.timeout(3e3)})).json();n=a.green(`healthy \u2014 ${t.agents?.length||0} agents`)}catch{}console.log(` ${a.cyan(o.name)} ${a.dim(o.url)} ${n}`)}}console.log()});L.command("add").description("add a mesh peer (another agentx server)").action(async()=>{let e=b(),o=await x([{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 s=await(await fetch(`${o.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:o.url,name:o.name,...o.token?{token:o.token}:{}}),v(e),console.log(a.green(` Peer "${o.name}" added`)),console.log()}});L.command("remove <name>").alias("rm").description("remove a mesh peer").action(e=>{let o=b();o.mesh?.peers&&(o.mesh.peers=o.mesh.peers.filter(n=>n.name!==e),o.mesh.peers.length===0&&(o.mesh.enabled=!1),v(o),console.log(a.green(` Peer "${e}" removed`)))});var z=new I().name("skill").description("manage skills \u2014 add to agent(s), list");z.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=b(),s=u(e);if(!k(s)){console.log(a.red(` Skill not found: ${s}`));return}let t=k(W(s,"SKILL.md"))?s.split("/").pop():s.replace(/\/SKILL\.md$/,"").split("/").pop(),i;if(o.all)i=Object.keys(n.agents||{});else if(o.agent)i=o.agent;else{let r=Object.keys(n.agents||{});i=(await x({type:"multiselect",name:"agents",message:"Install to which agents?",choices:r.map(c=>({title:`${c} (${n.agents[c].name})`,value:c}))})).agents||[]}for(let r of i){let l=n.agents[r];if(!l){console.log(a.yellow(` Agent "${r}" not found, skipping`));continue}let c=u(l.workspace,".claude/skills",t);N(c,{recursive:!0}),k(W(s,"SKILL.md"))?Y(s,c,{recursive:!0}):s.endsWith(".md")&&Y(s,W(c,"SKILL.md")),console.log(a.green(` ${t} -> ${r} (${l.workspace})`))}console.log()});z.command("list").alias("ls").description("list skills per agent").action(()=>{let e=b();console.log();for(let[o,n]of Object.entries(e.agents||{})){let s=u(n.workspace,".claude/skills"),t=k(s)?se(s).filter(i=>!i.startsWith(".")):[];console.log(` ${a.cyan(o)}: ${t.length?t.join(", "):a.dim("(none)")}`)}console.log()});var q=new I().name("hook").description("manage hooks \u2014 add to agent workspace");q.command("add <agent>").description("add a hook to an agent's workspace settings").action(async e=>{let n=b().agents?.[e];if(!n){console.log(a.red(` Agent "${e}" not found`));return}let s=u(n.workspace,".claude/settings.json"),t=k(s)?JSON.parse(G(s,"utf-8")):{},i=await x([{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:c=>c==="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 l={hooks:[{type:i.type,...i.type==="command"?{command:i.value}:{url:i.value}}]};i.matcher&&(l.matcher=i.matcher),t.hooks[i.event].push(l),N(u(n.workspace,".claude"),{recursive:!0}),J(s,JSON.stringify(t,null,2)),console.log(a.green(` Hook added to ${e}: ${i.event} -> ${i.type}`)),console.log()});var X=new I().name("migrate").description("import configuration from OpenClaw or other tools");X.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,u(process.env.HOME||"",".openclaw/openclaw.json"),u(process.env.HOME||"",".openclaw/clawdbot.json")].filter(Boolean),s;for(let p of n)if(p&&k(p)){s=p;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(G(s,"utf-8")),i=k(u(process.cwd(),"agentx.json"))?b():{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:[]}},r=t.agents?.list||[],l=t.bindings||[],c={};for(let p of l)p.match?.channel==="telegram"&&(c[p.match.accountId]=p.agentId);r.find(p=>p.id==="main"||p.default)&&(c.default="main");let y=0;for(let p of r){if(p.workspace?.startsWith("/data"))continue;let f=p.id.replace(/-agent$/,"").replace(/^main$/,"atlas"),w=p.groupChat?.mentionPatterns||[];w.some(O=>O===f)||w.push(f),i.agents[f]={name:p.name,workspace:p.workspace,tier:"claude-code",model:"claude-sonnet-4-6",mentions:w,maxConcurrent:p.id==="main"?2:1,systemPrompt:`You are ${p.name} on AgentX.`,permissionMode:"bypassPermissions"},y++,o.dryRun||N(u(p.workspace,".claude/skills"),{recursive:!0})}console.log(` ${a.green(y)} agents imported`);let g=t.channels?.telegram?.accounts||{},h=0;for(let[p,f]of Object.entries(g)){if(!f.botToken)continue;let O=c[p]?.replace(/-agent$/,"").replace(/^main$/,"atlas")||"atlas";i.channels.telegram.accounts[p]={token:f.botToken,agentBinding:O},i.channels.telegram.enabled=!0,h++}console.log(` ${a.green(h)} Telegram accounts imported`);let S=u(s,"../cron/jobs.json");if(k(S)){let p=JSON.parse(G(S,"utf-8")),f=0;for(let w of p.jobs||[]){let O=w.name||w.id,B=w.agentId?.replace(/-agent$/,"").replace(/^main$/,"atlas")||"atlas";i.crons[O]={enabled:w.enabled||!1,schedule:w.schedule?.expr||"0 9 * * *",timezone:w.schedule?.tz||"UTC",agent:B,prompt:w.payload?.message||"",timeout:w.payload?.timeoutSeconds||600,onError:"log"},f++}console.log(` ${a.green(f)} cron jobs imported`)}o.dryRun?(console.log(a.yellow(`
|
|
9
|
-
|
|
10
|
-
Migration complete! Review agentx.json and run: agentx daemon start`))),console.log()});var H=new I().name("config").description("validate and inspect configuration");H.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=C(e.config);console.log(a.green(" \u2713 Config valid")),console.log(a.dim(` Node: ${o.node.name} (${o.node.id})`)),console.log(a.dim(` Bind: ${o.node.bind}`)),console.log(a.dim(` Agents: ${Object.keys(o.agents).length}`)),console.log(a.dim(` Crons: ${Object.keys(o.crons).length}`)),console.log(a.dim(` Mesh peers: ${o.mesh.peers.length}`));let n=Object.keys(o.channels.telegram.accounts).length;console.log(a.dim(` Telegram: ${o.channels.telegram.enabled?`${n} accounts`:"disabled"}`)),console.log(a.dim(` WhatsApp: ${o.channels.whatsapp.enabled?`${o.channels.whatsapp.routes.length} routes`:"disabled"}`)),console.log(a.dim(` Discord: ${o.channels.discord?.enabled?"enabled":"disabled"}`));let s=U(o);if(s.length){console.log(),console.log(a.yellow(" Warnings:"));for(let t of s)console.log(a.yellow(` \u26A0 ${t}`))}else console.log(a.green(" \u2713 All workspaces valid"));console.log();for(let[t,i]of Object.entries(o.agents)){let r=i.workspace,l=k(u(r,".claude")),c=k(u(r,"CLAUDE.md")),y=k(u(r,".claude/settings.json")),g=k(u(r,".claude/skills"))?se(u(r,".claude/skills")).filter(S=>!S.startsWith(".")).length:0,h=[l?a.green("\u2713"):a.red("\u2717"),".claude",c?a.green("\u2713"):a.yellow("\u25CB"),"CLAUDE.md",y?a.green("\u2713"):a.yellow("\u25CB"),"settings",`${g} skills`];console.log(` ${a.cyan(t)}: ${h.join(" ")}`)}}catch(o){console.log(a.red(` \u2717 ${o.message}`))}console.log()});H.command("show").description("print the resolved configuration").option("-c, --config <path>","path to agentx.json").action(e=>{try{let o=C(e.config);console.log(JSON.stringify(o,null,2))}catch(o){console.log(a.red(o.message))}});import{Command as ge}from"commander";import $ from"chalk";var K=new ge().name("usage").description("token usage analysis and reporting");K.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=C(),[o,n]=e.node.bind.split(":"),t=await(await fetch(`http://${o||"127.0.0.1"}:${n}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log($.bold(" Token Usage (last 7 days)")),console.log(),t.totalTasks===0){console.log($.dim(" No tasks recorded yet")),console.log();return}let i=l=>l.toLocaleString();console.log(` Total: ${$.bold(i(t.totalTokens))} tokens across ${t.totalTasks} tasks`),console.log(` Input: ${i(t.totalInput)}`),console.log(` Output: ${i(t.totalOutput)}`),console.log(` Cache read: ${i(t.totalCacheRead)}`),console.log(` Cache create: ${i(t.totalCacheCreate)}`),t.cacheHitRatio>0&&console.log(` Cache hit: ${(t.cacheHitRatio*100).toFixed(1)}%`),t.totalErrors>0&&console.log(` Errors: ${$.red(String(t.totalErrors))}`),console.log(),console.log($.bold(" By Agent:"));let r=Object.entries(t.byAgent||{});r.sort((l,c)=>c[1].total-l[1].total);for(let[l,c]of r){let y=i(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${$.cyan(l)}: ${y} tokens (${c.tasks} tasks) ${$.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log($.red(" Daemon not running. Start with: agentx daemon start")):console.log($.red(` ${e.message}`))}});K.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:n}=await import("fs"),{resolve:s}=await import("path"),t=s(process.cwd(),"scripts/token-report.py");if(!n(t)){console.log($.red(` Script not found: ${t}`)),console.log($.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log($.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${t}"`,{stdio:"inherit"})}catch{console.log($.red(" Analysis failed. Is Python 3 installed?"))}});import{Command as me}from"commander";import m from"chalk";import{resolve as Q}from"path";import{execSync as pe}from"child_process";import{writeFileSync as ue,mkdirSync as he}from"fs";function M(e){let o=e||Q(process.cwd(),".agentx/wiki");return new Z(o)}var D=new me().name("wiki").description("wiki knowledge base management");D.command("status").description("show wiki status: entries, articles, unabsorbed count").option("--dir <path>","wiki directory").action(e=>{let o=M(e.dir),n=o.listEntries(),s=o.getUnabsorbedEntries(),t=o.rebuildIndex();if(console.log(),console.log(m.bold(" Wiki Status")),console.log(),console.log(` Raw entries: ${n.length}`),console.log(` Articles: ${t.articles.length}`),console.log(` Unabsorbed: ${m.yellow(String(s.length))}`),console.log(),s.length>0){console.log(m.dim(" Run 'agentx wiki absorb' to compile entries into articles")),console.log();let i=new Map;for(let r of s)i.set(r.agentId,(i.get(r.agentId)||0)+1);for(let[r,l]of i)console.log(` ${m.cyan(r)}: ${l} unabsorbed entries`);console.log()}});D.command("lint").description("check wiki for issues: broken links, orphans, stubs, unsourced").option("--dir <path>","wiki directory").action(e=>{let n=M(e.dir).lint();if(console.log(),n.length===0)console.log(m.green(" No issues found"));else{console.log(m.bold(` ${n.length} issues found:`)),console.log();for(let s of n){let t=s.type==="broken-link"?"x":s.type==="orphan"?"?":"!";console.log(` [${t}] ${m.dim(s.type)} ${s.article}: ${s.message}`)}}console.log()});D.command("absorb").description("compile unabsorbed raw entries into wiki articles using Claude").option("--dir <path>","wiki directory").option("--dry-run","show what would be absorbed without running").option("--max <n>","max entries to process","20").action(async e=>{let o=M(e.dir),n=o.getUnabsorbedEntries().slice(0,parseInt(e.max));if(n.length===0){console.log(m.green(" All entries are absorbed. Nothing to do."));return}console.log(m.bold(` ${n.length} entries to absorb`)),console.log();let s=new Map;for(let g of n){let h=s.get(g.agentId)||[];h.push(g),s.set(g.agentId,h)}for(let[g,h]of s){console.log(` ${m.cyan(g)}: ${h.length} entries`);for(let S of h.slice(0,3))console.log(m.dim(` [${S.date} via ${S.source}] ${S.content.slice(0,80)}...`));h.length>3&&console.log(m.dim(` ... and ${h.length-3} more`))}if(console.log(),e.dryRun){console.log(m.dim(" Dry run \u2014 no changes made"));return}let t=o.rebuildIndex(),i=t.articles.length>0?`
|
|
2
|
+
import{g as ge,h as $e}from"./chunk-BAIQJHQF.js";import{f as K}from"./chunk-IVVVYXPH.js";import"./chunk-CJ45Y2IR.js";import"./chunk-X32247GM.js";import{b as M,c as ne}from"./chunk-BHDLKX3G.js";import"./chunk-34UAFPK4.js";import"./chunk-M7HKBG3V.js";import"./chunk-DSYKYZMT.js";import"./chunk-ZRYBSI5G.js";import{a as ye}from"./chunk-4YCH6IZV.js";import{Command as Fe}from"commander";import{Command as Ee}from"commander";import m from"chalk";var L=new Ee().name("daemon").description("manage the agentx daemon \u2014 start, stop, status, logs");L.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:d}=await import("child_process"),h=["dist/cli.js","daemon","start"];e.config&&h.push("-c",e.config),e.port&&h.push("--port",e.port);let p=d("node",h,{detached:!0,stdio:["ignore","ignore","ignore"],cwd:process.cwd()});p.unref();let{writeFileSync:g}=await import("fs");g("/tmp/agentx-daemon.pid",String(p.pid)),console.log(m.green(`Daemon started in background (PID: ${p.pid})`)),console.log(m.dim(" Logs: tail -f /tmp/agentx-daemon.log")),console.log(m.dim(" Stop: agentx daemon stop"));return}let{readFileSync:t,writeFileSync:s,mkdirSync:o,existsSync:n}=await import("fs"),{resolve:i}=await import("path"),r=i(process.cwd(),".agentx");n(r)||o(r,{recursive:!0});let c=i(r,"daemon.pid");if(n(c)){let d=parseInt(t(c,"utf-8").trim(),10);if(d&&d!==process.pid)try{process.kill(d,0),console.error(`Another agentx daemon is already running (PID ${d}). Exiting.`),process.exit(0)}catch{}}s(c,String(process.pid)),await new ge(e.config).start()});L.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:t,unlinkSync:s}=await import("fs"),{resolve:o}=await import("path"),n=[o(process.cwd(),".agentx/daemon.pid"),"/tmp/agentx-daemon.pid"];for(let r of n)if(t(r))try{let c=parseInt(e(r,"utf-8").trim(),10);process.kill(c,"SIGTERM"),await new Promise(a=>setTimeout(a,2e3));try{s(r)}catch{}console.log(m.green(`Daemon stopped (PID: ${c})`));return}catch{try{s(r)}catch{}}let{execSync:i}=await import("child_process");try{i("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(m.green("Daemon stopped"))}catch{console.log(m.yellow("No daemon process found"))}});L.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let t=M(e.config),[s,o]=t.node.bind.split(":"),n=`http://${s||"127.0.0.1"}:${o}/health`,r=await(await fetch(n,{signal:AbortSignal.timeout(3e3)})).json();if(e.json){console.log(JSON.stringify(r,null,2));return}console.log(),console.log(m.bold(` ${r.node.name}`)+m.dim(` (${r.node.id})`)),console.log(m.green(" Status: running")+m.dim(` \u2014 uptime ${je(r.uptime)}`)),console.log(),console.log(m.bold(" Agents:"));for(let a of r.agents){let d=a.active>0?m.yellow(` [${a.active} active]`):"",h=a.errors>0?m.red(` (${a.errors} errors)`):"";console.log(` ${m.cyan(a.name)} ${m.dim(`(${a.tier})`)}${d}${h}`),console.log(m.dim(` ${a.workspace}`))}let c=r.crons.filter(a=>a.enabled);if(r.crons.length){console.log(),console.log(m.bold(` Crons: ${c.length} enabled / ${r.crons.length} total`));for(let a of r.crons){let d=a.enabled?m.green("\u25CF"):m.dim("\u25CB"),h=a.nextRun?m.dim(` next: ${new Date(a.nextRun).toLocaleTimeString()}`):"";console.log(` ${d} ${a.id}${h}`)}}if(r.mesh?.length){console.log(),console.log(m.bold(" Mesh:"));for(let a of r.mesh){let d=a.healthy?m.green("\u25CF"):m.red("\u25CF"),h=a.skills?.length?m.dim(` (${a.skills.length} agents)`):"";console.log(` ${d} ${a.peer} ${m.dim(a.peerUrl)}${h}`)}}console.log()}catch(t){if(t.cause?.code==="ECONNREFUSED"||t.name==="TimeoutError")console.log(m.red(" Daemon is not running")),console.log(m.dim(" Start with: agentx daemon start"));else try{let s=M(e.config),o=ne(s);if(console.log(),console.log(m.bold(` ${s.node.name}`)+m.dim(` (${s.node.id})`)),console.log(m.yellow(" Status: stopped")),console.log(m.dim(` ${Object.keys(s.agents).length} agents, ${Object.keys(s.crons).length} crons configured`)),o.length){console.log();for(let n of o)console.log(m.yellow(` \u26A0 ${n}`))}console.log()}catch(s){console.log(m.red(` ${s.message}`))}}});L.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:t,spawn:s}=await import("child_process"),o="/tmp/agentx-daemon.log",{existsSync:n}=await import("fs");if(!n(o)){console.log(m.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let i=s("tail",["-f","-n",e.lines,o],{stdio:"inherit"});process.on("SIGINT",()=>{i.kill(),process.exit(0)})}else t(`tail -n ${e.lines} ${o}`,{stdio:"inherit"})});L.command("watch").description("stream live agent activity (SSE)").option("-c, --config <path>","path to agentx.json").action(async e=>{let o=`http://${(M(e.config).node.bind||"127.0.0.1:18800").replace("0.0.0.0","127.0.0.1")}/events`;console.log(m.dim(` Connecting to ${o}...`)),console.log(m.dim(` Press Ctrl+C to stop
|
|
3
|
+
`));try{let n=await fetch(o);if(!n.ok||!n.body){console.log(m.red(` Failed: ${n.status}`));return}let i=n.body.getReader(),r=new TextDecoder,c="";for(;;){let{done:a,value:d}=await i.read();if(a)break;c+=r.decode(d,{stream:!0});let h=c.split(`
|
|
4
|
+
`);c=h.pop()||"";for(let p of h)if(p.startsWith("data: "))try{let g=JSON.parse(p.slice(6)),y=new Date(g.time).toLocaleTimeString(),f=g.message?.replace(/^\[agentx\]\s*/,"")||"";f.includes("executing")?console.log(`${m.dim(y)} ${m.cyan("\u25B6")} ${f}`):f.includes("completed")?console.log(`${m.dim(y)} ${m.green("\u2713")} ${f}`):f.includes("error")||f.includes("Error")?console.log(`${m.dim(y)} ${m.red("\u2717")} ${f}`):f.includes("Routing")?console.log(`${m.dim(y)} ${m.yellow("\u2192")} ${f}`):f.includes("mention")?console.log(`${m.dim(y)} ${m.magenta("@")} ${f}`):f.includes("Skipping")?console.log(`${m.dim(y)} ${m.dim("\u2298")} ${m.dim(f)}`):console.log(`${m.dim(y)} ${f}`)}catch{}else p.startsWith("event: status")}}catch(n){console.log(m.red(` Connection failed: ${n.message}`)),console.log(m.dim(" Is the daemon running? Try: agentx daemon status"))}});L.command("send <agent> <message...>").description("send a task to an agent via the daemon API").option("-c, --config <path>","path to agentx.json").option("--peer <peer>","send to a mesh peer's agent").option("--json","output raw JSON response").action(async(e,t,s)=>{let o=t.join(" ");try{let n=M(s.config),[i,r]=n.node.bind.split(":"),c=`http://${i||"127.0.0.1"}:${r}`,a,d;s.peer?(a=`${c}/mesh/task`,d={peer:s.peer,message:o,agent:e}):(a=`${c}/task`,d={agent:e,message:o}),console.log(m.dim(` Sending to ${s.peer?`${s.peer}/${e}`:e}...`));let p=await(await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)})).json();s.json?console.log(JSON.stringify(p,null,2)):p.error?console.log(m.red(` Error: ${p.error}`)):(console.log(),console.log(p.content||p.response||"No response"),p.duration&&console.log(m.dim(`
|
|
5
|
+
(${(p.duration/1e3).toFixed(1)}s)`)))}catch(n){console.log(m.red(` Failed: ${n.message}`)),console.log(m.dim(" Is the daemon running? Try: agentx daemon status"))}});L.command("deploy <host>").description("deploy agentx to a remote server via rsync").option("-i, --identity <key>","SSH identity file").option("-u, --user <user>","SSH user","root").option("-p, --path <path>","remote agentx path","~/agentx").option("--restart","restart remote daemon after deploy",!1).option("--skip-checks","skip build and test before deploy",!1).action(async(e,t)=>{let{execSync:s}=await import("child_process"),o=t.identity?`-e "ssh -i ${t.identity}"`:"",n=`${t.user}@${e}:${t.path}/dist/`;if(!t.skipChecks){try{console.log(m.dim(" Running tests...")),s("npx vitest run --reporter=dot",{stdio:"pipe",cwd:process.cwd()}),console.log(m.green(" \u2713 Tests passed"))}catch{console.log(m.red(" \u2717 Tests failed \u2014 aborting deploy")),console.log(m.dim(" Use --skip-checks to deploy anyway"));return}let{existsSync:i,statSync:r}=await import("fs"),{resolve:c}=await import("path"),a=c(process.cwd(),"dist/cli.js");if(!i(a)){console.log(m.red(" \u2717 dist/ not found \u2014 run build first"));return}Date.now()-r(a).mtimeMs>3e5&&(console.log(m.yellow(" \u26A0 dist/ is older than 5 minutes \u2014 rebuilding...")),s("npx tsup --no-dts",{stdio:"pipe",cwd:process.cwd()}),console.log(m.green(" \u2713 Build complete")))}console.log(m.dim(` Deploying to ${t.user}@${e}:${t.path}...`));try{if(s(`rsync -avzL --delete ${o} dist/ ${n}`,{stdio:"inherit",cwd:process.cwd()}),console.log(m.green(" \u2713 Deploy complete")),t.restart){console.log(m.dim(" Restarting remote daemon..."));let i=t.identity?`ssh -i ${t.identity}`:"ssh";s(`${i} ${t.user}@${e} "pkill -f 'node dist/cli.js daemon' 2>/dev/null; sleep 2; cd ${t.path} && nohup node dist/cli.js daemon start > /tmp/agentx-daemon.log 2>&1 &"`,{stdio:"inherit"}),console.log(m.green(" Remote daemon restarted"))}}catch(i){console.log(m.red(` Deploy failed: ${i.message}`))}});L.action(async e=>{await new ge(e.config).start()});function je(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 Re}from"commander";import D from"chalk";import{existsSync as q,readFileSync as Te,writeFileSync as we,mkdirSync as ke}from"fs";import{resolve as J}from"path";var ve=new Re().name("init").description("initialize agentx configuration in the current directory").option("--force","overwrite existing config").action(async e=>{let t=process.cwd(),s=J(t,"agentx.json"),o=J(t,".env"),n=J(t,".agentx/sessions");if(console.log(),console.log(D.bold(" agentx init")),console.log(),q(s)&&!e.force){console.log(D.yellow(" agentx.json already exists. Use --force to overwrite.")),console.log();return}let i=[J(t,"agentx.example.json"),J(t,"node_modules/agentix-cli/agentx.example.json")],r;for(let a of i)if(q(a)){r=Te(a,"utf-8");break}r||(r=JSON.stringify({node:{id:ye("os").hostname().toLowerCase().replace(/[^a-z0-9-]/g,"-"),name:ye("os").hostname(),bind:"127.0.0.1:18800"},providers:{claude:{apiKey:"${ANTHROPIC_API_KEY}"}},agents:{assistant:{name:"Assistant",workspace:t,tier:"claude-code",model:"claude-sonnet-4-6",mentions:["@assistant","assistant"],maxConcurrent:2,systemPrompt:"You are a helpful assistant.",permissionMode:"default"}},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}}},null,2)),we(s,r),console.log(D.green(" \u2713 Created agentx.json")),q(o)||(we(o,["# AgentX environment variables","# ANTHROPIC_API_KEY=sk-ant-...","# TG_BOT_TOKEN=123456:ABC...","# MESH_TOKEN=your-mesh-secret",""].join(`
|
|
6
|
+
`)),console.log(D.green(" \u2713 Created .env template"))),q(n)||(ke(n,{recursive:!0}),console.log(D.green(" \u2713 Created .agentx/sessions/")));let c=J(t,".claude");q(c)||(ke(c,{recursive:!0}),console.log(D.green(" \u2713 Created .claude/"))),console.log(),console.log(D.bold(" Next steps:")),console.log(` 1. Edit ${D.cyan("agentx.json")} \u2014 configure agents, channels, crons`),console.log(` 2. Edit ${D.cyan(".env")} \u2014 add API keys and bot tokens`),console.log(` 3. Run ${D.cyan("agentx daemon start")} \u2014 start the daemon`),console.log(` 4. Run ${D.cyan("agentx daemon status")} \u2014 verify everything`),console.log()});import{Command as B}from"commander";import l from"chalk";import O from"prompts";import{readFileSync as se,writeFileSync as ae,existsSync as R,mkdirSync as _,cpSync as pe,readdirSync as xe}from"fs";import{resolve as I,join as oe}from"path";function j(){let e=I(process.cwd(),"agentx.json");if(!R(e))throw new Error("No agentx.json found. Run: agentx init");return JSON.parse(se(e,"utf-8"))}function N(e){ae(I(process.cwd(),"agentx.json"),JSON.stringify(e,null,2))}var X=new B().name("agent").description("manage agents \u2014 add, list, remove");X.command("list").alias("ls").description("list configured agents").action(()=>{let e=j();console.log();for(let[t,s]of Object.entries(e.agents||{})){let o=s.mentions?.join(", ")||"";console.log(` ${l.cyan(t)} \u2014 ${s.name} (${s.tier})`),console.log(l.dim(` workspace: ${s.workspace}`)),o&&console.log(l.dim(` mentions: ${o}`))}console.log()});X.command("add").description("add a new agent interactively").action(async()=>{let e=j(),t=await O([{type:"text",name:"id",message:"Agent ID (kebab-case)",validate:c=>/^[a-z0-9-]+$/.test(c)||"Use lowercase, numbers, hyphens"},{type:"text",name:"name",message:"Display name"},{type:"text",name:"workspace",message:"Workspace path",initial:I(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(!t.id)return;let s=t.workspace.endsWith(t.id)?t.workspace:oe(t.workspace,t.id);_(I(s,".claude/skills"),{recursive:!0});let o=`# ${t.name}
|
|
7
|
+
|
|
8
|
+
${t.systemPrompt}
|
|
9
|
+
`;ae(I(s,"CLAUDE.md"),o),ae(I(s,".claude/settings.json"),JSON.stringify({permissions:{allow:["Bash(git *)","Bash(curl *)","Bash(node *)","Read","Write","Edit","Glob","Grep","WebFetch","WebSearch"]}},null,2));let n=I(process.cwd(),"src/wiki/SKILL.md"),i=I(__dirname,"../wiki/SKILL.md"),r=R(n)?n:i;R(r)&&(_(I(s,".claude/skills/wiki"),{recursive:!0}),pe(r,I(s,".claude/skills/wiki/SKILL.md"))),e.agents=e.agents||{},e.agents[t.id]={name:t.name,workspace:s,tier:t.tier,model:t.model,mentions:t.mentions?.map(c=>c.trim()).filter(Boolean)||[],maxConcurrent:t.maxConcurrent,systemPrompt:t.systemPrompt,permissionMode:"default"},N(e),console.log(l.green(`
|
|
10
|
+
Agent "${t.id}" added`)),console.log(l.dim(` Workspace: ${s}`)),console.log(l.dim(" Wiki skill installed")),console.log(l.dim(" CLAUDE.md + settings.json created")),console.log()});X.command("remove <id>").alias("rm").description("remove an agent from config (keeps workspace)").action(e=>{let t=j();if(!t.agents?.[e]){console.log(l.red(` Agent "${e}" not found`));return}delete t.agents[e],N(t),console.log(l.green(` Agent "${e}" removed from config (workspace preserved)`))});var ie=new B().name("channel").description("manage channels \u2014 add telegram/whatsapp/discord, list");ie.command("list").alias("ls").description("list configured channels and bindings").action(()=>{let e=j();console.log();let t=e.channels?.telegram;if(t?.enabled){console.log(l.bold(" Telegram:"));for(let[i,r]of Object.entries(t.accounts||{}))console.log(` ${l.cyan(i)} -> agent: ${r.agentBinding}`)}else console.log(l.dim(" Telegram: disabled"));let s=e.channels?.whatsapp;if(s?.enabled){console.log(l.bold(" WhatsApp:")),console.log(` default agent: ${s.defaultAgent||"(none)"}`),console.log(` session: ${s.sessionDir||".agentx/whatsapp-sessions"}`);for(let i of s.routes||[]){let r=i.contact?`contact ${i.contact}`:`group "${i.group}"`;console.log(` ${r} -> agent: ${i.agent}`)}}else console.log(l.dim(" WhatsApp: disabled"));let o=e.channels?.discord;o?.enabled?(console.log(l.bold(" Discord:")),console.log(` agent: ${o.agentBinding||"(none)"}`)):console.log(l.dim(" Discord: disabled"));let n=e.channels?.gitlab;if(n?.enabled){console.log(l.bold(" GitLab:")),console.log(` host: ${n.host}`),console.log(` webhook: :${n.webhookPort}`);for(let i of n.routes||[])console.log(` ${i.project} -> agent: ${i.agent}`)}else console.log(l.dim(" GitLab: disabled"));console.log()});ie.command("add").description("add a channel (telegram, whatsapp, or discord)").action(async()=>{let e=j(),t=Object.keys(e.agents||{});if(!t.length){console.log(l.red(" No agents configured. Run: agentx agent add"));return}let s=t.map(n=>({title:`${n} (${e.agents[n].name})`,value:n})),{channelType:o}=await O({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(o){if(e.channels=e.channels||{},o==="telegram"){let n=await O([{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:s}]);if(!n.accountName||!n.token)return;try{let r=await(await fetch(`https://api.telegram.org/bot${n.token}/getMe`)).json();if(!r.ok)throw new Error(r.description);console.log(l.green(` Bot verified: @${r.result.username}`));let c=`@${r.result.username}`,a=e.agents[n.agentBinding].mentions||[];a.includes(c)||(a.push(c,r.result.username),e.agents[n.agentBinding].mentions=a)}catch(i){console.log(l.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[n.accountName]={token:n.token,agentBinding:n.agentBinding},N(e),console.log(l.green(` Telegram "${n.accountName}" added -> ${n.agentBinding}`))}if(o==="whatsapp"){let n=await O([{type:"select",name:"defaultAgent",message:"Default agent for WhatsApp messages",choices:s},{type:"text",name:"sessionDir",message:"Session directory",initial:".agentx/whatsapp-sessions"},{type:"confirm",name:"addRoute",message:"Add a contact/group route?",initial:!0}]);if(!n.defaultAgent)return;let i=[],r=n.addRoute;for(;r;){let c=await O([{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:a=>a==="contact"?"Phone number (e.g. +21624309128)":"Group name (partial match)"},{type:"select",name:"agent",message:"Route to agent",choices:s},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);c.value&&c.agent&&i.push({[c.type]:c.value,agent:c.agent}),r=c.more}e.channels.whatsapp={enabled:!0,sessionDir:n.sessionDir,defaultAgent:n.defaultAgent,routes:i},N(e),_(I(process.cwd(),n.sessionDir),{recursive:!0}),console.log(l.green(` WhatsApp enabled (${i.length} routes, default: ${n.defaultAgent})`)),console.log(l.dim(" Start daemon to scan QR code: agentx daemon start"))}if(o==="discord"){let n=await O([{type:"text",name:"token",message:"Discord bot token (from developer portal)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:s}]);if(!n.token)return;e.channels.discord={enabled:!0,token:n.token,agentBinding:n.agentBinding},N(e),console.log(l.green(` Discord added -> ${n.agentBinding}`))}if(o==="gitlab"){let n=await O([{type:"text",name:"host",message:"GitLab instance URL",initial:"https://gitlab.example.com"},{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(!n.token)return;let i=[],r=n.addRoute;for(;r;){let c=await O([{type:"text",name:"project",message:"GitLab project path (e.g. group/project, or * for default)"},{type:"select",name:"agent",message:"Route to agent",choices:s},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);c.project&&c.agent&&i.push({project:c.project,agent:c.agent}),r=c.more}e.channels.gitlab={enabled:!0,host:n.host,token:n.token,webhookPort:n.webhookPort,webhookSecret:n.webhookSecret||void 0,routes:i},N(e),console.log(l.green(` GitLab enabled (${i.length} routes, webhook :${n.webhookPort})`)),console.log(l.dim(` Add webhook in GitLab: ${n.host}/<project>/-/hooks`)),console.log(l.dim(` URL: http://your-server:${n.webhookPort}/`)),n.webhookSecret&&console.log(l.dim(` Secret token: ${n.webhookSecret}`)),console.log(l.dim(" Events: Comments, Issues, Merge requests, Pipeline"))}console.log(l.dim(" Restart daemon to apply: agentx daemon stop && agentx daemon start")),console.log()}});var Y=new B().name("cron").description("manage cron jobs \u2014 add, list, enable, disable");Y.command("list").alias("ls").description("list cron jobs").action(()=>{let e=j();console.log();for(let[t,s]of Object.entries(e.crons||{})){let o=s.enabled?l.green("\u25CF"):l.dim("\u25CB");console.log(` ${o} ${l.cyan(t)} \u2014 ${s.schedule} (${s.timezone})`),console.log(l.dim(` agent: ${s.agent} | timeout: ${s.timeout}s`))}Object.keys(e.crons||{}).length||console.log(l.dim(" No cron jobs configured")),console.log()});Y.command("add").description("add a cron job").action(async()=>{let e=j(),t=Object.keys(e.agents||{}),s=await O([{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:t.map(o=>({title:o,value:o}))},{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}]);!s.id||!s.schedule||(e.crons=e.crons||{},e.crons[s.id]={enabled:s.enabled,schedule:s.schedule,timezone:s.timezone,agent:s.agent,prompt:s.prompt,timeout:s.timeout,onError:"log"},N(e),console.log(l.green(` Cron "${s.id}" added (${s.enabled?"enabled":"disabled"})`)),console.log())});Y.command("enable <id>").description("enable a cron job").action(e=>{let t=j();if(!t.crons?.[e]){console.log(l.red(` Cron "${e}" not found`));return}t.crons[e].enabled=!0,N(t),console.log(l.green(` Cron "${e}" enabled`))});Y.command("disable <id>").description("disable a cron job").action(e=>{let t=j();if(!t.crons?.[e]){console.log(l.red(` Cron "${e}" not found`));return}t.crons[e].enabled=!1,N(t),console.log(l.green(` Cron "${e}" disabled`))});var V=new B().name("mesh").description("manage mesh peers \u2014 add, list, remove");V.command("list").alias("ls").description("list mesh peers").action(async()=>{let e=j();if(console.log(),!e.mesh?.enabled)console.log(l.dim(" Mesh: disabled"));else{console.log(l.bold(" Mesh peers:"));for(let t of e.mesh.peers||[]){let s=l.red("unreachable");try{let n=await(await fetch(`${t.url}/health`,{signal:AbortSignal.timeout(3e3)})).json();s=l.green(`healthy \u2014 ${n.agents?.length||0} agents`)}catch{}console.log(` ${l.cyan(t.name)} ${l.dim(t.url)} ${s}`)}}console.log()});V.command("add").description("add a mesh peer (another agentx server)").action(async()=>{let e=j(),t=await O([{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(!(!t.name||!t.url)){try{let o=await(await fetch(`${t.url}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)})).json();console.log(l.green(` Connected: ${o.name} (${o.skills?.length||0} agents)`))}catch{console.log(l.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:t.url,name:t.name,...t.token?{token:t.token}:{}}),N(e),console.log(l.green(` Peer "${t.name}" added`)),console.log()}});V.command("remove <name>").alias("rm").description("remove a mesh peer").action(e=>{let t=j();t.mesh?.peers&&(t.mesh.peers=t.mesh.peers.filter(s=>s.name!==e),t.mesh.peers.length===0&&(t.mesh.enabled=!1),N(t),console.log(l.green(` Peer "${e}" removed`)))});var re=new B().name("skill").description("manage skills \u2014 add to agent(s), list");re.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,t)=>{let s=j(),o=I(e);if(!R(o)){console.log(l.red(` Skill not found: ${o}`));return}let n=R(oe(o,"SKILL.md"))?o.split("/").pop():o.replace(/\/SKILL\.md$/,"").split("/").pop(),i;if(t.all)i=Object.keys(s.agents||{});else if(t.agent)i=t.agent;else{let r=Object.keys(s.agents||{});i=(await O({type:"multiselect",name:"agents",message:"Install to which agents?",choices:r.map(a=>({title:`${a} (${s.agents[a].name})`,value:a}))})).agents||[]}for(let r of i){let c=s.agents[r];if(!c){console.log(l.yellow(` Agent "${r}" not found, skipping`));continue}let a=I(c.workspace,".claude/skills",n);_(a,{recursive:!0}),R(oe(o,"SKILL.md"))?pe(o,a,{recursive:!0}):o.endsWith(".md")&&pe(o,oe(a,"SKILL.md")),console.log(l.green(` ${n} -> ${r} (${c.workspace})`))}console.log()});re.command("list").alias("ls").description("list skills per agent").action(()=>{let e=j();console.log();for(let[t,s]of Object.entries(e.agents||{})){let o=I(s.workspace,".claude/skills"),n=R(o)?xe(o).filter(i=>!i.startsWith(".")):[];console.log(` ${l.cyan(t)}: ${n.length?n.join(", "):l.dim("(none)")}`)}console.log()});var me=new B().name("hook").description("manage hooks \u2014 add to agent workspace");me.command("add <agent>").description("add a hook to an agent's workspace settings").action(async e=>{let s=j().agents?.[e];if(!s){console.log(l.red(` Agent "${e}" not found`));return}let o=I(s.workspace,".claude/settings.json"),n=R(o)?JSON.parse(se(o,"utf-8")):{},i=await O([{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:a=>a==="command"?"Shell command":"URL"},{type:"text",name:"matcher",message:"Matcher regex (optional, e.g. 'Bash' to match tool)"}]);if(!i.event||!i.value)return;n.hooks=n.hooks||{},n.hooks[i.event]=n.hooks[i.event]||[];let c={hooks:[{type:i.type,...i.type==="command"?{command:i.value}:{url:i.value}}]};i.matcher&&(c.matcher=i.matcher),n.hooks[i.event].push(c),_(I(s.workspace,".claude"),{recursive:!0}),ae(o,JSON.stringify(n,null,2)),console.log(l.green(` Hook added to ${e}: ${i.event} -> ${i.type}`)),console.log()});var he=new B().name("migrate").description("import configuration from OpenClaw or other tools");he.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,t)=>{let s=[e,I(process.env.HOME||"",".openclaw/openclaw.json"),I(process.env.HOME||"",".openclaw/clawdbot.json")].filter(Boolean),o;for(let y of s)if(y&&R(y)){o=y;break}if(!o){console.log(l.red(" OpenClaw config not found. Pass the path: agentx migrate openclaw /path/to/config.json"));return}console.log(l.dim(` Reading: ${o}`));let n=JSON.parse(se(o,"utf-8")),i=R(I(process.cwd(),"agentx.json"))?j():{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:[]}},r=n.agents?.list||[],c=n.bindings||[],a={};for(let y of c)y.match?.channel==="telegram"&&(a[y.match.accountId]=y.agentId);r.find(y=>y.id==="main"||y.default)&&(a.default="main");let d=0;for(let y of r){if(y.workspace?.startsWith("/data"))continue;let f=y.id.replace(/-agent$/,"").replace(/^main$/,"main-agent"),b=y.groupChat?.mentionPatterns||[];b.some(w=>w===f)||b.push(f),i.agents[f]={name:y.name,workspace:y.workspace,tier:"claude-code",model:"claude-sonnet-4-6",mentions:b,maxConcurrent:y.id==="main"?2:1,systemPrompt:`You are ${y.name} on AgentX.`,permissionMode:"bypassPermissions"},d++,t.dryRun||_(I(y.workspace,".claude/skills"),{recursive:!0})}console.log(` ${l.green(d)} agents imported`);let h=n.channels?.telegram?.accounts||{},p=0;for(let[y,f]of Object.entries(h)){if(!f.botToken)continue;let w=a[y]?.replace(/-agent$/,"").replace(/^main$/,"main-agent")||"default";i.channels.telegram.accounts[y]={token:f.botToken,agentBinding:w},i.channels.telegram.enabled=!0,p++}console.log(` ${l.green(p)} Telegram accounts imported`);let g=I(o,"../cron/jobs.json");if(R(g)){let y=JSON.parse(se(g,"utf-8")),f=0;for(let b of y.jobs||[]){let w=b.name||b.id,k=b.agentId?.replace(/-agent$/,"").replace(/^main$/,"main-agent")||"default";i.crons[w]={enabled:b.enabled||!1,schedule:b.schedule?.expr||"0 9 * * *",timezone:b.schedule?.tz||"UTC",agent:k,prompt:b.payload?.message||"",timeout:b.payload?.timeoutSeconds||600,onError:"log"},f++}console.log(` ${l.green(f)} cron jobs imported`)}t.dryRun?(console.log(l.yellow(`
|
|
11
|
+
Dry run \u2014 nothing written`)),console.log(JSON.stringify(i,null,2))):(N(i),console.log(l.green(`
|
|
12
|
+
Migration complete! Review agentx.json and run: agentx daemon start`))),console.log()});var ce=new B().name("config").description("validate and inspect configuration");ce.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 t=M(e.config);console.log(l.green(" \u2713 Config valid")),console.log(l.dim(` Node: ${t.node.name} (${t.node.id})`)),console.log(l.dim(` Bind: ${t.node.bind}`)),console.log(l.dim(` Agents: ${Object.keys(t.agents).length}`)),console.log(l.dim(` Crons: ${Object.keys(t.crons).length}`)),console.log(l.dim(` Mesh peers: ${t.mesh.peers.length}`));let s=Object.keys(t.channels.telegram.accounts).length;console.log(l.dim(` Telegram: ${t.channels.telegram.enabled?`${s} accounts`:"disabled"}`)),console.log(l.dim(` WhatsApp: ${t.channels.whatsapp.enabled?`${t.channels.whatsapp.routes.length} routes`:"disabled"}`)),console.log(l.dim(` Discord: ${t.channels.discord?.enabled?"enabled":"disabled"}`));let o=ne(t);if(o.length){console.log(),console.log(l.yellow(" Warnings:"));for(let n of o)console.log(l.yellow(` \u26A0 ${n}`))}else console.log(l.green(" \u2713 All workspaces valid"));console.log();for(let[n,i]of Object.entries(t.agents)){let r=i.workspace,c=R(I(r,".claude")),a=R(I(r,"CLAUDE.md")),d=R(I(r,".claude/settings.json")),h=R(I(r,".claude/skills"))?xe(I(r,".claude/skills")).filter(g=>!g.startsWith(".")).length:0,p=[c?l.green("\u2713"):l.red("\u2717"),".claude",a?l.green("\u2713"):l.yellow("\u25CB"),"CLAUDE.md",d?l.green("\u2713"):l.yellow("\u25CB"),"settings",`${h} skills`];console.log(` ${l.cyan(n)}: ${p.join(" ")}`)}}catch(t){console.log(l.red(` \u2717 ${t.message}`))}console.log()});ce.command("show").description("print the resolved configuration").option("-c, --config <path>","path to agentx.json").action(e=>{try{let t=M(e.config);console.log(JSON.stringify(t,null,2))}catch(t){console.log(l.red(t.message))}});import{Command as We}from"commander";import U from"chalk";var Q=new We().name("usage").description("token usage analysis and reporting");Q.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=M(),[t,s]=e.node.bind.split(":"),n=await(await fetch(`http://${t||"127.0.0.1"}:${s}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(U.bold(" Token Usage (last 7 days)")),console.log(),n.totalTasks===0){console.log(U.dim(" No tasks recorded yet")),console.log();return}let i=c=>c.toLocaleString();console.log(` Total: ${U.bold(i(n.totalTokens))} tokens across ${n.totalTasks} tasks`),console.log(` Input: ${i(n.totalInput)}`),console.log(` Output: ${i(n.totalOutput)}`),console.log(` Cache read: ${i(n.totalCacheRead)}`),console.log(` Cache create: ${i(n.totalCacheCreate)}`),n.cacheHitRatio>0&&console.log(` Cache hit: ${(n.cacheHitRatio*100).toFixed(1)}%`),n.totalErrors>0&&console.log(` Errors: ${U.red(String(n.totalErrors))}`),console.log(),console.log(U.bold(" By Agent:"));let r=Object.entries(n.byAgent||{});r.sort((c,a)=>a[1].total-c[1].total);for(let[c,a]of r){let d=i(a.total||a.input+a.output+a.cacheRead+a.cacheCreate),h=a.avgDuration?`${(a.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${U.cyan(c)}: ${d} tokens (${a.tasks} tasks) ${U.dim(h)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(U.red(" Daemon not running. Start with: agentx daemon start")):console.log(U.red(` ${e.message}`))}});Q.command("serve").description("start a web dashboard for token usage visualization").option("--port <n>","port number","4201").action(async e=>{let{startUsageDashboard:t}=await import("./usage-dashboard-2TJQBFSH.js");t(parseInt(e.port))});Q.command("report").description("run full session analysis (parses Claude Code JSONL files)").option("--days <n>","analyze last N days","7").action(async e=>{let{execSync:t}=await import("child_process"),{existsSync:s}=await import("fs"),{resolve:o}=await import("path"),n=o(process.cwd(),"scripts/token-report.py");if(!s(n)){console.log(U.red(` Script not found: ${n}`)),console.log(U.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(U.dim(" Analyzing Claude Code sessions..."));try{t(`SINCE_DAYS=${e.days} python3 "${n}"`,{stdio:"inherit"})}catch{console.log(U.red(" Analysis failed. Is Python 3 installed?"))}});import{Command as Ge}from"commander";import u from"chalk";import{createServer as Pe}from"http";var le=class{peers;cache=new Map;ttl=3e4;constructor(t){this.peers=t.map(s=>({url:s.replace(/\/$/,"")}))}async getRemoteAgents(){let t=[];return await Promise.all(this.peers.map(async s=>{try{let o=await this.fetchJson(`${s.url}/wiki/agents`);s.nodeId=o.nodeId;for(let n of o.agents||[])(n.totalEntries>0||n.totalArticles>0)&&t.push({...n,nodeId:o.nodeId,peerUrl:s.url})}catch{}})),t}async getRemoteArticles(t,s){try{return(await this.fetchJson(`${t}/wiki/articles?agent=${encodeURIComponent(s)}`)).articles||[]}catch{return[]}}async getRemoteArticle(t,s,o){try{let n=await this.fetchJson(`${t}/wiki/article?agent=${encodeURIComponent(s)}&path=${encodeURIComponent(o)}`);return{meta:{title:n.title,tags:n.tags||[],owner:n.owner,access:"public",created:n.created,lastUpdated:n.lastUpdated,sources:n.sources||[]},content:n.content,path:n.path}}catch{return null}}async fetchJson(t){let s=this.cache.get(t);if(s&&Date.now()-s.ts<this.ttl)return s.data;let o=await fetch(t,{signal:AbortSignal.timeout(5e3)});if(!o.ok)throw new Error(`HTTP ${o.status}`);let n=await o.json();return this.cache.set(t,{data:n,ts:Date.now()}),n}};function $(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function de(e,t,s=""){let o=$(e);return o=o.replace(/```(\w*)\n([\s\S]*?)```/g,(n,i,r)=>`<pre><code class="lang-${i}">${r.trim()}</code></pre>`),o=o.replace(/`([^`]+)`/g,"<code>$1</code>"),o=o.replace(/^(\|.+\|)\n(\|[-| :]+\|)\n((?:\|.+\|\n?)*)/gm,(n,i,r,c)=>{let a=i.split("|").filter(h=>h.trim()).map(h=>`<th>${h.trim()}</th>`).join(""),d=c.trim().split(`
|
|
13
|
+
`).map(h=>`<tr>${h.split("|").filter(g=>g.trim()).map(g=>`<td>${g.trim()}</td>`).join("")}</tr>`).join("");return`<table><thead><tr>${a}</tr></thead><tbody>${d}</tbody></table>`}),o=o.replace(/^#### (.+)$/gm,"<h4>$1</h4>"),o=o.replace(/^### (.+)$/gm,"<h3>$1</h3>"),o=o.replace(/^## (.+)$/gm,"<h2>$1</h2>"),o=o.replace(/^# (.+)$/gm,"<h1>$1</h1>"),o=o.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"),o=o.replace(/\*(.+?)\*/g,"<em>$1</em>"),o=o.replace(/\[\[([^\]]+)\]\]/g,(n,i)=>{let r=t.get(i);return r?`<a href="${s}/article/${encodeURIComponent(r)}" class="wikilink">${i}</a>`:`<a href="${s}/search?q=${encodeURIComponent(i)}" class="wikilink broken">${i}</a>`}),o=o.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank">$1</a>'),o=o.replace(/^- (.+)$/gm,"<li>$1</li>"),o=o.replace(/(<li>.*<\/li>\n?)+/g,"<ul>$&</ul>"),o=o.replace(/^---$/gm,"<hr>"),o=o.replace(/\n\n+/g,"</p><p>"),o=`<p>${o}</p>`,o=o.replace(/<p>(<(?:h[1-4]|pre|table|ul|hr|div))/g,"$1"),o=o.replace(/(<\/(?:h[1-4]|pre|table|ul|hr|div)>)<\/p>/g,"$1"),o=o.replace(/<p>\s*<\/p>/g,""),o}var Ue=`
|
|
14
|
+
:root {
|
|
15
|
+
--bg: #f8f9fa; --card: #ffffff; --border: #a2a9b1;
|
|
16
|
+
--link: #0645ad; --link-visited: #0b0080; --link-broken: #ba0000;
|
|
17
|
+
--heading-border: #a2a9b1; --text: #202122; --text-dim: #54595d;
|
|
18
|
+
--accent: #eaecf0; --tag: #eaf3ff;
|
|
19
|
+
}
|
|
20
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
21
|
+
body { font-family: -apple-system, 'Segoe UI', Roboto, sans-serif; color: var(--text); background: var(--bg); line-height: 1.6; }
|
|
22
|
+
.layout { display: grid; grid-template-columns: 260px 1fr; min-height: 100vh; }
|
|
23
|
+
.sidebar { background: var(--card); border-right: 1px solid var(--border); padding: 20px 16px; position: sticky; top: 0; height: 100vh; overflow-y: auto; }
|
|
24
|
+
.sidebar h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); margin: 20px 0 6px; padding-bottom: 4px; border-bottom: 1px solid var(--accent); }
|
|
25
|
+
.sidebar h2:first-child { margin-top: 0; }
|
|
26
|
+
.sidebar a { display: block; padding: 3px 8px; color: var(--link); text-decoration: none; font-size: 14px; border-radius: 3px; }
|
|
27
|
+
.sidebar a:hover { background: var(--accent); }
|
|
28
|
+
.sidebar a.active { background: var(--tag); font-weight: 600; }
|
|
29
|
+
.sidebar .logo { font-size: 20px; font-weight: 700; color: var(--text); text-decoration: none; display: block; margin-bottom: 12px; padding: 4px 8px; }
|
|
30
|
+
.sidebar .search-box { width: 100%; padding: 6px 10px; border: 1px solid var(--border); border-radius: 4px; font-size: 14px; margin-bottom: 12px; }
|
|
31
|
+
.sidebar .agent-badge { display: inline-block; background: #dcedc8; color: #33691e; border-radius: 3px; padding: 1px 6px; font-size: 11px; font-weight: 600; margin-left: 4px; }
|
|
32
|
+
.main { padding: 32px 48px; max-width: 960px; }
|
|
33
|
+
.main h1 { font-size: 28px; font-weight: 400; border-bottom: 1px solid var(--heading-border); padding-bottom: 8px; margin-bottom: 16px; }
|
|
34
|
+
.main h2 { font-size: 22px; font-weight: 400; border-bottom: 1px solid var(--accent); padding-bottom: 4px; margin: 24px 0 12px; }
|
|
35
|
+
.main h3 { font-size: 18px; margin: 20px 0 8px; }
|
|
36
|
+
.main h4 { font-size: 16px; margin: 16px 0 8px; }
|
|
37
|
+
.main p { margin: 8px 0; }
|
|
38
|
+
.main ul { margin: 8px 0 8px 24px; }
|
|
39
|
+
.main li { margin: 2px 0; }
|
|
40
|
+
.main a { color: var(--link); }
|
|
41
|
+
.main a:visited { color: var(--link-visited); }
|
|
42
|
+
.main a.wikilink.broken { color: var(--link-broken); }
|
|
43
|
+
.meta { background: var(--accent); border: 1px solid var(--border); border-radius: 4px; padding: 12px 16px; margin-bottom: 20px; font-size: 13px; display: grid; grid-template-columns: auto 1fr; gap: 4px 16px; }
|
|
44
|
+
.meta dt { font-weight: 600; color: var(--text-dim); }
|
|
45
|
+
.tag { display: inline-block; background: var(--tag); border-radius: 3px; padding: 1px 8px; font-size: 12px; margin: 1px 2px; }
|
|
46
|
+
table { border-collapse: collapse; margin: 12px 0; width: 100%; }
|
|
47
|
+
th, td { border: 1px solid var(--border); padding: 6px 12px; text-align: left; font-size: 14px; }
|
|
48
|
+
th { background: var(--accent); font-weight: 600; }
|
|
49
|
+
tr:hover td { background: #f0f4ff; }
|
|
50
|
+
pre { background: #f5f5f5; border: 1px solid var(--border); border-radius: 4px; padding: 12px; overflow-x: auto; font-size: 13px; margin: 12px 0; }
|
|
51
|
+
code { font-family: 'SF Mono', Menlo, monospace; font-size: 13px; }
|
|
52
|
+
p code { background: #f5f5f5; padding: 1px 4px; border-radius: 2px; }
|
|
53
|
+
.entry-card { background: var(--card); border: 1px solid var(--border); border-radius: 4px; padding: 12px 16px; margin: 8px 0; }
|
|
54
|
+
.entry-card .meta-line { font-size: 12px; color: var(--text-dim); margin-bottom: 4px; }
|
|
55
|
+
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 16px 0; }
|
|
56
|
+
.stat-card { background: var(--card); border: 1px solid var(--border); border-radius: 6px; padding: 16px; text-align: center; }
|
|
57
|
+
.stat-card .number { font-size: 32px; font-weight: 700; color: var(--link); }
|
|
58
|
+
.stat-card .label { font-size: 13px; color: var(--text-dim); margin-top: 4px; }
|
|
59
|
+
.agent-card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 20px; margin: 12px 0; transition: box-shadow 0.15s; }
|
|
60
|
+
.agent-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
|
|
61
|
+
.agent-card h3 { margin: 0 0 8px; }
|
|
62
|
+
.agent-card h3 a { text-decoration: none; font-size: 20px; }
|
|
63
|
+
.agent-card .agent-stats { display: flex; gap: 16px; font-size: 14px; color: var(--text-dim); }
|
|
64
|
+
.agent-card .agent-stats strong { color: var(--text); }
|
|
65
|
+
.agent-card .article-list { margin-top: 8px; font-size: 13px; }
|
|
66
|
+
.agent-card .article-list a { margin-right: 8px; }
|
|
67
|
+
.backlinks { background: #fffbe6; border: 1px solid #e6d98c; border-radius: 4px; padding: 12px 16px; margin-top: 24px; font-size: 13px; }
|
|
68
|
+
.backlinks h4 { margin-bottom: 4px; }
|
|
69
|
+
.breadcrumb { font-size: 13px; color: var(--text-dim); margin-bottom: 12px; }
|
|
70
|
+
.breadcrumb a { color: var(--link); text-decoration: none; }
|
|
71
|
+
@media (max-width: 768px) { .layout { grid-template-columns: 1fr; } .sidebar { position: static; height: auto; } .main { padding: 20px; } }
|
|
72
|
+
`;function W(e,t,s){return`<!DOCTYPE html>
|
|
73
|
+
<html lang="en">
|
|
74
|
+
<head>
|
|
75
|
+
<meta charset="utf-8">
|
|
76
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
77
|
+
<title>${$(e)} \u2014 AgentX Wiki</title>
|
|
78
|
+
<style>${Ue}</style>
|
|
79
|
+
</head>
|
|
80
|
+
<body>
|
|
81
|
+
<div class="layout">
|
|
82
|
+
<nav class="sidebar">${t}</nav>
|
|
83
|
+
<main class="main">${s}</main>
|
|
84
|
+
</div>
|
|
85
|
+
</body>
|
|
86
|
+
</html>`}function Se(e){let t=new Map;for(let s of e){let o=s.path.includes("/")?s.path.split("/").slice(0,-1).join("/"):"/",n=t.get(o)||[];n.push(s),t.set(o,n)}return new Map([...t].sort((s,o)=>s[0].localeCompare(o[0])))}function Ae(e){return e==="/"?"Root":e.split("/").pop().replace(/-/g," ")}function z(e,t){let s='<a href="/" class="logo">AgentX Wiki</a>';s+='<form action="/search" method="get"><input type="text" name="q" class="search-box" placeholder="Search all wikis..."></form>',s+="<h2>Hub</h2>",s+=`<a href="/"${t?"":' class="active"'}>Home</a>`,s+='<a href="/entries">All Entries</a>';for(let o of e){let n=`/agent/${encodeURIComponent(o.agentId)}`;s+=`<h2><a href="${n}" style="color:inherit;text-decoration:none">${$(o.agentId)}</a> <span class="agent-badge">${o.totalArticles}</span></h2>`;let i=Se(o.articles);for(let[r,c]of i){s+=`<div style="font-size:11px;text-transform:uppercase;letter-spacing:0.3px;color:#888;margin:8px 8px 2px;font-weight:600">${Ae(r)}</div>`;for(let a of c){let h=`${o.agentId}/${a.path}`===t;s+=`<a href="${n}/article/${encodeURIComponent(a.path)}"${h?' class="active"':""} style="padding-left:16px;font-size:13px">${$(a.title)}</a>`}}}return s}function Oe(e,t,s){let o=t||e.summary(),i=e.getSharedStore().listEntries().length,r=o.reduce((h,p)=>h+p.totalArticles,0),c=o.reduce((h,p)=>h+p.unabsorbed,0),a=new Set((s||[]).map(h=>h.agentId)),d="<h1>AgentX Wiki Hub</h1>";if(d+='<div class="stats">',d+=`<div class="stat-card"><div class="number">${o.length}</div><div class="label">Agents</div></div>`,d+=`<div class="stat-card"><div class="number">${r}</div><div class="label">Articles</div></div>`,d+=`<div class="stat-card"><div class="number">${i}</div><div class="label">Raw Entries</div></div>`,s&&s.length>0){let h=new Set(s.map(p=>p.nodeId));d+=`<div class="stat-card"><div class="number">${h.size}</div><div class="label">Mesh Nodes</div></div>`}d+="</div>",d+="<h2>Agent Wikis</h2>";for(let h of o){let p=h.unabsorbed>0?`<span style="color: #e6a700;">${h.unabsorbed} unabsorbed</span>`:'<span style="color: green;">up to date</span>',y=a.has(h.agentId)&&!e.listAgents().includes(h.agentId)?' <span class="tag" style="background:#fff3cd;color:#856404">remote</span>':"";if(d+='<div class="agent-card">',d+=`<h3><a href="/agent/${encodeURIComponent(h.agentId)}">${$(h.agentId)}</a>${y}</h3>`,d+=`<div class="agent-stats">
|
|
87
|
+
<span><strong>${h.totalArticles}</strong> articles</span>
|
|
88
|
+
<span><strong>${h.totalEntries}</strong> entries</span>
|
|
89
|
+
<span>${p}</span>
|
|
90
|
+
</div>`,h.articles.length>0){d+='<div class="article-list">';for(let f of h.articles)d+=`<a href="/agent/${encodeURIComponent(h.agentId)}/article/${encodeURIComponent(f.path)}"><span class="tag">${(f.tags||[]).slice(0,3).join(", ")}</span> ${$(f.title)}</a> `;d+="</div>"}d+="</div>"}return W("Hub",z(o),d)}function Ne(e,t,s){let o=s||e.summary(),n=o.find(g=>g.agentId===t);if(!n)return W("Not Found",z(o),"<h1>Agent not found</h1>");let i=n.peerUrl!==void 0,r=e.getAgentEntries(t),c=n.articles||[],a=`<div class="breadcrumb"><a href="/">Hub</a> / ${$(t)}</div>`;if(a+=`<h1>${$(t)}</h1>`,i&&(a+=`<p><span class="tag" style="background:#fff3cd;color:#856404">remote @ ${$(n.nodeId)}</span></p>`),a+='<div class="stats">',a+=`<div class="stat-card"><div class="number">${n.totalArticles}</div><div class="label">Articles</div></div>`,a+=`<div class="stat-card"><div class="number">${n.totalEntries}</div><div class="label">Entries</div></div>`,a+=`<div class="stat-card"><div class="number">${n.unabsorbed}</div><div class="label">Unabsorbed</div></div>`,a+="</div>",c.length>0){a+="<h2>Articles</h2><table>",a+="<tr><th>Title</th><th>Tags</th></tr>";for(let g of c)a+=`<tr>
|
|
91
|
+
<td><a href="/agent/${encodeURIComponent(t)}/article/${encodeURIComponent(g.path)}">${$(g.title)}</a></td>
|
|
92
|
+
<td>${(g.tags||[]).slice(0,4).map(y=>`<span class="tag">${y}</span>`).join(" ")}</td>
|
|
93
|
+
</tr>`;a+="</table>"}let d=r.slice(-5).reverse();if(d.length>0){a+="<h2>Recent Entries</h2>";for(let g of d)a+=`<div class="entry-card">
|
|
94
|
+
<div class="meta-line">${g.date} via ${g.source} · <code>${g.id}</code></div>
|
|
95
|
+
<p>${$(g.content.slice(0,300))}${g.content.length>300?"...":""}</p>
|
|
96
|
+
</div>`}let p=e.getAgentWiki(t).lint();if(p.length>0){a+=`<h2>Health Issues (${p.length})</h2><table>`,a+="<tr><th>Type</th><th>Article</th><th>Issue</th></tr>";for(let g of p)a+=`<tr><td><span class="tag">${g.type}</span></td><td>${$(g.article)}</td><td>${$(g.message)}</td></tr>`;a+="</table>"}return W(t,z(o,t),a)}function De(e,t,s,o){let n=e.getAgentWiki(t),i=n.readArticle(s);if(!i)return null;let r=o||e.summary(),c=n.rebuildIndex(),a=new Map;for(let y of c.articles)a.set(y.title,y.path);let d=`/agent/${encodeURIComponent(t)}`,p=n.buildBacklinks()[i.meta.title]||[],g=`<div class="breadcrumb"><a href="/">Hub</a> / <a href="${d}">${$(t)}</a> / ${$(i.meta.title)}</div>`;if(g+=`<h1>${$(i.meta.title)}</h1>`,g+='<dl class="meta">',g+=`<dt>Tags</dt><dd>${(i.meta.tags||[]).map(y=>`<span class="tag">${y}</span>`).join(" ")}</dd>`,g+=`<dt>Owner</dt><dd>${$(i.meta.owner)}</dd>`,g+=`<dt>Created</dt><dd>${i.meta.created}</dd>`,g+=`<dt>Updated</dt><dd>${i.meta.lastUpdated}</dd>`,i.meta.sources?.length&&(g+=`<dt>Sources</dt><dd>${i.meta.sources.length} entries</dd>`),g+="</dl>",g+=de(i.content,a,d),p.length>0){g+='<div class="backlinks"><h4>Pages that link here:</h4><ul>';for(let y of p){let f=n.readArticle(y);g+=`<li><a href="${d}/article/${encodeURIComponent(y)}">${$(f?.meta.title||y)}</a></li>`}g+="</ul></div>"}return W(i.meta.title,z(r,`${t}/${s}`),g)}function Me(e,t){let s=t||e.summary(),n=e.getSharedStore().listEntries(),i='<div class="breadcrumb"><a href="/">Hub</a> / Entries</div>';i+=`<h1>All Raw Entries (${n.length})</h1>`;let r=new Map;for(let c of n){let a=r.get(c.date)||[];a.push(c),r.set(c.date,a)}for(let[c,a]of[...r].reverse()){i+=`<h2>${c} (${a.length})</h2>`;for(let d of a)i+=`<div class="entry-card">
|
|
97
|
+
<div class="meta-line">
|
|
98
|
+
<a href="/agent/${encodeURIComponent(d.agentId)}">${$(d.agentId)}</a>
|
|
99
|
+
via ${d.source} · <code>${d.id}</code>
|
|
100
|
+
</div>
|
|
101
|
+
<p>${$(d.content.slice(0,400))}${d.content.length>400?"...":""}</p>
|
|
102
|
+
</div>`}return W("All Entries",z(s),i)}function Le(e,t,s){let o=s||e.summary(),n=`<h1>Search: "${$(t)}"</h1>`,i=0;for(let r of o){let a=e.getAgentWiki(r.agentId).findRelevant(t,void 0,10);if(a.length>0){n+=`<h2>${$(r.agentId)} (${a.length})</h2>`;for(let d of a){let h=`/agent/${encodeURIComponent(r.agentId)}`;n+=`<div class="entry-card">
|
|
103
|
+
<div class="meta-line">${(d.meta.tags||[]).slice(0,3).map(p=>`<span class="tag">${p}</span>`).join(" ")}</div>
|
|
104
|
+
<h3><a href="${h}/article/${encodeURIComponent(d.path)}">${$(d.meta.title)}</a></h3>
|
|
105
|
+
<p>${$(d.content.slice(0,200))}...</p>
|
|
106
|
+
</div>`}i+=a.length}}return i===0&&(n+="<p>No matching articles found.</p>"),W(`Search: ${t}`,z(o),n)}function Z(e,t,s){let o=e.rebuildIndex(),n=Se(o.articles.map(r=>({title:r.title,path:r.path,tags:r.tags}))),i=`<a href="/" class="logo">${$(t)}</a>`;i+='<form action="/search" method="get"><input type="text" name="q" class="search-box" placeholder="Search..."></form>',i+="<h2>Navigation</h2>",i+=`<a href="/"${s?"":' class="active"'}>Home</a>`,i+='<a href="/lint">Health Check</a>';for(let[r,c]of n){i+=`<h2>${Ae(r)}</h2>`;for(let a of c){let d=a.path===s;i+=`<a href="/article/${encodeURIComponent(a.path)}"${d?' class="active"':""}>${$(a.title)}</a>`}}return i}function Ie(e,t=4200,s,o=[],n="unified"){let i=new K(e,void 0,n),r=o.length>0?new le(o):null;Pe(async(a,d)=>{let h=new URL(a.url||"/",`http://localhost:${t}`),p=decodeURIComponent(h.pathname),g=null,y=200;try{if(p.startsWith("/remote/")&&r){let f=p.slice(8).split("/article/");if(f.length===2){let[b,w]=f,k=b.indexOf("/"),S=decodeURIComponent(b.slice(0,k)),v=b.slice(k+1),A=await r.getRemoteArticle(S,v,w);if(A){let P=await r.getRemoteAgents(),G=[...i.summary(),...P.map(C=>({...C,agentId:`${C.agentId} @${C.nodeId}`}))],E=`<div class="breadcrumb"><a href="/">Hub</a> / <span class="tag">remote</span> ${$(v)} @ ${$(S)}</div>`;E+=`<h1>${$(A.meta.title)}</h1>`,E+='<dl class="meta">',E+=`<dt>Tags</dt><dd>${(A.meta.tags||[]).map(C=>`<span class="tag">${C}</span>`).join(" ")}</dd>`,E+=`<dt>Owner</dt><dd>${$(A.meta.owner)}</dd>`,E+=`<dt>Source</dt><dd><span class="tag">remote</span> ${$(S)}</dd>`,E+=`<dt>Updated</dt><dd>${A.meta.lastUpdated}</dd>`,E+="</dl>";let T=new Map;E+=de(A.content,T),g=W(A.meta.title,z(G),E)}}}if(!g&&s){let f=i.getAgentWiki(s);if(p==="/"||p===""){let b=f.rebuildIndex(),w=i.getAgentEntries(s),k=`<h1>${$(s)}</h1>`;if(k+='<div class="stats">',k+=`<div class="stat-card"><div class="number">${b.articles.length}</div><div class="label">Articles</div></div>`,k+=`<div class="stat-card"><div class="number">${w.length}</div><div class="label">Entries</div></div>`,k+="</div>",b.articles.length>0){k+="<h2>Articles</h2><table><tr><th>Title</th><th>Type</th><th>Updated</th></tr>";for(let S of b.articles)k+=`<tr><td><a href="/article/${encodeURIComponent(S.path)}">${$(S.title)}</a></td><td><span class="tag">${(S.tags||[]).slice(0,3).join(", ")}</span></td><td>${S.lastUpdated||""}</td></tr>`;k+="</table>"}g=W(s,Z(f,s),k)}else if(p.startsWith("/article/")){let b=p.slice(9),w=f.readArticle(b);if(w){let k=f.rebuildIndex(),S=new Map;for(let A of k.articles)S.set(A.title,A.path);let v=`<h1>${$(w.meta.title)}</h1>`;v+='<dl class="meta">',v+=`<dt>Tags</dt><dd>${(w.meta.tags||[]).map(A=>`<span class="tag">${A}</span>`).join(" ")}</dd>`,v+=`<dt>Updated</dt><dd>${w.meta.lastUpdated}</dd>`,w.meta.sources?.length&&(v+=`<dt>Sources</dt><dd>${w.meta.sources.length} entries</dd>`),v+="</dl>",v+=de(w.content,S),g=W(w.meta.title,Z(f,s,b),v)}}else if(p==="/lint"){let b=f.lint(),w="<h1>Health Check</h1>";if(b.length===0)w+='<p style="color:green;">No issues.</p>';else{w+="<table><tr><th>Type</th><th>Article</th><th>Issue</th></tr>";for(let k of b)w+=`<tr><td><span class="tag">${k.type}</span></td><td>${$(k.article)}</td><td>${$(k.message)}</td></tr>`;w+="</table>"}g=W("Health Check",Z(f,s),w)}else if(p==="/search"){let b=h.searchParams.get("q")||"",w=f.findRelevant(b,void 0,20),k=`<h1>Search: "${$(b)}"</h1>`;for(let S of w)k+=`<div class="entry-card"><h3><a href="/article/${encodeURIComponent(S.path)}">${$(S.meta.title)}</a></h3><p>${$(S.content.slice(0,200))}...</p></div>`;w.length===0&&(k+="<p>No results.</p>"),g=W(`Search: ${b}`,Z(f,s),k)}}else{let f=r?await r.getRemoteAgents():[],b=i.summary(),w=new Map(b.map(v=>[v.agentId,v])),k=[],S=new Set;for(let v of b){let A=f.find(P=>P.agentId===v.agentId);A&&A.totalArticles>v.totalArticles?k.push({...A,totalEntries:Math.max(v.totalEntries,A.totalEntries),unabsorbed:Math.max(v.unabsorbed,A.unabsorbed)}):k.push(v),S.add(v.agentId)}for(let v of f)S.has(v.agentId)||(k.push(v),S.add(v.agentId));if(p==="/"||p==="")g=Oe(i,k,f);else if(p==="/entries")g=Me(i,k);else if(p==="/search")g=Le(i,h.searchParams.get("q")||"",k);else if(p.startsWith("/agent/")){let v=p.slice(7),A=v.indexOf("/article/");if(A===-1)g=Ne(i,v,k);else{let P=v.slice(0,A),G=v.slice(A+9);if(g=De(i,P,G,k),!g&&r){let E=f.find(T=>T.agentId===P);if(E){let T=await r.getRemoteArticle(E.peerUrl,P,G);if(T){let C=`<div class="breadcrumb"><a href="/">Hub</a> / <span class="tag">remote @ ${$(E.nodeId)}</span> / ${$(P)}</div>`;C+=`<h1>${$(T.meta.title)}</h1>`,C+='<dl class="meta">',C+=`<dt>Tags</dt><dd>${(T.meta.tags||[]).map(te=>`<span class="tag">${te}</span>`).join(" ")}</dd>`,C+=`<dt>Source</dt><dd><span class="tag">remote</span> ${$(E.nodeId)}</dd>`,C+=`<dt>Updated</dt><dd>${T.meta.lastUpdated}</dd>`,C+="</dl>",C+=de(T.content,new Map),g=W(T.meta.title,z(k),C)}}}}}}if(!g){y=404;let f=s?Z(i.getAgentWiki(s),s):z(i.summary());g=W("Not Found",f,"<h1>Page not found</h1>")}}catch(f){y=500,g=W("Error","",`<h1>Error</h1><pre>${$(f.message)}</pre>`)}d.writeHead(y,{"Content-Type":"text/html; charset=utf-8"}),d.end(g)}).listen(t)}function Ce(e,t,s,o,n,i){let r=o.length>0?`
|
|
11
107
|
Existing articles:
|
|
12
|
-
${
|
|
108
|
+
${o.map(a=>`- ${a.title} [${(a.tags||[]).join(", ")}] (${a.path})`).join(`
|
|
13
109
|
`)}
|
|
14
|
-
`:"",
|
|
15
|
-
|
|
16
|
-
|
|
110
|
+
`:"",c=s?`
|
|
111
|
+
## Worldview
|
|
112
|
+
|
|
113
|
+
${s}
|
|
114
|
+
`:"";return e==="flat"?He(t,c,r,n,i):e==="graph"?ze(t,c,r,n,i):Be(t,c,r,n,i)}function He(e,t,s,o,n){return`You are a wiki editor for the "${e}" agent. Compile raw entries into a personal wiki.
|
|
115
|
+
|
|
116
|
+
## Karpathy Pattern
|
|
117
|
+
|
|
118
|
+
- Plain markdown files. YOU choose the path and structure \u2014 it emerges from the data.
|
|
119
|
+
- Tag AGGRESSIVELY. Tags are the #1 mechanism for context narrowing.
|
|
120
|
+
- Use [[wikilinks]] to cross-reference between articles.
|
|
121
|
+
- Synthesize \u2014 distill conversations into factual wiki articles, don't copy-paste.
|
|
122
|
+
- If an existing article covers the topic, produce an UPDATE with full merged content.
|
|
123
|
+
${t}${s}
|
|
124
|
+
## Tagging Rules
|
|
125
|
+
|
|
126
|
+
Tag every article with ALL relevant dimensions:
|
|
127
|
+
- WHO: people, agents, teams (e.g., "alice", "deploy-bot", "cto")
|
|
128
|
+
- WHAT: project, client, topic, tech (e.g., "billing-api", "seo", "gitlab", "deploy")
|
|
129
|
+
- WHEN: dates, periods (e.g., "2026-04-06", "week-14")
|
|
130
|
+
- WHERE: server, environment, channel (e.g., "staging", "telegram", "production")
|
|
131
|
+
- HOW: type of knowledge (e.g., "process", "incident", "report", "decision")
|
|
132
|
+
|
|
133
|
+
Use section tags: \`<!-- tags: runbook, staging -->\`
|
|
134
|
+
|
|
135
|
+
## Gap Detection
|
|
136
|
+
|
|
137
|
+
After compiling, add a "gaps" array \u2014 topics MENTIONED but not yet covered.
|
|
138
|
+
|
|
139
|
+
## Output \u2014 ONLY valid JSON, no markdown fencing
|
|
140
|
+
|
|
141
|
+
{
|
|
142
|
+
"articles": [
|
|
143
|
+
{
|
|
144
|
+
"path": "infra/staging-deploy.md",
|
|
145
|
+
"title": "Staging Deployment Process",
|
|
146
|
+
"tags": ["deploy", "staging", "devops", "process", "2026-04-06"],
|
|
147
|
+
"content": "How we deploy to staging...\\n\\n## Steps\\n<!-- tags: runbook, staging -->\\n1. ...",
|
|
148
|
+
"sources": ["entry-id-1", "entry-id-2"]
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"gaps": ["Production server \u2014 mentioned but no article exists"]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
ENTRIES (${n}):
|
|
155
|
+
|
|
156
|
+
${o}`}function ze(e,t,s,o,n){return`You are building a knowledge graph for the "${e}" agent. Compile raw entries into a structured wiki.
|
|
157
|
+
|
|
158
|
+
## Knowledge Graph Model
|
|
159
|
+
|
|
160
|
+
Every article is a NODE with a kind and position in a hierarchy.
|
|
161
|
+
The path reflects the hierarchy: org/team/agent-name.md
|
|
162
|
+
|
|
163
|
+
### Node Kinds
|
|
164
|
+
|
|
165
|
+
**Entities** (things that persist):
|
|
166
|
+
person, agent, company, team, client, project, repo, server, service, domain
|
|
167
|
+
|
|
168
|
+
**Occurrences** (things that happen \u2014 always have a date):
|
|
169
|
+
event, incident, deploy, decision
|
|
17
170
|
|
|
18
|
-
|
|
171
|
+
**Knowledge** (what we know):
|
|
172
|
+
process, pattern, concept, report
|
|
19
173
|
|
|
20
|
-
|
|
21
|
-
${i}
|
|
22
|
-
Rules:
|
|
23
|
-
1. Group related entries into articles by topic (e.g., "Weekly Marketing Brief", "MTGL Deploy Process", "GitLab Token Issues")
|
|
24
|
-
2. Each article should synthesize information, not just copy-paste
|
|
25
|
-
3. Use wikilinks [[Article Title]] to cross-reference related articles
|
|
26
|
-
4. If an existing article covers the topic, produce an UPDATE with merged content
|
|
27
|
-
5. Output ONLY valid JSON \u2014 no markdown fencing, no explanation
|
|
174
|
+
### Rules
|
|
28
175
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
176
|
+
1. Ask: "What ENTITY is this about? What HAPPENED? Where in the hierarchy?"
|
|
177
|
+
2. Entities go under their parent: agent under team, server under project
|
|
178
|
+
3. Events go under events/YYYY-MM-DD/ and list which entities are involved
|
|
179
|
+
4. Path = hierarchy: org/<company>/<area>/<entity>.md
|
|
180
|
+
5. Use [[wikilinks]] to cross-reference between nodes
|
|
181
|
+
6. Synthesize \u2014 distill conversations into factual wiki content
|
|
182
|
+
7. If an existing article covers the topic, produce an UPDATE with full merged content
|
|
183
|
+
8. Tag aggressively too \u2014 tags help narrow context
|
|
184
|
+
${t}${s}
|
|
185
|
+
## Gap Detection
|
|
36
186
|
|
|
37
|
-
|
|
38
|
-
"sources": ["entry-id-1", "entry-id-2"]
|
|
39
|
-
}
|
|
40
|
-
]
|
|
187
|
+
After compiling, add a "gaps" array \u2014 entities or events MENTIONED but missing.
|
|
41
188
|
|
|
42
|
-
|
|
189
|
+
## Output \u2014 ONLY valid JSON, no markdown fencing
|
|
43
190
|
|
|
44
|
-
|
|
191
|
+
{
|
|
192
|
+
"articles": [
|
|
193
|
+
{
|
|
194
|
+
"path": "org/team/marketing-bot.md",
|
|
195
|
+
"title": "Marketing Bot \u2014 Content Agent",
|
|
196
|
+
"tags": ["marketing-bot", "agent", "marketing"],
|
|
197
|
+
"kind": "agent",
|
|
198
|
+
"parent": "org/team",
|
|
199
|
+
"content": "Marketing bot handles content and SEO.",
|
|
200
|
+
"sources": ["entry-id-1"],
|
|
201
|
+
"date": null,
|
|
202
|
+
"involves": null
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"path": "events/2026-04-06/token-expiry.md",
|
|
206
|
+
"title": "GitLab Token Expiry",
|
|
207
|
+
"tags": ["incident", "gitlab", "2026-04-06"],
|
|
208
|
+
"kind": "incident",
|
|
209
|
+
"parent": "events/2026-04-06",
|
|
210
|
+
"content": "The GITLAB_TOKEN expired, blocking deploys.",
|
|
211
|
+
"sources": ["entry-id-2"],
|
|
212
|
+
"date": "2026-04-06",
|
|
213
|
+
"involves": ["org/clients/acme"]
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
"gaps": ["Production server \u2014 entity mentioned but missing"]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
ENTRIES (${n}):
|
|
220
|
+
|
|
221
|
+
${o}`}function Be(e,t,s,o,n){return`You are compiling a personal wiki for the "${e}" agent.
|
|
222
|
+
|
|
223
|
+
## Your Job
|
|
224
|
+
|
|
225
|
+
Read ${n} raw conversation entries. For each, ask:
|
|
226
|
+
1. **Who** is mentioned? (people, agents, companies, teams)
|
|
227
|
+
2. **What** is this about? (project, server, tool, concept)
|
|
228
|
+
3. **What happened?** (deploy, incident, decision, report)
|
|
229
|
+
4. **What's missing?** (entities mentioned but undocumented)
|
|
230
|
+
|
|
231
|
+
Then compile articles \u2014 one topic per article, synthesized (not copy-pasted).
|
|
232
|
+
|
|
233
|
+
## How to Organize
|
|
234
|
+
|
|
235
|
+
- YOU choose the file path. Let structure emerge from the data.
|
|
236
|
+
- Use whatever directory names make sense: projects/, incidents/, agents/ \u2014 your call.
|
|
237
|
+
- Use [[wikilinks]] to cross-reference between articles.
|
|
238
|
+
- If an existing article covers the topic, produce an UPDATE with full merged content.
|
|
239
|
+
${t}${s}
|
|
240
|
+
## How to Tag (CRITICAL)
|
|
241
|
+
|
|
242
|
+
Tags are how agents find relevant context. Tag EVERY article with ALL dimensions:
|
|
243
|
+
|
|
244
|
+
| Dimension | Examples |
|
|
245
|
+
|-----------|----------|
|
|
246
|
+
| **Who** | agent names, people, team names |
|
|
247
|
+
| **What** | project names, tools, technologies |
|
|
248
|
+
| **Type** | person, agent, server, project, incident, process, report, decision |
|
|
249
|
+
| **When** | 2026-04-06, week-14, q2-2026 |
|
|
250
|
+
| **Where** | staging, production, telegram, server-name |
|
|
251
|
+
| **How** | deploy, runbook, spike, review |
|
|
252
|
+
|
|
253
|
+
Minimum 6 tags per article. More is better.
|
|
254
|
+
Use section-level tags too: \`<!-- tags: runbook, staging -->\`
|
|
255
|
+
|
|
256
|
+
## How to Find Gaps
|
|
257
|
+
|
|
258
|
+
After compiling, identify MISSING PIECES:
|
|
259
|
+
- People mentioned but no article (e.g., "Alice gives deploy instructions but who is Alice?")
|
|
260
|
+
- Servers referenced but undocumented (e.g., "10.0.1.5 \u2014 what is this?")
|
|
261
|
+
- Processes implied but not written down (e.g., "deploy to staging \u2014 how exactly?")
|
|
262
|
+
- Projects named but no overview (e.g., "Project X \u2014 what is it?")
|
|
263
|
+
|
|
264
|
+
Be specific. "X is undocumented" is useless. "Alice \u2014 stakeholder who issues deploy instructions via Telegram, no profile article" is useful.
|
|
265
|
+
|
|
266
|
+
## Output \u2014 ONLY valid JSON, no markdown fencing
|
|
267
|
+
|
|
268
|
+
{
|
|
269
|
+
"articles": [
|
|
270
|
+
{
|
|
271
|
+
"path": "agents/marketing-bot.md",
|
|
272
|
+
"title": "Marketing Bot \u2014 Content Agent",
|
|
273
|
+
"tags": ["marketing-bot", "agent", "marketing", "content", "seo"],
|
|
274
|
+
"content": "Marketing bot handles content, marketing, and SEO.\\n\\n## Capabilities\\n<!-- tags: capabilities, tools -->\\n...",
|
|
275
|
+
"sources": ["entry-id-1"]
|
|
276
|
+
}
|
|
277
|
+
],
|
|
278
|
+
"gaps": [
|
|
279
|
+
"Alice \u2014 stakeholder who issues deploy instructions via Telegram, no profile article",
|
|
280
|
+
"10.0.1.5 \u2014 production server IP referenced but no infrastructure article"
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
ENTRIES (${n}):
|
|
285
|
+
|
|
286
|
+
${o}`}import{resolve as ee}from"path";import{execSync as Je}from"child_process";import{writeFileSync as _e,mkdirSync as Ye}from"fs";function F(e,t){return new K(e||ee(process.cwd(),".agentx/wiki"),void 0,t||"graph")}function ue(e){return e==="graph"?"Knowledge Graph":e==="flat"?"Karpathy Flat":"Unified"}var H=new Ge().name("wiki").description("wiki knowledge base management");H.command("status").description("show wiki status per agent").option("--dir <path>","wiki directory").option("--mode <mode>","unified (default), graph, or flat","unified").action(e=>{let t=e.mode,s=F(e.dir,t),o=s.summary(),i=s.getSharedStore().listEntries().length;console.log(),console.log(u.bold(` Wiki Hub Status [${ue(t)}]`)),console.log(),console.log(` Total raw entries: ${i}`),console.log(` Agents: ${o.length}`),console.log();for(let c of o){let a=c.unabsorbed>0?u.yellow(`${c.unabsorbed} unabsorbed`):u.green("up to date");if(console.log(` ${u.cyan(c.agentId)}`),console.log(` Entries: ${c.totalEntries} Articles: ${c.totalArticles} ${a}`),c.articles.length>0){for(let d of c.articles.slice(0,3))console.log(u.dim(` - ${d.title} [${(d.tags||[]).slice(0,3).join(", ")}]`));c.articles.length>3&&console.log(u.dim(` ... and ${c.articles.length-3} more`))}console.log()}o.reduce((c,a)=>c+a.unabsorbed,0)>0&&(console.log(u.dim(" Run 'agentx wiki absorb' to compile all, or 'agentx wiki absorb --agent <id>' for one agent")),console.log())});H.command("lint").description("check wiki for issues per agent").option("--dir <path>","wiki directory").option("--mode <mode>","unified (default), graph, or flat","unified").option("--agent <id>","lint a specific agent's wiki").action(e=>{let t=F(e.dir,e.mode),s=e.agent?[e.agent]:t.listAgents(),o=0;console.log();for(let n of s){let r=t.getAgentWiki(n).lint();if(o+=r.length,r.length===0)console.log(` ${u.cyan(n)}: ${u.green("healthy")}`);else{console.log(` ${u.cyan(n)}: ${u.yellow(`${r.length} issues`)}`);for(let c of r){let a=c.type==="broken-link"?"x":c.type==="orphan"?"?":"!";console.log(` [${a}] ${u.dim(c.type)} ${c.article}: ${c.message}`)}}}console.log(),o===0&&console.log(u.green(" All agent wikis are healthy")),console.log()});H.command("absorb").description("compile unabsorbed entries into per-agent wiki articles").option("--dir <path>","wiki directory").option("--mode <mode>","unified (default), graph, or flat","unified").option("--agent <id>","absorb only this agent").option("--dry-run","preview without running").option("--max <n>","max entries per agent","20").action(async e=>{let t=e.mode,s=F(e.dir,t),o=e.agent?[e.agent]:s.listAgents(),n=parseInt(e.max),i=0;for(let r of o){let c=s.getUnabsorbedEntries(r).slice(0,n);if(c.length===0){console.log(` ${u.cyan(r)}: ${u.green("all absorbed")}`);continue}console.log(),console.log(u.bold(` ${u.cyan(r)}: ${c.length} entries to absorb`));for(let b of c.slice(0,3))console.log(u.dim(` [${b.date} via ${b.source}] ${b.content.slice(0,80)}...`));if(c.length>3&&console.log(u.dim(` ... and ${c.length-3} more`)),e.dryRun)continue;let a=s.getAgentWiki(r),d=a.rebuildIndex(),h=a.getWorldview()||s.getSharedStore().getWorldview()||"",p=c.map(b=>`--- ENTRY ${b.id} [${b.date} ${b.agentId} via ${b.source}] ---
|
|
287
|
+
${b.content}
|
|
288
|
+
--- END ENTRY ---`).join(`
|
|
45
289
|
|
|
46
|
-
${
|
|
290
|
+
`),g=Ce(t,r,h,d.articles,p,c.length);console.log(u.dim(` Mode: ${ue(t)}`));let y=ee(a.baseDir,"_tmp");Ye(y,{recursive:!0});let f=ee(y,"absorb-prompt.txt");_e(f,g),console.log(u.dim(" Compiling with Claude..."));try{let b;try{b=Je(`cat '${f}' | claude -p - --output-format json --max-turns 3 --model sonnet --disallowedTools "Bash Read Write Edit Glob Grep Agent WebSearch WebFetch NotebookEdit"`,{encoding:"utf-8",timeout:3e5,maxBuffer:10*1024*1024})}catch(x){if(b=x.stdout||"",!b)throw x}let w=b;try{let x=JSON.parse(b);w=x.result||x.content||"",w||(console.log(u.dim(` Claude envelope keys: ${Object.keys(x).join(", ")}`)),console.log(u.dim(` is_error: ${x.is_error}, stop_reason: ${x.stop_reason}`)))}catch{}let k,S=[],v=w.indexOf("{"),A=w.indexOf("["),P=v>=0&&(A<0||v<A)?v:A;if(P===-1){console.log(u.red(" No JSON found in response")),console.log(u.dim(w.slice(0,500)));continue}let G=w[P],E=G==="{"?"}":"]",T=0,C=-1;for(let x=P;x<w.length;x++)if(w[x]===G)T++;else if(w[x]===E&&(T--,T===0)){C=x+1;break}if(C===-1){console.log(u.red(" Unbalanced JSON"));continue}let te=w.slice(P,C);try{let x=JSON.parse(te);Array.isArray(x)?k=x:(k=x.articles||[],S=x.gaps||[])}catch(x){console.log(u.red(` JSON parse error: ${x.message}`)),console.log(u.dim(` First 300 chars: ${te.slice(0,300)}`));continue}for(let x of k){let fe=new Date().toISOString().slice(0,10);a.writeArticle(x.path,{title:x.title,tags:x.tags||[],owner:r,access:"public",created:fe,lastUpdated:fe,sources:x.sources||[]},x.content,r);let be=(x.tags||[]).slice(0,5).join(", ");console.log(` ${u.green("+")} ${x.path}: ${x.title}`),be&&console.log(u.dim(` [${be}]`)),i++}if(S.length>0){console.log(),console.log(u.yellow(` Gaps detected (${S.length} missing pieces):`));for(let x of S)console.log(u.yellow(` ? ${x}`))}a.rebuildIndex()}catch(b){console.log(u.red(` Absorb failed: ${b.message?.slice(0,200)}`)),b.stderr&&console.log(u.dim(String(b.stderr).slice(0,300))),b.stdout&&console.log(u.dim("stdout: "+String(b.stdout).slice(0,300)))}}console.log(),e.dryRun?console.log(u.dim(" Dry run \u2014 no changes made")):i>0&&console.log(u.green(` ${i} articles compiled across ${o.length} agent(s)`)),console.log()});H.command("entries").description("list raw entries").option("--dir <path>","wiki directory").option("--agent <id>","filter by agent").action(e=>{let o=F(e.dir).getSharedStore().listEntries();e.agent&&(o=o.filter(n=>n.agentId===e.agent)),console.log(),console.log(u.bold(` ${o.length} raw entries`)),console.log();for(let n of o.slice(-20))console.log(` ${u.dim(n.date)} ${u.cyan(n.agentId)} via ${n.source}: ${n.content.slice(0,80)}...`);o.length>20&&console.log(u.dim(` ... showing last 20 of ${o.length}`)),console.log()});H.command("serve").description("start a local web server to browse agent wikis (local + mesh)").option("--dir <path>","wiki directory").option("--mode <mode>","unified (default), graph, or flat","unified").option("--agent <id>","serve only this agent's wiki").option("--port <n>","port number","4200").option("--peer <urls...>","mesh peer URLs to federate").action(async e=>{let t=e.dir||ee(process.cwd(),".agentx/wiki"),s=parseInt(e.port),o=e.peer||[];if(o.length===0)try{let{loadDaemonConfig:n}=await import("./config-MSWKC466.js");o=(n().mesh?.peers||[]).map(r=>r.url)}catch{}console.log(),console.log(u.bold(" AgentX Wiki Server")),console.log(),console.log(` ${u.green(">")} http://localhost:${s}`),e.agent?console.log(` Agent: ${u.cyan(e.agent)}`):console.log(` Mode: ${u.cyan("Hub")} (all agents)`),o.length>0&&console.log(` Mesh: ${u.cyan(o.length+" peer(s)")} \u2014 ${o.join(", ")}`),console.log(u.dim(` Wiki: ${t}`)),console.log(u.dim(" Press Ctrl+C to stop")),console.log(),Ie(t,s,e.agent,o,e.mode)});H.command("search <query>").description("search wiki articles").option("--dir <path>","wiki directory").option("--mode <mode>","unified (default), graph, or flat","unified").option("--agent <id>","search specific agent's wiki").action((e,t)=>{let s=F(t.dir,t.mode),o=t.agent?[t.agent]:s.listAgents();console.log();let n=0;for(let i of o){let c=s.getAgentWiki(i).findRelevant(e,void 0,10);if(c.length>0){console.log(u.bold(` ${u.cyan(i)}:`));for(let a of c)console.log(` ${a.meta.title} [${(a.meta.tags||[]).slice(0,3).join(", ")}]`),console.log(u.dim(` ${a.path} \u2014 ${a.content.slice(0,100)}...`));n+=c.length}}n===0&&console.log(u.dim(" No matching articles")),console.log()});H.command("sync").description("pull raw entries from mesh peers into local wiki").option("--dir <path>","wiki directory").option("--peer <url>","sync from a specific peer URL (e.g., http://100.67.108.119:19900)").option("--dry-run","show what would be synced without writing").action(async e=>{let s=F(e.dir).getSharedStore(),o=[];if(e.peer)o=[e.peer];else try{let{loadDaemonConfig:r}=await import("./config-MSWKC466.js");o=(r().mesh?.peers||[]).map(a=>a.url)}catch{console.log(u.red(" No --peer specified and no daemon config found")),console.log(u.dim(" Usage: agentx wiki sync --peer http://100.67.108.119:19900"));return}if(o.length===0){console.log(u.dim(" No mesh peers configured"));return}let n=new Set(s.listEntries().map(r=>r.id)),i=0;for(let r of o){console.log(),console.log(u.bold(` Syncing from ${r}...`));try{let c=await fetch(`${r}/wiki/entries`,{signal:AbortSignal.timeout(1e4)});if(!c.ok){console.log(u.red(` HTTP ${c.status}`));continue}let a=await c.json(),d=a.entries||[],h=a.nodeId||"unknown";console.log(u.dim(` Node: ${h} \u2014 ${d.length} entries`));let p=0;for(let g of d)n.has(g.id)||(e.dryRun||(s.addEntry({id:g.id,date:g.date,agentId:g.agentId,source:`${g.source}@${h}`,sourceContext:g.sourceContext,content:g.content}),n.add(g.id)),p++);p>0?console.log(u.green(` ${p} new entries${e.dryRun?" (dry run)":" synced"}`)):console.log(u.dim(" Already up to date")),i+=p;try{let g=await fetch(`${r}/wiki/agents`,{signal:AbortSignal.timeout(5e3)});if(g.ok){let y=await g.json();for(let f of y.agents||[])f.totalEntries>0&&console.log(u.dim(` ${f.agentId}: ${f.totalEntries} entries, ${f.totalArticles} articles`))}}catch{}}catch(c){c.cause?.code==="ECONNREFUSED"?console.log(u.red(" Connection refused")):console.log(u.red(` ${c.message}`))}}console.log(),i>0&&!e.dryRun?console.log(u.green(` ${i} entries synced. Run 'agentx wiki absorb' to compile.`)):i>0?console.log(u.dim(` ${i} entries would be synced (dry run)`)):console.log(u.dim(" All peers up to date")),console.log()});H.command("compare").description("compare all wiki compilation modes for an agent").option("--dir <path>","wiki directory").requiredOption("--agent <id>","agent to compare").action(e=>{let t=e.dir||ee(process.cwd(),".agentx/wiki"),s=e.agent,n=["flat","graph","unified"].map(a=>{let d=new K(t,void 0,a),p=d.getAgentWiki(s).rebuildIndex(),g=d.getAgentEntries(s),y=d.getUnabsorbedEntries(s),f=new Set,b=0,w=new Set;for(let S of p.articles){for(let v of S.tags||[])f.add(v);b+=S.tags?.length||0;for(let v of S.sources||[])w.add(v)}let k=new Set(p.articles.map(S=>S.path.includes("/")?S.path.split("/")[0]:"/"));return{mode:a,label:ue(a),articles:p.articles.length,entries:g.length,unabsorbed:y.length,uniqueTags:f.size,avgTags:p.articles.length>0?(b/p.articles.length).toFixed(1):"0",dirs:k.size,coverage:w.size,articleList:p.articles}});console.log(),console.log(u.bold(` Wiki Compare: ${s}`)),console.log(` Raw entries: ${n[0].entries}`),console.log();let i=22;console.log(` ${"".padEnd(20)} ${n.map(a=>a.label.padEnd(i)).join(" ")}`),console.log(` ${"\u2500".repeat(20)} ${n.map(()=>"\u2500".repeat(i)).join(" ")}`);let r=[["Articles",a=>String(a.articles)],["Unabsorbed",a=>String(a.unabsorbed)],["Unique tags",a=>String(a.uniqueTags)],["Avg tags/article",a=>a.avgTags],["Directories",a=>String(a.dirs)],["Entry coverage",a=>`${a.coverage}/${a.entries}`]];for(let[a,d]of r){let h=n.map(p=>d(p).padEnd(i));console.log(` ${a.padEnd(20)} ${h.join(" ")}`)}console.log();let c=(a,d)=>{let h=Math.max(...n.map(g=>g[a])),p=n.filter(g=>g[a]===h).map(g=>g.label);h>0&&console.log(u.dim(` Best ${d}: ${p.join(", ")} (${h})`))};c("uniqueTags","tag richness"),c("articles","article count"),c("coverage","entry coverage"),console.log()});process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function Ke(){let e=await $e(),t=new Fe().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(t.addCommand(L).addCommand(ve).addCommand(X).addCommand(ie).addCommand(Y).addCommand(V).addCommand(re).addCommand(me).addCommand(he).addCommand(ce).addCommand(Q).addCommand(H),process.argv.slice(2).length===0){t.outputHelp();return}t.parse()}Ke();
|
|
47
291
|
//# sourceMappingURL=cli.js.map
|