agentix-cli 0.21.0 → 0.22.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.
Files changed (62) hide show
  1. package/dist/{agent-I3ILI3MO.js → agent-Y4U4R3ZZ.js} +2 -2
  2. package/dist/{board-dashboard-ASI6MDKX.js → board-dashboard-2CPBWFOB.js} +4 -4
  3. package/dist/{chunk-EQNM3TOF.js → chunk-2HXSJYAJ.js} +2 -2
  4. package/dist/{chunk-K6MC66D6.js → chunk-ABVZHJUO.js} +2 -2
  5. package/dist/chunk-BHSPAP4U.js +44 -0
  6. package/dist/chunk-BHSPAP4U.js.map +1 -0
  7. package/dist/chunk-CO4YCIIA.js +13 -0
  8. package/dist/{chunk-5GDCJ2SF.js.map → chunk-CO4YCIIA.js.map} +1 -1
  9. package/dist/{chunk-4MREHZP5.js → chunk-GOLZ6NEL.js} +2 -2
  10. package/dist/chunk-GOLZ6NEL.js.map +1 -0
  11. package/dist/{chunk-FUYZUGNQ.js → chunk-KX626FN4.js} +2 -2
  12. package/dist/chunk-OPKQNLGX.js +450 -0
  13. package/dist/chunk-OPKQNLGX.js.map +1 -0
  14. package/dist/chunk-OZOQKPJV.js +102 -0
  15. package/dist/chunk-OZOQKPJV.js.map +1 -0
  16. package/dist/{chunk-AANSVC5A.js → chunk-P3TJHGO5.js} +2 -2
  17. package/dist/{chunk-AGINLNAW.js → chunk-VYLZ7UYM.js} +2 -2
  18. package/dist/{chunk-2B2DIQKD.js → chunk-WHP4I44J.js} +2 -2
  19. package/dist/chunk-X5D5AV5N.js +833 -0
  20. package/dist/chunk-X5D5AV5N.js.map +1 -0
  21. package/dist/cli.js +1 -1
  22. package/dist/{config-RWHSEE4N.js → config-BLOKGMER.js} +2 -2
  23. package/dist/config-mutator-RG7QY2EL.js +2 -0
  24. package/dist/doctor-ZTECTUHX.js +2 -0
  25. package/dist/index.d.ts +140 -3
  26. package/dist/index.js +1 -1
  27. package/dist/program-GZOJIWTB.js +2 -0
  28. package/dist/registry-QZIUSQ5J.js +2 -0
  29. package/dist/scheduler-B2BQPV4M.js +2 -0
  30. package/dist/workspace-setup-DQCZX2NE.js +2 -0
  31. package/package.json +1 -1
  32. package/dist/chunk-4MREHZP5.js.map +0 -1
  33. package/dist/chunk-5GDCJ2SF.js +0 -13
  34. package/dist/chunk-5XZ73VM4.js +0 -102
  35. package/dist/chunk-5XZ73VM4.js.map +0 -1
  36. package/dist/chunk-BLRLUF2H.js +0 -743
  37. package/dist/chunk-BLRLUF2H.js.map +0 -1
  38. package/dist/chunk-IFQQVDM6.js +0 -442
  39. package/dist/chunk-IFQQVDM6.js.map +0 -1
  40. package/dist/chunk-ZE2YFX4K.js +0 -45
  41. package/dist/chunk-ZE2YFX4K.js.map +0 -1
  42. package/dist/config-mutator-JKCNCY2F.js +0 -2
  43. package/dist/doctor-KWN7NUFQ.js +0 -2
  44. package/dist/program-JEKM7SCS.js +0 -2
  45. package/dist/registry-EGKDMVSP.js +0 -2
  46. package/dist/scheduler-ED4FCI2Y.js +0 -2
  47. package/dist/workspace-setup-FPGN5VNY.js +0 -2
  48. /package/dist/{agent-I3ILI3MO.js.map → agent-Y4U4R3ZZ.js.map} +0 -0
  49. /package/dist/{board-dashboard-ASI6MDKX.js.map → board-dashboard-2CPBWFOB.js.map} +0 -0
  50. /package/dist/{chunk-EQNM3TOF.js.map → chunk-2HXSJYAJ.js.map} +0 -0
  51. /package/dist/{chunk-K6MC66D6.js.map → chunk-ABVZHJUO.js.map} +0 -0
  52. /package/dist/{chunk-FUYZUGNQ.js.map → chunk-KX626FN4.js.map} +0 -0
  53. /package/dist/{chunk-AANSVC5A.js.map → chunk-P3TJHGO5.js.map} +0 -0
  54. /package/dist/{chunk-AGINLNAW.js.map → chunk-VYLZ7UYM.js.map} +0 -0
  55. /package/dist/{chunk-2B2DIQKD.js.map → chunk-WHP4I44J.js.map} +0 -0
  56. /package/dist/{config-RWHSEE4N.js.map → config-BLOKGMER.js.map} +0 -0
  57. /package/dist/{config-mutator-JKCNCY2F.js.map → config-mutator-RG7QY2EL.js.map} +0 -0
  58. /package/dist/{doctor-KWN7NUFQ.js.map → doctor-ZTECTUHX.js.map} +0 -0
  59. /package/dist/{program-JEKM7SCS.js.map → program-GZOJIWTB.js.map} +0 -0
  60. /package/dist/{registry-EGKDMVSP.js.map → registry-QZIUSQ5J.js.map} +0 -0
  61. /package/dist/{scheduler-ED4FCI2Y.js.map → scheduler-B2BQPV4M.js.map} +0 -0
  62. /package/dist/{workspace-setup-FPGN5VNY.js.map → workspace-setup-DQCZX2NE.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{c as V}from"./chunk-N67JZAXU.js";import{b as Y}from"./chunk-AFRHKA7B.js";import{a as Te,b as Pe}from"./chunk-EW27SCCC.js";import{a as ve,c as Se,d as $e,e as Re}from"./chunk-K6MC66D6.js";import{e as Ae}from"./chunk-CDNWCYF7.js";import{c as Ie}from"./chunk-4MREHZP5.js";import{existsSync as I,mkdirSync as kt,readdirSync as Ce,readFileSync as X,unlinkSync as Q,writeFileSync as bt}from"fs";import{resolve as R,relative as ee}from"path";import{z as u}from"zod";var it=u.enum(["trigger.channel","trigger.manual","trigger.cron","trigger.hook","trigger.form","agent","transform","branch","gateway.parallel","rule","action.send","action.createIssue","action.setLabel","action.readLabel","action.react","action.editMessage","action.logTime","action.callHTTP","action.run","userTask","subProcess","signal.emit","signal.wait","timer.boundary","checkpoint","end"]),at=u.enum(["equals","contains","matches","exists"]),dt=u.object({kind:at,params:u.record(u.unknown()).default({})}),xe=u.object({id:u.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_-]*$/,"node id must be identifier-safe"),type:it,config:u.record(u.unknown()).default({}),position:u.object({x:u.number(),y:u.number()}).optional()}),je=u.object({from:u.string(),fromPort:u.string().optional(),to:u.string(),toPort:u.string().optional(),label:u.string().optional()}),j=u.object({id:u.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"workflow id must be lower-kebab"),version:u.literal(2).default(2),title:u.string().min(1),description:u.string().optional(),state:u.enum(["active","disabled","quarantined"]).default("active"),priority:u.number().int().default(0),fanOut:u.boolean().default(!1),nodes:u.array(xe).refine(s=>s.length>0,{message:"workflow must have at least one node"}),edges:u.array(je).default([]),envAllow:u.array(u.string()).default([]),retention:u.object({maxRuns:u.number().int().positive().default(500),maxDays:u.number().int().positive().default(90)}).default({maxRuns:500,maxDays:90}),maxChildDepth:u.number().int().positive().default(5),mesh:u.object({allowRemote:u.boolean().default(!1),peers:u.array(u.string()).optional()}).default({allowRemote:!1}),created:u.string().optional(),updated:u.string().optional()});function Z(s){let e=[],t=new Map(s.nodes.map(i=>[i.id,i])),n=s.nodes.filter(i=>i.type.startsWith("trigger."));n.length===0&&e.push("workflow must have exactly one trigger.* node (found 0)"),n.length>1&&e.push(`workflow has ${n.length} trigger.* nodes; v1 supports exactly one`);for(let i of s.edges)t.has(i.from)||e.push(`edge references missing node: from="${i.from}"`),t.has(i.to)||e.push(`edge references missing node: to="${i.to}"`);let r=n[0];if(r){let i=new Map;for(let l of s.edges)i.has(l.from)||i.set(l.from,[]),i.get(l.from).push(l.to);let a=new Set,d=[r.id];for(;d.length;){let l=d.pop();if(!a.has(l)){a.add(l);for(let g of i.get(l)??[])d.push(g)}}for(let l of s.nodes)a.has(l.id)||e.push(`node "${l.id}" is unreachable from trigger "${r.id}"`);s.nodes.some(l=>a.has(l.id)&&lt(l.type))||e.push("no reachable `end`, `checkpoint`, `userTask`, `subProcess`, `signal.wait`, or `timer.boundary` node \u2014 the run cannot terminate or pause")}for(let i of s.nodes){if(i.type!=="branch"&&i.type!=="rule")continue;let a=i.type==="branch"?i.config.cases??[]:(i.config.rules??[]).filter(c=>typeof c.to=="string"),d=i.type==="branch"?i.config.default:i.config.default?.to,l=new Set(a.map(c=>c.to));d&&l.add(d);let g=s.edges.filter(c=>c.from===i.id);for(let c of g){let p=c.fromPort??"";l.has(p)||e.push(`${i.type} "${i.id}" has outgoing edge with port "${p}" not declared in cases or default`)}}let o=ut(s);for(let i of o)e.push(`cycle without agent/checkpoint: ${i.join(" -> ")}`);return e}function lt(s){return s==="end"||s==="checkpoint"||s==="userTask"||s==="subProcess"||s==="signal.wait"||s==="timer.boundary"}function ct(s){return s==="agent"||s==="checkpoint"||s==="userTask"||s==="subProcess"||s==="signal.wait"||s==="timer.boundary"}function ut(s){let e=new Map;for(let a of s.edges)e.has(a.from)||e.set(a.from,[]),e.get(a.from).push(a.to);let t=new Map(s.nodes.map(a=>[a.id,a])),n=[],r=new Map,o=[],i=a=>{if(r.get(a)===1){let d=o.indexOf(a);if(d>=0){let l=o.slice(d).concat(a);l.some(c=>{let p=t.get(c)?.type;return p?ct(p):!1})||n.push(l)}return}if(r.get(a)!==2){r.set(a,1),o.push(a);for(let d of e.get(a)??[])i(d);o.pop(),r.set(a,2)}};for(let a of s.nodes)r.get(a.id)!==2&&i(a.id);return n}var We=u.enum(["running","paused","completed","failed","canceled"]),pt=u.enum(["ok","failed","timeout","skipped","paused","resumed"]),gt=u.object({at:u.string(),nodeId:u.string(),inputKeys:u.array(u.string()).default([]),status:pt,output:u.record(u.unknown()).optional(),idempotencyKey:u.string(),note:u.string().optional()}),ft=u.object({backend:u.string(),id:u.string()}),mt=u.discriminatedUnion("kind",[u.object({kind:u.literal("checkpoint"),nodeId:u.string(),checkpointName:u.string(),resumeMatch:u.record(u.unknown()).default({})}),u.object({kind:u.literal("userTask"),nodeId:u.string(),taskId:u.string(),assignee:u.string(),assignedTo:u.array(u.string()).default([])}),u.object({kind:u.literal("subProcess"),nodeId:u.string(),childRunId:u.string(),childWorkflowId:u.string()}),u.object({kind:u.literal("signalWait"),nodeId:u.string(),signalName:u.string(),match:u.record(u.unknown()).default({}),scope:u.enum(["workflow","global"]).default("workflow")}),u.object({kind:u.literal("timerWait"),nodeId:u.string(),fireAt:u.string()})]),ht=u.object({id:u.string(),workflowId:u.string(),workflowVersion:u.literal(2),homeNode:u.string(),status:We,pausedAt:mt.optional(),context:u.record(u.record(u.unknown())).default({}),pending:u.array(u.string()).default([]),joinCounters:u.record(u.array(u.string())).default({}),entityRef:ft,history:u.array(gt).default([]),parentRunId:u.string().nullable().default(null),parentNodeId:u.string().nullable().default(null),rootRunId:u.string().nullable().default(null),depth:u.number().int().min(0).default(0),createdAt:u.string(),updatedAt:u.string()});import Oe from"js-yaml";var yt=new Set(["branch","gateway.parallel","rule","signal.wait","userTask","subProcess","timer.boundary","checkpoint"]),b=class extends Error{constructor(t,n){super(t);this.mark=n;this.name="WorkflowYamlError"}};function U(s,e={}){if(!s||s.trim()==="")throw new b(`${$(e)}empty file \u2014 workflow YAML must contain at least an id, version, title, and one node.`);let t;try{t=Oe.loadAll(s)}catch(r){let o=r?.mark;throw new b(`${$(e)}YAML parse error: ${r?.reason??r?.message??r}`+(o?` (line ${o.line+1}, column ${o.column+1})`:""),o)}if(t.length===0||t.length===1&&t[0]==null)throw new b(`${$(e)}YAML produced no document.`);if(t.length>1)throw new b(`${$(e)}multi-document YAML is not supported in v1; one workflow per file.`);let n=t[0];if(typeof n!="object"||n===null||Array.isArray(n)){let r=Array.isArray(n)?"array":typeof n;throw new b(`${$(e)}top-level YAML must be a mapping (got ${r}).`)}return Ee(n,e)}function Ee(s,e={}){if(!("flow"in s))return s;let t=s.flow;if(t==null){let c={...s};return delete c.flow,c}if(!Array.isArray(t))throw new b(`${$(e)}flow must be an array of node ids (got ${typeof t}).`);for(let c of t)if(typeof c!="string")throw new b(`${$(e)}flow entries must be strings (got ${typeof c}).`);let n=t,r=Array.isArray(s.nodes)?s.nodes:[],o=new Map;for(let c of r)c&&typeof c=="object"&&typeof c.id=="string"&&typeof c.type=="string"&&o.set(c.id,c.type);for(let c of n){if(!o.has(c))throw new b(`${$(e)}flow references unknown node "${c}".`);let p=o.get(c);if(yt.has(p))throw new b(`${$(e)}flow cannot include ${p} node "${c}"; use explicit edges for ${p} nodes.`)}let i=[];for(let c=0;c<n.length-1;c++)i.push({from:n[c],to:n[c+1]});let a=Array.isArray(s.edges)?s.edges:[],d=new Set,l=[];for(let c of a){if(!c||typeof c!="object")continue;let p=Ne(c.from,c.fromPort,c.to);p&&!d.has(p)?(d.add(p),l.push(c)):p||l.push(c)}for(let c of i){let p=Ne(c.from,void 0,c.to);p&&!d.has(p)&&(d.add(p),l.push(c))}let g={...s,edges:l};return delete g.flow,g}function Ne(s,e,t){return typeof s!="string"||typeof t!="string"?null:`${s}::${typeof e=="string"?e:""}::${t}`}function $(s){return s.filePath?`${s.filePath}: `:""}function wt(s){return Oe.dump(s,{noRefs:!0,lineWidth:100,sortKeys:!1})}var te=class{baseDir;constructor(e={}){this.baseDir=e.baseDir??R(process.cwd(),".agentx/workflows"),kt(this.baseDir,{recursive:!0})}pathFor(e){return this.pathForJson(e)}pathForJson(e){return R(this.baseDir,`${e}.json`)}pathForYaml(e){return R(this.baseDir,`${e}.yaml`)}isWorkflowFile(e){return e.startsWith("_")?!1:e.endsWith(".json")||e.endsWith(".yaml")||e.endsWith(".yml")}idFromFilename(e){return e.replace(/\.(json|ya?ml)$/,"")}readAndParse(e){let t=R(this.baseDir,e),n=X(t,"utf-8");return e.endsWith(".json")?JSON.parse(n):U(n,{filePath:e})}list(){if(!I(this.baseDir))return[];let e=new Map;for(let n of Ce(this.baseDir,{withFileTypes:!0})){if(!n.isFile()||!this.isWorkflowFile(n.name))continue;let r=this.idFromFilename(n.name),o=e.get(r)??[];o.push(n.name),e.set(r,o)}let t=[];for(let[,n]of e)if(!(n.length>1))try{let r=this.readAndParse(n[0]),o=j.safeParse(r);o.success&&t.push(o.data)}catch{}return t.sort((n,r)=>n.id.localeCompare(r.id))}validateAll(){let e=[];if(!I(this.baseDir))return e;let t=new Map;for(let n of Ce(this.baseDir,{withFileTypes:!0})){if(!n.isFile()||!this.isWorkflowFile(n.name))continue;let r=this.idFromFilename(n.name),o=t.get(r)??[];o.push(n.name),t.set(r,o)}for(let[n,r]of t){if(r.length>1){let c=[...r].sort();for(let p of c)e.push({id:n,path:ee(this.baseDir,R(this.baseDir,p)),issues:[`duplicate workflow id "${n}" \u2014 found ${c.join(" and ")}; delete one to disambiguate`],isValid:!1});continue}let o=r[0],i=R(this.baseDir,o),a=ee(this.baseDir,i),d;try{d=this.readAndParse(o)}catch(c){let p=c instanceof b?c.message:`parse error: ${c?.message??c}`;e.push({id:n,path:a,issues:[p],isValid:!1});continue}let l=j.safeParse(d);if(!l.success){let c=l.error.issues.map(p=>`${p.path.join(".")||"<root>"}: ${p.message}`);e.push({id:String(d?.id??n),path:a,issues:c,isValid:!1});continue}let g=Z(l.data);e.push({workflow:l.data,issues:g,isValid:g.length===0})}return e}get(e){let t=this.pathForJson(e),n=this.pathForYaml(e),r=R(this.baseDir,`${e}.yml`),o=I(t),i=I(n)||I(r);if(o&&i)return null;if(o)try{let d=JSON.parse(X(t,"utf-8")),l=j.safeParse(d);return l.success?l.data:null}catch{return null}let a=I(n)?n:I(r)?r:null;if(!a)return null;try{let d=X(a,"utf-8"),l=U(d,{filePath:ee(this.baseDir,a)}),g=j.safeParse(l);return g.success?g.data:null}catch{return null}}save(e){let t=new Date().toISOString().slice(0,10),n=j.parse({...e,created:e.created||t,updated:t}),r=this.pathForYaml(n.id),o=R(this.baseDir,`${n.id}.yml`);if(I(r)||I(o))throw new Error(`yaml-authored workflow "${n.id}" exists at ${I(r)?r:o}; edit on disk or delete the YAML before saving from the editor`);return bt(this.pathForJson(n.id),JSON.stringify(n,null,2)+`
1
+ import{c as V}from"./chunk-N67JZAXU.js";import{b as Y}from"./chunk-AFRHKA7B.js";import{a as Te,b as Pe}from"./chunk-EW27SCCC.js";import{a as ve,c as Se,d as $e,e as Re}from"./chunk-ABVZHJUO.js";import{e as Ae}from"./chunk-CDNWCYF7.js";import{c as Ie}from"./chunk-GOLZ6NEL.js";import{existsSync as I,mkdirSync as kt,readdirSync as Ce,readFileSync as X,unlinkSync as Q,writeFileSync as bt}from"fs";import{resolve as R,relative as ee}from"path";import{z as u}from"zod";var it=u.enum(["trigger.channel","trigger.manual","trigger.cron","trigger.hook","trigger.form","agent","transform","branch","gateway.parallel","rule","action.send","action.createIssue","action.setLabel","action.readLabel","action.react","action.editMessage","action.logTime","action.callHTTP","action.run","userTask","subProcess","signal.emit","signal.wait","timer.boundary","checkpoint","end"]),at=u.enum(["equals","contains","matches","exists"]),dt=u.object({kind:at,params:u.record(u.unknown()).default({})}),xe=u.object({id:u.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_-]*$/,"node id must be identifier-safe"),type:it,config:u.record(u.unknown()).default({}),position:u.object({x:u.number(),y:u.number()}).optional()}),je=u.object({from:u.string(),fromPort:u.string().optional(),to:u.string(),toPort:u.string().optional(),label:u.string().optional()}),j=u.object({id:u.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"workflow id must be lower-kebab"),version:u.literal(2).default(2),title:u.string().min(1),description:u.string().optional(),state:u.enum(["active","disabled","quarantined"]).default("active"),priority:u.number().int().default(0),fanOut:u.boolean().default(!1),nodes:u.array(xe).refine(s=>s.length>0,{message:"workflow must have at least one node"}),edges:u.array(je).default([]),envAllow:u.array(u.string()).default([]),retention:u.object({maxRuns:u.number().int().positive().default(500),maxDays:u.number().int().positive().default(90)}).default({maxRuns:500,maxDays:90}),maxChildDepth:u.number().int().positive().default(5),mesh:u.object({allowRemote:u.boolean().default(!1),peers:u.array(u.string()).optional()}).default({allowRemote:!1}),created:u.string().optional(),updated:u.string().optional()});function Z(s){let e=[],t=new Map(s.nodes.map(i=>[i.id,i])),n=s.nodes.filter(i=>i.type.startsWith("trigger."));n.length===0&&e.push("workflow must have exactly one trigger.* node (found 0)"),n.length>1&&e.push(`workflow has ${n.length} trigger.* nodes; v1 supports exactly one`);for(let i of s.edges)t.has(i.from)||e.push(`edge references missing node: from="${i.from}"`),t.has(i.to)||e.push(`edge references missing node: to="${i.to}"`);let r=n[0];if(r){let i=new Map;for(let l of s.edges)i.has(l.from)||i.set(l.from,[]),i.get(l.from).push(l.to);let a=new Set,d=[r.id];for(;d.length;){let l=d.pop();if(!a.has(l)){a.add(l);for(let g of i.get(l)??[])d.push(g)}}for(let l of s.nodes)a.has(l.id)||e.push(`node "${l.id}" is unreachable from trigger "${r.id}"`);s.nodes.some(l=>a.has(l.id)&&lt(l.type))||e.push("no reachable `end`, `checkpoint`, `userTask`, `subProcess`, `signal.wait`, or `timer.boundary` node \u2014 the run cannot terminate or pause")}for(let i of s.nodes){if(i.type!=="branch"&&i.type!=="rule")continue;let a=i.type==="branch"?i.config.cases??[]:(i.config.rules??[]).filter(c=>typeof c.to=="string"),d=i.type==="branch"?i.config.default:i.config.default?.to,l=new Set(a.map(c=>c.to));d&&l.add(d);let g=s.edges.filter(c=>c.from===i.id);for(let c of g){let p=c.fromPort??"";l.has(p)||e.push(`${i.type} "${i.id}" has outgoing edge with port "${p}" not declared in cases or default`)}}let o=ut(s);for(let i of o)e.push(`cycle without agent/checkpoint: ${i.join(" -> ")}`);return e}function lt(s){return s==="end"||s==="checkpoint"||s==="userTask"||s==="subProcess"||s==="signal.wait"||s==="timer.boundary"}function ct(s){return s==="agent"||s==="checkpoint"||s==="userTask"||s==="subProcess"||s==="signal.wait"||s==="timer.boundary"}function ut(s){let e=new Map;for(let a of s.edges)e.has(a.from)||e.set(a.from,[]),e.get(a.from).push(a.to);let t=new Map(s.nodes.map(a=>[a.id,a])),n=[],r=new Map,o=[],i=a=>{if(r.get(a)===1){let d=o.indexOf(a);if(d>=0){let l=o.slice(d).concat(a);l.some(c=>{let p=t.get(c)?.type;return p?ct(p):!1})||n.push(l)}return}if(r.get(a)!==2){r.set(a,1),o.push(a);for(let d of e.get(a)??[])i(d);o.pop(),r.set(a,2)}};for(let a of s.nodes)r.get(a.id)!==2&&i(a.id);return n}var We=u.enum(["running","paused","completed","failed","canceled"]),pt=u.enum(["ok","failed","timeout","skipped","paused","resumed"]),gt=u.object({at:u.string(),nodeId:u.string(),inputKeys:u.array(u.string()).default([]),status:pt,output:u.record(u.unknown()).optional(),idempotencyKey:u.string(),note:u.string().optional()}),ft=u.object({backend:u.string(),id:u.string()}),mt=u.discriminatedUnion("kind",[u.object({kind:u.literal("checkpoint"),nodeId:u.string(),checkpointName:u.string(),resumeMatch:u.record(u.unknown()).default({})}),u.object({kind:u.literal("userTask"),nodeId:u.string(),taskId:u.string(),assignee:u.string(),assignedTo:u.array(u.string()).default([])}),u.object({kind:u.literal("subProcess"),nodeId:u.string(),childRunId:u.string(),childWorkflowId:u.string()}),u.object({kind:u.literal("signalWait"),nodeId:u.string(),signalName:u.string(),match:u.record(u.unknown()).default({}),scope:u.enum(["workflow","global"]).default("workflow")}),u.object({kind:u.literal("timerWait"),nodeId:u.string(),fireAt:u.string()})]),ht=u.object({id:u.string(),workflowId:u.string(),workflowVersion:u.literal(2),homeNode:u.string(),status:We,pausedAt:mt.optional(),context:u.record(u.record(u.unknown())).default({}),pending:u.array(u.string()).default([]),joinCounters:u.record(u.array(u.string())).default({}),entityRef:ft,history:u.array(gt).default([]),parentRunId:u.string().nullable().default(null),parentNodeId:u.string().nullable().default(null),rootRunId:u.string().nullable().default(null),depth:u.number().int().min(0).default(0),createdAt:u.string(),updatedAt:u.string()});import Oe from"js-yaml";var yt=new Set(["branch","gateway.parallel","rule","signal.wait","userTask","subProcess","timer.boundary","checkpoint"]),b=class extends Error{constructor(t,n){super(t);this.mark=n;this.name="WorkflowYamlError"}};function U(s,e={}){if(!s||s.trim()==="")throw new b(`${$(e)}empty file \u2014 workflow YAML must contain at least an id, version, title, and one node.`);let t;try{t=Oe.loadAll(s)}catch(r){let o=r?.mark;throw new b(`${$(e)}YAML parse error: ${r?.reason??r?.message??r}`+(o?` (line ${o.line+1}, column ${o.column+1})`:""),o)}if(t.length===0||t.length===1&&t[0]==null)throw new b(`${$(e)}YAML produced no document.`);if(t.length>1)throw new b(`${$(e)}multi-document YAML is not supported in v1; one workflow per file.`);let n=t[0];if(typeof n!="object"||n===null||Array.isArray(n)){let r=Array.isArray(n)?"array":typeof n;throw new b(`${$(e)}top-level YAML must be a mapping (got ${r}).`)}return Ee(n,e)}function Ee(s,e={}){if(!("flow"in s))return s;let t=s.flow;if(t==null){let c={...s};return delete c.flow,c}if(!Array.isArray(t))throw new b(`${$(e)}flow must be an array of node ids (got ${typeof t}).`);for(let c of t)if(typeof c!="string")throw new b(`${$(e)}flow entries must be strings (got ${typeof c}).`);let n=t,r=Array.isArray(s.nodes)?s.nodes:[],o=new Map;for(let c of r)c&&typeof c=="object"&&typeof c.id=="string"&&typeof c.type=="string"&&o.set(c.id,c.type);for(let c of n){if(!o.has(c))throw new b(`${$(e)}flow references unknown node "${c}".`);let p=o.get(c);if(yt.has(p))throw new b(`${$(e)}flow cannot include ${p} node "${c}"; use explicit edges for ${p} nodes.`)}let i=[];for(let c=0;c<n.length-1;c++)i.push({from:n[c],to:n[c+1]});let a=Array.isArray(s.edges)?s.edges:[],d=new Set,l=[];for(let c of a){if(!c||typeof c!="object")continue;let p=Ne(c.from,c.fromPort,c.to);p&&!d.has(p)?(d.add(p),l.push(c)):p||l.push(c)}for(let c of i){let p=Ne(c.from,void 0,c.to);p&&!d.has(p)&&(d.add(p),l.push(c))}let g={...s,edges:l};return delete g.flow,g}function Ne(s,e,t){return typeof s!="string"||typeof t!="string"?null:`${s}::${typeof e=="string"?e:""}::${t}`}function $(s){return s.filePath?`${s.filePath}: `:""}function wt(s){return Oe.dump(s,{noRefs:!0,lineWidth:100,sortKeys:!1})}var te=class{baseDir;constructor(e={}){this.baseDir=e.baseDir??R(process.cwd(),".agentx/workflows"),kt(this.baseDir,{recursive:!0})}pathFor(e){return this.pathForJson(e)}pathForJson(e){return R(this.baseDir,`${e}.json`)}pathForYaml(e){return R(this.baseDir,`${e}.yaml`)}isWorkflowFile(e){return e.startsWith("_")?!1:e.endsWith(".json")||e.endsWith(".yaml")||e.endsWith(".yml")}idFromFilename(e){return e.replace(/\.(json|ya?ml)$/,"")}readAndParse(e){let t=R(this.baseDir,e),n=X(t,"utf-8");return e.endsWith(".json")?JSON.parse(n):U(n,{filePath:e})}list(){if(!I(this.baseDir))return[];let e=new Map;for(let n of Ce(this.baseDir,{withFileTypes:!0})){if(!n.isFile()||!this.isWorkflowFile(n.name))continue;let r=this.idFromFilename(n.name),o=e.get(r)??[];o.push(n.name),e.set(r,o)}let t=[];for(let[,n]of e)if(!(n.length>1))try{let r=this.readAndParse(n[0]),o=j.safeParse(r);o.success&&t.push(o.data)}catch{}return t.sort((n,r)=>n.id.localeCompare(r.id))}validateAll(){let e=[];if(!I(this.baseDir))return e;let t=new Map;for(let n of Ce(this.baseDir,{withFileTypes:!0})){if(!n.isFile()||!this.isWorkflowFile(n.name))continue;let r=this.idFromFilename(n.name),o=t.get(r)??[];o.push(n.name),t.set(r,o)}for(let[n,r]of t){if(r.length>1){let c=[...r].sort();for(let p of c)e.push({id:n,path:ee(this.baseDir,R(this.baseDir,p)),issues:[`duplicate workflow id "${n}" \u2014 found ${c.join(" and ")}; delete one to disambiguate`],isValid:!1});continue}let o=r[0],i=R(this.baseDir,o),a=ee(this.baseDir,i),d;try{d=this.readAndParse(o)}catch(c){let p=c instanceof b?c.message:`parse error: ${c?.message??c}`;e.push({id:n,path:a,issues:[p],isValid:!1});continue}let l=j.safeParse(d);if(!l.success){let c=l.error.issues.map(p=>`${p.path.join(".")||"<root>"}: ${p.message}`);e.push({id:String(d?.id??n),path:a,issues:c,isValid:!1});continue}let g=Z(l.data);e.push({workflow:l.data,issues:g,isValid:g.length===0})}return e}get(e){let t=this.pathForJson(e),n=this.pathForYaml(e),r=R(this.baseDir,`${e}.yml`),o=I(t),i=I(n)||I(r);if(o&&i)return null;if(o)try{let d=JSON.parse(X(t,"utf-8")),l=j.safeParse(d);return l.success?l.data:null}catch{return null}let a=I(n)?n:I(r)?r:null;if(!a)return null;try{let d=X(a,"utf-8"),l=U(d,{filePath:ee(this.baseDir,a)}),g=j.safeParse(l);return g.success?g.data:null}catch{return null}}save(e){let t=new Date().toISOString().slice(0,10),n=j.parse({...e,created:e.created||t,updated:t}),r=this.pathForYaml(n.id),o=R(this.baseDir,`${n.id}.yml`);if(I(r)||I(o))throw new Error(`yaml-authored workflow "${n.id}" exists at ${I(r)?r:o}; edit on disk or delete the YAML before saving from the editor`);return bt(this.pathForJson(n.id),JSON.stringify(n,null,2)+`
2
2
  `),n}delete(e){let t=this.pathForJson(e),n=this.pathForYaml(e),r=R(this.baseDir,`${e}.yml`),o=!1;return I(t)&&(Q(t),o=!0),I(n)&&(Q(n),o=!0),I(r)&&(Q(r),o=!0),o}};import{createHash as It,randomUUID as vt}from"crypto";import{appendFileSync as De,existsSync as E,mkdirSync as _e,readdirSync as Fe,readFileSync as ne,statSync as Le,unlinkSync as Ue,writeFileSync as St}from"fs";import{resolve as W}from"path";function $t(s){return s.replace(/[^a-zA-Z0-9._:#@-]/g,"_").slice(0,200)}function A(s,e,t){return It("sha1").update(`${s}|${e}|${t}`).digest("hex").slice(0,16)}var re=class{baseDir;runsDir;indexDir;nodeId;constructor(e){this.baseDir=e.baseDir??W(process.cwd(),".agentx/workflows"),this.runsDir=W(this.baseDir,"_runs"),this.indexDir=W(this.baseDir,"_index"),this.nodeId=e.nodeId,_e(this.runsDir,{recursive:!0}),_e(this.indexDir,{recursive:!0})}runPath(e){return W(this.runsDir,`${e}.jsonl`)}indexPath(e){return W(this.indexDir,`${e.backend}__${$t(e.id)}.json`)}create(e){let t=new Date().toISOString(),n=vt(),r={id:n,workflowId:e.workflowId,workflowVersion:2,homeNode:this.nodeId,status:"running",pausedAt:void 0,context:e.initialContext??{},pending:e.initialPending,entityRef:e.entityRef,history:[],parentRunId:e.parentRunId??null,parentNodeId:e.parentNodeId??null,rootRunId:e.rootRunId??n,depth:e.depth??0,joinCounters:{},createdAt:t,updatedAt:t};return this.appendSnapshot(r),this.writeIndex(e.entityRef,r.id),r}get(e){let t=this.runPath(e);if(!E(t))return null;let n=ne(t,"utf-8").trim();if(!n)return null;let r=null;for(let o of n.split(`
3
3
  `)){let i;try{i=JSON.parse(o)}catch{continue}if(i.v===2){if(i.kind==="snapshot")r=i.run;else if(i.kind==="exec"&&r&&r.id===i.runId){let a=r;r={...a,history:[...a.history,i.entry],pending:i.pending,status:i.status??a.status,pausedAt:i.pausedAt===null?void 0:i.pausedAt??a.pausedAt,context:i.context??a.context,joinCounters:i.joinCounters??a.joinCounters,updatedAt:i.entry.at}}}}return r}getActiveByEntity(e){let t=this.indexPath(e);if(!E(t))return null;try{return JSON.parse(ne(t,"utf-8")).runId}catch{return null}}getHomeNodeByEntity(e){let t=this.indexPath(e);if(!E(t))return null;try{return JSON.parse(ne(t,"utf-8")).homeNode}catch{return null}}recordExecution(e){let t=this.get(e.runId);if(!t)return null;if(t.history.some(o=>o.idempotencyKey===e.entry.idempotencyKey))return t;let n={v:2,kind:"exec",runId:e.runId,entry:e.entry,pending:e.nextPending,status:e.status,pausedAt:e.pausedAt===null?null:e.pausedAt,context:e.context,joinCounters:e.joinCounters};De(this.runPath(e.runId),JSON.stringify(n)+`
4
4
  `);let r=e.status??t.status;return r==="completed"||r==="failed"||r==="canceled"?this.clearIndex(t.entityRef):this.writeIndex(t.entityRef,t.id),this.get(e.runId)}setStatus(e,t){let n=this.get(e);if(!n)return null;let r={...n,status:t,updatedAt:new Date().toISOString()};return this.appendSnapshot(r),t!=="running"&&t!=="paused"&&this.clearIndex(r.entityRef),r}list(e={}){if(!E(this.runsDir))return[];let t=Fe(this.runsDir).filter(r=>r.endsWith(".jsonl")).map(r=>({name:r,mtime:Le(W(this.runsDir,r)).mtimeMs})).sort((r,o)=>o.mtime-r.mtime),n=[];for(let r of t){let o=this.get(r.name.replace(/\.jsonl$/,""));if(o&&!(e.workflowId&&o.workflowId!==e.workflowId)&&(n.push(o),e.limit&&n.length>=e.limit))break}return n}prune(e){if(!E(this.runsDir))return 0;let t=Date.now()-e.maxDays*24*60*60*1e3,n=[];for(let o of Fe(this.runsDir)){if(!o.endsWith(".jsonl"))continue;let i=W(this.runsDir,o),a=Le(i).mtimeMs,d=this.get(o.replace(/\.jsonl$/,""));d&&(d.status==="running"||d.status==="paused"||n.push({file:i,run:d,mtime:a}))}n.sort((o,i)=>i.mtime-o.mtime);let r=0;for(let o=0;o<n.length;o++){let i=n[o],a=i.mtime<t,d=o>=e.maxRuns;if(a||d)try{Ue(i.file),r++}catch{}}return r}appendSnapshot(e){let t={v:2,kind:"snapshot",run:e};De(this.runPath(e.id),JSON.stringify(t)+`
@@ -12,4 +12,4 @@ import{c as V}from"./chunk-N67JZAXU.js";import{b as Y}from"./chunk-AFRHKA7B.js";
12
12
  `);for(let i=0;i<o.length;i++){let a=o[i].match(ye);if(!a||a[2].toLowerCase()==="x")continue;let d=a[3].match(J);!d||d[1].toLowerCase()!==e.toLowerCase()||n.push({id:`wiki:${r}:${i}`,title:a[3].replace(J,"").trim(),assignee:d[1],priority:i})}}return n}async claim(){}async report(e,t){let n=e.split(":"),r=parseInt(n[n.length-1],10),o=n.slice(1,-1).join(":");if(!me(o))return;let i=fe(o,"utf-8").split(`
13
13
  `);t.status==="done"&&i[r]&&(i[r]=i[r].replace(/- \[ \]/,"- [x]"),et(o,i.join(`
14
14
  `)))}},be=class{constructor(e,t,n,r,o){this.host=e;this.token=t;this.projects=n;this.agentUsernames=r;this.log=o}type="gitlab";capabilities={listAll:!0,create:!0,transition:!0,labels:!0,search:!0};usernameToAgent(e){for(let[t,n]of Object.entries(this.agentUsernames))if(n.some(r=>r.toLowerCase()===e.toLowerCase()))return t}mapIssue(e,t){let n=e.references?.full?.split("#")[0]||t,r=[],o;Array.isArray(e.labels)&&(e.labels.length&&typeof e.labels[0]=="object"?(o=e.labels.map(l=>({name:l.name,color:l.color,text_color:l.text_color})),r=o.map(l=>l.name)):r=e.labels);let a=(Array.isArray(e.assignees)&&e.assignees.length?e.assignees:e.assignee?[e.assignee]:[]).map(l=>({username:l.username,name:l.name,avatarUrl:l.avatar_url})),d=a[0]?.username;return{id:`gitlab:${n}:issue:${e.iid}`,title:e.title,description:e.description||void 0,assignee:d?this.usernameToAgent(d)||d:void 0,assignees:a,url:e.web_url,priority:e.weight??99,estimatedSeconds:e.time_stats?.time_estimate||void 0,labels:r,labelDetails:o,updatedAt:e.updated_at,state:e.state==="closed"?"closed":"opened",milestone:e.milestone?.title||void 0}}async api(e,t={}){let n=await fetch(`${this.host}/api/v4${e}`,{...t,headers:{"PRIVATE-TOKEN":this.token,"Content-Type":"application/json",...t.headers||{}}});if(!n.ok)throw new Error(`GitLab ${n.status}: ${await n.text().catch(()=>"")}`);return n.json()}async listOpen(e){let t=this.agentUsernames[e]||[];if(!t.length)return[];let n=[],r=this.projects.length?this.projects:["__ALL__"];for(let o of t)for(let i of r)try{let a=`assignee_username=${encodeURIComponent(o)}&state=opened&scope=all&per_page=20`,d=i==="__ALL__"?`/issues?${a}`:`/projects/${encodeURIComponent(i)}/issues?${a}`,l=await this.api(d);for(let g of l){let c=this.mapIssue(g,i);c.assignee=e,n.push(c)}}catch(a){this.log(`[business] GitLab listOpen failed for ${o} on ${i}: ${a.message}`)}return n}async claim(e,t){let{project:n,iid:r,type:o}=this.parseId(t),i=`/projects/${encodeURIComponent(n)}/${o==="issue"?"issues":"merge_requests"}/${r}?add_labels=Doing&remove_labels=To Do`;try{await this.api(i,{method:"PUT"})}catch(a){this.log(`[business] claim label update failed: ${a.message}`)}}async report(e,t){let{project:n,iid:r,type:o}=this.parseId(e),i=o==="issue"?"issues":"merge_requests";if(t.timeSeconds&&t.timeSeconds>0){let a=Math.max(1,Math.round(t.timeSeconds/60)),d=a>=60?`${Math.floor(a/60)}h${a%60?` ${a%60}m`:""}`:`${a}m`;try{await this.api(`/projects/${encodeURIComponent(n)}/${i}/${r}/add_spent_time?duration=${encodeURIComponent(d)}`,{method:"POST"})}catch(l){this.log(`[business] add_spent_time failed: ${l.message}`)}}if(t.status==="done")try{await this.api(`/projects/${encodeURIComponent(n)}/${i}/${r}?add_labels=Done&remove_labels=Doing`,{method:"PUT"})}catch(a){this.log(`[business] done label update failed: ${a.message}`)}else if(t.status==="blocked")try{await this.api(`/projects/${encodeURIComponent(n)}/${i}/${r}?add_labels=Blocked`,{method:"PUT"})}catch(a){this.log(`[business] blocked label update failed: ${a.message}`)}if(t.note)try{await this.api(`/projects/${encodeURIComponent(n)}/${i}/${r}/notes`,{method:"POST",body:JSON.stringify({body:t.note})})}catch(a){this.log(`[business] report note failed: ${a.message}`)}}async listAll(e={}){let t=e.sinceDays??30,n=new Date(Date.now()-t*24*36e5).toISOString(),r=new URLSearchParams,o=e.state??"opened";r.set("state",o),r.set("updated_after",n),r.set("scope","all"),r.set("per_page","100"),r.set("with_labels_details","true"),r.set("order_by","updated_at"),r.set("sort","desc"),e.labels?.length&&r.set("labels",e.labels.join(",")),e.milestone&&r.set("milestone",e.milestone),e.search&&r.set("search",e.search);let i=this.projects.length?this.projects:["__ALL__"],a=[];for(let l of i)try{let g=l==="__ALL__"?`/issues?${r.toString()}`:`/projects/${encodeURIComponent(l)}/issues?${r.toString()}`,c=await this.api(g);for(let p of c)a.push(this.mapIssue(p,l))}catch(g){this.log(`[business] GitLab listAll failed on ${l}: ${g.message}`)}let d=a;if(e.notLabels?.length){let l=new Set(e.notLabels);d=d.filter(g=>!(g.labels||[]).some(c=>l.has(c)))}if(e.withoutScopedPrefix){let l=e.withoutScopedPrefix+"::";d=d.filter(g=>!(g.labels||[]).some(c=>c.startsWith(l)))}return d}async setState(e,t){let{project:n,iid:r,type:o}=this.parseId(e),i=o==="issue"?"issues":"merge_requests";await this.api(`/projects/${encodeURIComponent(n)}/${i}/${r}?state_event=${t}`,{method:"PUT"})}async getItem(e){let{project:t,iid:n}=this.parseId(e);try{let r=await this.api(`/projects/${encodeURIComponent(t)}/issues/${n}?with_labels_details=true`);return{...this.mapIssue(r,t),descriptionHtml:r.description_html||void 0,createdAt:r.created_at,author:r.author?{username:r.author.username,name:r.author.name,avatarUrl:r.author.avatar_url}:void 0,allLabels:Array.isArray(r.labels)?typeof r.labels[0]=="object"?r.labels.map(i=>i.name):r.labels:[]}}catch(r){return this.log(`[board] GitLab getItem failed for ${e}: ${r.message}`),null}}async updateItem(e,t){let{project:n,iid:r}=this.parseId(e),o;t.assigneeUsernames&&(o=(await Promise.all(t.assigneeUsernames.map(async g=>{try{let c=await this.api(`/users?username=${encodeURIComponent(g)}`);return Array.isArray(c)&&c[0]?.id?c[0].id:null}catch{return null}}))).filter(g=>typeof g=="number"));let i;if(t.milestoneTitle!==void 0)if(t.milestoneTitle===null||t.milestoneTitle==="")i=0;else try{let l=await this.api(`/projects/${encodeURIComponent(n)}/milestones?title=${encodeURIComponent(t.milestoneTitle)}`);Array.isArray(l)&&l[0]?.id&&(i=l[0].id)}catch(l){this.log(`[board] milestone lookup failed for "${t.milestoneTitle}": ${l.message}`)}let a={};t.title!==void 0&&(a.title=t.title),t.description!==void 0&&(a.description=t.description),t.labels!==void 0&&(a.labels=t.labels.join(",")),t.addLabels?.length&&(a.add_labels=t.addLabels.join(",")),t.removeLabels?.length&&(a.remove_labels=t.removeLabels.join(",")),o!==void 0&&(a.assignee_ids=o),i!==void 0&&(a.milestone_id=i);let d=await this.api(`/projects/${encodeURIComponent(n)}/issues/${r}`,{method:"PUT",body:JSON.stringify(a)});return this.mapIssue(d,n)}async listMembers(){let e=new Map;for(let t of this.projects)try{let n=await this.api(`/projects/${encodeURIComponent(t)}/members/all?per_page=100`);for(let r of n)r.username&&!e.has(r.username)&&e.set(r.username,{username:r.username,name:r.name,avatarUrl:r.avatar_url})}catch(n){this.log(`[board] listMembers failed for ${t}: ${n.message}`)}return[...e.values()].sort((t,n)=>t.username.localeCompare(n.username))}async listMilestones(){let e=new Map;for(let n of this.projects)try{let r=await this.api(`/projects/${encodeURIComponent(n)}/milestones?per_page=100`);for(let o of r)o.title&&!e.has(o.title)&&e.set(o.title,{id:o.id,title:o.title,state:o.state,dueDate:o.due_date})}catch(r){this.log(`[board] listMilestones failed for ${n}: ${r.message}`)}let t=[...e.values()];return t.sort((n,r)=>n.state!==r.state?n.state==="active"?-1:1:n.title.localeCompare(r.title)),t}async create(e){let t=e.projectHint||this.projects[0];if(!t)throw new Error("GitLabWorkSource.create requires projectHint or configured projects");let n,r=e.assigneeUsernames?.length?e.assigneeUsernames:e.assignee?(this.agentUsernames[e.assignee]||[]).slice(0,1):[];r.length&&(n=(await Promise.all(r.map(async l=>{try{let g=await this.api(`/users?username=${encodeURIComponent(l)}`);return Array.isArray(g)&&g[0]?.id?g[0].id:null}catch(g){return this.log(`[board] user lookup failed for ${l}: ${g.message}`),null}}))).filter(l=>typeof l=="number"));let o;if(e.milestoneTitle)try{let d=await this.api(`/projects/${encodeURIComponent(t)}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);Array.isArray(d)&&d[0]?.id&&(o=d[0].id)}catch(d){this.log(`[board] milestone lookup failed for "${e.milestoneTitle}": ${d.message}`)}let i={title:e.title,description:e.description,labels:(e.labels||[]).join(",")};n?.length&&(i.assignee_ids=n),o!==void 0&&(i.milestone_id=o);let a=await this.api(`/projects/${encodeURIComponent(t)}/issues`,{method:"POST",body:JSON.stringify(i)});return this.mapIssue(a,t)}async transition(e,t,n){await this.transitionMany(e,t?[t]:[],n?[n]:[])}async transitionMany(e,t,n){let{project:r,iid:o,type:i}=this.parseId(e),a=i==="issue"?"issues":"merge_requests",d=new URLSearchParams;t.length&&d.set("add_labels",t.join(",")),n.length&&d.set("remove_labels",n.join(",")),d.toString()&&await this.api(`/projects/${encodeURIComponent(r)}/${a}/${o}?${d.toString()}`,{method:"PUT"})}parseId(e){let n=e.replace(/^gitlab:/,"").split(":"),r=n.pop(),o=n.pop()==="mr"?"mr":"issue";return{project:n.join(":"),type:o,iid:r}}};function ss(s,e,t){let n=s.workSource;switch(n.type){case"backlog":return new we(n.path,e,t);case"wiki":return new ke(n.path,n.glob);case"gitlab":{let r=e.channels.gitlab;if(!r?.token)throw new Error("business.workSource.type=gitlab requires channels.gitlab.token");let o={};for(let a of r.agentMappings)a.gitlabUsernames.length&&(o[a.agentId]=a.gitlabUsernames);let i=n.projects.length?n.projects:r.routes.map(a=>a.project);return new be(r.host,r.token,i,o,t)}}}export{j as a,Z as b,b as c,U as d,wt as e,te as f,re as g,oe as h,pe as i,un as j,fn as k,z as l,Zr as m,Xe as n,ge as o,be as p,ss as q};
