agentix-cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import{d as X,g as v,k as c}from"./chunk-PCAYW54Q.js";import{a as Ce,d as fe}from"./chunk-FRFR27IN.js";import{a as _e,b as Pe,c as ge}from"./chunk-SFQUP3BP.js";import{a as de,c as ue,g as me}from"./chunk-MGMZNJCE.js";import{a as F,b as ce,f as pe}from"./chunk-M7HKBG3V.js";import{z as R}from"zod";var Se=R.object({provider:R.enum(["claude-code","claude","openai","ollama","custom"]).default("claude-code"),model:R.string().optional(),apiKey:R.string().optional(),skills:R.array(R.string()).default([]),output:R.object({dir:R.string().default("./generated")}).default({}),context7:R.object({enabled:R.boolean().default(!0),apiKey:R.string().optional()}).default({}),agentic:R.object({maxIterations:R.number().default(20),enabledTools:R.array(R.string()).default(["create_files","ask_user","read_file","search_files","list_directory","run_command","edit_file"]),disabledTools:R.array(R.string()).default([])}).default({})}),pt=["component","page","api","website","document","script","config","skill","media","report","test","workflow","schema","email","diagram","auto"],dt={component:"UI component (any framework)",page:"Full page or screen",api:"API endpoint, route handler, or service",website:"Multi-page website or app",document:"Markdown, documentation, or specification",script:"Standalone script or utility",config:"Configuration file or setup",skill:"Agent skill (SKILL.md format for skills.sh)",media:"Media generation prompt (image/audio/video description)",report:"Analysis report or audit",test:"Test suite, test fixtures, or test data",workflow:"CI/CD pipeline, GitHub Actions, or automation",schema:"Database schema, Zod validators, or GraphQL types",email:"Email template (React Email, MJML, HTML)",diagram:"Mermaid, D2, or PlantUML diagram",auto:"Auto-detect the best output type"};import{existsSync as He,promises as Ke}from"fs";import q from"path";import Ye from"fast-glob";var Te={"prisma/schema.prisma":{type:"prisma",category:"database"},"drizzle/schema.ts":{type:"drizzle",category:"database"},"schema.graphql":{type:"graphql",category:"api"},"schema.gql":{type:"graphql",category:"api"},"openapi.yaml":{type:"openapi",category:"api"},"openapi.json":{type:"openapi",category:"api"},"swagger.yaml":{type:"openapi",category:"api"},"swagger.json":{type:"openapi",category:"api"}};async function Re(o){let e={},t=await Ye.glob("**/*",{cwd:o,deep:4,ignore:["**/node_modules/**","**/dist/**","**/build/**","**/.next/**","**/target/**","**/__pycache__/**","**/vendor/**","**/.git/**"],onlyFiles:!0});for(let[s,i]of Object.entries(Te)){let l=t.find(a=>a.endsWith(s)||a===s);if(l&&i.category==="database"){let a=await K(q.resolve(o,l));if(a){e.database={type:i.type,content:Z(a,3e3),tables:Je(a,i.type)};break}}}for(let[s,i]of Object.entries(Te)){let l=t.find(a=>a.endsWith(s)||a===s);if(l&&i.category==="api"){let a=await K(q.resolve(o,l));if(a){e.api={type:i.type,content:Z(a,3e3)};break}}}if(!e.api){let s=t.find(i=>i.includes("trpc")&&(i.endsWith("router.ts")||i.endsWith("router.js")));if(s){let i=await K(q.resolve(o,s));i&&(e.api={type:"trpc",content:Z(i,3e3)})}}let n=t.find(s=>s===".env.example"||s===".env.local.example"||s===".env.template");if(n){let s=await K(q.resolve(o,n));s&&(e.env=Qe(s))}let r=t.filter(s=>(s.includes("models")||s.includes("types")||s.includes("schemas"))&&(s.endsWith(".ts")||s.endsWith(".py")||s.endsWith(".rs")||s.endsWith(".go")));if(r.length){e.models=[];for(let s of r.slice(0,5)){let i=await K(q.resolve(o,s));i&&e.models.push({path:s,content:Z(i,2e3),type:q.extname(s).slice(1)})}}return e}function Je(o,e){if(e==="prisma"){let t=o.match(/model\s+(\w+)\s*\{/g);return t?t.map(n=>n.replace(/model\s+/,"").replace(/\s*\{/,"")):[]}return[]}function Qe(o){return{variables:o.split(`
1
+ import{d as X,g as v,k as c}from"./chunk-Z4GC5D6D.js";import{a as Ce,d as fe}from"./chunk-FRFR27IN.js";import{a as _e,b as Pe,c as ge}from"./chunk-SFQUP3BP.js";import{a as de,c as ue,g as me}from"./chunk-MGMZNJCE.js";import{a as F,b as ce,f as pe}from"./chunk-M7HKBG3V.js";import{z as R}from"zod";var Se=R.object({provider:R.enum(["claude-code","claude","openai","ollama","custom"]).default("claude-code"),model:R.string().optional(),apiKey:R.string().optional(),skills:R.array(R.string()).default([]),output:R.object({dir:R.string().default("./generated")}).default({}),context7:R.object({enabled:R.boolean().default(!0),apiKey:R.string().optional()}).default({}),agentic:R.object({maxIterations:R.number().default(20),enabledTools:R.array(R.string()).default(["create_files","ask_user","read_file","search_files","list_directory","run_command","edit_file"]),disabledTools:R.array(R.string()).default([])}).default({})}),pt=["component","page","api","website","document","script","config","skill","media","report","test","workflow","schema","email","diagram","auto"],dt={component:"UI component (any framework)",page:"Full page or screen",api:"API endpoint, route handler, or service",website:"Multi-page website or app",document:"Markdown, documentation, or specification",script:"Standalone script or utility",config:"Configuration file or setup",skill:"Agent skill (SKILL.md format for skills.sh)",media:"Media generation prompt (image/audio/video description)",report:"Analysis report or audit",test:"Test suite, test fixtures, or test data",workflow:"CI/CD pipeline, GitHub Actions, or automation",schema:"Database schema, Zod validators, or GraphQL types",email:"Email template (React Email, MJML, HTML)",diagram:"Mermaid, D2, or PlantUML diagram",auto:"Auto-detect the best output type"};import{existsSync as He,promises as Ke}from"fs";import q from"path";import Ye from"fast-glob";var Te={"prisma/schema.prisma":{type:"prisma",category:"database"},"drizzle/schema.ts":{type:"drizzle",category:"database"},"schema.graphql":{type:"graphql",category:"api"},"schema.gql":{type:"graphql",category:"api"},"openapi.yaml":{type:"openapi",category:"api"},"openapi.json":{type:"openapi",category:"api"},"swagger.yaml":{type:"openapi",category:"api"},"swagger.json":{type:"openapi",category:"api"}};async function Re(o){let e={},t=await Ye.glob("**/*",{cwd:o,deep:4,ignore:["**/node_modules/**","**/dist/**","**/build/**","**/.next/**","**/target/**","**/__pycache__/**","**/vendor/**","**/.git/**"],onlyFiles:!0});for(let[s,i]of Object.entries(Te)){let l=t.find(a=>a.endsWith(s)||a===s);if(l&&i.category==="database"){let a=await K(q.resolve(o,l));if(a){e.database={type:i.type,content:Z(a,3e3),tables:Je(a,i.type)};break}}}for(let[s,i]of Object.entries(Te)){let l=t.find(a=>a.endsWith(s)||a===s);if(l&&i.category==="api"){let a=await K(q.resolve(o,l));if(a){e.api={type:i.type,content:Z(a,3e3)};break}}}if(!e.api){let s=t.find(i=>i.includes("trpc")&&(i.endsWith("router.ts")||i.endsWith("router.js")));if(s){let i=await K(q.resolve(o,s));i&&(e.api={type:"trpc",content:Z(i,3e3)})}}let n=t.find(s=>s===".env.example"||s===".env.local.example"||s===".env.template");if(n){let s=await K(q.resolve(o,n));s&&(e.env=Qe(s))}let r=t.filter(s=>(s.includes("models")||s.includes("types")||s.includes("schemas"))&&(s.endsWith(".ts")||s.endsWith(".py")||s.endsWith(".rs")||s.endsWith(".go")));if(r.length){e.models=[];for(let s of r.slice(0,5)){let i=await K(q.resolve(o,s));i&&e.models.push({path:s,content:Z(i,2e3),type:q.extname(s).slice(1)})}}return e}function Je(o,e){if(e==="prisma"){let t=o.match(/model\s+(\w+)\s*\{/g);return t?t.map(n=>n.replace(/model\s+/,"").replace(/\s*\{/,"")):[]}return[]}function Qe(o){return{variables:o.split(`
2
2
  `).filter(n=>n.trim()&&!n.trim().startsWith("#")).map(n=>{let[r]=n.split("="),s=r.trim(),i=n.includes("=")&&n.split("=")[1]?.trim().length>0;return{key:s,required:!i}})}}async function K(o){try{return He(o)?await Ke.readFile(o,"utf8"):null}catch{return null}}function Z(o,e){return o.length<=e?o:o.slice(0,e)+`
3
3
  ... (truncated)`}function Ae(o){let e=[];if(o.database&&e.push(`## Database Schema (${o.database.type})
4
4
  `+(o.database.tables?.length?`Tables: ${o.database.tables.join(", ")}
@@ -45,7 +45,7 @@ Options: ${n.join(", ")}`),{tool_use_id:e.id,content:"Question sent to user.",fo
45
45
  `);l.push({role:"assistant",content:w.content+(G?`
46
46
 
47
47
  Files created:
48
- ${G}`:"")}),l.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}return{files:a,content:p,followUp:g,tokensUsed:x,iterations:b}}function ke(o){return typeof o.generateRaw=="function"}var se=class{queue=[];resolvers=[];closed=!1;push(e){if(this.closed)return;let t=this.resolvers.shift();if(t){t({value:e,done:!1});return}this.queue.push(e)}close(){if(!this.closed){this.closed=!0;for(let e of this.resolvers.splice(0))e({value:void 0,done:!0})}}async next(){return this.queue.length?{value:this.queue.shift(),done:!1}:this.closed?{value:void 0,done:!0}:new Promise(e=>{this.resolvers.push(e)})}async*[Symbol.asyncIterator](){for(;;){let{value:e,done:t}=await this.next();if(t)return;yield e}}};async function qe(o,e,t){let n=Se.parse(t||{}),r=new Y(o);await r.load();let[s,i,l]=await Promise.all([_e(o),Re(o),Ce(o)]),a="";if(n.context7.enabled)try{a=await $e(s,e,n.context7.apiKey)}catch{}let x=r.buildMemoryContext(e),p=be(o);return v.context("memory",x?"loaded":"empty"),v.context("instructions",p?"loaded from project":"none"),{techStack:s,schemas:i,skills:l,docs:a,config:n,memoryContext:x,projectInstructions:p}}async function Ro(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:x=!0}=o,p=e;if(c.has("pre:prompt")){let u=await c.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:prompt hook");u.modified?.task&&(p=String(u.modified.task))}if(c.has("pre:generate")){let u=await c.execute("pre:generate",{event:"pre:generate",task:p,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:generate hook")}F.info("Analyzing project...");let g=await qe(t,p,{provider:s,context7:{enabled:a,apiKey:l}}),b=he(o.outputType,p);F.info(`Output type: ${b}`);let w=fe(g.skills,p,b);w.length&&F.info(`Loaded ${w.length} relevant skill(s): ${w.map(u=>u.skill.frontmatter.name).join(", ")}`);let $=Be(g,b,w.map(u=>u.skill));if(!await pe(l))throw new Error("No credentials configured. Run `agentx model` to set up.");let C=me(s,l),S=i||ce()?.model,O=[...o.sessionMessages||[],{role:"user",content:p}];F.info("Generating...");let M=ke(C),k=o.maxSteps??(M?20:5),h=await xe({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...O],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:k,enabledTools:g.config.agentic.enabledTools.filter(u=>!g.config.agentic.disabledTools.includes(u)),interactive:x,overwrite:n,dryRun:r,onProgress:u=>{u.type==="iteration_start"&&u.iteration>1&&F.info(`Step ${u.iteration}/${k}...`),u.type==="tool_call"&&v.step(0,`Tool: ${u.name}`)}});if(h.tokensUsed){let u=S||"claude-sonnet-4-20250514",L=Math.round(h.tokensUsed*.3),ie=h.tokensUsed-L;X.recordStep(1,u,L,ie)}let{content:j}=h,{followUp:_,tokensUsed:y}=h;if(h.iterations>1&&F.info(`Completed in ${h.iterations} step(s)`),c.has("post:response")){let u=await c.execute("post:response",{event:"post:response",content:j,task:p,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by post:response hook");u.modified?.content&&(j=String(u.modified.content))}if(_&&x)return{files:{written:[],skipped:[],errors:[]},content:j,outputType:b,followUp:_,tokensUsed:y};let U=new Map;for(let u of h.files)U.set(u.path,u);let A=ne(b,g.techStack,o.outputDir),T=await oe(Array.from(U.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:A}),I;if(o.heal!==!1&&!r&&T.written.length>0){let{HealEngine:u}=await import("./heal-RDZZJXDZ.js");I=await new u(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(T.written,p),!I.healed&&I.error&&await c.execute("on:error",{event:"on:error",error:new Error(I.error),task:p,cwd:t})}return c.has("post:generate")&&await c.execute("post:generate",{event:"post:generate",task:p,content:j,cwd:t}),{files:T,content:j,outputType:b,tokensUsed:y,healResult:I}}async function*Ao(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:x=!0}=o,p=e;if(c.has("pre:prompt")){let d=await c.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by pre:prompt hook"};return}d.modified?.task&&(p=String(d.modified.task))}if(c.has("pre:generate")){let d=await c.execute("pre:generate",{event:"pre:generate",task:p,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by pre:generate hook"};return}}let g=await qe(t,p,{provider:s,context7:{enabled:a,apiKey:l}}),b=he(o.outputType,p);yield{type:"context_ready",outputType:b};let w=fe(g.skills,p,b),$=Be(g,b,w.map(d=>d.skill));if(!await pe(l)){yield{type:"error",error:"No credentials configured. Run `agentx model` to set up."};return}let C=me(s,l),S=i||ce()?.model,O=ke(C),M=o.maxSteps??(O?20:5),k=[...o.sessionMessages||[],{role:"user",content:p}];if(O){let d=new se,P,f,W=(async()=>{try{P=await xe({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...k],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:M,enabledTools:g.config.agentic.enabledTools.filter(m=>!g.config.agentic.disabledTools.includes(m)),interactive:x,overwrite:n,dryRun:r,onProgress:m=>{m.type==="text_delta"&&d.push({type:"text_delta",text:m.text}),m.type==="iteration_start"&&d.push({type:"iteration",iteration:m.iteration}),m.type==="tool_call"&&d.push({type:"tool_call",name:m.name,id:m.id}),m.type==="tool_result"&&d.push({type:"tool_result",name:m.name,id:m.id,is_error:m.is_error}),m.type==="files_created"&&d.push({type:"step_complete",step:0,filesCount:m.files.length})}})}catch(m){f=m}finally{d.close()}})();for await(let m of d)yield m;if(await W,f){yield{type:"error",error:f instanceof Error?f.message:String(f)};return}if(!P){yield{type:"error",error:"Agentic loop failed without a result"};return}yield{type:"done",result:{content:P.content,files:P.files,tokensUsed:P.tokensUsed,followUp:P.followUp}};let{content:E}=P;if(c.has("post:response")){let m=await c.execute("post:response",{event:"post:response",content:E,task:p,cwd:t});if(m.blocked){yield{type:"error",error:m.message||"Blocked by post:response hook"};return}m.modified?.content&&(E=String(m.modified.content))}if(P.followUp&&x){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:E,outputType:b,followUp:P.followUp,tokensUsed:P.tokensUsed}};return}let z=new Map;for(let m of P.files)z.set(m.path,m);let le=ne(b,g.techStack,o.outputDir),V=await oe(Array.from(z.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:le}),H;if(o.heal!==!1&&!r&&V.written.length>0){let{HealEngine:m}=await import("./heal-RDZZJXDZ.js");H=await new m(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(V.written,p)}c.has("post:generate")&&await c.execute("post:generate",{event:"post:generate",task:p,content:E,cwd:t}),yield{type:"generate_result",result:{files:V,content:E,outputType:b,tokensUsed:P.tokensUsed,healResult:H}};return}let h=[{role:"system",content:$},...k],j=[],_=0,y="",U,A=0;A++,v.step(A,`Starting generation (model: ${S||"default"})`);let T;if(C.stream){let d="",P;for await(let f of C.stream(h,{model:S,maxTokens:8192}))yield f,f.type==="text_delta"&&(d+=f.text),f.type==="done"&&(P=f.result);T=P||{content:d,files:[],tokensUsed:0}}else{let d=await C.generate(h,{model:S,maxTokens:8192});d.content&&(yield{type:"text_delta",text:d.content}),yield{type:"done",result:d},T=d}_+=T.tokensUsed||0,y=T.content;let I=T.tokensUsed||0,u=S||"claude-sonnet-4-20250514",L=Math.round(I*.3),ie=I-L;if(X.recordStep(A,u,L,ie),v.api("generate",u,I),v.step(A,`Generated ${T.files.length} file(s), ${I} tokens`),T.files.length&&j.push(...T.files),T.followUp&&(U=T.followUp),yield{type:"step_complete",step:A,filesCount:T.files.length},!U&&(y.includes("[CONTINUE]")||y.includes("Next, I'll")||y.includes("Now let me")||y.includes("I'll also generate"))&&T.files.length>0){let P=T.files.map(f=>`Created: ${f.path}${f.description?` \u2014 ${f.description}`:""}`).join(`
48
+ ${G}`:"")}),l.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}return{files:a,content:p,followUp:g,tokensUsed:x,iterations:b}}function ke(o){return typeof o.generateRaw=="function"}var se=class{queue=[];resolvers=[];closed=!1;push(e){if(this.closed)return;let t=this.resolvers.shift();if(t){t({value:e,done:!1});return}this.queue.push(e)}close(){if(!this.closed){this.closed=!0;for(let e of this.resolvers.splice(0))e({value:void 0,done:!0})}}async next(){return this.queue.length?{value:this.queue.shift(),done:!1}:this.closed?{value:void 0,done:!0}:new Promise(e=>{this.resolvers.push(e)})}async*[Symbol.asyncIterator](){for(;;){let{value:e,done:t}=await this.next();if(t)return;yield e}}};async function qe(o,e,t){let n=Se.parse(t||{}),r=new Y(o);await r.load();let[s,i,l]=await Promise.all([_e(o),Re(o),Ce(o)]),a="";if(n.context7.enabled)try{a=await $e(s,e,n.context7.apiKey)}catch{}let x=r.buildMemoryContext(e),p=be(o);return v.context("memory",x?"loaded":"empty"),v.context("instructions",p?"loaded from project":"none"),{techStack:s,schemas:i,skills:l,docs:a,config:n,memoryContext:x,projectInstructions:p}}async function Ro(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:x=!0}=o,p=e;if(c.has("pre:prompt")){let u=await c.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:prompt hook");u.modified?.task&&(p=String(u.modified.task))}if(c.has("pre:generate")){let u=await c.execute("pre:generate",{event:"pre:generate",task:p,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:generate hook")}F.info("Analyzing project...");let g=await qe(t,p,{provider:s,context7:{enabled:a,apiKey:l}}),b=he(o.outputType,p);F.info(`Output type: ${b}`);let w=fe(g.skills,p,b);w.length&&F.info(`Loaded ${w.length} relevant skill(s): ${w.map(u=>u.skill.frontmatter.name).join(", ")}`);let $=Be(g,b,w.map(u=>u.skill));if(!await pe(l))throw new Error("No credentials configured. Run `agentx model` to set up.");let C=me(s,l),S=i||ce()?.model,O=[...o.sessionMessages||[],{role:"user",content:p}];F.info("Generating...");let M=ke(C),k=o.maxSteps??(M?20:5),h=await xe({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...O],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:k,enabledTools:g.config.agentic.enabledTools.filter(u=>!g.config.agentic.disabledTools.includes(u)),interactive:x,overwrite:n,dryRun:r,onProgress:u=>{u.type==="iteration_start"&&u.iteration>1&&F.info(`Step ${u.iteration}/${k}...`),u.type==="tool_call"&&v.step(0,`Tool: ${u.name}`)}});if(h.tokensUsed){let u=S||"claude-sonnet-4-20250514",L=Math.round(h.tokensUsed*.3),ie=h.tokensUsed-L;X.recordStep(1,u,L,ie)}let{content:j}=h,{followUp:_,tokensUsed:y}=h;if(h.iterations>1&&F.info(`Completed in ${h.iterations} step(s)`),c.has("post:response")){let u=await c.execute("post:response",{event:"post:response",content:j,task:p,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by post:response hook");u.modified?.content&&(j=String(u.modified.content))}if(_&&x)return{files:{written:[],skipped:[],errors:[]},content:j,outputType:b,followUp:_,tokensUsed:y};let U=new Map;for(let u of h.files)U.set(u.path,u);let A=ne(b,g.techStack,o.outputDir),T=await oe(Array.from(U.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:A}),I;if(o.heal!==!1&&!r&&T.written.length>0){let{HealEngine:u}=await import("./heal-UV5A6B5T.js");I=await new u(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(T.written,p),!I.healed&&I.error&&await c.execute("on:error",{event:"on:error",error:new Error(I.error),task:p,cwd:t})}return c.has("post:generate")&&await c.execute("post:generate",{event:"post:generate",task:p,content:j,cwd:t}),{files:T,content:j,outputType:b,tokensUsed:y,healResult:I}}async function*Ao(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:x=!0}=o,p=e;if(c.has("pre:prompt")){let d=await c.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by pre:prompt hook"};return}d.modified?.task&&(p=String(d.modified.task))}if(c.has("pre:generate")){let d=await c.execute("pre:generate",{event:"pre:generate",task:p,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by pre:generate hook"};return}}let g=await qe(t,p,{provider:s,context7:{enabled:a,apiKey:l}}),b=he(o.outputType,p);yield{type:"context_ready",outputType:b};let w=fe(g.skills,p,b),$=Be(g,b,w.map(d=>d.skill));if(!await pe(l)){yield{type:"error",error:"No credentials configured. Run `agentx model` to set up."};return}let C=me(s,l),S=i||ce()?.model,O=ke(C),M=o.maxSteps??(O?20:5),k=[...o.sessionMessages||[],{role:"user",content:p}];if(O){let d=new se,P,f,W=(async()=>{try{P=await xe({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...k],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:M,enabledTools:g.config.agentic.enabledTools.filter(m=>!g.config.agentic.disabledTools.includes(m)),interactive:x,overwrite:n,dryRun:r,onProgress:m=>{m.type==="text_delta"&&d.push({type:"text_delta",text:m.text}),m.type==="iteration_start"&&d.push({type:"iteration",iteration:m.iteration}),m.type==="tool_call"&&d.push({type:"tool_call",name:m.name,id:m.id}),m.type==="tool_result"&&d.push({type:"tool_result",name:m.name,id:m.id,is_error:m.is_error}),m.type==="files_created"&&d.push({type:"step_complete",step:0,filesCount:m.files.length})}})}catch(m){f=m}finally{d.close()}})();for await(let m of d)yield m;if(await W,f){yield{type:"error",error:f instanceof Error?f.message:String(f)};return}if(!P){yield{type:"error",error:"Agentic loop failed without a result"};return}yield{type:"done",result:{content:P.content,files:P.files,tokensUsed:P.tokensUsed,followUp:P.followUp}};let{content:E}=P;if(c.has("post:response")){let m=await c.execute("post:response",{event:"post:response",content:E,task:p,cwd:t});if(m.blocked){yield{type:"error",error:m.message||"Blocked by post:response hook"};return}m.modified?.content&&(E=String(m.modified.content))}if(P.followUp&&x){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:E,outputType:b,followUp:P.followUp,tokensUsed:P.tokensUsed}};return}let z=new Map;for(let m of P.files)z.set(m.path,m);let le=ne(b,g.techStack,o.outputDir),V=await oe(Array.from(z.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:le}),H;if(o.heal!==!1&&!r&&V.written.length>0){let{HealEngine:m}=await import("./heal-UV5A6B5T.js");H=await new m(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(V.written,p)}c.has("post:generate")&&await c.execute("post:generate",{event:"post:generate",task:p,content:E,cwd:t}),yield{type:"generate_result",result:{files:V,content:E,outputType:b,tokensUsed:P.tokensUsed,healResult:H}};return}let h=[{role:"system",content:$},...k],j=[],_=0,y="",U,A=0;A++,v.step(A,`Starting generation (model: ${S||"default"})`);let T;if(C.stream){let d="",P;for await(let f of C.stream(h,{model:S,maxTokens:8192}))yield f,f.type==="text_delta"&&(d+=f.text),f.type==="done"&&(P=f.result);T=P||{content:d,files:[],tokensUsed:0}}else{let d=await C.generate(h,{model:S,maxTokens:8192});d.content&&(yield{type:"text_delta",text:d.content}),yield{type:"done",result:d},T=d}_+=T.tokensUsed||0,y=T.content;let I=T.tokensUsed||0,u=S||"claude-sonnet-4-20250514",L=Math.round(I*.3),ie=I-L;if(X.recordStep(A,u,L,ie),v.api("generate",u,I),v.step(A,`Generated ${T.files.length} file(s), ${I} tokens`),T.files.length&&j.push(...T.files),T.followUp&&(U=T.followUp),yield{type:"step_complete",step:A,filesCount:T.files.length},!U&&(y.includes("[CONTINUE]")||y.includes("Next, I'll")||y.includes("Now let me")||y.includes("I'll also generate"))&&T.files.length>0){let P=T.files.map(f=>`Created: ${f.path}${f.description?` \u2014 ${f.description}`:""}`).join(`
49
49
  `);for(h.push({role:"assistant",content:y+(P?`
50
50
 
51
51
  Files created:
@@ -53,7 +53,7 @@ ${P}`:"")}),h.push({role:"user",content:"Continue generating the remaining files
53
53
  `);h.push({role:"assistant",content:f.content+(H?`
54
54
 
55
55
  Files created:
56
- ${H}`:"")}),h.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}}if(c.has("post:response")){let d=await c.execute("post:response",{event:"post:response",content:y,task:p,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by post:response hook"};return}d.modified?.content&&(y=String(d.modified.content))}if(U&&x){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:y,outputType:b,followUp:U,tokensUsed:_}};return}let ve=new Map;for(let d of j)ve.set(d.path,d);let ze=ne(b,g.techStack,o.outputDir),ae=await oe(Array.from(ve.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:ze}),B;if(o.heal!==!1&&!r&&ae.written.length>0){let{HealEngine:d}=await import("./heal-RDZZJXDZ.js");B=await new d(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(ae.written,p),!B.healed&&B.error&&await c.execute("on:error",{event:"on:error",error:new Error(B.error),task:p,cwd:t})}c.has("post:generate")&&await c.execute("post:generate",{event:"post:generate",task:p,content:y,cwd:t}),yield{type:"generate_result",result:{files:ae,content:y,outputType:b,tokensUsed:_,healResult:B}}}function Be(o,e,t){let n=[];n.push(`You are agentx, an agentic code generation tool. You generate high-quality, production-ready output for any tech stack.
56
+ ${H}`:"")}),h.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}}if(c.has("post:response")){let d=await c.execute("post:response",{event:"post:response",content:y,task:p,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by post:response hook"};return}d.modified?.content&&(y=String(d.modified.content))}if(U&&x){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:y,outputType:b,followUp:U,tokensUsed:_}};return}let ve=new Map;for(let d of j)ve.set(d.path,d);let ze=ne(b,g.techStack,o.outputDir),ae=await oe(Array.from(ve.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:ze}),B;if(o.heal!==!1&&!r&&ae.written.length>0){let{HealEngine:d}=await import("./heal-UV5A6B5T.js");B=await new d(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(ae.written,p),!B.healed&&B.error&&await c.execute("on:error",{event:"on:error",error:new Error(B.error),task:p,cwd:t})}c.has("post:generate")&&await c.execute("post:generate",{event:"post:generate",task:p,content:y,cwd:t}),yield{type:"generate_result",result:{files:ae,content:y,outputType:b,tokensUsed:_,healResult:B}}}function Be(o,e,t){let n=[];n.push(`You are agentx, an agentic code generation tool. You generate high-quality, production-ready output for any tech stack.
57
57
 
58
58
  Your primary tool is \`create_files\` \u2014 use it to output all generated code, documents, and configs as files.
59
59
  If the request is ambiguous or you need critical information to proceed correctly, use \`ask_user\` to ask a clarifying question.
@@ -103,4 +103,4 @@ ${o.projectInstructions}`),o.memoryContext&&n.push(o.memoryContext),n.push(`# Ou
103
103
  Generate output appropriate for: ${e}. Use the \`create_files\` tool to output all files.`),n.join(`
104
104
 
105
105
  `)}export{Se as a,pt as b,dt as c,Re as d,Ae as e,$e as f,Ie as g,he as h,Oe as i,Ue as j,ye as k,ee as l,N as m,Y as n,Ne as o,be as p,we as q,Q as r,qe as s,Ro as t,Ao as u};
106
- //# sourceMappingURL=chunk-KVWUPUR5.js.map
106
+ //# sourceMappingURL=chunk-F73GPYCO.js.map
@@ -1,5 +1,5 @@
1
1
  import{a as c,b as w,d as x}from"./chunk-M7HKBG3V.js";import{z as u}from"zod";var f=["pre:generate","post:generate","pre:file-write","post:file-write","pre:prompt","post:response","pre:command","on:error","pre:tool-call","post:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run","post:cron-run"],$=["pre:generate","pre:file-write","pre:prompt","post:response","pre:command","pre:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run"],S=u.object({name:u.string(),type:u.enum(["command","prompt","script"]),command:u.string().optional(),prompt:u.string().optional(),provider:u.enum(["claude-code","claude","openai","ollama","custom"]).optional(),model:u.string().optional(),script:u.string().optional(),priority:u.number().default(100),enabled:u.boolean().default(!0)});var E={"claude-sonnet":{input:3,output:15},"claude-opus":{input:15,output:75},"claude-haiku":{input:.25,output:1.25}};function O(r){let o=r.toLowerCase();return o.includes("opus")?"claude-opus":o.includes("haiku")?"claude-haiku":"claude-sonnet"}var y=class{steps=[];models=new Map;recordStep(o,e,t,n){let s=O(e),i=E[s]||E["claude-sonnet"],p=t/1e6*i.input+n/1e6*i.output;this.steps.push({step:o,model:e,inputTokens:t,outputTokens:n,cost:p,timestamp:Date.now()});let a=this.models.get(e)||{inputTokens:0,outputTokens:0,cost:0,steps:0};a.inputTokens+=t,a.outputTokens+=n,a.cost+=p,a.steps++,this.models.set(e,a)}getSummary(){let o=0,e=0,t=0;for(let s of this.steps)o+=s.inputTokens,e+=s.outputTokens,t+=s.cost;let n={};for(let[s,i]of this.models)n[s]={...i};return{totalInputTokens:o,totalOutputTokens:e,totalTokens:o+e,totalCost:t,steps:[...this.steps],models:n}}reset(){this.steps=[],this.models.clear()}},D=new y;import l from"chalk";var d=!1;function R(r){d=r}function U(){return d}function k(){return new Date().toISOString().slice(11,23)}var g={log(...r){d&&console.log(l.dim(`[${k()}]`),...r)},step(r,o){d&&console.log(l.dim(`[${k()}]`),l.blue(`[step ${r}]`),o)},hook(r,o,e){d&&console.log(l.dim(`[${k()}]`),l.magenta("[hook]"),`${r} (${o}ms) \u2192 ${e}`)},api(r,o,e){if(!d)return;let t=e?` (${e} tokens)`:"";console.log(l.dim(`[${k()}]`),l.yellow("[api]"),`${r} \u2192 ${o}${t}`)},tokens(r,o,e){d&&console.log(l.dim(`[${k()}]`),l.green("[tokens]"),`in: ${r.toLocaleString()}, out: ${o.toLocaleString()}, cost: $${e.toFixed(4)}`)},context(r,o){d&&console.log(l.dim(`[${k()}]`),l.cyan(`[${r}]`),o)}};function j(r,o){let e=[];if(e.push(`# Session: ${r.id}`),e.push(""),e.push(`- **Created**: ${r.createdAt}`),e.push(`- **Updated**: ${r.updatedAt}`),e.push(`- **CWD**: ${r.cwd}`),e.push(`- **Messages**: ${r.messages.length}`),e.push(`- **Tokens**: ${r.tokensUsed.toLocaleString()}`),e.push(""),r.filesGenerated.length){e.push("## Files Generated"),e.push("");for(let t of r.filesGenerated)e.push(`- \`${t}\``);e.push("")}if(r.messages.length){e.push("## Conversation"),e.push("");for(let t of r.messages){if(t.role==="system")continue;let n=t.role==="user"?"**User**":"**Assistant**";e.push(`### ${n}`),e.push(""),t.role,e.push(t.content),e.push("")}}if(o){if(e.push("## Cost Summary"),e.push(""),e.push(`- **Total tokens**: ${o.totalTokens.toLocaleString()}`),e.push(` - Input: ${o.totalInputTokens.toLocaleString()}`),e.push(` - Output: ${o.totalOutputTokens.toLocaleString()}`),e.push(`- **Total cost**: $${o.totalCost.toFixed(4)}`),e.push(""),Object.keys(o.models).length){e.push("### Per Model"),e.push(""),e.push("| Model | Input | Output | Cost | Steps |"),e.push("|-------|-------|--------|------|-------|");for(let[t,n]of Object.entries(o.models))e.push(`| ${t} | ${n.inputTokens.toLocaleString()} | ${n.outputTokens.toLocaleString()} | $${n.cost.toFixed(4)} | ${n.steps} |`);e.push("")}if(o.steps.length){e.push("### Per Step"),e.push(""),e.push("| Step | Model | Input | Output | Cost |"),e.push("|------|-------|-------|--------|------|");for(let t of o.steps)e.push(`| ${t.step} | ${t.model} | ${t.inputTokens.toLocaleString()} | ${t.outputTokens.toLocaleString()} | $${t.cost.toFixed(4)} |`);e.push("")}}return e.join(`
2
- `)}import{execa as N}from"execa";var h=class{hooks=new Map;register(o,e){if(!e.enabled)return;let t=this.createHandler(e),n={event:o,definition:e,handler:t},s=this.hooks.get(o)||[];s.push(n),s.sort((i,p)=>i.definition.priority-p.definition.priority),this.hooks.set(o,s)}async execute(o,e){let t=this.hooks.get(o);if(!t?.length)return{};let n=$.includes(o),s={};for(let i of t){let p=Date.now();try{let a=await i.handler({...e,...s}),m=Date.now()-p;if(a.modified&&(s={...s,...a.modified}),n&&a.blocked)return g.hook(i.definition.name,m,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${i.definition.name}`,modified:s};g.hook(i.definition.name,m,"ok")}catch(a){let m=Date.now()-p;if(g.hook(i.definition.name,m,`error: ${a.message}`),c.warn(`Hook "${i.definition.name}" failed: ${a.message}`),n)return{blocked:!0,message:`Hook "${i.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(s).length?s:void 0}}has(o){return!!this.hooks.get(o)?.length}clear(){this.hooks.clear()}createHandler(o){switch(o.type){case"command":return this.createCommandHandler(o);case"script":return this.createScriptHandler(o);case"prompt":return this.createPromptHandler(o);default:throw new Error(`Unknown hook type: ${o.type}`)}}createCommandHandler(o){return async e=>{if(!o.command)return{};let t=o.command;t=t.replace(/\{\{(\w+)\}\}/g,(s,i)=>String(e[i]??""));let n=await N("sh",["-c",t],{cwd:e.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return n.exitCode!==0?{blocked:!0,message:n.stderr||n.stdout||`Command hook "${o.name}" failed`}:{}}}createScriptHandler(o){return async e=>{if(!o.script)return{};let n=await import(o.script.startsWith("/")?o.script:`${e.cwd||process.cwd()}/${o.script}`),s=n.default||n.handler||n;return typeof s=="function"?await s(e):{}}}createPromptHandler(o){return async e=>{if(!o.prompt)return{};let t=o.provider||w()?.provider||"claude-code",n=x();if(!n&&t!=="claude-code")return c.warn(`Prompt hook "${o.name}" skipped: no credentials available for provider "${t}"`),{};try{let{createProvider:s}=await import("./providers-Q3U3ONJO.js"),i=s(t,n?.token),p=o.prompt;p=p.replace(/\{\{(\w+)\}\}/g,(A,C)=>String(e[C]??""));let a=`You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).
2
+ `)}import{execa as N}from"execa";var h=class{hooks=new Map;register(o,e){if(!e.enabled)return;let t=this.createHandler(e),n={event:o,definition:e,handler:t},s=this.hooks.get(o)||[];s.push(n),s.sort((i,p)=>i.definition.priority-p.definition.priority),this.hooks.set(o,s)}async execute(o,e){let t=this.hooks.get(o);if(!t?.length)return{};let n=$.includes(o),s={};for(let i of t){let p=Date.now();try{let a=await i.handler({...e,...s}),m=Date.now()-p;if(a.modified&&(s={...s,...a.modified}),n&&a.blocked)return g.hook(i.definition.name,m,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${i.definition.name}`,modified:s};g.hook(i.definition.name,m,"ok")}catch(a){let m=Date.now()-p;if(g.hook(i.definition.name,m,`error: ${a.message}`),c.warn(`Hook "${i.definition.name}" failed: ${a.message}`),n)return{blocked:!0,message:`Hook "${i.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(s).length?s:void 0}}has(o){return!!this.hooks.get(o)?.length}clear(){this.hooks.clear()}createHandler(o){switch(o.type){case"command":return this.createCommandHandler(o);case"script":return this.createScriptHandler(o);case"prompt":return this.createPromptHandler(o);default:throw new Error(`Unknown hook type: ${o.type}`)}}createCommandHandler(o){return async e=>{if(!o.command)return{};let t=o.command;t=t.replace(/\{\{(\w+)\}\}/g,(s,i)=>String(e[i]??""));let n=await N("sh",["-c",t],{cwd:e.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return n.exitCode!==0?{blocked:!0,message:n.stderr||n.stdout||`Command hook "${o.name}" failed`}:{}}}createScriptHandler(o){return async e=>{if(!o.script)return{};let n=await import(o.script.startsWith("/")?o.script:`${e.cwd||process.cwd()}/${o.script}`),s=n.default||n.handler||n;return typeof s=="function"?await s(e):{}}}createPromptHandler(o){return async e=>{if(!o.prompt)return{};let t=o.provider||w()?.provider||"claude-code",n=x();if(!n&&t!=="claude-code")return c.warn(`Prompt hook "${o.name}" skipped: no credentials available for provider "${t}"`),{};try{let{createProvider:s}=await import("./providers-AVYG63KK.js"),i=s(t,n?.token),p=o.prompt;p=p.replace(/\{\{(\w+)\}\}/g,(A,C)=>String(e[C]??""));let a=`You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).
3
3
 
4
4
  Response format:
5
5
  {"action": "allow", "message": "optional explanation"}
@@ -9,4 +9,4 @@ OR
9
9
  {"action": "allow", "message": "optional", "modified": {"key": "new value"}}
10
10
 
11
11
  The "modified" field is optional and can contain updated values to pass forward.`,v=(await i.generate([{role:"system",content:a},{role:"user",content:p}],{model:o.model,maxTokens:1024})).content.trim().match(/\{[\s\S]*\}/);if(!v)return c.warn(`Prompt hook "${o.name}": LLM response was not valid JSON, allowing`),{};let H=JSON.parse(v[0]);return H.action==="block"?{blocked:!0,message:H.message||`Blocked by prompt hook: ${o.name}`}:H.modified?{modified:H.modified}:{}}catch(s){return c.warn(`Prompt hook "${o.name}" failed: ${s.message}`),{}}}}};import{existsSync as T,readFileSync as P,readdirSync as L}from"fs";import b from"path";function M(r,o){_(r,o),I(r,o)}function _(r,o){let e=b.join(r,"agentx.config.json");if(T(e))try{let t=JSON.parse(P(e,"utf8"));if(!t.hooks)return;for(let[n,s]of Object.entries(t.hooks)){if(!f.includes(n)){c.warn(`Unknown hook event in config: ${n}`);continue}let i=n;if(Array.isArray(s))for(let p of s)try{let a=S.parse(p);o.register(i,a)}catch(a){c.warn(`Invalid hook definition for ${i}: ${a.message}`)}}}catch(t){c.warn(`Failed to load hooks from config: ${t.message}`)}}function I(r,o){let e=b.join(r,".agentx","hooks");if(T(e))try{let t=L(e).filter(n=>n.endsWith(".ts")||n.endsWith(".js")||n.endsWith(".mjs"));for(let n of t){let s=n.replace(/\.(ts|js|mjs)$/,"").split(".");if(s.length<2){c.warn(`Hook file "${n}" should be named <event>.<name>.<ext>`);continue}let i=s[0],p=s.slice(1).join("."),a=i.replace(/-/g,":");if(!f.includes(a)){let m=i.replace("-",":");if(!f.includes(m)){c.warn(`Unknown hook event in filename: ${n}`);continue}o.register(m,{name:p,type:"script",script:b.join(e,n),priority:100,enabled:!0});continue}o.register(a,{name:p,type:"script",script:b.join(e,n),priority:100,enabled:!0})}}catch(t){c.warn(`Failed to load hooks from directory: ${t.message}`)}}var le=new h;export{f as a,$ as b,y as c,D as d,R as e,U as f,g,j as h,h as i,M as j,le as k};
12
- //# sourceMappingURL=chunk-PCAYW54Q.js.map
12
+ //# sourceMappingURL=chunk-Z4GC5D6D.js.map
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{d as N,e as H,p as L,q as z}from"./chunk-S74N276K.js";import"./chunk-PCAYW54Q.js";import"./chunk-M7HKBG3V.js";import{a as K}from"./chunk-MDR7SH7F.js";import{Command as ne}from"commander";import{Command as X}from"commander";import c from"chalk";var x=new X().name("daemon").description("manage the agentx daemon \u2014 start, stop, status, logs");x.command("start").description("start the daemon (default if no subcommand)").option("-c, --config <path>","path to agentx.json").option("-d, --detach","run in background (detached)").option("--port <port>","override bind port").action(async e=>{if(e.detach){let{spawn:o}=await import("child_process"),s=["dist/cli.js","daemon","start"];e.config&&s.push("-c",e.config),e.port&&s.push("--port",e.port);let t=o("node",s,{detached:!0,stdio:["ignore","ignore","ignore"],cwd:process.cwd()});t.unref();let{writeFileSync:i}=await import("fs");i("/tmp/agentx-daemon.pid",String(t.pid)),console.log(c.green(`Daemon started in background (PID: ${t.pid})`)),console.log(c.dim(" Logs: tail -f /tmp/agentx-daemon.log")),console.log(c.dim(" Stop: agentx daemon stop"));return}await new L(e.config).start()});x.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:n}=await import("fs"),o="/tmp/agentx-daemon.pid";n(o)||console.log(c.yellow("No daemon PID file found. Trying to find process..."));try{if(n(o)){let t=parseInt(e(o,"utf-8").trim(),10);process.kill(t,"SIGTERM"),console.log(c.green(`Daemon stopped (PID: ${t})`));return}}catch{}let{execSync:s}=await import("child_process");try{s("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(c.green("Daemon stopped"))}catch{console.log(c.yellow("No daemon process found"))}});x.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let n=N(e.config),[o,s]=n.node.bind.split(":"),t=`http://${o||"127.0.0.1"}:${s}/health`,l=await(await fetch(t,{signal:AbortSignal.timeout(3e3)})).json();if(e.json){console.log(JSON.stringify(l,null,2));return}console.log(),console.log(c.bold(` ${l.node.name}`)+c.dim(` (${l.node.id})`)),console.log(c.green(" Status: running")+c.dim(` \u2014 uptime ${Q(l.uptime)}`)),console.log(),console.log(c.bold(" Agents:"));for(let r of l.agents){let f=r.active>0?c.yellow(` [${r.active} active]`):"",v=r.errors>0?c.red(` (${r.errors} errors)`):"";console.log(` ${c.cyan(r.name)} ${c.dim(`(${r.tier})`)}${f}${v}`),console.log(c.dim(` ${r.workspace}`))}let d=l.crons.filter(r=>r.enabled);if(l.crons.length){console.log(),console.log(c.bold(` Crons: ${d.length} enabled / ${l.crons.length} total`));for(let r of l.crons){let f=r.enabled?c.green("\u25CF"):c.dim("\u25CB"),v=r.nextRun?c.dim(` next: ${new Date(r.nextRun).toLocaleTimeString()}`):"";console.log(` ${f} ${r.id}${v}`)}}if(l.mesh?.length){console.log(),console.log(c.bold(" Mesh:"));for(let r of l.mesh){let f=r.healthy?c.green("\u25CF"):c.red("\u25CF"),v=r.skills?.length?c.dim(` (${r.skills.length} agents)`):"";console.log(` ${f} ${r.peer} ${c.dim(r.peerUrl)}${v}`)}}console.log()}catch(n){if(n.cause?.code==="ECONNREFUSED"||n.name==="TimeoutError")console.log(c.red(" Daemon is not running")),console.log(c.dim(" Start with: agentx daemon start"));else try{let o=N(e.config),s=H(o);if(console.log(),console.log(c.bold(` ${o.node.name}`)+c.dim(` (${o.node.id})`)),console.log(c.yellow(" Status: stopped")),console.log(c.dim(` ${Object.keys(o.agents).length} agents, ${Object.keys(o.crons).length} crons configured`)),s.length){console.log();for(let t of s)console.log(c.yellow(` \u26A0 ${t}`))}console.log()}catch(o){console.log(c.red(` ${o.message}`))}}});x.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:n,spawn:o}=await import("child_process"),s="/tmp/agentx-daemon.log",{existsSync:t}=await import("fs");if(!t(s)){console.log(c.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let i=o("tail",["-f","-n",e.lines,s],{stdio:"inherit"});process.on("SIGINT",()=>{i.kill(),process.exit(0)})}else n(`tail -n ${e.lines} ${s}`,{stdio:"inherit"})});x.command("send <agent> <message...>").description("send a task to an agent via the daemon API").option("-c, --config <path>","path to agentx.json").option("--peer <peer>","send to a mesh peer's agent").option("--json","output raw JSON response").action(async(e,n,o)=>{let s=n.join(" ");try{let t=N(o.config),[i,l]=t.node.bind.split(":"),d=`http://${i||"127.0.0.1"}:${l}`,r,f;o.peer?(r=`${d}/mesh/task`,f={peer:o.peer,message:s,agent:e}):(r=`${d}/task`,f={agent:e,message:s}),console.log(c.dim(` Sending to ${o.peer?`${o.peer}/${e}`:e}...`));let $=await(await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)})).json();o.json?console.log(JSON.stringify($,null,2)):$.error?console.log(c.red(` Error: ${$.error}`)):(console.log(),console.log($.content||$.response||"No response"),$.duration&&console.log(c.dim(`
2
+ import{d as N,e as H,p as L,q as z}from"./chunk-AIBBZF4E.js";import"./chunk-Z4GC5D6D.js";import"./chunk-M7HKBG3V.js";import{a as K}from"./chunk-4YCH6IZV.js";import{Command as ne}from"commander";import{Command as X}from"commander";import c from"chalk";var x=new X().name("daemon").description("manage the agentx daemon \u2014 start, stop, status, logs");x.command("start").description("start the daemon (default if no subcommand)").option("-c, --config <path>","path to agentx.json").option("-d, --detach","run in background (detached)").option("--port <port>","override bind port").action(async e=>{if(e.detach){let{spawn:o}=await import("child_process"),s=["dist/cli.js","daemon","start"];e.config&&s.push("-c",e.config),e.port&&s.push("--port",e.port);let t=o("node",s,{detached:!0,stdio:["ignore","ignore","ignore"],cwd:process.cwd()});t.unref();let{writeFileSync:i}=await import("fs");i("/tmp/agentx-daemon.pid",String(t.pid)),console.log(c.green(`Daemon started in background (PID: ${t.pid})`)),console.log(c.dim(" Logs: tail -f /tmp/agentx-daemon.log")),console.log(c.dim(" Stop: agentx daemon stop"));return}await new L(e.config).start()});x.command("stop").description("stop the running daemon").action(async()=>{let{readFileSync:e,existsSync:n}=await import("fs"),o="/tmp/agentx-daemon.pid";n(o)||console.log(c.yellow("No daemon PID file found. Trying to find process..."));try{if(n(o)){let t=parseInt(e(o,"utf-8").trim(),10);process.kill(t,"SIGTERM"),console.log(c.green(`Daemon stopped (PID: ${t})`));return}}catch{}let{execSync:s}=await import("child_process");try{s("pkill -f 'node dist/cli.js daemon'",{stdio:"ignore"}),console.log(c.green("Daemon stopped"))}catch{console.log(c.yellow("No daemon process found"))}});x.command("status").alias("st").description("show daemon status, agents, crons, and mesh").option("-c, --config <path>","path to agentx.json").option("--json","output as JSON").action(async e=>{try{let n=N(e.config),[o,s]=n.node.bind.split(":"),t=`http://${o||"127.0.0.1"}:${s}/health`,l=await(await fetch(t,{signal:AbortSignal.timeout(3e3)})).json();if(e.json){console.log(JSON.stringify(l,null,2));return}console.log(),console.log(c.bold(` ${l.node.name}`)+c.dim(` (${l.node.id})`)),console.log(c.green(" Status: running")+c.dim(` \u2014 uptime ${Q(l.uptime)}`)),console.log(),console.log(c.bold(" Agents:"));for(let r of l.agents){let f=r.active>0?c.yellow(` [${r.active} active]`):"",v=r.errors>0?c.red(` (${r.errors} errors)`):"";console.log(` ${c.cyan(r.name)} ${c.dim(`(${r.tier})`)}${f}${v}`),console.log(c.dim(` ${r.workspace}`))}let d=l.crons.filter(r=>r.enabled);if(l.crons.length){console.log(),console.log(c.bold(` Crons: ${d.length} enabled / ${l.crons.length} total`));for(let r of l.crons){let f=r.enabled?c.green("\u25CF"):c.dim("\u25CB"),v=r.nextRun?c.dim(` next: ${new Date(r.nextRun).toLocaleTimeString()}`):"";console.log(` ${f} ${r.id}${v}`)}}if(l.mesh?.length){console.log(),console.log(c.bold(" Mesh:"));for(let r of l.mesh){let f=r.healthy?c.green("\u25CF"):c.red("\u25CF"),v=r.skills?.length?c.dim(` (${r.skills.length} agents)`):"";console.log(` ${f} ${r.peer} ${c.dim(r.peerUrl)}${v}`)}}console.log()}catch(n){if(n.cause?.code==="ECONNREFUSED"||n.name==="TimeoutError")console.log(c.red(" Daemon is not running")),console.log(c.dim(" Start with: agentx daemon start"));else try{let o=N(e.config),s=H(o);if(console.log(),console.log(c.bold(` ${o.node.name}`)+c.dim(` (${o.node.id})`)),console.log(c.yellow(" Status: stopped")),console.log(c.dim(` ${Object.keys(o.agents).length} agents, ${Object.keys(o.crons).length} crons configured`)),s.length){console.log();for(let t of s)console.log(c.yellow(` \u26A0 ${t}`))}console.log()}catch(o){console.log(c.red(` ${o.message}`))}}});x.command("logs").description("tail daemon logs").option("-n, --lines <n>","number of lines","50").option("-f, --follow","follow log output",!1).action(async e=>{let{execSync:n,spawn:o}=await import("child_process"),s="/tmp/agentx-daemon.log",{existsSync:t}=await import("fs");if(!t(s)){console.log(c.yellow("No log file found at /tmp/agentx-daemon.log"));return}if(e.follow){let i=o("tail",["-f","-n",e.lines,s],{stdio:"inherit"});process.on("SIGINT",()=>{i.kill(),process.exit(0)})}else n(`tail -n ${e.lines} ${s}`,{stdio:"inherit"})});x.command("send <agent> <message...>").description("send a task to an agent via the daemon API").option("-c, --config <path>","path to agentx.json").option("--peer <peer>","send to a mesh peer's agent").option("--json","output raw JSON response").action(async(e,n,o)=>{let s=n.join(" ");try{let t=N(o.config),[i,l]=t.node.bind.split(":"),d=`http://${i||"127.0.0.1"}:${l}`,r,f;o.peer?(r=`${d}/mesh/task`,f={peer:o.peer,message:s,agent:e}):(r=`${d}/task`,f={agent:e,message:s}),console.log(c.dim(` Sending to ${o.peer?`${o.peer}/${e}`:e}...`));let $=await(await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)})).json();o.json?console.log(JSON.stringify($,null,2)):$.error?console.log(c.red(` Error: ${$.error}`)):(console.log(),console.log($.content||$.response||"No response"),$.duration&&console.log(c.dim(`
3
3
  (${($.duration/1e3).toFixed(1)}s)`)))}catch(t){console.log(c.red(` Failed: ${t.message}`)),console.log(c.dim(" Is the daemon running? Try: agentx daemon status"))}});x.command("deploy <host>").description("deploy agentx to a remote server via rsync").option("-i, --identity <key>","SSH identity file").option("-u, --user <user>","SSH user","clawd").option("-p, --path <path>","remote agentx path","~/agentx").option("--restart","restart remote daemon after deploy",!1).action(async(e,n)=>{let{execSync:o}=await import("child_process"),s=n.identity?`-e "ssh -i ${n.identity}"`:"",t=`${n.user}@${e}:${n.path}/dist/`;console.log(c.dim(` Deploying to ${n.user}@${e}:${n.path}...`));try{if(o(`rsync -avz --delete ${s} dist/ ${t}`,{stdio:"inherit",cwd:process.cwd()}),console.log(c.green(" Deploy complete")),n.restart){console.log(c.dim(" Restarting remote daemon..."));let i=n.identity?`ssh -i ${n.identity}`:"ssh";o(`${i} ${n.user}@${e} "pkill -f 'node dist/cli.js daemon' 2>/dev/null; sleep 2; cd ${n.path} && nohup node dist/cli.js daemon start > /tmp/agentx-daemon.log 2>&1 &"`,{stdio:"inherit"}),console.log(c.green(" Remote daemon restarted"))}}catch(i){console.log(c.red(` Deploy failed: ${i.message}`))}});x.action(async e=>{await new L(e.config).start()});function Q(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:e<86400?`${Math.round(e/3600)}h ${Math.round(e%3600/60)}m`:`${Math.round(e/86400)}d ${Math.round(e%86400/3600)}h`}import{Command as V}from"commander";import h from"chalk";import{existsSync as I,readFileSync as Z,writeFileSync as _,mkdirSync as G}from"fs";import{resolve as j}from"path";var q=new V().name("init").description("initialize agentx configuration in the current directory").option("--force","overwrite existing config").action(async e=>{let n=process.cwd(),o=j(n,"agentx.json"),s=j(n,".env"),t=j(n,".agentx/sessions");if(console.log(),console.log(h.bold(" agentx init")),console.log(),I(o)&&!e.force){console.log(h.yellow(" agentx.json already exists. Use --force to overwrite.")),console.log();return}let i=[j(n,"agentx.example.json"),j(n,"node_modules/agentix-cli/agentx.example.json")],l;for(let r of i)if(I(r)){l=Z(r,"utf-8");break}l||(l=JSON.stringify({node:{id:K("os").hostname().toLowerCase().replace(/[^a-z0-9-]/g,"-"),name:K("os").hostname(),bind:"127.0.0.1:18800"},providers:{claude:{apiKey:"${ANTHROPIC_API_KEY}"}},agents:{assistant:{name:"Assistant",workspace:n,tier:"claude-code",model:"claude-sonnet-4-6",mentions:["@assistant","assistant"],maxConcurrent:2,systemPrompt:"You are a helpful assistant.",permissionMode:"default"}},channels:{telegram:{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},whatsapp:{enabled:!1}},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}}},null,2)),_(o,l),console.log(h.green(" \u2713 Created agentx.json")),I(s)||(_(s,["# AgentX environment variables","# ANTHROPIC_API_KEY=sk-ant-...","# TG_BOT_TOKEN=123456:ABC...","# MESH_TOKEN=your-mesh-secret",""].join(`
4
4
  `)),console.log(h.green(" \u2713 Created .env template"))),I(t)||(G(t,{recursive:!0}),console.log(h.green(" \u2713 Created .agentx/sessions/")));let d=j(n,".claude");I(d)||(G(d,{recursive:!0}),console.log(h.green(" \u2713 Created .claude/"))),console.log(),console.log(h.bold(" Next steps:")),console.log(` 1. Edit ${h.cyan("agentx.json")} \u2014 configure agents, channels, crons`),console.log(` 2. Edit ${h.cyan(".env")} \u2014 add API keys and bot tokens`),console.log(` 3. Run ${h.cyan("agentx daemon start")} \u2014 start the daemon`),console.log(` 4. Run ${h.cyan("agentx daemon status")} \u2014 verify everything`),console.log()});import{Command as S}from"commander";import a from"chalk";import k from"prompts";import{readFileSync as R,writeFileSync as B,existsSync as y,mkdirSync as C,cpSync as W,readdirSync as ee}from"fs";import{resolve as m,join as T}from"path";function p(){let e=m(process.cwd(),"agentx.json");if(!y(e))throw new Error("No agentx.json found. Run: agentx init");return JSON.parse(R(e,"utf-8"))}function w(e){B(m(process.cwd(),"agentx.json"),JSON.stringify(e,null,2))}var P=new S().name("agent").description("manage agents \u2014 add, list, remove");P.command("list").alias("ls").description("list configured agents").action(()=>{let e=p();console.log();for(let[n,o]of Object.entries(e.agents||{})){let s=o.mentions?.join(", ")||"";console.log(` ${a.cyan(n)} \u2014 ${o.name} (${o.tier})`),console.log(a.dim(` workspace: ${o.workspace}`)),s&&console.log(a.dim(` mentions: ${s}`))}console.log()});P.command("add").description("add a new agent interactively").action(async()=>{let e=p(),n=await k([{type:"text",name:"id",message:"Agent ID (kebab-case)",validate:d=>/^[a-z0-9-]+$/.test(d)||"Use lowercase, numbers, hyphens"},{type:"text",name:"name",message:"Display name"},{type:"text",name:"workspace",message:"Workspace path",initial:m(process.cwd(),"agents/")},{type:"select",name:"tier",message:"Execution tier",choices:[{title:"claude-code (subscription, full features)",value:"claude-code"},{title:"sdk (API key, programmatic)",value:"sdk"},{title:"orchestrator (any provider)",value:"orchestrator"}]},{type:"text",name:"model",message:"Model",initial:"claude-sonnet-4-6"},{type:"list",name:"mentions",message:"Mention patterns (comma-separated)",separator:","},{type:"number",name:"maxConcurrent",message:"Max concurrent tasks",initial:2},{type:"text",name:"systemPrompt",message:"System prompt"}]);if(!n.id)return;let o=n.workspace.endsWith(n.id)?n.workspace:T(n.workspace,n.id);C(m(o,".claude/skills"),{recursive:!0});let s=`# ${n.name}
5
5
 
@@ -1,2 +1,2 @@
1
- import{a}from"./chunk-X7UN6JAA.js";import"./chunk-SFQUP3BP.js";import"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-MDR7SH7F.js";export{a as HealEngine};
2
- //# sourceMappingURL=heal-RDZZJXDZ.js.map
1
+ import{a}from"./chunk-X7UN6JAA.js";import"./chunk-SFQUP3BP.js";import"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-4YCH6IZV.js";export{a as HealEngine};
2
+ //# sourceMappingURL=heal-UV5A6B5T.js.map
package/dist/index.d.ts CHANGED
@@ -1868,6 +1868,11 @@ interface AgentTask {
1868
1868
  channel?: string;
1869
1869
  sender?: string;
1870
1870
  group?: string;
1871
+ /** Attached media file (image, audio, video, document) */
1872
+ mediaPath?: string;
1873
+ mediaType?: string;
1874
+ /** Text of the message being replied to */
1875
+ replyToText?: string;
1871
1876
  conversationHistory?: Array<{
1872
1877
  role: string;
1873
1878
  content: string;
@@ -1970,7 +1975,13 @@ interface IncomingMessage {
1970
1975
  };
1971
1976
  text: string;
1972
1977
  replyTo?: string;
1978
+ replyToText?: string;
1973
1979
  timestamp: Date;
1980
+ media?: {
1981
+ path: string;
1982
+ type: string;
1983
+ fileName?: string;
1984
+ };
1974
1985
  raw?: unknown;
1975
1986
  resolvedAgent?: string;
1976
1987
  }
@@ -2005,6 +2016,7 @@ declare class MessageRouter {
2005
2016
  private channels;
2006
2017
  private hooks?;
2007
2018
  private mesh?;
2019
+ private groupLogs;
2008
2020
  private log;
2009
2021
  constructor(registry: AgentRegistry, config: DaemonConfig, hooks?: HookRegistry, log?: (...args: unknown[]) => void);
2010
2022
  setMesh(mesh: A2AMesh): void;
@@ -2012,11 +2024,13 @@ declare class MessageRouter {
2012
2024
  startAll(): Promise<void>;
2013
2025
  stopAll(): Promise<void>;
2014
2026
  private handleMessage;
2027
+ private static readonly MAX_BOT_CHAIN_DEPTH;
2015
2028
  /**
2016
- * Check if an agent's response mentions another agent.
2017
- * If so, route the response as a new task to that agent.
2029
+ * Bot-to-bot conversation chain.
2030
+ * When an agent's response mentions another agent, route it and continue
2031
+ * the chain if the target agent also mentions someone (up to MAX depth).
2018
2032
  */
2019
- private handleBotToBotMentions;
2033
+ private handleBotToBotChain;
2020
2034
  private adapterSend;
2021
2035
  private adapterEdit;
2022
2036
  private adapterReact;
@@ -2026,6 +2040,15 @@ declare class MessageRouter {
2026
2040
  * Searches peer agent cards for mention matches.
2027
2041
  */
2028
2042
  private handleViaMesh;
2043
+ /**
2044
+ * Log a message in the group conversation history.
2045
+ */
2046
+ private logGroupMessage;
2047
+ /**
2048
+ * Build group conversation context for an agent.
2049
+ * Returns recent messages from the group so the agent knows what's been discussed.
2050
+ */
2051
+ private buildGroupContext;
2029
2052
  private getAccountForAgent;
2030
2053
  private resolveAgent;
2031
2054
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import{a as de,b as pe,c as pt,d as gt,e as mt,f as ut,g as ft,h as ht,i as yt,j as kt,k as wt,l as St,m as vt,n as xt,o as bt,p as Ct,q as Pt}from"./chunk-S74N276K.js";import{a as H}from"./chunk-X7UN6JAA.js";import{a as Me,b as Ee,c as Oe,d as Ke,e as Be,f as We,g as ze,h as te,i as J,j as ot,k as rt,l as it,m as R,n as ne,o as at,p as ct,q as lt,r as dt,s as T,t as b,u as j}from"./chunk-KVWUPUR5.js";import{a as Ve,b as Ye,c as Xe,d as F,e as Qe,f as Ze,g as et,h as se,i as tt,j as st,k as nt}from"./chunk-PCAYW54Q.js";import{a as Z,b as qe,c as _,d as ee}from"./chunk-FRFR27IN.js";import{a as Q,b as x,c as U}from"./chunk-SFQUP3BP.js";import{a as Ne,b as _e,c as Fe,d as Je,e as Ue,f as He,g as G}from"./chunk-MGMZNJCE.js";import{a as m,b as Ie,c as Ge,d as je,e as Le,f as De}from"./chunk-M7HKBG3V.js";import"./chunk-MDR7SH7F.js";import{execa as $t}from"execa";import{existsSync as ge,promises as oe}from"fs";import C from"path";import fe from"node-fetch";async function Rt(o,e){let t=o.split("/");if(t.length<2)throw new Error(`Invalid skill package ID: ${o}. Expected format: owner/repo`);let s=t[0],r=t[1],n=t[2];try{let a=n?`${s}/${r}/${n}`:`${s}/${r}`;await $t("npx",["-y","skills","add",a],{cwd:e,stdio:"pipe"}),m.success(`Installed skill package: ${o}`);let i=C.resolve(e,".skills",`${s}_${r}`);if(ge(i))return await ue(i,o);let c=C.resolve(e,".skills");return ge(c)?await ue(c,o):[]}catch{return m.info(`Fetching skills directly from GitHub: ${s}/${r}`),await Tt(s,r,n,e)}}async function Tt(o,e,t,s){let r=[];try{let n=`https://api.github.com/repos/${o}/${e}/git/trees/main?recursive=1`,a=await fe(n);if(!a.ok)throw new Error(`GitHub API error: ${a.status}`);let c=(await a.json()).tree.filter(l=>l.type==="blob"&&l.path.endsWith("SKILL.md"));if(t){let l=c.find(g=>g.path.includes(`/${t}/`)||g.path===`${t}/SKILL.md`);if(l){let g=await me(o,e,l.path,s);g&&r.push(g)}}else for(let l of c){let g=await me(o,e,l.path,s);g&&r.push(g)}}catch(n){m.error(`Failed to fetch skills from GitHub: ${n.message}`)}return r}async function me(o,e,t,s){try{let r=`https://raw.githubusercontent.com/${o}/${e}/main/${t}`,n=await fe(r);if(!n.ok)return null;let a=await n.text(),i=_(a);if(i){i.source="remote",i.packageId=`${o}/${e}`;let c=C.dirname(t),l=C.resolve(s,".skills",`${o}_${e}`,c);await oe.mkdir(l,{recursive:!0}),await oe.writeFile(C.resolve(l,"SKILL.md"),a),i.path=C.resolve(l,"SKILL.md")}return i}catch{return null}}async function ue(o,e){let t=[],{default:s}=await import("fast-glob"),r=await s.glob("**/SKILL.md",{cwd:o,deep:5});for(let n of r)try{let a=C.resolve(o,n),i=await oe.readFile(a,"utf8"),c=_(i);c&&(c.source="remote",c.path=a,c.packageId=e,t.push(c))}catch{}return t}async function At(o,e,t,s,r){let n=["---",`name: ${o}`,`description: ${e}`];if(s?.length){n.push("tags:");for(let a of s)n.push(` - ${a}`)}if(r?.length){n.push("globs:");for(let a of r)n.push(` - ${a}`)}return n.push("---"),`${n.join(`
1
+ import{a as de,b as pe,c as pt,d as gt,e as mt,f as ut,g as ft,h as ht,i as yt,j as kt,k as wt,l as St,m as vt,n as xt,o as bt,p as Ct,q as Pt}from"./chunk-AIBBZF4E.js";import{a as H}from"./chunk-X7UN6JAA.js";import{a as Me,b as Ee,c as Oe,d as Ke,e as Be,f as We,g as ze,h as te,i as J,j as ot,k as rt,l as it,m as R,n as ne,o as at,p as ct,q as lt,r as dt,s as T,t as b,u as j}from"./chunk-F73GPYCO.js";import{a as Ve,b as Ye,c as Xe,d as F,e as Qe,f as Ze,g as et,h as se,i as tt,j as st,k as nt}from"./chunk-Z4GC5D6D.js";import{a as Z,b as qe,c as _,d as ee}from"./chunk-FRFR27IN.js";import{a as Q,b as x,c as U}from"./chunk-SFQUP3BP.js";import{a as Ne,b as _e,c as Fe,d as Je,e as Ue,f as He,g as G}from"./chunk-MGMZNJCE.js";import{a as m,b as Ie,c as Ge,d as je,e as Le,f as De}from"./chunk-M7HKBG3V.js";import"./chunk-4YCH6IZV.js";import{execa as $t}from"execa";import{existsSync as ge,promises as oe}from"fs";import C from"path";import fe from"node-fetch";async function Rt(o,e){let t=o.split("/");if(t.length<2)throw new Error(`Invalid skill package ID: ${o}. Expected format: owner/repo`);let s=t[0],r=t[1],n=t[2];try{let a=n?`${s}/${r}/${n}`:`${s}/${r}`;await $t("npx",["-y","skills","add",a],{cwd:e,stdio:"pipe"}),m.success(`Installed skill package: ${o}`);let i=C.resolve(e,".skills",`${s}_${r}`);if(ge(i))return await ue(i,o);let c=C.resolve(e,".skills");return ge(c)?await ue(c,o):[]}catch{return m.info(`Fetching skills directly from GitHub: ${s}/${r}`),await Tt(s,r,n,e)}}async function Tt(o,e,t,s){let r=[];try{let n=`https://api.github.com/repos/${o}/${e}/git/trees/main?recursive=1`,a=await fe(n);if(!a.ok)throw new Error(`GitHub API error: ${a.status}`);let c=(await a.json()).tree.filter(l=>l.type==="blob"&&l.path.endsWith("SKILL.md"));if(t){let l=c.find(g=>g.path.includes(`/${t}/`)||g.path===`${t}/SKILL.md`);if(l){let g=await me(o,e,l.path,s);g&&r.push(g)}}else for(let l of c){let g=await me(o,e,l.path,s);g&&r.push(g)}}catch(n){m.error(`Failed to fetch skills from GitHub: ${n.message}`)}return r}async function me(o,e,t,s){try{let r=`https://raw.githubusercontent.com/${o}/${e}/main/${t}`,n=await fe(r);if(!n.ok)return null;let a=await n.text(),i=_(a);if(i){i.source="remote",i.packageId=`${o}/${e}`;let c=C.dirname(t),l=C.resolve(s,".skills",`${o}_${e}`,c);await oe.mkdir(l,{recursive:!0}),await oe.writeFile(C.resolve(l,"SKILL.md"),a),i.path=C.resolve(l,"SKILL.md")}return i}catch{return null}}async function ue(o,e){let t=[],{default:s}=await import("fast-glob"),r=await s.glob("**/SKILL.md",{cwd:o,deep:5});for(let n of r)try{let a=C.resolve(o,n),i=await oe.readFile(a,"utf8"),c=_(i);c&&(c.source="remote",c.path=a,c.packageId=e,t.push(c))}catch{}return t}async function At(o,e,t,s,r){let n=["---",`name: ${o}`,`description: ${e}`];if(s?.length){n.push("tags:");for(let a of s)n.push(` - ${a}`)}if(r?.length){n.push("globs:");for(let a of r)n.push(` - ${a}`)}return n.push("---"),`${n.join(`
2
2
  `)}
3
3
 
4
- ${t}`}async function Mt(o){let{loadLocalSkills:e}=await import("./loader-RL2LKXIF.js");return e(o)}async function Et(o,e,t,s,r){let a=[{role:"system",content:`You are a skill author for the Agent Skills ecosystem (skills.sh).
4
+ ${t}`}async function Mt(o){let{loadLocalSkills:e}=await import("./loader-6VSM6FSY.js");return e(o)}async function Et(o,e,t,s,r){let a=[{role:"system",content:`You are a skill author for the Agent Skills ecosystem (skills.sh).
5
5
  You create high-quality SKILL.md files that provide reusable instructions for AI coding agents.
6
6
 
7
7
  A skill is a markdown document with YAML frontmatter that teaches an agent how to perform a specific task.
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d}from"./chunk-FRFR27IN.js";import"./chunk-4YCH6IZV.js";export{a as loadLocalSkills,d as matchSkillsToTask,c as parseSkillContent,b as parseSkillFile};
2
+ //# sourceMappingURL=loader-6VSM6FSY.js.map
@@ -1,2 +1,2 @@
1
- import{e as a,f as b,g as c}from"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-MDR7SH7F.js";export{b as ClaudeCodeProvider,a as ClaudeProvider,c as createProvider};
2
- //# sourceMappingURL=providers-Q3U3ONJO.js.map
1
+ import{e as a,f as b,g as c}from"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-4YCH6IZV.js";export{b as ClaudeCodeProvider,a as ClaudeProvider,c as createProvider};
2
+ //# sourceMappingURL=providers-AVYG63KK.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentix-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Self-hosted multi-agent orchestrator — routes Telegram, WhatsApp, crons, and A2A mesh tasks to Claude Code, OpenAI, or any LLM provider",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -1,2 +0,0 @@
1
- import{s as a,t as b,u as c}from"./chunk-KVWUPUR5.js";import"./chunk-PCAYW54Q.js";import"./chunk-FRFR27IN.js";import"./chunk-SFQUP3BP.js";import"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-MDR7SH7F.js";export{a as createAgentContext,b as generate,c as generateStream};
2
- //# sourceMappingURL=agent-CRA5PU6S.js.map
@@ -1,2 +0,0 @@
1
- var d=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(b,c)=>(typeof require<"u"?require:b)[c]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+a+'" is not supported')});export{d as a};
2
- //# sourceMappingURL=chunk-MDR7SH7F.js.map
@@ -1,35 +0,0 @@
1
- import{i as X,j as Z}from"./chunk-PCAYW54Q.js";var M=class{baseUrl;token;constructor(e,t){this.baseUrl=e.replace(/\/$/,""),this.token=t}async getAgentCard(){let e=await fetch(`${this.baseUrl}/.well-known/agent-card.json`,{headers:this.headers()});if(!e.ok)throw new Error(`Failed to fetch agent card: ${e.status}`);return e.json()}async sendTask(e,t){let s=await this.rpc("tasks/send",{id:`task-${Date.now().toString(36)}`,message:{role:"user",parts:[{type:"text",text:e}]},metadata:t});if(s.error)throw new Error(`A2A error: ${s.error.message}`);return s.result}async*sendTaskStream(e,t){let s=JSON.stringify({jsonrpc:"2.0",id:1,method:"tasks/sendSubscribe",params:{id:`task-${Date.now().toString(36)}`,message:{role:"user",parts:[{type:"text",text:e}]},metadata:t}}),n=await fetch(this.baseUrl,{method:"POST",headers:{...this.headers(),"Content-Type":"application/json",Accept:"text/event-stream"},body:s});if(!n.ok||!n.body)throw new Error(`A2A stream error: ${n.status}`);let r=n.body.getReader(),i=new TextDecoder,o="";for(;;){let{done:a,value:g}=await r.read();if(a)break;o+=i.decode(g,{stream:!0});let c=o.split(`
2
- `);o=c.pop()||"";for(let h of c)if(h.startsWith("data: "))try{let u=JSON.parse(h.slice(6));yield{state:u.state,message:u.message?.parts?.[0]?.text,final:u.final}}catch{}}}async getTask(e){let t=await this.rpc("tasks/get",{id:e});if(t.error)throw new Error(`A2A error: ${t.error.message}`);return t.result}async cancelTask(e){let t=await this.rpc("tasks/cancel",{id:e});if(t.error)throw new Error(`A2A error: ${t.error.message}`);return t.result}async rpc(e,t){let s=await fetch(this.baseUrl,{method:"POST",headers:{...this.headers(),"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:e,params:t})});if(!s.ok)throw new Error(`A2A HTTP error: ${s.status}`);return s.json()}headers(){let e={};return this.token&&(e.Authorization=`Bearer ${this.token}`),e}};var D=class{peers=new Map;healthTimer;config;log;constructor(e,t=console.error.bind(console,"[mesh]")){this.config=e,this.log=t;for(let s of e.mesh.peers)this.peers.set(s.name,{peer:s,client:new M(s.url,s.token),healthy:!1,agents:[]})}async start(){this.log(`Mesh starting with ${this.peers.size} peer(s)`),await this.discoverAll();let e=this.config.mesh.healthCheck.interval*1e3;this.healthTimer=setInterval(()=>this.discoverAll(),e)}async stop(){this.healthTimer&&clearInterval(this.healthTimer)}async discoverAll(){let e=await Promise.allSettled(Array.from(this.peers.entries()).map(([s,n])=>this.discoverPeer(s,n))),t=Array.from(this.peers.values()).filter(s=>s.healthy).length;this.log(`Discovery complete: ${t}/${this.peers.size} peers healthy`)}async discoverPeer(e,t){let s=this.config.mesh.healthCheck.timeout*1e3;try{let n=new AbortController,r=setTimeout(()=>n.abort(),s),i=await t.client.getAgentCard();clearTimeout(r),t.healthy=!0,t.lastCheck=new Date,t.agentCard=i,t.agents=i.skills||[],this.log(`Peer "${e}" healthy: ${i.name} (${t.agents.length} skills)`)}catch(n){t.healthy=!1,t.lastCheck=new Date,this.log(`Peer "${e}" unreachable: ${n.message}`)}}async sendTask(e,t,s){let n=this.peers.get(e);if(!n)throw new Error(`Unknown peer: ${e}`);if(!n.healthy)throw new Error(`Peer "${e}" is not healthy`);let r=s||n.agents[0]?.id;if(!r)throw new Error(`Peer "${e}" has no agents`);let i=`${n.peer.url}/task`,o={"Content-Type":"application/json"};n.peer.token&&(o.Authorization=`Bearer ${n.peer.token}`);let a=await fetch(i,{method:"POST",headers:o,body:JSON.stringify({agent:r,message:t})});if(!a.ok)throw new Error(`Peer "${e}" /task error: ${a.status}`);let g=await a.json();if(g.error)throw new Error(`Peer "${e}" agent error: ${g.error}`);return g.content||"No response"}findPeerWithSkill(e){for(let t of this.peers.values())if(t.healthy&&t.agents.some(s=>s.id===e))return t}directory(){return Array.from(this.peers.entries()).map(([e,t])=>({peer:e,peerUrl:t.peer.url,healthy:t.healthy,skills:t.agents,lastCheck:t.lastCheck}))}};import{z as d}from"zod";import{readFileSync as ee,existsSync as I}from"fs";import{resolve as P}from"path";function ye(l){let e=P(l,".env");if(!I(e))return;let t=ee(e,"utf-8");for(let s of t.split(`
3
- `)){let n=s.trim();if(!n||n.startsWith("#"))continue;let r=n.indexOf("=");if(r===-1)continue;let i=n.slice(0,r).trim(),o=n.slice(r+1).trim();process.env[i]||(process.env[i]=o)}}var we=d.object({apiKey:d.string().optional(),defaultModel:d.string().optional(),baseUrl:d.string().optional()}),ke=d.object({name:d.string(),workspace:d.string(),tier:d.enum(["claude-code","sdk","orchestrator"]).default("claude-code"),provider:d.string().optional(),model:d.string().optional(),systemPrompt:d.string().optional(),mentions:d.array(d.string()).default([]),maxConcurrent:d.number().default(1),permissionMode:d.string().default("default")}),ve=d.object({token:d.string(),agentBinding:d.string()}),Ae=d.object({telegram:d.object({enabled:d.boolean().default(!1),accounts:d.record(d.string(),ve).default({}),policy:d.object({dm:d.enum(["pair","block"]).default("pair"),group:d.enum(["mention-required","all"]).default("mention-required")}).default({})}).default({}),whatsapp:d.object({enabled:d.boolean().default(!1),sessionDir:d.string().default(".agentx/whatsapp-sessions"),defaultAgent:d.string().optional(),allowFrom:d.array(d.string()).optional(),routes:d.array(d.object({contact:d.string().optional(),group:d.string().optional(),agent:d.string()})).default([])}).default({}),discord:d.object({enabled:d.boolean().default(!1),token:d.string().optional(),agentBinding:d.string().optional()}).default({})}),$e=d.object({enabled:d.boolean().default(!0),schedule:d.string(),timezone:d.string().default("UTC"),agent:d.string(),prompt:d.string(),timeout:d.number().default(600),model:d.string().optional(),onError:d.enum(["log","notify","disable"]).default("log")}),be=d.object({url:d.string(),name:d.string(),token:d.string().optional()}),xe=d.object({enabled:d.boolean().default(!1),peers:d.array(be).default([]),discovery:d.enum(["static","mdns"]).default("static"),healthCheck:d.object({interval:d.number().default(60),timeout:d.number().default(10)}).default({})}),Se=d.object({node:d.object({id:d.string(),name:d.string(),bind:d.string().default("127.0.0.1:18800")}),providers:d.record(d.string(),we).default({}),agents:d.record(d.string(),ke).default({}),channels:Ae.default({}),crons:d.record(d.string(),$e).default({}),mesh:xe.default({})});function G(l){if(typeof l=="string")return l.replace(/\$\{(\w+)\}/g,(e,t)=>process.env[t]||"");if(Array.isArray(l))return l.map(G);if(l!==null&&typeof l=="object"){let e={};for(let[t,s]of Object.entries(l))e[t]=G(s);return e}return l}function te(l){let e=l?[l]:[P(process.cwd(),"agentx.json"),P(process.cwd(),".agentx/config.json")];ye(process.cwd());let t,s;for(let o of e)if(I(o)){t=ee(o,"utf-8"),s=o;break}if(!t||!s)throw new Error(`No config found. Create agentx.json or .agentx/config.json
4
- Searched: ${e.join(", ")}`);let n;try{n=JSON.parse(t)}catch(o){throw new Error(`Invalid JSON in ${s}: ${o.message}`)}let r=G(n),i=Se.safeParse(r);if(!i.success){let o=i.error.issues.map(a=>` ${a.path.join(".")}: ${a.message}`).join(`
5
- `);throw new Error(`Config validation failed (${s}):
6
- ${o}`)}return i.data}function se(l){let e=[];for(let[t,s]of Object.entries(l.agents)){if(!I(s.workspace)){e.push(`Agent "${t}": workspace not found at ${s.workspace}`);continue}if(s.tier==="claude-code"){let i=P(s.workspace,".claude");I(i)||e.push(`Agent "${t}": no .claude/ directory in workspace ${s.workspace}. Claude Code native features (hooks, MCP, skills) won't be available.`)}let n=s.provider||"claude",r=l.providers[n];s.tier!=="claude-code"&&(!r||!r.apiKey)&&e.push(`Agent "${t}": provider "${n}" has no API key configured. Set providers.${n}.apiKey in config or use tier "claude-code" for subscription.`)}for(let[t,s]of Object.entries(l.crons))l.agents[s.agent]||e.push(`Cron "${t}": references unknown agent "${s.agent}"`);if(l.channels.telegram.enabled)for(let[t,s]of Object.entries(l.channels.telegram.accounts))l.agents[s.agentBinding]||e.push(`Telegram account "${t}": references unknown agent "${s.agentBinding}"`);return e}import{execa as Te}from"execa";import{execFile as Ce}from"child_process";function ne(l,e,t){let s=[];if(l.systemPrompt&&s.push(l.systemPrompt),e.context){let n=e.context,r=["","[Environment]"];if(n.channel&&r.push(`Channel: ${n.channel}`),n.group&&r.push(`Group: ${n.group}`),n.sender&&r.push(`Message from: ${n.sender}`),n.myHandle&&r.push(`Your handle on this channel: ${n.myHandle}`),n.peers?.length){r.push(""),r.push("[Team \u2014 other agents you can mention to delegate or collaborate]");for(let i of n.peers){let o=i.handle?` (mention: ${i.handle})`:"",a=i.role?` \u2014 ${i.role}`:"";r.push(`\u2022 ${i.name}${o}${a}`)}r.push(""),r.push("To involve another agent, mention their handle in your response and they will automatically see it and reply.")}s.push(r.join(`
7
- `))}return t&&(s.push(""),s.push(t)),s.push(""),s.push(e.message),s.join(`
8
- `)}function re(l,e,t,s){let n=["-p",e,"--output-format",t?"stream-json":"json"];return t&&n.push("--verbose"),s&&n.push("--resume",s),l.model&&n.push("--model",l.model),l.permissionMode==="bypassPermissions"&&n.push("--dangerously-skip-permissions"),n}function Me(l){try{let e=JSON.parse(l);return{text:e.result||e.content||"",sessionId:e.session_id}}catch{return{text:l}}}async function De(l,e,t,s){let n=Date.now(),r=ne(l,e,s?void 0:t),i=re(l,r,!1,s);try{let{stdout:o,stderr:a,exitCode:g}=await new Promise((h,u)=>{let m=Ce("claude",i,{cwd:l.workspace,timeout:6e5,maxBuffer:10485760,env:{...process.env,HOME:process.env.HOME||"/home/"+(process.env.USER||"clawd")}},(f,y,p)=>{h({stdout:y||"",stderr:p||"",exitCode:f?f.code??1:0})})});if(!o&&g!==0)return{content:"",error:(a?.trim()||`Claude Code exited with code ${g}`).slice(0,300),duration:Date.now()-n};let c=Me(o);return{content:c.text,duration:Date.now()-n,claudeSessionId:c.sessionId}}catch(o){return console.error(`[runtime] execFile threw: ${o.message}`),{content:"",error:o.message||"Claude Code failed",duration:Date.now()-n}}}async function Ie(l,e,t,s,n){let r=Date.now(),i=ne(l,e,n?void 0:s),o=re(l,i,!0,n),a="";try{let g=Te("claude",o,{cwd:l.workspace,timeout:6e5,reject:!1,env:process.env,buffer:!1});if(g.stdout){let h="";g.stdout.on("data",u=>{h+=u.toString();let m=h.split(`
9
- `);h=m.pop()||"";for(let f of m)if(f.trim())try{let y=JSON.parse(f);if(y.type==="assistant"&&y.message?.content){for(let p of y.message.content)if(p.type==="text"&&p.text){let w=p.text.slice(a.length);w&&(a=p.text,t(w,a))}}if(y.type==="content_block_delta"&&y.delta?.text&&(a+=y.delta.text,t(y.delta.text,a)),y.type==="result"&&y.result){let p=(typeof y.result=="string",y.result);if(typeof p=="string"&&p.length>a.length){let w=p.slice(a.length);a=p,w&&t(w,a)}}}catch{f.trim()&&!f.startsWith("{")&&(a+=f+`
10
- `,t(f+`
11
- `,a))}})}let c=await g;return!a&&c.stdout&&(a=typeof c.stdout=="string"?c.stdout:""),c.exitCode!==0&&!a?{content:"",error:(typeof c.stderr=="string"?c.stderr:"")||`Claude Code exited with code ${c.exitCode}`,duration:Date.now()-r}:{content:a,duration:Date.now()-r}}catch(g){return{content:a||"",error:g.message,duration:Date.now()-r}}}async function Pe(l,e,t){let s=Date.now();try{let n=await import("@anthropic-ai/claude-agent-sdk"),{query:r}=n,i=l.systemPrompt?`${l.systemPrompt}
12
-
13
- ${e.message}`:e.message,o="",a=r({prompt:i,options:{model:l.model,cwd:l.workspace,permissionMode:"bypassPermissions"}});for await(let g of a)g.type==="result"&&g.subtype==="success"&&(o=g.result||"");return{content:o,duration:Date.now()-s}}catch(n){return{content:"",error:`SDK error: ${n.message}`,duration:Date.now()-s}}}async function Re(l,e,t){let s=Date.now();try{let{generate:n}=await import("./agent-CRA5PU6S.js"),r=l.provider||"claude-code",i=await n({task:e.message,cwd:l.workspace,provider:r,model:l.model,apiKey:t,overwrite:!0,interactive:!1,context7:!1});return{content:i.content||"Done.",tokensUsed:i.tokensUsed,duration:Date.now()-s}}catch(n){return{content:"",error:`Orchestrator error: ${n.message}`,duration:Date.now()-s}}}async function ie(l,e,t,s,n,r){switch(l.tier){case"claude-code":return s?Ie(l,e,s,n,r):De(l,e,n,r);case"sdk":{let i=l.provider||"claude",o=t[i]?.apiKey;return o?Pe(l,e,o):{content:"",error:`No API key for provider "${i}". Configure providers.${i}.apiKey`}}case"orchestrator":{let i=l.provider||"claude-code",o=t[i]?.apiKey;return Re(l,e,o)}default:return{content:"",error:`Unknown tier: ${l.tier}`}}}import{readFileSync as oe,writeFileSync as R,existsSync as _,mkdirSync as K,readdirSync as z,statSync as _e}from"fs";import{resolve as v,join as Ee,relative as E,dirname as je}from"path";var S=class{baseDir;rawDir;log;constructor(e=v(process.cwd(),".agentx/wiki"),t=console.error.bind(console,"[wiki]")){this.baseDir=e,this.rawDir=v(e,"raw/entries"),this.log=t,K(this.rawDir,{recursive:!0}),K(v(e,"raw"),{recursive:!0})}canRead(e,t){return!!(e.access==="public"||e.owner===t||e.access==="shared"&&e.sharedWith?.includes(t))}canWrite(e,t){return e.owner===t}addEntry(e){let t=`${e.date}_${e.id}.md`,s=v(this.rawDir,t),n=["---",`id: ${e.id}`,`date: ${e.date}`,`agent: ${e.agentId}`,`source: ${e.source}`];if(e.sourceContext&&n.push(`context: ${e.sourceContext}`),e.meta)for(let[r,i]of Object.entries(e.meta))n.push(`${r}: ${JSON.stringify(i)}`);return n.push("---","",e.content),R(s,n.join(`
14
- `)),t}listEntries(e){if(!_(this.rawDir))return[];let t=z(this.rawDir).filter(n=>n.endsWith(".md")).sort(),s=[];for(let n of t){let r=oe(v(this.rawDir,n),"utf-8"),i=this.parseEntry(r,n);i&&(e?.agentId&&i.agentId!==e.agentId||e?.after&&i.date<e.after||e?.before&&i.date>e.before||s.push(i))}return s}parseEntry(e,t){let s=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!s)return null;let n=s[1],r=s[2].trim(),i=o=>n.match(new RegExp(`^${o}:\\s*(.+)$`,"m"))?.[1]?.trim()||"";return{id:i("id")||t.replace(".md",""),date:i("date"),agentId:i("agent"),source:i("source"),sourceContext:i("context")||void 0,content:r}}writeArticle(e,t,s,n){let r=this.readArticle(e);if(r&&!this.canWrite(r.meta,n))return this.log(`Permission denied: "${n}" cannot write "${e}" (owner: ${r.meta.owner})`),!1;let i=v(this.baseDir,e);K(je(i),{recursive:!0});let o=["---",`title: "${t.title}"`,`type: ${t.type}`,`owner: ${t.owner}`,`access: ${t.access}`];return t.sharedWith?.length&&o.push(`shared_with: [${t.sharedWith.map(a=>`"${a}"`).join(", ")}]`),o.push(`created: ${t.created}`,`last_updated: ${t.lastUpdated}`,`related: [${t.related.map(a=>`"${a}"`).join(", ")}]`,`sources: [${t.sources.map(a=>`"${a}"`).join(", ")}]`),t.tags?.length&&o.push(`tags: [${t.tags.map(a=>`"${a}"`).join(", ")}]`),o.push("---","",s),R(i,o.join(`
15
- `)),!0}readArticle(e){let t=v(this.baseDir,e);if(!_(t))return null;let s=oe(t,"utf-8");return this.parseArticle(s,e)}readArticleAs(e,t){let s=this.readArticle(e);return!s||!this.canRead(s.meta,t)?null:s}parseArticle(e,t){let s=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!s)return null;let n=s[1],r=s[2].trim(),i=a=>n.match(new RegExp(`^${a}:\\s*(.+)$`,"m"))?.[1]?.trim().replace(/^"(.*)"$/,"$1")||"",o=a=>{let g=n.match(new RegExp(`^${a}:\\s*\\[(.*)\\]$`,"m"));return g?g[1].split(",").map(c=>c.trim().replace(/^"(.*)"$/,"$1")).filter(Boolean):[]};return{meta:{title:i("title"),type:i("type"),owner:i("owner"),access:i("access")||"public",sharedWith:o("shared_with"),created:i("created"),lastUpdated:i("last_updated"),related:o("related"),sources:o("sources"),tags:o("tags")},content:r,path:t}}listArticles(e){let t=[];return this.walkDir(this.baseDir,s=>{if(!s.endsWith(".md"))return;let n=E(this.baseDir,s);if(n.startsWith("raw/")||n.startsWith("_"))return;let r=this.readArticle(n);r&&this.canRead(r.meta,e)&&t.push(r)}),t}search(e,t,s=10){let n=e.toLowerCase(),r=[];return this.walkDir(this.baseDir,i=>{if(!i.endsWith(".md"))return;let o=E(this.baseDir,i);if(o.startsWith("raw/")||o.startsWith("_"))return;let a=this.readArticle(o);if(!a||!this.canRead(a.meta,t))return;let g=0,c=a.meta.title.toLowerCase(),h=a.content.toLowerCase();c.includes(n)&&(g+=10),a.meta.tags?.some(m=>m.toLowerCase().includes(n))&&(g+=5);let u=(h.match(new RegExp(n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"))||[]).length;g+=Math.min(u,5),g>0&&r.push({article:a,score:g})}),r.sort((i,o)=>o.score-i.score).slice(0,s).map(i=>i.article)}findRelevant(e,t,s=3){let n=new Set(["the","a","an","is","are","was","were","be","been","being","have","has","had","do","does","did","will","would","could","should","may","might","can","shall","to","of","in","for","on","with","at","by","from","as","into","about","through","and","but","or","not","no","if","then","so","what","how","when","where","who","which","that","this","it","i","you","we","they","he","she","me","my","your","our","their","please","just","also","very","much","some","any","all"]),r=e.toLowerCase().replace(/[^a-z0-9\s@_-]/g," ").split(/\s+/).filter(o=>o.length>2&&!n.has(o));if(r.length===0)return[];let i=new Map;for(let o of r){let a=this.search(o,t,5);for(let g of a){let c=i.get(g.path);c?c.score+=1:i.set(g.path,{article:g,score:1})}}return Array.from(i.values()).sort((o,a)=>a.score-o.score).slice(0,s).map(o=>o.article)}buildContext(e,t=4e3){if(e.length===0)return"";let s=["[Wiki Knowledge]"],n=0;for(let r of e){let i=`
16
- ## ${r.meta.title} (${r.meta.type})`,o=r.content.length>600?r.content.slice(0,600)+"...":r.content,a=i+`
17
- `+o;if(n+a.length>t)break;s.push(a),n+=a.length}return s.push(`
18
- [End Wiki Knowledge]`),s.join(`
19
- `)}rebuildIndex(){let e=[],t=new Map;this.walkDir(this.baseDir,i=>{if(!i.endsWith(".md"))return;let o=E(this.baseDir,i);if(o.startsWith("raw/")||o.startsWith("_"))return;let a=this.readArticle(o);if(!a)return;let g=a.content.match(/\[\[([^\]]+)\]\]/g)||[];for(let h of g){let u=h.replace(/\[\[|\]\]/g,"");t.set(u,(t.get(u)||0)+1)}let c=[a.meta.title.toLowerCase()];a.meta.tags&&c.push(...a.meta.tags.map(h=>h.toLowerCase())),e.push({path:o,title:a.meta.title,type:a.meta.type,owner:a.meta.owner,access:a.meta.access,sharedWith:a.meta.sharedWith,aliases:c,backlinks:t.get(a.meta.title)||0})});let s={articles:e,lastRebuilt:new Date().toISOString()};R(v(this.baseDir,"_index.json"),JSON.stringify(s,null,2));let n=["# Wiki Index","",`Last rebuilt: ${s.lastRebuilt}`,""],r=new Map;for(let i of e){let o=r.get(i.type)||[];o.push(i),r.set(i.type,o)}for(let[i,o]of Array.from(r.entries()).sort()){n.push(`## ${i}`,"");for(let a of o.sort((g,c)=>g.title.localeCompare(c.title))){let g=a.access==="private"?" (private)":a.access==="shared"?" (shared)":"";n.push(`- [${a.title}](${a.path})${g} \u2014 owner: ${a.owner}`)}n.push("")}return R(v(this.baseDir,"WIKI.md"),n.join(`
20
- `)),this.log(`Index rebuilt: ${e.length} articles`),s}stats(){let e=0,t={},s={},n={};this.walkDir(this.baseDir,i=>{if(!i.endsWith(".md"))return;let o=E(this.baseDir,i);if(o.startsWith("raw/")||o.startsWith("_")||o==="WIKI.md")return;let a=this.readArticle(o);a&&(e++,t[a.meta.type]=(t[a.meta.type]||0)+1,s[a.meta.access]=(s[a.meta.access]||0)+1,n[a.meta.owner]=(n[a.meta.owner]||0)+1)});let r=_(this.rawDir)?z(this.rawDir).filter(i=>i.endsWith(".md")).length:0;return{totalArticles:e,totalEntries:r,articlesByType:t,articlesByAccess:s,articlesByOwner:n}}walkDir(e,t){if(_(e))for(let s of z(e)){let n=Ee(e,s);_e(n).isDirectory()?this.walkDir(n,t):t(n)}}};import{readFileSync as We,writeFileSync as Oe,mkdirSync as Le,existsSync as ae}from"fs";import{resolve as ce}from"path";var Be=12e3,le=30,j=class{sessionsDir;cache=new Map;constructor(e=process.cwd()){this.sessionsDir=ce(e,".agentx/sessions"),ae(this.sessionsDir)||Le(this.sessionsDir,{recursive:!0})}sessionKey(e,t,s){let n=new Date().toISOString().slice(0,10);return`${e}:${t}:${s}:${n}`}sessionFile(e){let t=e.replace(/[^a-zA-Z0-9_:-]/g,"_");return ce(this.sessionsDir,`${t}.json`)}getSession(e,t,s){let n=this.sessionKey(e,t,s);if(this.cache.has(n))return this.cache.get(n);let r=this.sessionFile(n);if(ae(r))try{let a=JSON.parse(We(r,"utf-8"));return this.cache.set(n,a),a}catch{}let i=new Date().toISOString().slice(0,10),o={id:n,agentId:e,channel:t,chatId:s,day:i,messages:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};return this.cache.set(n,o),this.save(o),o}addUserMessage(e,t,s,n,r){let i=this.getSession(e,t,s);i.messages.push({role:"user",name:n,content:r,timestamp:new Date().toISOString()}),this.trim(i),i.updatedAt=new Date().toISOString(),this.save(i)}addAgentMessage(e,t,s,n){let r=this.getSession(e,t,s);r.messages.push({role:"agent",name:e,content:n,timestamp:new Date().toISOString()}),this.trim(r),r.updatedAt=new Date().toISOString(),this.save(r)}getClaudeSessionId(e,t,s){return this.getSession(e,t,s).claudeSessionId}setClaudeSessionId(e,t,s,n){let r=this.getSession(e,t,s);r.claudeSessionId=n,r.updatedAt=new Date().toISOString(),this.save(r)}buildHistoryContext(e,t,s){let n=this.getSession(e,t,s);if(n.messages.length===0)return"";let r=[`[Conversation history for today (${n.day})]`];for(let i of n.messages){let o=i.timestamp.slice(11,16);i.role==="user"?r.push(`[${o}] ${i.name||"User"}: ${i.content}`):r.push(`[${o}] ${i.name||"Agent"}: ${i.content}`)}return r.push("[End of history \u2014 respond to the latest message above]"),r.push(""),r.join(`
21
- `)}trim(e){e.messages.length>le&&(e.messages=e.messages.slice(-le));let t=e.messages.reduce((s,n)=>s+n.content.length,0);for(;t>Be&&e.messages.length>2;){let s=e.messages.shift();t-=s.content.length}}save(e){try{let t=this.sessionFile(e.id);Oe(t,JSON.stringify(e,null,2))}catch{}}};var W=class{agents=new Map;config;providers={};sessions;wiki;log;constructor(e,t=console.error.bind(console,"[agents]")){this.log=t,this.config=e,this.providers=e.providers,this.sessions=new j,this.wiki=new S;for(let[s,n]of Object.entries(e.agents))this.agents.set(s,{id:s,def:n,activeTasks:0,totalTasks:0,errors:0})}getAgent(e){return this.agents.get(e)?.def}findByMention(e){let t=e.toLowerCase(),s,n=0;for(let[r,i]of this.agents)for(let o of i.def.mentions){let a=o.toLowerCase();t.includes(a)&&a.length>n&&(s=r,n=a.length)}return s}findAllMentioned(e){let t=e.toLowerCase(),s=[];for(let[n,r]of this.agents)for(let i of r.def.mentions)if(t.includes(i.toLowerCase())){s.push(n);break}return s}getChannelHandle(e,t){let s=this.agents.get(e)?.def;if(s)return t==="telegram"?s.mentions.find(n=>n.startsWith("@")):s.mentions[0]}enrichTaskContext(e){let t=e.context?.channel,s=[];for(let[r,i]of this.agents)r!==e.agentId&&s.push({id:r,name:i.def.name,handle:this.getChannelHandle(r,t),role:i.def.systemPrompt?.split(`
22
- `)[0]?.slice(0,100)});let n=this.getChannelHandle(e.agentId,t);return{...e,context:{...e.context,myHandle:n,peers:s}}}async execute(e,t){let s=this.agents.get(e.agentId);if(!s)return{content:"",error:`Unknown agent: ${e.agentId}`};if(s.activeTasks>=s.def.maxConcurrent)return{content:"",error:`Agent "${e.agentId}" is busy (${s.activeTasks}/${s.def.maxConcurrent} tasks)`};s.activeTasks++,s.totalTasks++,s.lastActive=new Date,this.log(`[${e.agentId}] executing task (${s.activeTasks}/${s.def.maxConcurrent})`);let n=e.context?.channel||"api",r=e.context?.group||e.context?.sender||"default",i=e.context?.sender||"User";this.sessions.addUserMessage(e.agentId,n,r,i,e.message),e=this.enrichTaskContext(e);let o=this.wiki.findRelevant(e.message,e.agentId,3),a=this.wiki.buildContext(o),g=s.def.tier==="claude-code"?this.sessions.getClaudeSessionId(e.agentId,n,r):void 0,c=g?void 0:this.sessions.buildHistoryContext(e.agentId,n,r),h=[a,c].filter(Boolean).join(`
23
-
24
- `)||void 0;try{let u=await ie(s.def,e,this.providers,t,h,g);if(u.error)s.errors++,this.log(`[${e.agentId}] error: ${u.error}`);else{if(this.sessions.addAgentMessage(e.agentId,n,r,u.content),u.claudeSessionId&&this.sessions.setClaudeSessionId(e.agentId,n,r,u.claudeSessionId),u.content.length>50)try{let m=`${e.agentId}-${Date.now().toString(36)}`;this.wiki.addEntry({id:m,date:new Date().toISOString().slice(0,10),agentId:e.agentId,source:n,sourceContext:e.context?.group||e.context?.sender,content:`User: ${e.message}
25
-
26
- Agent: ${u.content}`})}catch{}this.log(`[${e.agentId}] completed in ${u.duration}ms`+(u.tokensUsed?` (${u.tokensUsed} tokens)`:""))}return u}catch(u){return s.errors++,this.log(`[${e.agentId}] unexpected error: ${u.message}`),{content:"",error:u.message}}finally{s.activeTasks--}}list(){return Array.from(this.agents.values()).map(e=>({id:e.id,name:e.def.name,tier:e.def.tier,workspace:e.def.workspace,active:e.activeTasks,total:e.totalTasks,errors:e.errors,lastActive:e.lastActive}))}};var O=class{registry;config;channels=new Map;hooks;mesh;log;constructor(e,t,s,n=console.error.bind(console,"[router]")){this.registry=e,this.config=t,this.hooks=s,this.log=n}setMesh(e){this.mesh=e}addChannel(e){this.channels.set(e.name,e),e.onMessage(t=>this.handleMessage(e,t))}async startAll(){for(let[e,t]of this.channels)this.log(`Starting channel: ${e}`),await t.start()}async stopAll(){for(let[e,t]of this.channels)this.log(`Stopping channel: ${e}`),await t.stop()}async handleMessage(e,t){if(this.hooks?.has("pre:channel-message")){let p=await this.hooks.execute("pre:channel-message",{event:"pre:channel-message",channel:t.channel,sender:t.sender.name,text:t.text,group:t.group?.name});if(p.blocked){this.log(`Message blocked by hook: ${p.message}`);return}p.modified?.text&&(t={...t,text:p.modified.text})}let s=this.resolveAgent(t);if(!s)return;if(t.group&&t.channel==="telegram"){let p=this.getAccountForAgent(s);if(p&&p!==t.accountId)return}let n=t.group?.id||t.sender.id,i=this.registry.getAgent(s)?.name||s,o=this.getAccountForAgent(s)||t.accountId;this.log(`Routing [${t.channel}/${t.sender.name}] -> "${i}": ${t.text.slice(0,80)}`),this.adapterReact(e,n,t.id,"\u{1F440}",o);let a=this.startTypingLoop(e,n,o),g=typeof e.editMessage=="function",c,h=0,u=g?async(p,w)=>{let k=Date.now();if(!(k-h<1500))if(c)try{await this.adapterEdit(e,n,c,w,void 0,o),h=k}catch{}else{let x=w.length>20?w:`_${i} is writing..._
27
-
28
- ${w}`;try{c=await this.adapterSend(e,{channel:t.channel,chatId:n,text:x,replyTo:t.id,accountId:o}),h=k}catch{}}}:void 0,m=await this.registry.execute({message:t.text,agentId:s,context:{channel:t.channel,sender:t.sender.name,group:t.group?.name}},u);if(clearInterval(a),m.error){this.log(`Agent error: ${m.error}`);let p=`Error: ${m.error}`;c?await this.adapterEdit(e,n,c,p,"plain",o):await this.adapterSend(e,{channel:t.channel,chatId:n,text:p,replyTo:t.id,parseMode:"plain",accountId:o});return}let f=m.content;if(this.hooks?.has("post:channel-message")){let p=await this.hooks.execute("post:channel-message",{event:"post:channel-message",channel:t.channel,sender:t.sender.name,response:f,agentId:s});if(p.blocked){this.log(`Response blocked by hook: ${p.message}`);return}p.modified?.response&&(f=p.modified.response)}let y;f&&(c?(await this.adapterEdit(e,n,c,f,void 0,o),y=c):y=await this.adapterSend(e,{channel:t.channel,chatId:n,text:f,replyTo:t.id,accountId:o})),f&&y&&this.handleBotToBotMentions(e,t,s,f,y).catch(p=>{this.log(`Bot-to-bot error: ${p.message}`)})}async handleBotToBotMentions(e,t,s,n,r){for(let[i,o]of Object.entries(this.config.agents)){if(i===s||!o.mentions.some(h=>n.toLowerCase().includes(h.toLowerCase())))continue;this.log(`Bot-to-bot: "${s}" mentioned "${i}" \u2014 routing`);let g=t.group?.id||t.sender.id,c=this.getAccountForAgent(i);try{this.adapterReact(e,g,r,"\u{1F440}",c);let h=this.startTypingLoop(e,g,c),u=await this.registry.execute({message:n,agentId:i,context:{channel:t.channel,sender:`agent:${s}`,group:t.group?.name}});clearInterval(h),u.content&&!u.error?await this.adapterSend(e,{channel:t.channel,chatId:g,text:u.content,accountId:c}):u.error&&this.log(`Bot-to-bot "${i}" error: ${u.error}`)}catch(h){this.log(`Bot-to-bot "${i}" failed: ${h.message}`)}break}}async adapterSend(e,t){return e.name==="telegram"&&t.accountId?e.send({...t,parseMode:t.parseMode,accountId:t.accountId}):e.send(t)||""}async adapterEdit(e,t,s,n,r,i){return e.name==="telegram"&&i?e.editMessage(t,s,n,r,i):e.editMessage?.(t,s,n,r)??!1}adapterReact(e,t,s,n,r){e.name==="telegram"&&r?e.react(t,s,n,r):e.react?.(t,s,n)}startTypingLoop(e,t,s){let n=()=>{e.name==="telegram"&&s?e.sendTyping(t,s):e.sendTyping?.(t)};return n(),setInterval(n,4e3)}async handleViaMesh(e,t){if(!this.mesh)return!1;let s=t.text.toLowerCase(),n=this.mesh.directory();for(let r of n)if(r.healthy){for(let i of r.skills)if(s.includes(i.id.toLowerCase())||s.includes(i.name.toLowerCase())){this.log(`Mesh routing [${t.channel}/${t.sender.name}] -> peer "${r.peer}" agent "${i.id}"`);let o=t.group?.id||t.sender.id,a=t.accountId;this.adapterReact(e,o,t.id,"\u{1F440}",a);let g=this.startTypingLoop(e,o,a);try{let c=await this.mesh.sendTask(r.peer,t.text,i.id);if(clearInterval(g),c){let h=`**${i.name}** _(${r.peer})_:
29
-
30
- `;await this.adapterSend(e,{channel:t.channel,chatId:o,text:h+c,replyTo:t.id,accountId:a})}return!0}catch(c){return clearInterval(g),this.log(`Mesh routing error: ${c.message}`),await this.adapterSend(e,{channel:t.channel,chatId:o,text:`Error from ${r.peer}/${i.name}: ${c.message}`,replyTo:t.id,parseMode:"plain",accountId:a}),!0}}}return!1}getAccountForAgent(e){for(let[t,s]of Object.entries(this.config.channels.telegram.accounts))if(s.agentBinding===e)return t}resolveAgent(e){if(e.resolvedAgent)return e.resolvedAgent;if(!e.group)return e.channel==="telegram"?this.config.channels.telegram.accounts[e.accountId]?.agentBinding:e.channel==="whatsapp"?this.config.channels.whatsapp.defaultAgent:void 0;if(e.channel==="telegram"&&this.config.channels.telegram.policy.group==="mention-required"){let n=this.registry.findByMention(e.text);return n||void 0}let t=this.registry.findByMention(e.text);return t||(e.channel==="telegram"?this.config.channels.telegram.accounts[e.accountId]?.agentBinding:this.config.channels.whatsapp.defaultAgent)}};var Ne=/([_*\[\]()~`>#+=|{}.!\-\\])/g;function A(l){return l.replace(Ne,"\\$1")}function B(l){return l.replace(/([`\\])/g,"\\$1")}function V(l){let e=l.split(`
31
- `),t=[],s=!1,n="",r=[];for(let i=0;i<e.length;i++){let o=e[i];if(o.trimStart().startsWith("```"))if(s){s=!1;let h=r.join(`
32
- `);n?t.push("```"+B(n)):t.push("```"),t.push(B(h)),t.push("```");continue}else{s=!0,n=o.trimStart().slice(3).trim(),r=[];continue}if(s){r.push(o);continue}let a=o.match(/^(#{1,6})\s+(.+)$/);if(a){t.push(""),t.push("*"+ge(a[2])+"*");continue}if(/^[-*_]{3,}\s*$/.test(o.trim())){t.push("\u2014\u2014\u2014");continue}if(o.trimStart().startsWith("> ")){let h=o.replace(/^>\s*/,"");t.push(">"+L(h));continue}let g=o.match(/^(\s*)[-*+]\s+(.+)$/);if(g){let h=g[1].length>0?" ":"";t.push(h+"\u2022 "+L(g[2]));continue}let c=o.match(/^(\s*)\d+[.)]\s+(.+)$/);if(c){let h=c[1].length>0?" ":"",u=o.match(/^(\s*)(\d+)/)?.[2]||"1";t.push(h+A(u)+"\\. "+L(c[2]));continue}if(!o.trim()){t.push("");continue}t.push(L(o))}return s&&(t.push("```"),t.push(B(r.join(`
33
- `))),t.push("```")),t.join(`
34
- `).trim()}function L(l){let e=[],t=l.replace(/`([^`]+)`/g,(r,i)=>{let o=e.length;return e.push("`"+B(i)+"`"),`\0CODE${o}\0`}),s=[];t=t.replace(/@(\w{5,})/g,(r,i)=>{let o=s.length;return s.push("@"+A(i)),`\0MENTION${o}\0`});let n=[];return t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(r,i,o)=>{let a=n.length;return n.push("["+ge(i)+"]("+o.replace(/([)\\])/g,"\\$1")+")"),`\0LINK${a}\0`}),t=t.replace(/\*\*\*(.+?)\*\*\*/g,(r,i)=>"*_"+A(i)+"_*"),t=t.replace(/\*\*(.+?)\*\*/g,(r,i)=>"*"+A(i)+"*"),t=t.replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g,(r,i)=>"_"+A(i)+"_"),t=t.replace(/(?<!_)_([^_]+?)_(?!_)/g,(r,i)=>"_"+A(i)+"_"),t=t.replace(/~~(.+?)~~/g,(r,i)=>"~"+A(i)+"~"),t=Je(t),t=t.replace(/\x00CODE(\d+)\x00/g,(r,i)=>e[parseInt(i)]),t=t.replace(/\x00MENTION(\d+)\x00/g,(r,i)=>s[parseInt(i)]),t=t.replace(/\x00LINK(\d+)\x00/g,(r,i)=>n[parseInt(i)]),t}function ge(l){return A(l)}function Je(l){return l.split(/(\*[^*]+\*|_[^_]+_|~[^~]+~|\x00\w+\d+\x00)/g).map(t=>/^\*[^*]+\*$/.test(t)||/^_[^_]+_$/.test(t)||/^~[^~]+~$/.test(t)||/^\x00/.test(t)?t:A(t)).join("")}var N=class{name="telegram";accounts;offsets=new Map;handler;polling=!1;log;constructor(e,t=console.error.bind(console,"[telegram]")){this.accounts=new Map(Object.entries(e)),this.log=t}onMessage(e){this.handler=e}async start(){this.polling=!0;let e=Array.from(this.accounts.entries());this.log(`${e.length} Telegram account(s) to start`);for(let t=0;t<e.length;t++){let[s,n]=e[t];this.log(`Starting polling for account "${s}" (${t+1}/${e.length})`);try{let r=await this.apiCall(n.token,"getMe");this.log(`Bot @${r.result?.username} ready (account: ${s})`),this.pollLoop(s,n)}catch(r){this.log(`Failed to verify bot for account "${s}": ${r.message}`)}t<e.length-1&&await new Promise(r=>setTimeout(r,300))}this.log(`All ${e.length} Telegram account(s) started`)}async stop(){this.polling=!1}getTokenForAccount(e){return this.accounts.get(e)?.token}getDefaultToken(){let[,e]=Array.from(this.accounts.entries())[0];return e?.token}resolveToken(e,t){if(t){let s=this.getTokenForAccount(t);if(s)return s}return this.chatAccountMap.get(e)?this.getTokenForAccount(this.chatAccountMap.get(e)):this.getDefaultToken()}chatAccountMap=new Map;async send(e){let t=this.resolveToken(e.chatId,e.accountId);if(!t)return this.log("No telegram token found for sending"),"";let s=4096,n=e.text.length>s?e.text.slice(0,s-3)+"...":e.text,r=e.parseMode==="markdown"||e.parseMode===void 0?V(n):n,i={chat_id:e.chatId,text:r,parse_mode:"MarkdownV2"};e.replyTo&&(i.reply_to_message_id=parseInt(e.replyTo,10)),e.parseMode==="html"?(i.parse_mode="HTML",i.text=n):e.parseMode==="plain"&&(delete i.parse_mode,i.text=n);try{let o=await this.apiCall(t,"sendMessage",i);return String(o.result?.message_id||"")}catch(o){if(i.parse_mode){delete i.parse_mode,i.text=n;let a=await this.apiCall(t,"sendMessage",i);return String(a.result?.message_id||"")}throw o}}async editMessage(e,t,s,n,r){let i=this.resolveToken(e,r);if(!i)return!1;let o=4096,a=s.length>o?s.slice(0,o-3)+"...":s,g=n!=="html"&&n!=="plain"?V(a):a,c={chat_id:e,message_id:parseInt(t,10),text:g,parse_mode:"MarkdownV2"};n==="html"?(c.parse_mode="HTML",c.text=a):n==="plain"&&(delete c.parse_mode,c.text=a);try{return await this.apiCall(i,"editMessageText",c),!0}catch(h){if(h.message?.includes("message is not modified"))return!0;if(c.parse_mode){delete c.parse_mode,c.text=a;try{return await this.apiCall(i,"editMessageText",c),!0}catch{return!1}}return!1}}async react(e,t,s="\u{1F440}",n){let r=this.resolveToken(e,n);if(r)try{await this.apiCall(r,"setMessageReaction",{chat_id:e,message_id:parseInt(t,10),reaction:[{type:"emoji",emoji:s}]})}catch{}}async sendTyping(e,t){let s=this.resolveToken(e,t);if(s)try{await this.apiCall(s,"sendChatAction",{chat_id:e,action:"typing"})}catch{}}async pollLoop(e,t){for(;this.polling;)try{let s=this.offsets.get(e)||0,r=(await this.apiCall(t.token,"getUpdates",{offset:s||void 0,timeout:30,allowed_updates:["message"]})).result||[];for(let i of r)if(this.offsets.set(e,i.update_id+1),i.message?.text&&this.handler){let o=i.message,a={id:String(o.message_id),channel:"telegram",accountId:e,sender:{id:String(o.from.id),name:[o.from.first_name,o.from.last_name].filter(Boolean).join(" "),username:o.from.username},group:o.chat.type!=="private"?{id:String(o.chat.id),name:o.chat.title||""}:void 0,text:o.text,replyTo:o.reply_to_message?String(o.reply_to_message.message_id):void 0,timestamp:new Date(o.date*1e3),raw:i};this.chatAccountMap.set(String(o.chat.id),e),this.handler(a).catch(g=>{this.log(`Error handling message: ${g.message}`)})}}catch(s){this.log(`Poll error (${e}): ${s.message}`),await new Promise(n=>setTimeout(n,5e3))}}async apiCall(e,t,s){let n=`https://api.telegram.org/bot${e}/${t}`,r=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0});if(!r.ok){let i=await r.text();throw new Error(`Telegram API error: ${r.status} ${i}`)}return r.json()}};import{mkdirSync as He}from"fs";import{resolve as Fe}from"path";var J=class{name="whatsapp";sessionDir;defaultAgent;allowFrom;routes;handler;sock=null;sentMessageIds=new Set;log;constructor(e,t=console.error.bind(console,"[whatsapp]")){this.sessionDir=Fe(e.sessionDir),this.defaultAgent=e.defaultAgent,this.allowFrom=e.allowFrom,this.routes=e.routes||[],this.log=t}resolveAgent(e,t,s){for(let n of this.routes){if(n.contact){let r=n.contact.replace(/\+/g,"");if(e.includes(r)||r.includes(e))return n.agent}if(n.group&&(t||s)){let r=n.group.toLowerCase();if(t?.toLowerCase().includes(r)||s?.toLowerCase().includes(r))return n.agent}}return this.defaultAgent}onMessage(e){this.handler=e}async start(){let e,t,s,n;try{n=await import("@whiskeysockets/baileys"),e=n.default||n.makeWASocket,t=n.useMultiFileAuthState,s=n.DisconnectReason}catch{this.log("WhatsApp requires @whiskeysockets/baileys. Install with:"),this.log(" npm install @whiskeysockets/baileys");return}He(this.sessionDir,{recursive:!0});let{state:r,saveCreds:i}=await t(this.sessionDir),o;try{let{version:g}=await n.fetchLatestBaileysVersion();o=g,this.log(`WhatsApp Web version: ${g.join(".")}`)}catch{this.log("Could not fetch WA version, using default")}let a={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:(...g)=>this.log("WA error:",...g),child:()=>a};this.sock=e({auth:{creds:r.creds,keys:n.makeCacheableSignalKeyStore?n.makeCacheableSignalKeyStore(r.keys,a):r.keys},...o?{version:o}:{},logger:a,printQRInTerminal:!1,browser:["agentx","server","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1}),this.sock.ev.on("creds.update",i),this.sock.ev.on("messaging-history.set",g=>{this.log(`WA history sync: ${g.messages?.length||0} messages, ${g.isLatest?"latest":"partial"}`)}),this.sock.ev.on("connection.update",async g=>{let{connection:c,lastDisconnect:h,qr:u}=g;if(u){this.log("Scan QR code with WhatsApp to connect:");try{let{default:m}=await import("qrcode-terminal");m.generate(u,{small:!0})}catch{this.log(`QR: ${u}`),this.log("Install qrcode-terminal for visual QR: npm install qrcode-terminal")}}if(c==="close"){let m=h?.error?.output?.statusCode;this.log(`WhatsApp connection closed (status: ${m})`),m===515?(this.log("Stream error, reconnecting in 5s..."),setTimeout(()=>this.start(),5e3)):m===s?.loggedOut||m===401?this.log("Logged out. Delete session dir and restart to re-scan QR."):m!==void 0&&(this.log("Reconnecting in 3s..."),setTimeout(()=>this.start(),3e3))}c==="open"&&this.log("WhatsApp connected")}),this.sock.ev.on("messages.upsert",async g=>{if(this.log(`WA messages.upsert: ${g.messages?.length||0} messages, type: ${g.type}`),!!this.handler)for(let c of g.messages||[]){let h=(c.key.remoteJid||"").replace(/@.*/,"").slice(-6),u=!!(c.message?.conversation||c.message?.extendedTextMessage?.text);if(this.log(`WA msg: from=${h} fromMe=${c.key.fromMe} hasText=${u} type=${Object.keys(c.message||{}).join(",")}`),c.key.remoteJid==="status@broadcast")continue;if(c.key.id&&this.sentMessageIds.has(c.key.id)){this.sentMessageIds.delete(c.key.id);continue}if(c.key.fromMe){let b=this.sock?.user,U=c.key.remoteJid||"",C=b?.id?.replace(/:.*/,"")||"",fe=b?.lid?.replace(/:.*/,"")||"",Y=U.replace(/:.*/,"").replace(/@.*/,"");if(!(Y===C||Y===fe))continue}let m=c.message?.conversation||c.message?.extendedTextMessage?.text||c.message?.imageMessage?.caption||c.message?.videoMessage?.caption||"";if(!m)continue;let f=c.key.remoteJid||"",y=f.endsWith("@g.us"),p=f.replace(/@.*$/,""),k=(y?c.key.participant||"":f).replace(/@.*$/,"");if(this.allowFrom?.length&&!c.key.fromMe&&!this.allowFrom.some(U=>{let C=U.replace(/\+/g,"");return k.includes(C)||p.includes(C)}))continue;let x=c.key.fromMe?"me":c.pushName||k,$;if(y&&this.sock)try{$=(await this.sock.groupMetadata(f)).subject}catch{}let Q=this.resolveAgent(k,$,y?f:void 0);if(!Q){this.log(`No route for ${y?`group ${$||f}`:k}, skipping`);continue}let me={id:c.key.id||String(Date.now()),channel:"whatsapp",accountId:"default",sender:{id:c.key.fromMe?(this.sock?.user?.id?.replace(/:.*/,"")||k)+"@s.whatsapp.net":k,name:x,username:k},group:y?{id:f,name:$||f}:void 0,text:m,replyTo:c.message?.extendedTextMessage?.contextInfo?.stanzaId,timestamp:new Date((c.messageTimestamp||0)*1e3),raw:c,resolvedAgent:Q};this.handler(me).catch(b=>{this.log(`Error handling message: ${b.message}`)})}})}async stop(){this.sock&&(this.sock.end(),this.sock=null)}async send(e){if(!this.sock)return this.log("WhatsApp not connected"),"";let t=e.chatId.includes("@")?e.chatId:`${e.chatId}@s.whatsapp.net`;try{let n=(await this.sock.sendMessage(t,{text:e.text}))?.key?.id||"";return n&&this.sentMessageIds.add(n),n}catch(s){return this.log(`Send error: ${s.message}`),""}}async editMessage(e,t,s){if(!this.sock)return!1;let n=e.includes("@")?e:`${e}@s.whatsapp.net`;try{return await this.sock.sendMessage(n,{text:s,edit:{remoteJid:n,id:t,fromMe:!0}}),!0}catch{return!1}}async sendTyping(e){if(!this.sock)return;let t=e.includes("@")?e:`${e}@s.whatsapp.net`;try{await this.sock.sendPresenceUpdate("composing",t)}catch{}}async react(e,t,s="\u{1F440}"){if(!this.sock)return;let n=e.includes("@")?e:`${e}@s.whatsapp.net`;try{await this.sock.sendMessage(n,{react:{text:s,key:{remoteJid:n,id:t}}})}catch{}}};import{writeFileSync as Ue,mkdirSync as de,existsSync as he}from"fs";import{resolve as q}from"path";function T(l,e,t){let s=[];for(let n of l.split(","))if(n==="*")for(let r=e;r<=t;r++)s.push(r);else if(n.includes("/")){let[r,i]=n.split("/"),o=parseInt(i,10),a=r==="*"?e:parseInt(r,10);for(let g=a;g<=t;g+=o)s.push(g)}else if(n.includes("-")){let[r,i]=n.split("-").map(Number);for(let o=r;o<=i;o++)s.push(o)}else s.push(parseInt(n,10));return[...new Set(s)].sort((n,r)=>n-r)}function Ge(l,e,t){let s=l.trim().split(/\s+/);if(s.length!==5)throw new Error(`Invalid cron: ${l}`);let n=T(s[0],0,59),r=T(s[1],0,23),i=T(s[2],1,31),o=T(s[3],1,12),a=T(s[4],0,6),g=new Intl.DateTimeFormat("en-US",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1}),c=new Date(e.getTime()+6e4);c.setSeconds(0,0);let h=new Date(c.getTime()+366*24*60*60*1e3);for(;c<h;){let u=g.formatToParts(c),m=x=>parseInt(u.find($=>$.type===x)?.value||"0",10),f=m("minute"),y=m("hour"),p=m("day"),w=m("month"),k=c.getDay();if(n.includes(f)&&r.includes(y)&&i.includes(p)&&o.includes(w)&&a.includes(k))return c;c.setTime(c.getTime()+6e4)}throw new Error(`No next run found for cron "${l}" within 1 year`)}var H=class{jobs=new Map;timers=new Map;registry;hooks;runsDir;running=!1;log;constructor(e,t,s,n=console.error.bind(console,"[cron]")){this.registry=t,this.hooks=s,this.log=n,this.runsDir=q(process.cwd(),".agentx/cron/runs");for(let[r,i]of Object.entries(e.crons))this.jobs.set(r,{id:r,enabled:i.enabled,schedule:i.schedule,timezone:i.timezone,agent:i.agent,prompt:i.prompt,timeout:i.timeout,model:i.model,onError:i.onError,consecutiveErrors:0,totalRuns:0})}async start(){this.running=!0,he(this.runsDir)||de(this.runsDir,{recursive:!0});for(let[e,t]of this.jobs){if(!t.enabled){this.log(`Job "${e}" is disabled, skipping`);continue}this.scheduleNext(e)}this.log(`${this.jobs.size} cron job(s) loaded, ${Array.from(this.jobs.values()).filter(e=>e.enabled).length} enabled`)}async stop(){this.running=!1;for(let e of this.timers.values())clearTimeout(e);this.timers.clear()}scheduleNext(e){let t=this.jobs.get(e);if(!(!t||!t.enabled||!this.running))try{let s=Ge(t.schedule,new Date,t.timezone);t.nextRun=s;let n=s.getTime()-Date.now();this.log(`Job "${e}" next run: ${s.toISOString()} (in ${Math.round(n/1e3)}s)`);let r=setTimeout(()=>this.executeJob(e),n);this.timers.set(e,r)}catch(s){this.log(`Failed to schedule "${e}": ${s.message}`)}}async executeJob(e){let t=this.jobs.get(e);if(!t||!this.running)return;if(this.hooks?.has("pre:cron-run")){let n=await this.hooks.execute("pre:cron-run",{event:"pre:cron-run",jobId:e,agent:t.agent,prompt:t.prompt});if(n.blocked){this.log(`Job "${e}" blocked by hook: ${n.message}`),this.scheduleNext(e);return}}this.log(`Executing job "${e}" -> agent "${t.agent}"`);let s=new Date;t.lastRun=s,t.totalRuns++;try{let n=await this.registry.execute({message:t.prompt,agentId:t.agent,context:{channel:"cron"}}),r={jobId:e,startedAt:s,completedAt:new Date,success:!n.error,response:n.content,error:n.error,duration:n.duration||Date.now()-s.getTime()};n.error?(t.consecutiveErrors++,this.log(`Job "${e}" failed (${t.consecutiveErrors} consecutive): ${n.error}`),t.onError==="disable"&&t.consecutiveErrors>=3&&(t.enabled=!1,this.log(`Job "${e}" disabled after ${t.consecutiveErrors} consecutive errors`))):(t.consecutiveErrors=0,this.log(`Job "${e}" completed in ${r.duration}ms`)),this.logRun(r),this.hooks?.has("post:cron-run")&&await this.hooks.execute("post:cron-run",{event:"post:cron-run",jobId:e,success:r.success,duration:r.duration,error:r.error?new Error(r.error):void 0})}catch(n){t.consecutiveErrors++,this.log(`Job "${e}" threw: ${n.message}`)}this.scheduleNext(e)}logRun(e){try{let t=q(this.runsDir,e.jobId);he(t)||de(t,{recursive:!0});let s=`${e.startedAt.toISOString().replace(/[:.]/g,"-")}.json`;Ue(q(t,s),JSON.stringify(e,null,2))}catch{}}list(){return Array.from(this.jobs.values())}};import{createServer as Ke}from"http";var F=class{name="discord";token;agentBinding;handler;client=null;log;constructor(e,t=console.error.bind(console,"[discord]")){this.token=e.token,this.agentBinding=e.agentBinding,this.log=t}onMessage(e){this.handler=e}async start(){let e;try{e=await import("discord.js")}catch{this.log("Discord requires discord.js. Install with:"),this.log(" npm install discord.js");return}let{Client:t,GatewayIntentBits:s}=e;this.client=new t({intents:[s.Guilds,s.GuildMessages,s.MessageContent,s.DirectMessages]}),this.client.on("ready",()=>{this.log(`Discord connected as ${this.client.user?.tag}`)}),this.client.on("messageCreate",async n=>{if(!this.handler||n.author.bot)return;let r=n.mentions.users.has(this.client.user?.id),i=!n.guild;if(!r&&!i)return;let o=n.content;if(this.client.user&&(o=o.replace(new RegExp(`<@!?${this.client.user.id}>`,"g"),"").trim()),!o)return;let a={id:n.id,channel:"discord",accountId:"default",sender:{id:n.author.id,name:n.author.displayName||n.author.username,username:n.author.username},group:n.guild?{id:n.channelId,name:n.channel?.name||n.channelId}:void 0,text:o,replyTo:n.reference?.messageId,timestamp:n.createdAt,raw:n};this.handler(a).catch(g=>{this.log(`Error handling message: ${g.message}`)})});try{await this.client.login(this.token)}catch(n){this.log(`Discord login failed: ${n.message}`)}}async stop(){this.client&&(this.client.destroy(),this.client=null)}async send(e){if(!this.client)return"";try{let t=await this.client.channels.fetch(e.chatId);return t?.isTextBased()?(await t.send({content:e.text,...e.replyTo?{reply:{messageReference:e.replyTo}}:{}})).id:""}catch(t){return this.log(`Send error: ${t.message}`),""}}async editMessage(e,t,s){if(!this.client)return!1;try{let n=await this.client.channels.fetch(e);return n?.isTextBased()?(await(await n.messages.fetch(t)).edit(s),!0):!1}catch{return!1}}async sendTyping(e){if(this.client)try{let t=await this.client.channels.fetch(e);t?.isTextBased()&&await t.sendTyping()}catch{}}async react(e,t,s="\u{1F440}"){if(this.client)try{let n=await this.client.channels.fetch(e);if(!n?.isTextBased())return;await(await n.messages.fetch(t)).react(s)}catch{}}};var ue=class{config;registry;router;cron;mesh;hooks;httpServer;log;constructor(e){this.log=console.error.bind(console,"[agentx]"),this.log("Loading configuration..."),this.config=te(e);let t=se(this.config);for(let s of t)this.log(` \u26A0 ${s}`);this.hooks=new X,Z(process.cwd(),this.hooks),this.registry=new W(this.config,this.log),this.router=new O(this.registry,this.config,this.hooks,this.log),this.cron=new H(this.config,this.registry,this.hooks,this.log),this.config.mesh.enabled&&(this.mesh=new D(this.config,this.log),this.router.setMesh(this.mesh))}async start(){this.log(""),this.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),this.log(" \u2502 agentx daemon \u2502"),this.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),this.log(""),this.log(` Node: ${this.config.node.name} (${this.config.node.id})`),this.log(` Bind: ${this.config.node.bind}`),this.log(""),await this.startChannels(),await this.cron.start(),this.mesh&&await this.mesh.start(),await this.startHttpApi(),this.log(""),this.log(" Agents:");for(let t of this.registry.list())this.log(` ${t.id} (${t.tier}) \u2192 ${t.workspace}`);let e=this.cron.list();if(e.length){this.log(""),this.log(" Cron Jobs:");for(let t of e){let s=t.enabled?"enabled":"disabled";this.log(` ${t.id} [${s}] \u2192 ${t.agent} (${t.schedule})`)}}if(this.mesh){this.log(""),this.log(" Mesh Peers:");for(let t of this.mesh.directory()){let s=t.healthy?"\u2713":"\u2717";this.log(` ${s} ${t.peer} (${t.peerUrl})`)}}this.log(""),this.log(" Ready."),this.log(""),process.on("SIGINT",()=>this.stop()),process.on("SIGTERM",()=>this.stop())}async stop(){this.log("Shutting down..."),await this.router.stopAll(),await this.cron.stop(),this.mesh&&await this.mesh.stop(),this.httpServer&&this.httpServer.close(),this.log("Goodbye."),process.exit(0)}async startChannels(){if(this.config.channels.telegram.enabled){let e=this.config.channels.telegram.accounts;if(Object.keys(e).length>0){let t=new N(e,this.log);this.router.addChannel(t),this.log(" Telegram: enabled")}}if(this.config.channels.whatsapp.enabled){let e=new J({sessionDir:this.config.channels.whatsapp.sessionDir,defaultAgent:this.config.channels.whatsapp.defaultAgent,allowFrom:this.config.channels.whatsapp.allowFrom,routes:this.config.channels.whatsapp.routes},this.log);this.router.addChannel(e),this.log(` WhatsApp: enabled (${this.config.channels.whatsapp.routes.length} routes)`)}if(this.config.channels.discord?.enabled&&this.config.channels.discord.token){let e=new F({token:this.config.channels.discord.token,agentBinding:this.config.channels.discord.agentBinding},this.log);this.router.addChannel(e),this.log(" Discord: enabled")}await this.router.startAll()}async startHttpApi(){let[e,t]=this.config.node.bind.split(":"),s=parseInt(t||"18800",10);this.httpServer=Ke(async(n,r)=>{if(r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),r.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),n.method==="OPTIONS"){r.writeHead(204),r.end();return}await this.handleHttp(n,r)}),this.httpServer.on("error",n=>{n.code==="EADDRINUSE"?(this.log(` ERROR: Port ${s} is already in use. Retrying in 5s...`),setTimeout(()=>{this.httpServer?.close(),this.httpServer?.listen(s,e||"0.0.0.0")},5e3)):this.log(` HTTP error: ${n.message}`)}),this.httpServer.listen(s,e||"0.0.0.0",()=>{this.log(` HTTP API: http://${e||"0.0.0.0"}:${s}`)})}async handleHttp(e,t){let n=new URL(e.url||"/",`http://${e.headers.host||"localhost"}`).pathname;try{switch(`${e.method} ${n}`){case"GET /health":this.json(t,200,{status:"ok",node:this.config.node,uptime:process.uptime(),agents:this.registry.list(),crons:this.cron.list().map(r=>({id:r.id,enabled:r.enabled,nextRun:r.nextRun})),mesh:this.mesh?.directory()||[]});break;case"GET /agents":this.json(t,200,this.registry.list());break;case"GET /crons":this.json(t,200,this.cron.list());break;case"GET /mesh":this.json(t,200,this.mesh?.directory()||[]);break;case"POST /task":{let r=await pe(e);if(!r.agent||!r.message){this.json(t,400,{error:"Missing: agent, message"});return}let i=await this.registry.execute({agentId:r.agent,message:r.message,context:r.context});this.json(t,i.error?500:200,i);break}case"POST /mesh/task":{let r=await pe(e);if(!r.peer||!r.message){this.json(t,400,{error:"Missing: peer, message"});return}if(!this.mesh){this.json(t,400,{error:"Mesh not enabled"});return}let i=await this.mesh.sendTask(r.peer,r.message);this.json(t,200,{response:i});break}case"GET /.well-known/agent-card.json":this.json(t,200,{name:this.config.node.name,description:`AgentX daemon node "${this.config.node.name}"`,url:`http://${this.config.node.bind}`,version:"1.0.0",capabilities:{streaming:!1,pushNotifications:!1,stateTransitionHistory:!1},skills:this.registry.list().map(r=>({id:r.id,name:r.name,description:`Agent "${r.name}" (${r.tier})`,tags:[r.tier]})),defaultInputModes:["text"],defaultOutputModes:["text"]});break;default:this.json(t,404,{error:"Not found",endpoints:["GET /health","GET /agents","GET /crons","GET /mesh","POST /task { agent, message, context? }","POST /mesh/task { peer, message }","GET /.well-known/agent-card.json"]})}}catch(r){this.json(t,500,{error:r.message})}}json(e,t,s){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(s,null,2))}};async function pe(l){return new Promise((e,t)=>{let s="";l.on("data",n=>s+=n.toString()),l.on("end",()=>{try{e(s?JSON.parse(s):{})}catch{e({})}}),l.on("error",t)})}import ze from"path";import Ve from"fs-extra";function Ut(){let l=ze.join("package.json");return Ve.readJSONSync(l)}export{M as a,D as b,Se as c,te as d,se as e,De as f,Pe as g,Re as h,ie as i,S as j,W as k,O as l,N as m,J as n,H as o,ue as p,Ut as q};
35
- //# sourceMappingURL=chunk-S74N276K.js.map