15
- //# sourceMappingURL=chunk-EQNM3TOF.js.map
15
+ //# sourceMappingURL=chunk-2HXSJYAJ.js.map
@@ -1,7 +1,7 @@
1
- import{a as C,b as T}from"./chunk-AANSVC5A.js";import{a as S,c as x}from"./chunk-4MREHZP5.js";import{a as L}from"./chunk-VJUTQAPJ.js";import{writeFileSync as P,mkdirSync as R,existsSync as D,readFileSync as q}from"fs";import{resolve as v}from"path";var H=["off","shadow","authoritative"],z={telegram:"INTENT_LEDGER_MODE_TELEGRAM",slack:"INTENT_LEDGER_MODE_SLACK",whatsapp:"INTENT_LEDGER_MODE_WHATSAPP",discord:"INTENT_LEDGER_MODE_DISCORD",gitlab:"INTENT_LEDGER_MODE_GITLAB",github:"INTENT_LEDGER_MODE_GITHUB",workflow:"INTENT_LEDGER_MODE_WORKFLOW",cron:"INTENT_LEDGER_MODE_CRON",mesh:"INTENT_LEDGER_MODE_MESH"},K="INTENT_LEDGER_MODE";function O(s,e=process.env){let n=_(e[z[s]]);if(n)return n;let t=_(e[K]);return t||"off"}function _(s){if(typeof s!="string")return null;let e=s.trim().toLowerCase();return H.includes(e)?e:null}var A;function X(s){A=s}function N(){return A}function k(s,e,n,t=Date.now,r){return s.db.transaction(i=>{let c=s.recordEvent(e),a=r??N(),u=a?.pmFor?.(c.project),d=u?`pm:${u}`:n.decidedBy,p=s.getDecisionsForEvent(c.id).find(h=>h.decidedBy===d);if(p)return p;let y=s.getActiveDecisionForSubject(c.project,c.subject);if(y){let h={eventId:c.id,decidedAt:i,decidedBy:d,agentId:null,outcome:"deduped",reason:`active dispatch in flight: ${y.decidedBy} \u2192 ${y.agentId??"?"}`};return s.recordDecision(h),h}let g=n.decide(c),l=g?g.agentId:null,f=g?g.outcome:"halted",m=g?g.reason:"no policy match";if(a?.canHandle&&f==="dispatched"&&l&&!a.canHandle(l,c.project,c.intent)){let $=l;l=null,f="halted",m=`org-chart: agent "${$}" cannot handle (${c.project??"no-project"}/${c.intent??"no-intent"})`}if(a?.withinDelegationBudget&&f==="dispatched"&&l&&!a.withinDelegationBudget(l,c.project,c.subject)){let h=l;l=null,f="halted",m=`delegation-budget: agent "${h}" depth-limit exceeded on ${c.project??"?"}/${c.subject??"?"}`}u&&f==="dispatched"&&l&&(m=m?`${m} (pm-gate: rubber-stamped by ${u})`:`pm-gate: rubber-stamped by ${u}`);let E={eventId:c.id,decidedAt:i,decidedBy:d,agentId:l,outcome:f,reason:m};return s.recordDecision(E),E})(t())}function M(s,e,n,t,r=Date.now){if(U(n,t))return!1;let o=r(),i={id:S(o),ts:o,source:e,eventId:n.eventId,decidedBy:n.decidedBy,ledgerAgentId:n.agentId,ledgerOutcome:n.outcome,ledgerReason:n.reason,legacyAgentId:t.agentId,legacyOutcome:t.outcome,legacyReason:t.reason??null};return s.recordDivergence(i),L.warn(`[ledger-divergence] source=${e} event=${n.eventId} decided_by=${n.decidedBy} ledger=${n.outcome}/${n.agentId??"null"} legacy=${t.outcome}/${t.agentId??"null"}`),!0}function U(s,e){return s.outcome===e.outcome&&s.agentId===e.agentId}function V(s,e,n=Date.now){return{ts:n(),source:"cron",sourceEventId:`${s.jobId}:${s.firedAt.getTime()}`,project:null,subject:`cron:${s.jobId}`,intent:"cron.fired",rawJson:e}}function W(s){return{decidedBy:"cron-scheduler",decide:()=>({agentId:s.agentId,outcome:s.outcome==="deduped"?"halted":s.outcome,reason:s.outcome==="deduped"?`legacy-dedup: ${s.reason??""}`.trim():s.reason??null})}}function J(s,e,n,t,r=Date.now){let o=V(e,n,r),i=W(t),c=k(s,o,i,r);return M(s,"cron",c,t,r),c}function F(s,e){if(!e)return s;let n=e*4;return`${s}
1
+ import{a as C,b as T}from"./chunk-P3TJHGO5.js";import{a as S,c as x}from"./chunk-GOLZ6NEL.js";import{a as L}from"./chunk-VJUTQAPJ.js";import{writeFileSync as P,mkdirSync as R,existsSync as D,readFileSync as q}from"fs";import{resolve as v}from"path";var H=["off","shadow","authoritative"],z={telegram:"INTENT_LEDGER_MODE_TELEGRAM",slack:"INTENT_LEDGER_MODE_SLACK",whatsapp:"INTENT_LEDGER_MODE_WHATSAPP",discord:"INTENT_LEDGER_MODE_DISCORD",gitlab:"INTENT_LEDGER_MODE_GITLAB",github:"INTENT_LEDGER_MODE_GITHUB",workflow:"INTENT_LEDGER_MODE_WORKFLOW",cron:"INTENT_LEDGER_MODE_CRON",mesh:"INTENT_LEDGER_MODE_MESH"},K="INTENT_LEDGER_MODE";function O(s,e=process.env){let n=_(e[z[s]]);if(n)return n;let t=_(e[K]);return t||"off"}function _(s){if(typeof s!="string")return null;let e=s.trim().toLowerCase();return H.includes(e)?e:null}var A;function X(s){A=s}function N(){return A}function k(s,e,n,t=Date.now,r){return s.db.transaction(i=>{let c=s.recordEvent(e),a=r??N(),u=a?.pmFor?.(c.project),d=u?`pm:${u}`:n.decidedBy,p=s.getDecisionsForEvent(c.id).find(h=>h.decidedBy===d);if(p)return p;let y=s.getActiveDecisionForSubject(c.project,c.subject);if(y){let h={eventId:c.id,decidedAt:i,decidedBy:d,agentId:null,outcome:"deduped",reason:`active dispatch in flight: ${y.decidedBy} \u2192 ${y.agentId??"?"}`};return s.recordDecision(h),h}let g=n.decide(c),l=g?g.agentId:null,f=g?g.outcome:"halted",m=g?g.reason:"no policy match";if(a?.canHandle&&f==="dispatched"&&l&&!a.canHandle(l,c.project,c.intent)){let $=l;l=null,f="halted",m=`org-chart: agent "${$}" cannot handle (${c.project??"no-project"}/${c.intent??"no-intent"})`}if(a?.withinDelegationBudget&&f==="dispatched"&&l&&!a.withinDelegationBudget(l,c.project,c.subject)){let h=l;l=null,f="halted",m=`delegation-budget: agent "${h}" depth-limit exceeded on ${c.project??"?"}/${c.subject??"?"}`}u&&f==="dispatched"&&l&&(m=m?`${m} (pm-gate: rubber-stamped by ${u})`:`pm-gate: rubber-stamped by ${u}`);let E={eventId:c.id,decidedAt:i,decidedBy:d,agentId:l,outcome:f,reason:m};return s.recordDecision(E),E})(t())}function M(s,e,n,t,r=Date.now){if(U(n,t))return!1;let o=r(),i={id:S(o),ts:o,source:e,eventId:n.eventId,decidedBy:n.decidedBy,ledgerAgentId:n.agentId,ledgerOutcome:n.outcome,ledgerReason:n.reason,legacyAgentId:t.agentId,legacyOutcome:t.outcome,legacyReason:t.reason??null};return s.recordDivergence(i),L.warn(`[ledger-divergence] source=${e} event=${n.eventId} decided_by=${n.decidedBy} ledger=${n.outcome}/${n.agentId??"null"} legacy=${t.outcome}/${t.agentId??"null"}`),!0}function U(s,e){return s.outcome===e.outcome&&s.agentId===e.agentId}function V(s,e,n=Date.now){return{ts:n(),source:"cron",sourceEventId:`${s.jobId}:${s.firedAt.getTime()}`,project:null,subject:`cron:${s.jobId}`,intent:"cron.fired",rawJson:e}}function W(s){return{decidedBy:"cron-scheduler",decide:()=>({agentId:s.agentId,outcome:s.outcome==="deduped"?"halted":s.outcome,reason:s.outcome==="deduped"?`legacy-dedup: ${s.reason??""}`.trim():s.reason??null})}}function J(s,e,n,t,r=Date.now){let o=V(e,n,r),i=W(t),c=k(s,o,i,r);return M(s,"cron",c,t,r),c}function F(s,e){if(!e)return s;let n=e*4;return`${s}
2
2
 
3
3
  [Response budget]
4
4
  Keep your response under ~${e} tokens (~${n} chars). Be concise \u2014 this is automated batch work, not a conversation.`}function b(s,e,n){let t=[];for(let r of s.split(","))if(r==="*")for(let o=e;o<=n;o++)t.push(o);else if(r.includes("/")){let[o,i]=r.split("/"),c=parseInt(i,10),a=o==="*"?e:parseInt(o,10);for(let u=a;u<=n;u+=c)t.push(u)}else if(r.includes("-")){let[o,i]=r.split("-").map(Number);for(let c=o;c<=i;c++)t.push(c)}else t.push(parseInt(r,10));return[...new Set(t)].sort((r,o)=>r-o)}function B(s,e,n){let t=s.trim().split(/\s+/);if(t.length!==5)throw new Error(`Invalid cron: ${s}`);let r=b(t[0],0,59),o=b(t[1],0,23),i=b(t[2],1,31),c=b(t[3],1,12),a=b(t[4],0,6),u=new Intl.DateTimeFormat("en-US",{timeZone:n,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1}),d=new Date(e.getTime()+6e4);d.setSeconds(0,0);let p=new Date(d.getTime()+366*24*60*60*1e3);for(;d<p;){let y=u.formatToParts(d),g=$=>parseInt(y.find(j=>j.type===$)?.value||"0",10),l=g("minute"),f=g("hour"),m=g("day"),E=g("month"),h=d.getDay();if(r.includes(l)&&o.includes(f)&&i.includes(m)&&c.includes(E)&&a.includes(h))return d;d.setTime(d.getTime()+6e4)}throw new Error(`No next run found for cron "${s}" within 1 year`)}var I=5,w=[3e4,6e4,3e5,9e5,36e5],G=class{jobs=new Map;timers=new Map;registry;hooks;runsDir;lastRunFile;running=!1;notifyCallback;log;constructor(e,n,t,r=console.error.bind(console,"[cron]")){this.registry=n,this.hooks=t,this.log=r,this.runsDir=v(process.cwd(),".agentx/cron/runs"),this.lastRunFile=v(process.cwd(),".agentx/cron/last-runs.json");for(let[o,i]of Object.entries(e.crons))this.jobs.set(o,{id:o,enabled:i.enabled,schedule:i.schedule,timezone:i.timezone,agent:i.agent,prompt:i.prompt,timeout:i.timeout,model:i.model,maxOutputTokens:i.maxOutputTokens,onError:i.onError,consecutiveErrors:0,totalRuns:0,totalFailures:0})}setNotifyCallback(e){this.notifyCallback=e}async start(){this.running=!0,D(this.runsDir)||R(this.runsDir,{recursive:!0});let e=this.detectMissedRuns();if(e.length>0){this.log(`Detected ${e.length} missed cron run(s) while daemon was down:`);for(let{jobId:n,missedAt:t}of e)this.log(` "${n}" should have run at ${t.toISOString()}`);this.executeMissedRuns(e).catch(n=>{this.log(`Error executing missed runs: ${n.message}`)})}for(let[n,t]of this.jobs){if(!t.enabled){this.log(`Job "${n}" is disabled, skipping`);continue}this.scheduleNext(n)}this.log(`${this.jobs.size} cron job(s) loaded, ${Array.from(this.jobs.values()).filter(n=>n.enabled).length} enabled`)}async stop(){this.running=!1;for(let e of this.timers.values())clearTimeout(e);this.timers.clear(),this.saveLastRuns()}scheduleNext(e){let n=this.jobs.get(e);if(!n||!n.enabled||!this.running)return;let t=this.timers.get(e);t&&clearTimeout(t);try{let r=B(n.schedule,new Date,n.timezone);n.nextRun=r,n.retryPending=!1;let o=r.getTime()-Date.now();this.log(`Job "${e}" next run: ${r.toISOString()} (in ${Math.round(o/1e3)}s)`);let i=setTimeout(()=>this.executeJob(e),o);this.timers.set(e,i)}catch(r){this.log(`Failed to schedule "${e}": ${r.message}`)}}scheduleRetry(e,n){let t=this.jobs.get(e);if(!t||!t.enabled||!this.running)return;if(n>=I){this.log(`Job "${e}" exhausted all ${I} retries, scheduling next regular run`),this.scheduleNext(e);return}let r=w[n]||w[w.length-1];t.retryPending=!0,this.log(`Job "${e}" retry ${n+1}/${I} in ${Math.round(r/1e3)}s`);let o=setTimeout(()=>this.executeJob(e,n+1),r);this.timers.set(e,o)}recordCronDecisionInLedger(e,n,t,r){if(O("cron")!=="off")try{let o=J(x(),{jobId:e,agentId:n,firedAt:t},JSON.stringify({jobId:e,agentId:n,firedAt:t.toISOString()}),r);return o.outcome==="dispatched"?{eventId:o.eventId,decidedBy:o.decidedBy}:void 0}catch(o){this.log(`[ledger] cron "${e}" record failed: ${o?.message??o}`);return}}async executeJob(e,n=0){let t=this.jobs.get(e);if(!t||!this.running)return;let r=n>0,o=new Date;if(this.hooks?.has("pre:cron-run")){let a=await this.hooks.execute("pre:cron-run",{event:"pre:cron-run",jobId:e,agent:t.agent,prompt:t.prompt});if(a.blocked){this.log(`Job "${e}" blocked by hook: ${a.message}`),this.recordCronDecisionInLedger(e,t.agent,o,{agentId:null,outcome:"halted",reason:`pre-hook blocked: ${a.message??""}`.trim()}),this.scheduleNext(e);return}}this.log(`${r?`[retry ${n}] `:""}Executing job "${e}" -> agent "${t.agent}"`);let i=o;t.lastRun=i,t.totalRuns++;let c=this.recordCronDecisionInLedger(e,t.agent,o,{agentId:t.agent,outcome:"dispatched",reason:r?`retry ${n}`:null});try{let a=await this.registry.execute({message:F(t.prompt,t.maxOutputTokens),agentId:t.agent,model:t.model,intentRef:c,context:{channel:"cron",chatId:`cron:${e}`}}),u={jobId:e,startedAt:i,completedAt:new Date,success:!a.error,response:a.content,error:a.error,duration:a.duration||Date.now()-i.getTime(),isRetry:r,retryAttempt:n};if(a.error){if(t.consecutiveErrors++,t.totalFailures++,t.lastError=a.error,this.log(`Job "${e}" failed (${t.consecutiveErrors} consecutive): ${a.error}`),await this.notifyFailure(t,a.error),t.onError.includes("disable")&&t.consecutiveErrors>=3){t.enabled=!1,this.log(`Job "${e}" disabled after ${t.consecutiveErrors} consecutive errors`);try{let d=await C(p=>T(p,`crons.${e}.enabled`,!1),{reload:!1});d.success||this.log(`Failed to persist disable for "${e}": ${d.error}`)}catch(d){this.log(`Failed to persist disable for "${e}": ${d.message}`)}await this.notifyDisabled(t)}this.logRun(u),this.scheduleRetry(e,n);return}else t.consecutiveErrors>0&&this.log(`Job "${e}" recovered after ${t.consecutiveErrors} failure(s)`),t.consecutiveErrors=0,t.lastSuccess=new Date,t.lastError=void 0,t.retryPending=!1,this.log(`Job "${e}" completed in ${u.duration}ms`);this.logRun(u),this.hooks?.has("post:cron-run")&&await this.hooks.execute("post:cron-run",{event:"post:cron-run",jobId:e,success:u.success,duration:u.duration,error:u.error?new Error(u.error):void 0})}catch(a){t.consecutiveErrors++,t.totalFailures++,t.lastError=a.message,this.log(`Job "${e}" threw: ${a.message}`),await this.notifyFailure(t,a.message),this.scheduleRetry(e,n);return}this.saveLastRuns(),this.scheduleNext(e)}detectMissedRuns(){let e=[],n=this.loadLastRuns();if(!n)return e;for(let[t,r]of this.jobs){if(!r.enabled)continue;let o=n[t];if(!o)continue;let i=new Date(o);try{let c=B(r.schedule,i,r.timezone);c.getTime()<Date.now()&&e.push({jobId:t,missedAt:c})}catch{}}return e}async executeMissedRuns(e){for(let{jobId:n,missedAt:t}of e){let r=this.jobs.get(n);if(!(!r||!r.enabled)){this.log(`Running missed job "${n}" (was due at ${t.toISOString()})`);try{let o=await this.registry.execute({message:F(`[MISSED RUN \u2014 was scheduled for ${t.toISOString()}]
5
5
 
6
6
  ${r.prompt}`,r.maxOutputTokens),agentId:r.agent,context:{channel:"cron",chatId:`cron:${n}`}}),i={jobId:n,startedAt:new Date,completedAt:new Date,success:!o.error,response:o.content,error:o.error,duration:o.duration||0,isRetry:!1};this.logRun(i),o.error?this.log(`Missed job "${n}" failed: ${o.error}`):(this.log(`Missed job "${n}" completed`),r.lastSuccess=new Date),r.lastRun=new Date,r.totalRuns++}catch(o){this.log(`Missed job "${n}" threw: ${o.message}`)}}}this.saveLastRuns()}async notifyFailure(e,n){if(!(!e.onError.includes("notify")&&e.consecutiveErrors<2)){if(!this.notifyCallback){this.log(`[ALERT] Cron "${e.id}" failed (${e.consecutiveErrors}x): ${n.slice(0,200)}`);return}try{await this.notifyCallback(e.id,e.agent,n,e.consecutiveErrors)}catch{}}}async notifyDisabled(e){if(!this.notifyCallback){this.log(`[ALERT] Cron "${e.id}" has been DISABLED after ${e.consecutiveErrors} consecutive failures`);return}try{await this.notifyCallback(e.id,e.agent,`AUTO-DISABLED after ${e.consecutiveErrors} consecutive failures. Last error: ${e.lastError||"unknown"}`,e.consecutiveErrors)}catch{}}saveLastRuns(){try{let e={};for(let[t,r]of this.jobs)r.lastRun&&(e[t]=r.lastRun.toISOString());let n=v(process.cwd(),".agentx/cron");D(n)||R(n,{recursive:!0}),P(this.lastRunFile,JSON.stringify(e,null,2))}catch{}}loadLastRuns(){try{return D(this.lastRunFile)?JSON.parse(q(this.lastRunFile,"utf-8")):null}catch{return null}}logRun(e){try{let n=v(this.runsDir,e.jobId);D(n)||R(n,{recursive:!0});let t=`${e.startedAt.toISOString().replace(/[:.]/g,"-")}.json`;P(v(n,t),JSON.stringify(e,null,2))}catch{}}list(){return Array.from(this.jobs.values())}health(){let e=Array.from(this.jobs.values()),n=this.detectMissedRuns();return{healthy:e.filter(t=>t.enabled&&t.consecutiveErrors===0).length,failing:e.filter(t=>t.enabled&&t.consecutiveErrors>0).length,disabled:e.filter(t=>!t.enabled).length,missed:n.length,jobs:e.map(t=>({id:t.id,status:t.enabled?t.retryPending?"retrying":t.consecutiveErrors>0?"failing":"healthy":"disabled",consecutiveErrors:t.consecutiveErrors,lastError:t.lastError}))}}};export{O as a,X as b,k as c,M as d,B as e,G as f};
7
- //# sourceMappingURL=chunk-K6MC66D6.js.map
7
+ //# sourceMappingURL=chunk-ABVZHJUO.js.map
@@ -0,0 +1,44 @@
1
+ import{c as k}from"./chunk-WJXU5F4Z.js";import{existsSync as p,mkdirSync as b,writeFileSync as h,readFileSync as w}from"fs";import{resolve as c}from"path";import{createHash as D}from"crypto";var d="<!-- agentx-managed: hash=",g=" -->";function v(n){return D("sha256").update(n??"").digest("hex").slice(0,16)}function S(n){return`${d}${v(n)}${g}`}function M(n){let s=n.split(`
2
+ `,1)[0]??"";return!s.startsWith(d)||!s.endsWith(g)?null:s.slice(d.length,s.length-g.length)}function A(n,s){let r=`${n} ${s.systemPrompt||""} ${s.name}`.toLowerCase();return/cod(e|ing|er)|develop|engineer|program/.test(r)?"coding":/pm|project.?manag|product|scrum/.test(r)?"pm":/devops|deploy|infra|ops|sre|ci.?cd/.test(r)?"devops":/qa|test|quality|forensic/.test(r)?"qa":"general"}function $(n,s,r){let t=A(n,s),e=[];switch(e.push(S(s.systemPrompt)),e.push(`# ${s.name}`),e.push(""),e.push("@AGENTS.md"),e.push(""),s.systemPrompt&&s.systemPrompt.trim().length>0&&(e.push("## Role"),e.push(""),e.push(s.systemPrompt.trimEnd()),e.push("")),e.push("## Commands"),e.push(""),p(c(s.workspace,"package.json"))?(e.push("```bash"),e.push("npm install # install dependencies"),e.push("npm test # run tests"),e.push("npm run build # build project"),e.push("```")):p(c(s.workspace,"requirements.txt"))&&(e.push("```bash"),e.push("pip install -r requirements.txt"),e.push("pytest"),e.push("```")),e.push(""),e.push("## Conventions"),e.push(""),t){case"coding":e.push("- Write tests for new code before committing"),e.push("- Keep functions small and focused"),e.push("- Follow existing patterns in the codebase"),e.push("- Run tests before pushing");break;case"pm":e.push("- Keep responses concise (3-5 lines main message)"),e.push("- Reference issues with #IID and MRs with !IID"),e.push("- Update issue labels and milestones when relevant"),e.push("- Summarize decisions, don't narrate process");break;case"devops":e.push("- Always check service status before making changes"),e.push("- Never run destructive commands without confirmation"),e.push("- Log all deployment actions"),e.push("- Verify changes in staging before production");break;case"qa":e.push("- Document reproduction steps for every bug"),e.push("- Include expected vs actual behavior"),e.push("- Check both happy path and edge cases"),e.push("- Attach screenshots when reporting UI issues");break;default:e.push("- Be concise \u2014 lead with the answer, skip preamble"),e.push("- Follow existing patterns in the codebase")}return e.push(""),e.push("## Cross-Channel Messaging"),e.push(""),e.push("You can send messages to any channel proactively:"),e.push("```bash"),e.push(`curl -X POST http://localhost:${r}/send \\`),e.push(' -H "Content-Type: application/json" \\'),e.push(` -d '{"channel":"telegram","chatId":"<id>","text":"<message>","agentId":"${n}"}'`),e.push("```"),e.push("Channels: telegram, whatsapp, gitlab, discord"),e.push(""),e.join(`
3
+ `)}function C(n,s){let r={autoMemoryEnabled:!0,env:{CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS:"1"}};s.permissionMode==="bypassPermissions"||(s.permissionMode==="plan"?r.permissions={deny:["Bash(rm -rf *)","Bash(drop *)","Bash(DELETE *)"]}:r.permissions={deny:["Bash(rm -rf /)","Bash(> /dev/sda*)","Bash(mkfs*)"]});let t={};return t.Notification=[{matcher:"",hooks:[{type:"command",command:`echo "[${n}] notification: $(jq -r '.type // "unknown"')" >> /tmp/agentx-${n}.log`}]}],t.PostToolUse=[{matcher:"Bash",hooks:[{type:"command",command:`jq -r '.tool_input.command // empty' >> /tmp/agentx-${n}-commands.log`}]}],t.SessionStart=[{matcher:"compact",hooks:[{type:"command",command:`echo "Reminder: You are ${s.name} (${n}). Follow the conventions in CLAUDE.md."`}]}],r.hooks=t,r}function j(n,s){let r=A(n,s),t=[];switch(r){case"coding":t.push({name:"testing.md",content:`---
4
+ paths:
5
+ - "**/*.test.{ts,tsx,js,jsx}"
6
+ - "**/*.spec.{ts,tsx,js,jsx}"
7
+ - "test/**/*"
8
+ ---
9
+
10
+ # Testing Rules
11
+
12
+ - Every new function should have a corresponding test
13
+ - Test both happy path and error cases
14
+ - Use descriptive test names that explain what's being tested
15
+ - Mock external dependencies, not internal modules
16
+ `}),t.push({name:"code-quality.md",content:`# Code Quality
17
+
18
+ - No console.log in production code (use a logger)
19
+ - Handle errors explicitly \u2014 no empty catch blocks
20
+ - Keep files under 300 lines
21
+ - Extract repeated logic into shared utilities
22
+ `});break;case"devops":t.push({name:"deployment-safety.md",content:`# Deployment Safety
23
+
24
+ - Always verify staging before production
25
+ - Check disk space and memory before deploying
26
+ - Never expose secrets in logs or commits
27
+ - Use rollback-safe deployment strategies
28
+ `});break;case"pm":t.push({name:"communication.md",content:`# Communication Rules
29
+
30
+ - Keep GitLab comments under 5 lines for the main message
31
+ - Use <details> for verbose output (logs, commands, steps)
32
+ - Reference issues with #IID, merge requests with !IID
33
+ - Never mention Telegram handles on GitLab
34
+ `});break;case"qa":t.push({name:"bug-reports.md",content:`# Bug Report Format
35
+
36
+ Always include:
37
+ 1. Steps to reproduce
38
+ 2. Expected behavior
39
+ 3. Actual behavior
40
+ 4. Environment (browser, OS, version)
41
+ 5. Screenshots if applicable
42
+ `});break}return t}function P(n,s,r="19900",t=console.error){let e=[],a=[],i=s.workspace;if(!p(i))return t(`Workspace not found: ${i}`),{created:e,skipped:a};if(s.tier!=="claude-code")return{created:e,skipped:a};let u=(o,l)=>{p(o)?a.push(o):(b(c(o,".."),{recursive:!0}),h(o,l),e.push(o))},m=(o,l,R)=>{if(!p(o)){b(c(o,".."),{recursive:!0}),h(o,l),e.push(o);return}let f;try{f=w(o,"utf8")}catch{a.push(o);return}let y=M(f);if(y===null){a.push(o);return}if(y===R){a.push(o);return}h(o,l),e.push(`${o} (refreshed)`)};u(c(i,"AGENTS.md"),k({name:s.name,id:n,role:s.systemPrompt?.split(`
43
+ `)[0],workspace:i,tier:s.tier})),m(c(i,"CLAUDE.md"),$(n,s,r),v(s.systemPrompt));let E=c(i,".claude/settings.json");u(E,JSON.stringify(C(n,s),null,2));let x=j(n,s);for(let o of x)u(c(i,".claude/rules",o.name),o.content);return e.length>0&&t(`[${n}] workspace setup: created ${e.length} file(s)`),{created:e,skipped:a}}function N(n,s){let r=c(n,".claude/settings.json");if(!p(r))return!1;try{let t=JSON.parse(w(r,"utf-8")),e=!1;for(let[a,i]of Object.entries(s))if(typeof i=="object"&&i!==null&&!Array.isArray(i)){t[a]||(t[a]={});for(let[u,m]of Object.entries(i))t[a][u]===void 0&&(t[a][u]=m,e=!0)}else t[a]===void 0&&(t[a]=i,e=!0);return e&&h(r,JSON.stringify(t,null,2)),e}catch{return!1}}function U(n,s="19900",r=console.error){let t=0,e=0;for(let[a,i]of Object.entries(n)){if(i.tier!=="claude-code")continue;let u=P(a,i,s,r);t+=u.created.length,N(i.workspace,{env:{CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS:"1"}})&&e++}t>0&&r(`Workspace setup: ${t} file(s) created across agent workspaces`),e>0&&r(`Workspace patch: ${e} workspace(s) updated with agent teams support`)}export{M as a,$ as b,P as c,U as d};
44
+ //# sourceMappingURL=chunk-BHSPAP4U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/workspace-setup.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync, readFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { createHash } from \"crypto\"\nimport type { AgentDef } from \"@/daemon/config\"\nimport { generateAgentsMd } from \"./bootstrap\"\n\n// Marker stamped into auto-generated CLAUDE.md so we can tell agentx-managed\n// files apart from user-edited ones. On daemon start, files with the marker\n// are silently regenerated when the systemPrompt hash changes; files without\n// the marker are treated as user-owned and never touched.\nconst MANAGED_MARKER_PREFIX = \"<!-- agentx-managed: hash=\"\nconst MANAGED_MARKER_SUFFIX = \" -->\"\n\nfunction systemPromptHash(systemPrompt: string | undefined): string {\n return createHash(\"sha256\")\n .update(systemPrompt ?? \"\")\n .digest(\"hex\")\n .slice(0, 16)\n}\n\nfunction buildManagedMarker(systemPrompt: string | undefined): string {\n return `${MANAGED_MARKER_PREFIX}${systemPromptHash(systemPrompt)}${MANAGED_MARKER_SUFFIX}`\n}\n\n/**\n * Read the managed marker from an existing file's first line, if present.\n * Returns the hash (truncated sha256 hex) when found, null otherwise.\n * Files without the marker are user-managed and untouchable.\n */\nexport function readManagedHash(content: string): string | null {\n const firstLine = content.split(\"\\n\", 1)[0] ?? \"\"\n if (!firstLine.startsWith(MANAGED_MARKER_PREFIX)) return null\n if (!firstLine.endsWith(MANAGED_MARKER_SUFFIX)) return null\n return firstLine.slice(MANAGED_MARKER_PREFIX.length, firstLine.length - MANAGED_MARKER_SUFFIX.length)\n}\n\n// --- Workspace Setup: align agent workspaces with Claude Code best practices ---\n//\n// Generates on daemon start (if missing):\n// CLAUDE.md — project conventions, under 200 lines, @AGENTS.md import\n// AGENTS.md — agents.md spec for cross-tool compatibility\n// .claude/settings.json — hooks, permissions, auto memory\n// .claude/rules/ — path-specific rules based on agent role\n\n/** Detect agent role from systemPrompt or agent ID */\nfunction detectRole(agentId: string, def: AgentDef): \"coding\" | \"pm\" | \"devops\" | \"qa\" | \"general\" {\n const text = `${agentId} ${def.systemPrompt || \"\"} ${def.name}`.toLowerCase()\n if (/cod(e|ing|er)|develop|engineer|program/.test(text)) return \"coding\"\n if (/pm|project.?manag|product|scrum/.test(text)) return \"pm\"\n if (/devops|deploy|infra|ops|sre|ci.?cd/.test(text)) return \"devops\"\n if (/qa|test|quality|forensic/.test(text)) return \"qa\"\n return \"general\"\n}\n\n/** Generate CLAUDE.md for an agent workspace */\nexport function generateClaudeMd(agentId: string, def: AgentDef, daemonPort: string): string {\n const role = detectRole(agentId, def)\n const lines: string[] = []\n\n // Managed-marker on line 1 — used by setupWorkspace to detect stale\n // auto-generated files and regenerate them when systemPrompt changes.\n // User-edited files (no marker) are left alone forever.\n lines.push(buildManagedMarker(def.systemPrompt))\n lines.push(`# ${def.name}`)\n lines.push(\"\")\n lines.push(\"@AGENTS.md\")\n lines.push(\"\")\n\n // Agent identity from systemPrompt — emitted verbatim. Truncating here would\n // silently drop instructions (e.g. multi-paragraph protocols), so we trade\n // a few extra tokens in CLAUDE.md for fidelity. The runtime path already\n // forwards the full systemPrompt via --append-system-prompt; this section\n // mirrors it for tools that read CLAUDE.md as workspace context.\n if (def.systemPrompt && def.systemPrompt.trim().length > 0) {\n lines.push(\"## Role\")\n lines.push(\"\")\n lines.push(def.systemPrompt.trimEnd())\n lines.push(\"\")\n }\n\n // Build/test commands\n lines.push(\"## Commands\")\n lines.push(\"\")\n if (existsSync(resolve(def.workspace, \"package.json\"))) {\n lines.push(\"```bash\")\n lines.push(\"npm install # install dependencies\")\n lines.push(\"npm test # run tests\")\n lines.push(\"npm run build # build project\")\n lines.push(\"```\")\n } else if (existsSync(resolve(def.workspace, \"requirements.txt\"))) {\n lines.push(\"```bash\")\n lines.push(\"pip install -r requirements.txt\")\n lines.push(\"pytest\")\n lines.push(\"```\")\n }\n lines.push(\"\")\n\n // Role-specific conventions\n lines.push(\"## Conventions\")\n lines.push(\"\")\n switch (role) {\n case \"coding\":\n lines.push(\"- Write tests for new code before committing\")\n lines.push(\"- Keep functions small and focused\")\n lines.push(\"- Follow existing patterns in the codebase\")\n lines.push(\"- Run tests before pushing\")\n break\n case \"pm\":\n lines.push(\"- Keep responses concise (3-5 lines main message)\")\n lines.push(\"- Reference issues with #IID and MRs with !IID\")\n lines.push(\"- Update issue labels and milestones when relevant\")\n lines.push(\"- Summarize decisions, don't narrate process\")\n break\n case \"devops\":\n lines.push(\"- Always check service status before making changes\")\n lines.push(\"- Never run destructive commands without confirmation\")\n lines.push(\"- Log all deployment actions\")\n lines.push(\"- Verify changes in staging before production\")\n break\n case \"qa\":\n lines.push(\"- Document reproduction steps for every bug\")\n lines.push(\"- Include expected vs actual behavior\")\n lines.push(\"- Check both happy path and edge cases\")\n lines.push(\"- Attach screenshots when reporting UI issues\")\n break\n default:\n lines.push(\"- Be concise — lead with the answer, skip preamble\")\n lines.push(\"- Follow existing patterns in the codebase\")\n }\n lines.push(\"\")\n\n // Cross-channel messaging capability\n lines.push(\"## Cross-Channel Messaging\")\n lines.push(\"\")\n lines.push(\"You can send messages to any channel proactively:\")\n lines.push(\"```bash\")\n lines.push(`curl -X POST http://localhost:${daemonPort}/send \\\\`)\n lines.push(` -H \"Content-Type: application/json\" \\\\`)\n lines.push(` -d '{\"channel\":\"telegram\",\"chatId\":\"<id>\",\"text\":\"<message>\",\"agentId\":\"${agentId}\"}'`)\n lines.push(\"```\")\n lines.push('Channels: telegram, whatsapp, gitlab, discord')\n lines.push(\"\")\n\n return lines.join(\"\\n\")\n}\n\n/** Generate .claude/settings.json with hooks and permissions */\nfunction generateSettings(agentId: string, def: AgentDef): Record<string, unknown> {\n const settings: Record<string, unknown> = {\n autoMemoryEnabled: true,\n env: {\n CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: \"1\",\n },\n }\n\n // Permission mode\n if (def.permissionMode === \"bypassPermissions\") {\n // No deny rules — full access\n } else if (def.permissionMode === \"plan\") {\n settings[\"permissions\"] = {\n deny: [\"Bash(rm -rf *)\", \"Bash(drop *)\", \"Bash(DELETE *)\"],\n }\n } else {\n // Default: deny destructive operations\n settings[\"permissions\"] = {\n deny: [\n \"Bash(rm -rf /)\",\n \"Bash(> /dev/sda*)\",\n \"Bash(mkfs*)\",\n ],\n }\n }\n\n // Hooks\n const hooks: Record<string, unknown[]> = {}\n\n // Notification hook — log when agent needs input\n hooks[\"Notification\"] = [{\n matcher: \"\",\n hooks: [{\n type: \"command\",\n command: `echo \"[${agentId}] notification: $(jq -r '.type // \\\"unknown\\\"')\" >> /tmp/agentx-${agentId}.log`,\n }],\n }]\n\n // PostToolUse — log tool activity\n hooks[\"PostToolUse\"] = [{\n matcher: \"Bash\",\n hooks: [{\n type: \"command\",\n command: `jq -r '.tool_input.command // empty' >> /tmp/agentx-${agentId}-commands.log`,\n }],\n }]\n\n // SessionStart after compaction — re-inject key context\n hooks[\"SessionStart\"] = [{\n matcher: \"compact\",\n hooks: [{\n type: \"command\",\n command: `echo \"Reminder: You are ${def.name} (${agentId}). Follow the conventions in CLAUDE.md.\"`,\n }],\n }]\n\n settings[\"hooks\"] = hooks\n return settings\n}\n\n/** Generate .claude/rules/ files based on agent role */\nfunction generateRules(agentId: string, def: AgentDef): Array<{ name: string; content: string }> {\n const role = detectRole(agentId, def)\n const rules: Array<{ name: string; content: string }> = []\n\n switch (role) {\n case \"coding\":\n rules.push({\n name: \"testing.md\",\n content: `---\npaths:\n - \"**/*.test.{ts,tsx,js,jsx}\"\n - \"**/*.spec.{ts,tsx,js,jsx}\"\n - \"test/**/*\"\n---\n\n# Testing Rules\n\n- Every new function should have a corresponding test\n- Test both happy path and error cases\n- Use descriptive test names that explain what's being tested\n- Mock external dependencies, not internal modules\n`,\n })\n rules.push({\n name: \"code-quality.md\",\n content: `# Code Quality\n\n- No console.log in production code (use a logger)\n- Handle errors explicitly — no empty catch blocks\n- Keep files under 300 lines\n- Extract repeated logic into shared utilities\n`,\n })\n break\n\n case \"devops\":\n rules.push({\n name: \"deployment-safety.md\",\n content: `# Deployment Safety\n\n- Always verify staging before production\n- Check disk space and memory before deploying\n- Never expose secrets in logs or commits\n- Use rollback-safe deployment strategies\n`,\n })\n break\n\n case \"pm\":\n rules.push({\n name: \"communication.md\",\n content: `# Communication Rules\n\n- Keep GitLab comments under 5 lines for the main message\n- Use <details> for verbose output (logs, commands, steps)\n- Reference issues with #IID, merge requests with !IID\n- Never mention Telegram handles on GitLab\n`,\n })\n break\n\n case \"qa\":\n rules.push({\n name: \"bug-reports.md\",\n content: `# Bug Report Format\n\nAlways include:\n1. Steps to reproduce\n2. Expected behavior\n3. Actual behavior\n4. Environment (browser, OS, version)\n5. Screenshots if applicable\n`,\n })\n break\n }\n\n return rules\n}\n\n/**\n * Set up an agent workspace with Claude Code best practices.\n * Only creates files that don't already exist (non-destructive).\n */\nexport function setupWorkspace(\n agentId: string,\n def: AgentDef,\n daemonPort: string = \"19900\",\n log: (...args: unknown[]) => void = console.error,\n): { created: string[]; skipped: string[] } {\n const created: string[] = []\n const skipped: string[] = []\n const workspace = def.workspace\n\n if (!existsSync(workspace)) {\n log(`Workspace not found: ${workspace}`)\n return { created, skipped }\n }\n\n // Only set up claude-code tier agents\n if (def.tier !== \"claude-code\") {\n return { created, skipped }\n }\n\n const writeIfMissing = (path: string, content: string) => {\n if (existsSync(path)) {\n skipped.push(path)\n } else {\n mkdirSync(resolve(path, \"..\"), { recursive: true })\n writeFileSync(path, content)\n created.push(path)\n }\n }\n\n /**\n * Write a managed file with the agentx-managed marker. If the file already\n * exists and starts with our marker, regenerate when the embedded hash\n * doesn't match the current expected hash. Files without the marker are\n * treated as user-owned and left alone.\n */\n const writeManaged = (path: string, content: string, expectedHash: string) => {\n if (!existsSync(path)) {\n mkdirSync(resolve(path, \"..\"), { recursive: true })\n writeFileSync(path, content)\n created.push(path)\n return\n }\n let existing: string\n try {\n existing = readFileSync(path, \"utf8\")\n } catch {\n skipped.push(path)\n return\n }\n const existingHash = readManagedHash(existing)\n if (existingHash === null) {\n // User-edited (no marker) — never overwrite.\n skipped.push(path)\n return\n }\n if (existingHash === expectedHash) {\n skipped.push(path)\n return\n }\n writeFileSync(path, content)\n created.push(`${path} (refreshed)`)\n }\n\n // AGENTS.md (agents.md spec) — first-line of systemPrompt only, currently\n // not managed-marker'd. Left as writeIfMissing for now.\n writeIfMissing(\n resolve(workspace, \"AGENTS.md\"),\n generateAgentsMd({ name: def.name, id: agentId, role: def.systemPrompt?.split(\"\\n\")[0], workspace, tier: def.tier }),\n )\n\n // CLAUDE.md — managed: silently refreshed when systemPrompt changes.\n writeManaged(\n resolve(workspace, \"CLAUDE.md\"),\n generateClaudeMd(agentId, def, daemonPort),\n systemPromptHash(def.systemPrompt),\n )\n\n // .claude/settings.json\n const settingsPath = resolve(workspace, \".claude/settings.json\")\n writeIfMissing(settingsPath, JSON.stringify(generateSettings(agentId, def), null, 2))\n\n // .claude/rules/\n const rules = generateRules(agentId, def)\n for (const rule of rules) {\n writeIfMissing(resolve(workspace, \".claude/rules\", rule.name), rule.content)\n }\n\n if (created.length > 0) {\n log(`[${agentId}] workspace setup: created ${created.length} file(s)`)\n }\n\n return { created, skipped }\n}\n\n/**\n * Patch existing .claude/settings.json to add missing keys (non-destructive).\n * Used to enable new features (like agent teams) on workspaces that already have settings.\n */\nfunction patchSettings(workspace: string, patches: Record<string, unknown>): boolean {\n const settingsPath = resolve(workspace, \".claude/settings.json\")\n if (!existsSync(settingsPath)) return false\n\n try {\n const existing = JSON.parse(readFileSync(settingsPath, \"utf-8\"))\n let changed = false\n\n for (const [key, value] of Object.entries(patches)) {\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n // Merge objects (e.g. env: { KEY: \"value\" })\n if (!existing[key]) existing[key] = {}\n for (const [subKey, subValue] of Object.entries(value as Record<string, unknown>)) {\n if (existing[key][subKey] === undefined) {\n existing[key][subKey] = subValue\n changed = true\n }\n }\n } else if (existing[key] === undefined) {\n existing[key] = value\n changed = true\n }\n }\n\n if (changed) {\n writeFileSync(settingsPath, JSON.stringify(existing, null, 2))\n }\n return changed\n } catch {\n return false\n }\n}\n\n/**\n * Set up all agent workspaces on daemon start.\n */\nexport function setupAllWorkspaces(\n agents: Record<string, AgentDef>,\n daemonPort: string = \"19900\",\n log: (...args: unknown[]) => void = console.error,\n): void {\n let totalCreated = 0\n let totalPatched = 0\n for (const [id, def] of Object.entries(agents)) {\n if (def.tier !== \"claude-code\") continue\n const result = setupWorkspace(id, def, daemonPort, log)\n totalCreated += result.created.length\n\n // Patch existing settings with new features (agent teams, etc.)\n if (patchSettings(def.workspace, {\n env: { CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: \"1\" },\n })) {\n totalPatched++\n }\n }\n if (totalCreated > 0) {\n log(`Workspace setup: ${totalCreated} file(s) created across agent workspaces`)\n }\n if (totalPatched > 0) {\n log(`Workspace patch: ${totalPatched} workspace(s) updated with agent teams support`)\n }\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","writeFileSync","readFileSync","resolve","createHash","MANAGED_MARKER_PREFIX","MANAGED_MARKER_SUFFIX","systemPromptHash","systemPrompt","createHash","buildManagedMarker","readManagedHash","content","firstLine","detectRole","agentId","def","text","generateClaudeMd","daemonPort","role","lines","existsSync","resolve","generateSettings","settings","hooks","generateRules","rules","setupWorkspace","log","created","skipped","workspace","writeIfMissing","path","mkdirSync","writeFileSync","writeManaged","expectedHash","existing","readFileSync","existingHash","generateAgentsMd","settingsPath","rule","patchSettings","patches","changed","key","value","subKey","subValue","setupAllWorkspaces","agents","totalCreated","totalPatched","id","result"]}
@@ -0,0 +1,13 @@
1
+ import{z as e}from"zod";import{readFileSync as x,existsSync as f}from"fs";import{resolve as p}from"path";import{z as t}from"zod";var S=t.enum(["mon","tue","wed","thu","fri","sat","sun"]),j=t.object({days:t.array(S).default(["mon","tue","wed","thu","fri"]),start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/),lunch:t.object({start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/)}).optional()}),w=t.object({title:t.string(),responsibilities:t.array(t.string()).default([]),sopPath:t.string().optional(),kpis:t.array(t.string()).default([])}),C=t.object({role:t.string(),reportsTo:t.string().optional(),schedule:j,utilizationTarget:t.number().min(0).max(1).default(.8)}),v=t.object({channel:t.string(),chatId:t.string(),accountId:t.string().optional()}),T=t.discriminatedUnion("type",[t.object({type:t.literal("backlog"),path:t.string().default(".agentx/backlog.md")}),t.object({type:t.literal("gitlab"),projects:t.array(t.string()).default([])}),t.object({type:t.literal("wiki"),path:t.string(),glob:t.string().default("**/*.md")})]),$=t.object({id:t.string(),pm:t.string().optional(),client:t.string().optional()}),D=t.object({channel:t.string().optional(),chatId:t.string().optional(),username:t.string().optional(),senderId:t.string().optional(),client:t.string(),project:t.string().optional(),displayName:t.string().optional()}),m=t.object({enabled:t.boolean().default(!1),timezone:t.string().default("UTC"),mainChannel:v,workSource:T,roles:t.record(t.string(),w).default({}),orgChart:t.record(t.string(),C).default({}),projects:t.array($).default([]),contactMap:t.array(D).default([]),workTickMinutes:t.number().int().min(1).max(60).default(15),idleQueueThreshold:t.number().int().min(0).default(0),standup:t.object({enabled:t.boolean().default(!0),plansDir:t.string().default(".agentx/plans"),maxAgentsPerDay:t.number().int().min(1).max(100).default(20),dryRun:t.boolean().default(!1)}).default({})});import{z as n}from"zod";var I=n.object({name:n.string(),color:n.string().regex(/^#[0-9a-f]{6}$/i).default("#6366f1"),description:n.string().optional()}),L=n.object({id:n.string().regex(/^[a-z0-9_-]+$/,"column id must be lowercase slug"),title:n.string(),kind:n.enum(["open-backlog","scoped-label","closed","label"]).default("label"),mapsToLabel:n.string().optional(),scopedLabel:n.string().optional(),scopedPrefix:n.string().default("Status"),accent:n.string().optional()}),z=n.object({enabled:n.boolean().default(!0),staleDoingMinutes:n.number().int().min(1).default(45),respectLunchBreak:n.boolean().default(!0),respectSchedule:n.boolean().default(!0),action:n.enum(["badge","notify"]).default("badge")}),B=n.discriminatedUnion("type",[n.object({type:n.literal("gitlab"),projects:n.array(n.string()).min(1)})]),P=[{id:"open",title:"Open",kind:"open-backlog",scopedPrefix:"Status",accent:"#6b7280"},{id:"todo",title:"To Do",kind:"scoped-label",scopedLabel:"Status::To Do",scopedPrefix:"Status",accent:"#fb7a35"},{id:"doing",title:"Doing",kind:"scoped-label",scopedLabel:"Status::Doing",scopedPrefix:"Status",accent:"#22c55e"},{id:"onhold",title:"On Hold",kind:"scoped-label",scopedLabel:"Status::On Hold",scopedPrefix:"Status",accent:"#f59e0b"},{id:"review",title:"Review",kind:"scoped-label",scopedLabel:"Status::Review",scopedPrefix:"Status",accent:"#3b82f6"},{id:"closed",title:"Closed",kind:"closed",scopedPrefix:"Status",accent:"#6b7280"}],A=n.object({id:n.string().regex(/^[a-z0-9_-]+$/,"board id must be lowercase slug"),name:n.string(),source:B,primaryToolLabel:n.string().optional(),labels:n.array(I).default([]),columns:n.array(L).min(1).default(P),timeRangeDays:n.number().int().min(1).max(365).default(30),closedWindowDays:n.number().int().min(1).max(365).default(30),reconciliation:z.default({})}),h=n.array(A).default([]),M=n.object({name:n.string(),url:n.string(),dashboardUrl:n.string().optional(),token:n.string().optional(),dashboardToken:n.string().optional()}),y=n.object({enabled:n.boolean().default(!1),port:n.number().int().default(4202),bind:n.string().default("127.0.0.1"),token:n.string().optional(),daemonUrl:n.string().default("http://localhost:18800"),daemons:n.array(M).default([]),draftAgent:n.string().optional()}).default({});function Y(a,i){let s=new Set(a.labels||[]);if(a.state==="closed"){let r=i.find(l=>l.kind==="closed");if(r)return r.id}for(let r of i)if(r.kind==="scoped-label"&&r.scopedLabel&&s.has(r.scopedLabel))return r.id;for(let r of i)if(r.kind==="label"&&r.mapsToLabel&&s.has(r.mapsToLabel))return r.id;let o=i.find(r=>r.kind==="open-backlog");if(o){let r=o.scopedPrefix+"::";return[...s].some(c=>c.startsWith(r))?null:o.id}return i[0]?.id??null}function ee(a,i){let s=[],o=[],r=!1,l=!1;return i.kind==="scoped-label"&&i.scopedLabel?s.push(i.scopedLabel):i.kind==="label"&&i.mapsToLabel?s.push(i.mapsToLabel):i.kind==="closed"&&(r=!0),a&&(a.kind==="scoped-label"&&a.scopedLabel?o.push(a.scopedLabel):a.kind==="label"&&a.mapsToLabel?o.push(a.mapsToLabel):a.kind==="closed"&&i.kind!=="closed"&&(l=!0)),{addLabels:s.length?s:void 0,removeLabels:o.length?o:void 0,closeIssue:r||void 0,reopen:l||void 0}}function R(a){let i=p(a,".env");if(!f(i))return;let s=x(i,"utf-8");for(let o of s.split(`
2
+ `)){let r=o.trim();if(!r||r.startsWith("#"))continue;let l=r.indexOf("=");if(l===-1)continue;let c=r.slice(0,l).trim(),d=r.slice(l+1).trim();process.env[c]||(process.env[c]=d)}}var E=e.object({apiKey:e.string().optional(),defaultModel:e.string().optional(),baseUrl:e.string().optional()}),O=e.object({command:e.string(),args:e.array(e.string()).default([]),env:e.record(e.string(),e.string()).optional()}),U=e.object({name:e.string(),workspace:e.string(),tier:e.enum(["claude-code","sdk","orchestrator"]).default("claude-code"),provider:e.string().optional(),model:e.string().optional(),systemPrompt:e.string().optional(),mentions:e.array(e.string()).default([]),intents:e.array(e.string()).default([]),maxDelegationDepth:e.number().int().min(0).max(50).default(5),mcp:e.record(e.string(),O).optional(),contextStrategy:e.enum(["layered","planner"]).optional(),contextReferences:e.boolean().default(!1),maxConcurrent:e.number().default(1),maxExecutionMinutes:e.number().int().min(1).max(240).default(20),permissionMode:e.string().default("default"),persistentProcess:e.boolean().default(!1),queueMode:e.enum(["collect","followup","drop"]).default("collect"),heartbeat:e.object({enabled:e.boolean().default(!1),intervalMinutes:e.number().default(30),prompt:e.string().default("Check inbox, pending tasks, and system health. Report anything that needs attention."),channel:e.string().default("heartbeat")}).default({}),access:e.enum(["private","public"]).default("private")}),_=e.object({token:e.string(),agentBinding:e.string(),allowFrom:e.array(e.string()).optional(),pollInbound:e.boolean().default(!0)}),N=e.object({telegram:e.object({enabled:e.boolean().default(!1),accounts:e.record(e.string(),_).default({}),policy:e.object({dm:e.enum(["pair","block"]).default("pair"),group:e.enum(["mention-required","all"]).default("mention-required"),allowFrom:e.array(e.string()).optional()}).default({})}).default({}),whatsapp:e.object({enabled:e.boolean().default(!1),sessionDir:e.string().default(".agentx/whatsapp-sessions"),defaultAgent:e.string().optional(),allowFrom:e.array(e.string()).optional(),routes:e.array(e.object({contact:e.string().optional(),group:e.string().optional(),agent:e.string()})).default([]),ingest:e.object({enabled:e.boolean().default(!1),mode:e.enum(["metadata-only","messages"]).default("metadata-only"),allowContacts:e.array(e.string()).default([]),allowGroups:e.array(e.string()).default([]),denyContacts:e.array(e.string()).default([]),denyGroups:e.array(e.string()).default([]),messageCap:e.number().int().min(1).max(500).default(50),historyDays:e.number().int().min(1).max(365).default(30),contactRefreshDays:e.number().int().min(1).max(90).default(7),throttle:e.object({minMsBetweenCalls:e.number().int().min(100).default(1500),maxCallsPerMinute:e.number().int().min(1).default(20),maxChatsPerSweep:e.number().int().min(1).default(25)}).default({}),retentionDays:e.number().int().min(0).default(0)}).default({})}).default({}),discord:e.object({enabled:e.boolean().default(!1),token:e.string().optional(),agentBinding:e.string().optional()}).default({}),slack:e.object({enabled:e.boolean().default(!1),botToken:e.string().optional(),appToken:e.string().optional(),agentBinding:e.string().optional()}).default({}),gitlab:e.object({enabled:e.boolean().default(!1),webhookPort:e.number().default(18810),webhookSecret:e.string().optional(),host:e.string().default("https://gitlab.com"),token:e.string().optional(),routes:e.array(e.object({project:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),gitlabUsernames:e.array(e.string()).default([]),keywords:e.array(e.string()).default([]),token:e.string().optional(),node:e.string().optional()})).default([])}).default({}),github:e.object({enabled:e.boolean().default(!1),token:e.string().optional(),tokenFile:e.string().optional(),appId:e.number().optional(),clientId:e.string().optional(),privateKeyFile:e.string().optional(),webhookSecret:e.string().optional(),routes:e.array(e.object({repo:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),githubUsernames:e.array(e.string()).default([]),token:e.string().optional(),tokenFile:e.string().optional(),node:e.string().optional()})).default([])}).default({}),webrtc:e.object({enabled:e.boolean().default(!1),stunServers:e.array(e.string()).default(["stun:stun.l.google.com:19302"]),turnServers:e.array(e.object({urls:e.string(),username:e.string().optional(),credential:e.string().optional()})).default([]),allowedCallers:e.array(e.string()).default([]),ringNotify:e.array(e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()})).default([]),callUrlBase:e.string().optional(),bot:e.object({enabled:e.boolean().default(!1),defaultAgentId:e.string().optional(),whisperBackend:e.enum(["auto","mlx","openai"]).default("auto"),whisperModel:e.string().optional(),whisperLanguage:e.string().default("auto"),mlxBinary:e.string().optional(),transcriptChannel:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),maxCallMinutes:e.number().int().min(1).max(240).default(30)}).default({})}).default({})}),F=e.object({enabled:e.boolean().default(!0),schedule:e.string(),timezone:e.string().default("UTC"),agent:e.string(),prompt:e.string(),timeout:e.number().default(600),model:e.string().optional(),maxOutputTokens:e.number().int().min(50).max(8e3).optional(),onError:e.union([e.enum(["log","notify","disable"]),e.array(e.enum(["log","notify","disable"]))]).default("log").transform(a=>Array.isArray(a)?a:[a]),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),W=e.object({name:e.string(),triggers:e.array(e.object({pattern:e.string(),channel:e.string().optional()})),allowedContacts:e.array(e.string()).optional(),agent:e.string(),prompt:e.string(),schedule:e.string().optional(),timezone:e.string().default("UTC"),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),q=e.object({url:e.string(),name:e.string(),token:e.string().optional()}),H=e.object({enabled:e.boolean().default(!1),peers:e.array(q).default([]),discovery:e.enum(["static","mdns"]).default("static"),healthCheck:e.object({interval:e.number().default(60),timeout:e.number().default(10)}).default({})}),J=e.object({enabled:e.boolean().default(!1),baseDir:e.string().default(".agentx/graph"),draftAgent:e.string().optional(),reviewAgent:e.string().optional(),autoApproveStructure:e.enum(["strict","extend-leaves","any"]).default("extend-leaves"),autoApproveConfidence:e.number().min(0).max(1).default(1),classifierModel:e.string().default("claude-haiku-4-5-20251001"),retrievalWeights:e.object({graph:e.number().min(0).default(.6),bm25:e.number().min(0).default(.4)}).default({})}).default({}),K=e.object({longTaskThreshold:e.number().default(30),destination:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),on:e.object({taskComplete:e.boolean().default(!0),taskError:e.boolean().default(!0),taskQueued:e.boolean().default(!1)}).default({})}).default({}),G=e.object({node:e.object({id:e.string(),name:e.string(),bind:e.string().default("127.0.0.1:18800"),defaultAgent:e.string().optional()}),providers:e.record(e.string(),E).default({}),agents:e.record(e.string(),U).default({}),channels:N.default({}),crons:e.record(e.string(),F).default({}),services:e.record(e.string(),W).default({}),notifications:K,mesh:H.default({}),business:m.optional(),boards:h,dashboard:y,graph:J,workflows:e.object({enabled:e.boolean().default(!1),dir:e.string().default(".agentx/workflows"),editor:e.enum(["disabled","readonly","edit"]).default("edit")}).default({}),webhooks:e.array(e.object({id:e.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"webhook id must be lowercase slug"),source:e.enum(["gitlab","github","sentry","stripe","discord","slack","custom"]),agentId:e.string(),secretEnv:e.string().optional(),description:e.string().optional(),enabled:e.boolean().default(!0),node:e.string().optional(),triggers:e.record(e.string(),e.string()).optional(),defaultWorkflow:e.string().optional()})).default([]),session:e.object({staleMinutes:e.number().int().min(1).max(1440).default(45),maxTurnsPerSession:e.number().int().min(2).max(200).default(15),tierTwoThresholdTokens:e.number().int().min(5e4).max(2e5).default(195e3),contextStrategy:e.enum(["layered","planner"]).default("layered"),maxClaudeCodeDispatchesPerHour:e.number().int().min(1).max(1e4).default(80),maxClaudeCodeDispatchesPer5h:e.number().int().min(1).max(5e4).default(180)}).default({}),plugins:e.array(e.string()).default([])});function g(a){if(typeof a=="string")return a.replace(/\$\{(\w+)\}/g,(i,s)=>process.env[s]||"");if(Array.isArray(a))return a.map(g);if(a!==null&&typeof a=="object"){let i={};for(let[s,o]of Object.entries(a))i[s]=g(o);return i}return a}function Q(a,i){let s=[],o=new Set;for(let r of a){let l=r.path.join("."),c=/^channels\.telegram\.accounts\.([^.]+)\.token$/.exec(l);if(c&&r.message.toLowerCase().includes("required")){let d=c[1],u=`tg:${d}`;if(o.has(u))continue;o.add(u),s.push(`Hint: Telegram account "${d}" is enabled but has no bot token.
3
+ Either:
4
+ A) Open ${i} and set channels.telegram.accounts.${d}.token to your bot token (or "\${TG_${d.toUpperCase()}_BOT_TOKEN}" + the matching .env entry).
5
+ B) If you don't need Telegram on this instance, remove the entire "telegram" block under "channels" (or set channels.telegram.enabled to false AND drop accounts.${d}).`)}}return s}function se(a){let i=a?[a]:[p(process.cwd(),"agentx.json"),p(process.cwd(),".agentx/config.json")];R(process.cwd());let s,o;for(let d of i)if(f(d)){s=x(d,"utf-8"),o=d;break}if(!s||!o)throw new Error(`No config found. Create agentx.json or .agentx/config.json
6
+ Searched: ${i.join(", ")}`);let r;try{r=JSON.parse(s)}catch(d){throw new Error(`Invalid JSON in ${o}: ${d.message}`)}let l=g(r),c=G.safeParse(l);if(!c.success){let d=c.error.issues.map(b=>` ${b.path.join(".")}: ${b.message}`).join(`
7
+ `),u=Q(c.error.issues,o),k=u.length?`
8
+
9
+ ${u.join(`
10
+
11
+ `)}`:"";throw new Error(`Config validation failed (${o}):
12
+ ${d}${k}`)}return c.data}function le(a){let i=[];for(let[s,o]of Object.entries(a.agents)){if(!f(o.workspace)){i.push(`Agent "${s}": workspace not found at ${o.workspace}`);continue}if(o.tier==="claude-code"){let c=p(o.workspace,".claude");f(c)||i.push(`Agent "${s}": no .claude/ directory in workspace ${o.workspace}. Claude Code native features (hooks, MCP, skills) won't be available.`)}let r=o.provider||"claude",l=a.providers[r];o.tier!=="claude-code"&&(!l||!l.apiKey)&&i.push(`Agent "${s}": provider "${r}" has no API key configured. Set providers.${r}.apiKey in config or use tier "claude-code" for subscription.`)}for(let[s,o]of Object.entries(a.crons))a.agents[o.agent]||i.push(`Cron "${s}": references unknown agent "${o.agent}"`);if(a.channels.telegram.enabled)for(let[s,o]of Object.entries(a.channels.telegram.accounts))a.agents[o.agentBinding]||i.push(`Telegram account "${s}": references unknown agent "${o.agentBinding}"`);return i}export{Y as a,ee as b,G as c,g as d,se as e,le as f};
13
+ //# sourceMappingURL=chunk-CO4YCIIA.js.map