agentix-cli 0.18.0 → 0.20.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 (171) hide show
  1. package/README.md +75 -27
  2. package/dist/{agent-RDVGL2TW.js → agent-57MG4LBM.js} +2 -2
  3. package/dist/{audit-Z47AQFFD.js → audit-JU3HWISB.js} +2 -2
  4. package/dist/{board-dashboard-KX2CNOSY.js → board-dashboard-HXDOYGIG.js} +2237 -69
  5. package/dist/board-dashboard-HXDOYGIG.js.map +1 -0
  6. package/dist/chunk-23AUU4S2.js +102 -0
  7. package/dist/chunk-23AUU4S2.js.map +1 -0
  8. package/dist/chunk-4MREHZP5.js +111 -0
  9. package/dist/chunk-4MREHZP5.js.map +1 -0
  10. package/dist/chunk-4YCH6IZV.js +2 -0
  11. package/dist/chunk-6B74TO2J.js +743 -0
  12. package/dist/chunk-6B74TO2J.js.map +1 -0
  13. package/dist/chunk-7GVXCOLO.js +440 -0
  14. package/dist/chunk-7GVXCOLO.js.map +1 -0
  15. package/dist/chunk-7P5QRX5W.js +108 -0
  16. package/dist/chunk-7P5QRX5W.js.map +1 -0
  17. package/dist/chunk-A6BKSZQA.js +3 -0
  18. package/dist/chunk-A6BKSZQA.js.map +1 -0
  19. package/dist/{chunk-6PPIFDOQ.js → chunk-CNNLREHD.js} +67 -22
  20. package/dist/{chunk-6PPIFDOQ.js.map → chunk-CNNLREHD.js.map} +1 -1
  21. package/dist/{chunk-J4WKMKTP.js → chunk-DLVOHCTA.js} +2 -2
  22. package/dist/chunk-E4ZZILAK.js +15 -0
  23. package/dist/chunk-E4ZZILAK.js.map +1 -0
  24. package/dist/{chunk-TRQSP67X.js → chunk-IKBHHTIT.js} +2 -2
  25. package/dist/chunk-JTJIPNXY.js +2 -0
  26. package/dist/chunk-JTJIPNXY.js.map +1 -0
  27. package/dist/chunk-MBOLXKA2.js +6 -0
  28. package/dist/chunk-MBOLXKA2.js.map +1 -0
  29. package/dist/{inbox-O5UB3YQN.js → chunk-MTRWXRFF.js} +69 -4
  30. package/dist/chunk-MTRWXRFF.js.map +1 -0
  31. package/dist/{processes-7W27G3J3.js → chunk-NOF4HSGK.js} +3 -3
  32. package/dist/{processes-7W27G3J3.js.map → chunk-NOF4HSGK.js.map} +1 -1
  33. package/dist/chunk-QW2OYR3N.js +7 -0
  34. package/dist/chunk-QW2OYR3N.js.map +1 -0
  35. package/dist/{chunk-JXEPJ3YD.js → chunk-TC3BSUP7.js} +5 -5
  36. package/dist/chunk-VWTBHLMX.js +1 -0
  37. package/dist/chunk-WFHIIVLL.js +719 -0
  38. package/dist/chunk-WFHIIVLL.js.map +1 -0
  39. package/dist/chunk-WPPUOTY6.js +6 -0
  40. package/dist/chunk-WPPUOTY6.js.map +1 -0
  41. package/dist/cli.js +1 -1
  42. package/dist/cli.js.map +1 -1
  43. package/dist/{compaction-S5H6DTOR.js → compaction-BTUJJ3LJ.js} +4 -4
  44. package/dist/config-QXWKEQON.js +2 -0
  45. package/dist/config-mutator-53XGR2NT.js +2 -0
  46. package/dist/conflict-detector-D7VIYPDI.js +2 -0
  47. package/dist/conflict-detector-D7VIYPDI.js.map +1 -0
  48. package/dist/{context-planner-2RGHJHSO.js → context-planner-I7ID7XF3.js} +3 -3
  49. package/dist/debug-N3B5NVJU.js +2 -0
  50. package/dist/{discover-OATU7SHI.js → discover-XJXQXXIO.js} +2 -2
  51. package/dist/doctor-SEOUFHSL.js +2 -0
  52. package/dist/{editor-chat-FUBQLMAQ.js → editor-chat-RVLCKKB7.js} +2 -2
  53. package/dist/{heal-YP7QI7D3.js → heal-YEQYWX2L.js} +2 -2
  54. package/dist/inbox-BIN2S5XN.js +2 -0
  55. package/dist/index.d.ts +830 -100
  56. package/dist/index.js +2 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/{ingest-whatsapp-C3O5UPBX.js → ingest-whatsapp-LZE62INA.js} +2 -2
  59. package/dist/loader-5CA3O5GM.js +2 -0
  60. package/dist/loader-6IHUCPVO.js +2 -0
  61. package/dist/memory-extract-KRCHD3OP.js +2 -0
  62. package/dist/migrate-v2-QO7SLKIM.js +4 -0
  63. package/dist/migrate-v2-QO7SLKIM.js.map +1 -0
  64. package/dist/processes-RJ6RDP32.js +2 -0
  65. package/dist/program-WWCXMRU2.js +2 -0
  66. package/dist/{providers-WCQSKTNP.js → providers-WVCMIW67.js} +2 -2
  67. package/dist/query-HZYYRCLU.js +2 -0
  68. package/dist/recipes-EPLE2SNT.js +2 -0
  69. package/dist/registry-HM4ELSXS.js +2 -0
  70. package/dist/rotation-memo-GMTZPMNE.js +13 -0
  71. package/dist/rotation-memo-GMTZPMNE.js.map +1 -0
  72. package/dist/scheduler-XVFIK4XH.js +2 -0
  73. package/dist/{slack-D27BE37Q.js → slack-6P7ZJ32Y.js} +2 -2
  74. package/dist/store-BAPDZHXE.js +2 -0
  75. package/dist/{subagent-EPOT3QDM.js → subagent-WV7QKQ3L.js} +2 -2
  76. package/dist/{task-store-3NUWLYRY.js → task-store-RHISEU6V.js} +2 -2
  77. package/dist/{telegram-UWV67KWG.js → telegram-PIYDRM46.js} +2 -2
  78. package/dist/timers-5LPZN55J.js +2 -0
  79. package/dist/types-VECTMYTO.js +2 -0
  80. package/dist/types-VECTMYTO.js.map +1 -0
  81. package/dist/types-ZRLHHCGB.js +2 -0
  82. package/dist/types-ZRLHHCGB.js.map +1 -0
  83. package/dist/web/activity-graph.global.js +654 -0
  84. package/dist/web/activity-graph.global.js.map +1 -0
  85. package/dist/web/workflow-editor.global.js +1 -1
  86. package/dist/web/workflow-editor.global.js.map +1 -1
  87. package/dist/{whatsapp-KJ2NRKKQ.js → whatsapp-PFRDMUMT.js} +2 -2
  88. package/dist/{whatsapp-state-3ZVQ6MQD.js → whatsapp-state-XMTCSRXU.js} +2 -2
  89. package/dist/wiki-53W5NLZV.js +2 -0
  90. package/dist/wiki-53W5NLZV.js.map +1 -0
  91. package/dist/workspace-setup-FPGN5VNY.js +2 -0
  92. package/dist/workspace-setup-FPGN5VNY.js.map +1 -0
  93. package/package.json +3 -2
  94. package/dist/board-dashboard-KX2CNOSY.js.map +0 -1
  95. package/dist/chunk-34NG7UDX.js +0 -11
  96. package/dist/chunk-34NG7UDX.js.map +0 -1
  97. package/dist/chunk-ASSJ4Z6Z.js +0 -164
  98. package/dist/chunk-ASSJ4Z6Z.js.map +0 -1
  99. package/dist/chunk-BLUXL6HR.js +0 -854
  100. package/dist/chunk-BLUXL6HR.js.map +0 -1
  101. package/dist/chunk-BTAEYL3P.js +0 -72
  102. package/dist/chunk-BTAEYL3P.js.map +0 -1
  103. package/dist/chunk-DSCMCVTV.js +0 -7
  104. package/dist/chunk-DSCMCVTV.js.map +0 -1
  105. package/dist/chunk-HPDHNIA3.js +0 -2
  106. package/dist/chunk-IM376SD6.js +0 -13
  107. package/dist/chunk-IM376SD6.js.map +0 -1
  108. package/dist/chunk-LEIYC3BF.js +0 -104
  109. package/dist/chunk-LEIYC3BF.js.map +0 -1
  110. package/dist/chunk-LY7JGDV7.js +0 -6
  111. package/dist/chunk-LY7JGDV7.js.map +0 -1
  112. package/dist/chunk-U364GNQX.js +0 -719
  113. package/dist/chunk-U364GNQX.js.map +0 -1
  114. package/dist/chunk-WZEYII2S.js +0 -6
  115. package/dist/chunk-WZEYII2S.js.map +0 -1
  116. package/dist/config-UOHEG4BW.js +0 -2
  117. package/dist/config-mutator-KSEBWKJH.js +0 -2
  118. package/dist/debug-TGAP7E7W.js +0 -2
  119. package/dist/inbox-O5UB3YQN.js.map +0 -1
  120. package/dist/loader-BGWA7IRY.js +0 -2
  121. package/dist/loader-LBHKSXBK.js +0 -2
  122. package/dist/memory-extract-KKPKAOPH.js +0 -2
  123. package/dist/program-2MDELQLX.js +0 -2
  124. package/dist/query-FZAL7AQD.js +0 -2
  125. package/dist/recipes-LZ56TA3X.js +0 -2
  126. package/dist/registry-ONJSILH4.js +0 -2
  127. package/dist/scheduler-XRM2RJIV.js +0 -2
  128. package/dist/store-4UCO56K2.js +0 -2
  129. package/dist/timers-QB4KYNAE.js +0 -2
  130. package/dist/types-ECMEC5BZ.js +0 -2
  131. package/dist/types-TTB6DJUE.js +0 -2
  132. package/dist/usage-dashboard-FQGPPABD.js +0 -803
  133. package/dist/usage-dashboard-FQGPPABD.js.map +0 -1
  134. package/dist/wiki-OUYKM7MB.js +0 -2
  135. package/dist/workspace-setup-6GDBEORT.js +0 -2
  136. /package/dist/{agent-RDVGL2TW.js.map → agent-57MG4LBM.js.map} +0 -0
  137. /package/dist/{audit-Z47AQFFD.js.map → audit-JU3HWISB.js.map} +0 -0
  138. /package/dist/{chunk-HPDHNIA3.js.map → chunk-4YCH6IZV.js.map} +0 -0
  139. /package/dist/{chunk-J4WKMKTP.js.map → chunk-DLVOHCTA.js.map} +0 -0
  140. /package/dist/{chunk-TRQSP67X.js.map → chunk-IKBHHTIT.js.map} +0 -0
  141. /package/dist/{chunk-JXEPJ3YD.js.map → chunk-TC3BSUP7.js.map} +0 -0
  142. /package/dist/{config-UOHEG4BW.js.map → chunk-VWTBHLMX.js.map} +0 -0
  143. /package/dist/{compaction-S5H6DTOR.js.map → compaction-BTUJJ3LJ.js.map} +0 -0
  144. /package/dist/{config-mutator-KSEBWKJH.js.map → config-QXWKEQON.js.map} +0 -0
  145. /package/dist/{debug-TGAP7E7W.js.map → config-mutator-53XGR2NT.js.map} +0 -0
  146. /package/dist/{context-planner-2RGHJHSO.js.map → context-planner-I7ID7XF3.js.map} +0 -0
  147. /package/dist/{heal-YP7QI7D3.js.map → debug-N3B5NVJU.js.map} +0 -0
  148. /package/dist/{discover-OATU7SHI.js.map → discover-XJXQXXIO.js.map} +0 -0
  149. /package/dist/{loader-BGWA7IRY.js.map → doctor-SEOUFHSL.js.map} +0 -0
  150. /package/dist/{editor-chat-FUBQLMAQ.js.map → editor-chat-RVLCKKB7.js.map} +0 -0
  151. /package/dist/{loader-LBHKSXBK.js.map → heal-YEQYWX2L.js.map} +0 -0
  152. /package/dist/{memory-extract-KKPKAOPH.js.map → inbox-BIN2S5XN.js.map} +0 -0
  153. /package/dist/{ingest-whatsapp-C3O5UPBX.js.map → ingest-whatsapp-LZE62INA.js.map} +0 -0
  154. /package/dist/{program-2MDELQLX.js.map → loader-5CA3O5GM.js.map} +0 -0
  155. /package/dist/{providers-WCQSKTNP.js.map → loader-6IHUCPVO.js.map} +0 -0
  156. /package/dist/{query-FZAL7AQD.js.map → memory-extract-KRCHD3OP.js.map} +0 -0
  157. /package/dist/{recipes-LZ56TA3X.js.map → processes-RJ6RDP32.js.map} +0 -0
  158. /package/dist/{registry-ONJSILH4.js.map → program-WWCXMRU2.js.map} +0 -0
  159. /package/dist/{scheduler-XRM2RJIV.js.map → providers-WVCMIW67.js.map} +0 -0
  160. /package/dist/{store-4UCO56K2.js.map → query-HZYYRCLU.js.map} +0 -0
  161. /package/dist/{task-store-3NUWLYRY.js.map → recipes-EPLE2SNT.js.map} +0 -0
  162. /package/dist/{timers-QB4KYNAE.js.map → registry-HM4ELSXS.js.map} +0 -0
  163. /package/dist/{types-ECMEC5BZ.js.map → scheduler-XVFIK4XH.js.map} +0 -0
  164. /package/dist/{slack-D27BE37Q.js.map → slack-6P7ZJ32Y.js.map} +0 -0
  165. /package/dist/{types-TTB6DJUE.js.map → store-BAPDZHXE.js.map} +0 -0
  166. /package/dist/{subagent-EPOT3QDM.js.map → subagent-WV7QKQ3L.js.map} +0 -0
  167. /package/dist/{wiki-OUYKM7MB.js.map → task-store-RHISEU6V.js.map} +0 -0
  168. /package/dist/{telegram-UWV67KWG.js.map → telegram-PIYDRM46.js.map} +0 -0
  169. /package/dist/{workspace-setup-6GDBEORT.js.map → timers-5LPZN55J.js.map} +0 -0
  170. /package/dist/{whatsapp-KJ2NRKKQ.js.map → whatsapp-PFRDMUMT.js.map} +0 -0
  171. /package/dist/{whatsapp-state-3ZVQ6MQD.js.map → whatsapp-state-XMTCSRXU.js.map} +0 -0
@@ -0,0 +1,15 @@
1
+ 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-QW2OYR3N.js";import{c as V}from"./chunk-N67JZAXU.js";import{e as Ae}from"./chunk-CDNWCYF7.js";import{b as Y}from"./chunk-AFRHKA7B.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","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
+ `),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
+ `)){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
+ `);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)+`
5
+ `)}writeIndex(e,t){St(this.indexPath(e),JSON.stringify({runId:t,homeNode:this.nodeId,updatedAt:new Date().toISOString()},null,2)+`
6
+ `)}clearIndex(e){let t=this.indexPath(e);if(E(t))try{Ue(t)}catch{}}};import{existsSync as Me,mkdirSync as Rt,readFileSync as At,unlinkSync as Tt,writeFileSync as Pt}from"fs";import{resolve as se}from"path";import{z as C}from"zod";var He=C.object({version:C.literal(1),nodes:C.record(C.object({x:C.number(),y:C.number()}))}),oe=class{baseDir;layoutsDir;constructor(e={}){this.baseDir=e.baseDir??se(process.cwd(),".agentx/workflows"),this.layoutsDir=se(this.baseDir,"_layouts"),Rt(this.layoutsDir,{recursive:!0})}pathFor(e){let t=e.replace(/[^a-zA-Z0-9._-]/g,"_");return se(this.layoutsDir,`${t}.json`)}get(e){let t=this.pathFor(e);if(!Me(t))return null;try{let n=He.safeParse(JSON.parse(At(t,"utf-8")));return n.success?n.data:null}catch{return null}}save(e,t){let n=He.parse(t);return Pt(this.pathFor(e),JSON.stringify(n,null,2)+`
7
+ `),n}sync(e,t){let n=this.get(e);if(!n)return null;let r={};for(let i of t)n.nodes[i]&&(r[i]=n.nodes[i]);let o={version:1,nodes:r};return this.save(e,o)}delete(e){let t=this.pathFor(e);return Me(t)?(Tt(t),!0):!1}};function ie(s){let{workflow:e,fromNodeId:t,selectedPort:n}=s,r=e.nodes.find(a=>a.id===t);if(!r)return{nextPending:[]};let o=e.edges.filter(a=>a.from===t);return{nextPending:(r.type==="branch"?o.filter(a=>(a.fromPort??"")===(n??"")):o).map(a=>a.to)}}function ae(s,e){let t=s.config.cases??[],n=s.config.default??"";for(let r of t)if(xt(r.when,e))return r.to;return n}function xt(s,e){let t=s.params??{},n=String(t.path??""),r=M(e,n);switch(s.kind){case"equals":return r===t.value;case"contains":return typeof r=="string"?r.includes(String(t.value??"")):Array.isArray(r)?r.some(o=>o===t.value):!1;case"matches":{if(typeof r!="string")return!1;try{return new RegExp(String(t.regex??"")).test(r)}catch{return!1}}case"exists":return r!=null&&r!=="";default:return!1}}function M(s,e){if(!e)return;let t=e.split("."),n=s;for(let r of t){if(n==null||typeof n!="object")return;n=n[r]}return n}function H(s){let e=s.nodes.find(n=>n.type.startsWith("trigger."));if(!e)return null;let t=s.edges.filter(n=>n.from===e.id).map(n=>n.to);return{triggerId:e.id,pending:t}}function T(s,e){return s.nodes.find(t=>t.id===e)}function jt(s,e,t){let n=s.split(".");if(n[0]==="env"){if(n.length!==2)return"";let o=n[1];if(!t.has(o))return"";let i=process.env[o];return typeof i=="string"?i:""}let r=e;for(let o of n){if(r==null||typeof r!="object")return"";r=r[o]}return r==null?"":typeof r=="object"?JSON.stringify(r):String(r)}function N(s,e,t={}){let n=new Set(t.envAllow||[]);return s.replace(/\{\{\s*([a-zA-Z_][a-zA-Z0-9_.-]*)\s*\}\}/g,(r,o)=>jt(o,e,n))}function k(s,e,t={}){let n={};for(let[r,o]of Object.entries(s))typeof o=="string"?n[r]=N(o,e,t):Array.isArray(o)?n[r]=o.map(i=>typeof i=="string"?N(i,e,t):i):o&&typeof o=="object"?n[r]=k(o,e,t):n[r]=o;return n}var de=class{active=new Map;waiters=new Map;async acquire(e,t){let n=this.active.get(e)??0;if(n<t){this.active.set(e,n+1);return}return new Promise(r=>{let o=this.waiters.get(e)??[];o.push({resolve:()=>{this.active.set(e,(this.active.get(e)??0)+1),r()}}),this.waiters.set(e,o)})}release(e){let t=this.active.get(e)??0;this.active.set(e,Math.max(0,t-1));let n=this.waiters.get(e);n&&n.length>0&&n.shift().resolve()}stats(e){return{active:this.active.get(e)??0,waiting:this.waiters.get(e)?.length??0}}},B=new de;function Be(s,e){return`${s}:${e}`}var D=async s=>({output:s.run.context[s.node.id]??{}}),Wt=async s=>{let e=s.node.config,t=String(e.agentId??""),n=String(e.prompt??"");if(!t)return{error:`agent node "${s.node.id}" missing config.agentId`};let r=N(n,s.run.context,{envAllow:s.workflow.envAllow}),o=typeof e.timeoutMinutes=="number"?e.timeoutMinutes:void 0,i=typeof e.maxConcurrent=="number"&&e.maxConcurrent>0?e.maxConcurrent:null,a=i?Be(s.workflow.id,s.node.id):null;if(a&&i){let l=B.stats(a);l.active>=i&&s.log(`[node:${s.node.id}] gated: ${l.active} active (cap ${i}), ${l.waiting+1} waiting`),await B.acquire(a,i)}let d=Date.now();try{let l=await s.agents.execute({agentId:t,message:r,workflowRunId:s.run.id,timeoutMinutes:o}),g=Date.now()-d;if(l.error)return s.log(`[node:${s.node.id}] agent "${t}" failed: ${l.error}`),{error:l.error};let p=String(e.resultParser??"noqta-result-token")==="json"?en(l.content):ze(l.content);return{output:{reply:l.content,result:p.result,json:p.json,taskId:l.taskId,durationMs:g}}}catch(l){return s.log(`[node:${s.node.id}] agent "${t}" threw: ${l.message}`),{error:l.message}}finally{a&&B.release(a)}},Nt=async s=>{let e=ae(s.node,s.run.context);return e?{output:{port:e},port:e}:(s.log(`[node:${s.node.id}] branch matched no case and no default port`),{output:{port:null}})},Ot=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??""),n=String(e.chatId??""),r=String(e.text??"");if(!t||!n){let a=String(s.node.config.chatId??""),d=String(s.node.config.channel??""),l=[];return t||l.push(`channel config="${d}" rendered=""`),n||l.push(`chatId config="${a}" rendered=""`),(/\{\{\s*env\./.test(a)||/\{\{\s*env\./.test(d))&&l.push("(env.* templates only resolve for names listed in workflow.envAllow and actually set in process.env)"),{error:`action.send "${s.node.id}" needs channel + chatId \u2014 ${l.join("; ")}`}}let o=ce(s,e.accountId),i=s.channels[t];if(i?.send)try{return{output:{messageId:await i.send({channel:t,chatId:n,text:r,...o?{accountId:o}:{}})??null}}}catch(a){return{error:`action.send failed: ${a.message}`}}if(s.forwardChannelSend)try{return{output:{messageId:(await s.forwardChannelSend({channel:t,chatId:n,text:r,accountId:o})).messageId,viaMesh:!0}}}catch(a){return s.log(`[node:${s.node.id}] mesh-forward of "${t}" send failed: ${a.message}`),{error:`action.send via mesh failed: ${a.message}`}}return s.log(`[node:${s.node.id}] adapter "${t}" not available locally and no mesh forwarder`),{error:`channel "${t}" not available (no local adapter, no mesh route)`}},Et=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),n=String(e.project??""),r=String(e.title??""),o=String(e.description??""),i=Array.isArray(e.labels)?e.labels.map(String):[],a=Array.isArray(e.assignees)?e.assignees.map(String):[];if(!n||!r)return{error:`action.createIssue "${s.node.id}" needs project + title`};let d=ue(s),l=s.channels[t];if(!l?.createIssue)return{error:`channel "${t}" does not support createIssue`};try{let g=await l.createIssue({project:n,title:r,description:o,labels:i,assignees:a,agentId:d});return g?{output:{issue:{iid:g.iid,url:g.url,webUrl:g.url}}}:{error:"createIssue returned null (see adapter log)"}}catch(g){return{error:`action.createIssue failed: ${g.message}`}}},Ct=async()=>({output:{}}),Dt=async s=>{let e=s.node.config,t=String(e.name??s.node.id),n=e.waitFor??{},r=e.resumeMatch??{};return{paused:!0,pausedAt:{kind:"checkpoint",nodeId:s.node.id,checkpointName:t,resumeMatch:{...n,...r}}}},_t=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),n=String(e.project??""),r=String(e.iid??""),o=Array.isArray(e.add)?e.add.map(String):[],i=Array.isArray(e.remove)?e.remove.map(String):[];if(!n||!r)return{error:`action.setLabel "${s.node.id}" needs project + iid (try {{trigger.project}} / {{trigger.issue.iid}})`};if(o.length===0&&i.length===0)return{output:{skipped:!0,reason:"no labels to add or remove"}};let a=s.channels[t];if(!a?.setLabels)return{error:`channel "${t}" does not support setLabels`};let d=ue(s),l=e.kind==="merge_request"?"merge_request":"issue";return{output:{labels:await a.setLabels({project:n,kind:l,iid:r,add:o,remove:i,agentId:d})??[],add:o,remove:i}}},Ft=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),n=String(e.project??""),r=String(e.iid??"");if(!n||!r)return{error:`action.readLabel "${s.node.id}" needs project + iid`};let o=s.channels[t];if(!o?.getLabels)return{error:`channel "${t}" does not support getLabels`};let i=e.kind==="merge_request"?"merge_request":"issue";return{output:{labels:await o.getLabels({project:n,kind:i,iid:r})??[]}}},Lt=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??""),n=String(e.chatId??""),r=String(e.messageId??""),o=String(e.emoji??"\u{1F440}");if(!t||!n||!r)return{error:`action.react "${s.node.id}" needs channel + chatId + messageId`};let i=ce(s,e.accountId),a=s.channels[t];if(!a?.react)return{error:`channel "${t}" does not support react`};try{return await a.react(n,r,o,i),{output:{emoji:o}}}catch(d){return{error:`action.react failed: ${d.message}`}}},Ut=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??""),n=String(e.chatId??""),r=String(e.messageId??""),o=String(e.text??""),i=e.parseMode?String(e.parseMode):void 0;if(!t||!n||!r||!o)return{error:`action.editMessage "${s.node.id}" needs channel + chatId + messageId + text`};let a=ce(s,e.accountId),d=s.channels[t];if(!d?.editMessage)return{error:`channel "${t}" does not support editMessage`};try{return{output:{edited:await d.editMessage(n,r,o,i,a)}}}catch(l){return{error:`action.editMessage failed: ${l.message}`}}},Mt=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),n=String(e.chatId??""),r=Number(e.durationMs??0);if(!n||!r)return{error:`action.logTime "${s.node.id}" needs chatId + durationMs`};let o=s.channels[t];if(!o?.logTimeSpent)return{error:`channel "${t}" does not support logTimeSpent`};let i=ue(s);try{return await o.logTimeSpent(n,r,i),{output:{durationMs:r}}}catch(a){return{error:`action.logTime failed: ${a.message}`}}},Ht=async s=>{let e=k(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.url??"");if(!t)return{error:`action.callHTTP "${s.node.id}" needs url`};let n=String(e.method??"POST").toUpperCase(),r=e.headers&&typeof e.headers=="object"?e.headers:{"Content-Type":"application/json"},o;e.body!==void 0&&(o=typeof e.body=="string"?e.body:JSON.stringify(e.body));try{let i=await fetch(t,{method:n,headers:r,body:o}),a=await i.text(),d=a;try{d=JSON.parse(a)}catch{}return{output:{ok:i.ok,status:i.status,body:d}}}catch(i){return{error:`action.callHTTP failed: ${i.message}`}}},Bt=async s=>{let e=s.node.config,t=s.run.context;return typeof e.path=="string"&&e.path?{output:{value:M(t,e.path)}}:e.template&&typeof e.template=="object"?{output:k(e.template,t,{envAllow:s.workflow.envAllow})}:{output:{}}},Kt=async s=>{let e=s.node.config,t=k(e,s.run.context,{envAllow:s.workflow.envAllow}),n=String(t.assignTo??"");if(!n)return{error:`userTask "${s.node.id}" missing config.assignTo`};let r=Te(n);if(!r)return{error:`userTask "${s.node.id}" assignTo must be "actor:<id>" or "role:<id>", got "${n}"`};let o=e.form??t.form,i=qt(o);if(!i)return{error:`userTask "${s.node.id}" missing or invalid config.form`};let a=String(t.title??i.title??s.node.id),d=typeof t.description=="string"?t.description:void 0;if(!s.actors)return{error:`userTask "${s.node.id}" requires ActorStore in context (engine misconfigured)`};if(!s.tasks)return{error:`userTask "${s.node.id}" requires TaskStore in context (engine misconfigured)`};let l=s.actors.pickAssignees(r);if(l.length===0)return{error:`userTask "${s.node.id}" assignee "${n}" resolved to zero actors`};let g=Ke(t.dueIn),c=s.tasks.create({runId:s.run.id,workflowId:s.workflow.id,nodeId:s.node.id,title:a,description:d,assignee:n,assignedTo:l,form:i,dueAt:g});return s.log(`[node:${s.node.id}] userTask created ${c.id} for ${n} \u2192 actors [${l.join(", ")}]`),{paused:!0,pausedAt:{kind:"userTask",nodeId:s.node.id,taskId:c.id,assignee:n,assignedTo:l}}};function qt(s){if(!s||typeof s!="object")return null;let e=Ae.safeParse(s);return e.success?e.data:null}function Ke(s){if(s!=null){if(typeof s=="number")return new Date(Date.now()+s*6e4).toISOString();if(typeof s=="object"&&s&&"minutes"in s){let e=Number(s.minutes);if(Number.isFinite(e))return new Date(Date.now()+e*6e4).toISOString()}if(typeof s=="string"){let e=/^P(?:([0-9]+)D)?(?:T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)S)?)?$/.exec(s);if(e){let t=Number(e[1]??0),n=Number(e[2]??0),r=Number(e[3]??0),o=Number(e[4]??0),i=((t*24+n)*60+r)*6e4+o*1e3;if(i>0)return new Date(Date.now()+i).toISOString()}}}}var zt=async s=>{let e=s.node.config,t=k(e,s.run.context,{envAllow:s.workflow.envAllow}),n=String(t.workflowId??"");if(!n)return{error:`subProcess "${s.node.id}" missing config.workflowId`};let r=s.run.depth??0,o=s.workflow.maxChildDepth??5;if(r+1>=o)return{error:`max child workflow depth ${o} exceeded at ${s.workflow.id} \u2192 ${n} (parent depth ${r})`};let i=e.inputMap,a={};if(i==="*")a={...s.run.context};else if(i&&typeof i=="object")for(let[d,l]of Object.entries(i))l&&typeof l=="object"&&!Array.isArray(l)?a[d]=k(l,s.run.context,{envAllow:s.workflow.envAllow}):typeof l=="string"&&(a[d]={value:N(l,s.run.context,{envAllow:s.workflow.envAllow})});return{paused:!0,pausedAt:{kind:"subProcess",nodeId:s.node.id,childRunId:"",childWorkflowId:n},spawnChild:{workflowId:n,input:a}}},Jt=D,Gt=async s=>{let e=s.node.config,t=k(e,s.run.context,{envAllow:s.workflow.envAllow}),n=String(t.name??"");if(!n)return{error:`signal.emit "${s.node.id}" missing config.name`};let r=t.scope==="global"?"global":"workflow",o=t.payload&&typeof t.payload=="object"?t.payload:{};return{output:{emittedAt:new Date().toISOString(),name:n,scope:r,payload:o},emitSignal:{name:n,scope:r,payload:o}}},Vt=async s=>{let e=s.node.config,t=k(e,s.run.context,{envAllow:s.workflow.envAllow}),n=String(t.name??"");if(!n)return{error:`signal.wait "${s.node.id}" missing config.name`};let r=t.scope==="global"?"global":"workflow",o=e.match&&typeof e.match=="object"?e.match:{};return{paused:!0,pausedAt:{kind:"signalWait",nodeId:s.node.id,signalName:n,match:o,scope:r}}},Yt=async s=>{let e=s.node.config,t=k(e,s.run.context,{envAllow:s.workflow.envAllow}),n=Ke(t.after??e.after);return n?{paused:!0,pausedAt:{kind:"timerWait",nodeId:s.node.id,fireAt:n}}:{error:`timer.boundary "${s.node.id}" needs config.after (duration or minutes)`}},Zt=async()=>({output:{}}),Xt=async s=>{let e=s.node.config,n=(Array.isArray(e.inputs)?e.inputs:[]).map(i=>typeof i=="string"?N(i,s.run.context,{envAllow:s.workflow.envAllow}):i),r=Array.isArray(e.rules)?e.rules:[];for(let i of r){let a=Array.isArray(i.when)?i.when:[];if(a.length!==n.length)continue;let d=!0;for(let l=0;l<a.length;l++)if(!Qt(a[l],n[l])){d=!1;break}if(d)return{output:{...i.output??{},matchedPort:i.to??""},port:i.to}}let o=e.default;return{output:{...o?.output??{},matchedPort:o?.to??""},port:o?.to}};function Qt(s,e){if(s==null||s==="*")return!0;let t=String(s),n=typeof e=="number"?e:String(e??""),r=/^(>=|<=|>|<)\s*(-?\d+(?:\.\d+)?)$/.exec(t);if(r){let o=r[1],i=Number(r[2]),a=typeof n=="number"?n:Number(n);if(Number.isNaN(a))return!1;switch(o){case">":return a>i;case"<":return a<i;case">=":return a>=i;case"<=":return a<=i}}if(t.startsWith("!="))return String(n)!==t.slice(2);if(t.startsWith("/")&&t.endsWith("/")&&t.length>2)try{return new RegExp(t.slice(1,-1)).test(String(n))}catch{return!1}return String(n)===t}var qe={"trigger.channel":D,"trigger.manual":D,"trigger.cron":D,"trigger.hook":D,"trigger.form":Jt,agent:Wt,branch:Nt,transform:Bt,"gateway.parallel":Zt,rule:Xt,"action.send":Ot,"action.createIssue":Et,"action.setLabel":_t,"action.readLabel":Ft,"action.react":Lt,"action.editMessage":Ut,"action.logTime":Mt,"action.callHTTP":Ht,userTask:Kt,subProcess:zt,"signal.emit":Gt,"signal.wait":Vt,"timer.boundary":Yt,checkpoint:Dt,end:Ct};function le(s){return qe[s]}function ce(s,e){if(typeof e=="string"&&e)return e;let t=s.workflow.nodes.find(o=>o.type.startsWith("trigger."));if(!t)return;let r=s.run.context[t.id]?.accountId;return typeof r=="string"&&r?r:void 0}function ue(s){for(let e=s.run.history.length-1;e>=0;e--){let t=s.run.history[e],n=s.workflow.nodes.find(r=>r.id===t.nodeId);if(n?.type==="agent")return n.config.agentId??void 0}}function ze(s){if(!s)return{};let e=s.match(/\bRESULT:\s*([a-z][a-z0-9_-]*)/i);if(e)return{result:e[1].toLowerCase()};let t=s.match(/\[(APPROVED|REJECTED|CHANGES[-_]REQUESTED|DONE|FAILED|SKIPPED)\]/i);return t?{result:t[1].toLowerCase().replace("_","-")}:{}}function en(s){let{result:e}=ze(s);if(!s)return{result:e};let t=s.match(/```(?:json)?\s*([\s\S]*?)```/);if(!t)return{result:e};try{return{result:e,json:JSON.parse(t[1])}}catch{return{result:e}}}var _=class{handlers=new Set;subscribe(e){return this.handlers.add(e),()=>this.handlers.delete(e)}emit(e){for(let t of this.handlers)try{Promise.resolve(t(e)).catch(()=>{})}catch{}}};function K(s,e){if(s.name!==e.name||s.scope==="workflow"&&s.workflowId!==e.workflowId)return!1;for(let[t,n]of Object.entries(s.match??{}))if(!(n===void 0||n===""||n==="*")&&e.payload[t]!==n)return!1;return!0}function Je(s,e){let t=[],n={};for(let r of s.fields){let o=e.values[r.key];if(!(o!=null&&o!=="")){r.required?t.push({field:r.key,message:`"${r.label}" is required`}):r.defaultValue!==void 0&&(n[r.key]=r.defaultValue);continue}let a=tn(r,o);if(a.error){t.push({field:r.key,message:a.error});continue}n[r.key]=a.value}return{ok:t.length===0,errors:t,values:n}}function tn(s,e){let t=s.label;switch(s.type){case"text":case"long-text":{let n=String(e);return s.validate?.min!==void 0&&n.length<s.validate.min?{error:`"${t}" must be at least ${s.validate.min} characters`}:s.validate?.max!==void 0&&n.length>s.validate.max?{error:`"${t}" must be at most ${s.validate.max} characters`}:s.validate?.pattern&&!new RegExp(s.validate.pattern).test(n)?{error:`"${t}" does not match the expected format`}:{value:n}}case"number":{let n=typeof e=="number"?e:Number(String(e));return Number.isFinite(n)?s.validate?.min!==void 0&&n<s.validate.min?{error:`"${t}" must be at least ${s.validate.min}`}:s.validate?.max!==void 0&&n>s.validate.max?{error:`"${t}" must be at most ${s.validate.max}`}:{value:n}:{error:`"${t}" must be a number`}}case"boolean":{if(typeof e=="boolean")return{value:e};let n=String(e).toLowerCase();return["true","yes","y","1"].includes(n)?{value:!0}:["false","no","n","0"].includes(n)?{value:!1}:{error:`"${t}" must be yes/no`}}case"date":{let n=typeof e=="string"||typeof e=="number"?new Date(e):null;return!n||Number.isNaN(n.getTime())?{error:`"${t}" is not a valid date`}:{value:n.toISOString()}}case"select":{let n=String(e),r=s.options??[];return r.length&&!r.includes(n)?{error:`"${t}" must be one of: ${r.join(", ")}`}:{value:n}}case"multi-select":{let n=Array.isArray(e)?e.map(String):String(e).split(",").map(o=>o.trim()).filter(Boolean),r=s.options??[];if(r.length){let o=n.filter(i=>!r.includes(i));if(o.length)return{error:`"${t}" contains invalid values: ${o.join(", ")}`}}return{value:n}}case"file":return{value:String(e)}}return{error:`unknown field type: ${s.type}`}}function nn(s,e,t=Date.now){return{ts:t(),source:"workflow",sourceEventId:`${s.workflowId}:${s.eventId}`,project:s.project,subject:`workflow:${s.workflowId}:entity:${s.entityRef.backend}:${s.entityRef.id}`,intent:`workflow.${s.triggerSource}`,rawJson:e}}function rn(s){return s.claimed&&s.runId?{agentId:`workflow-run:${s.runId}`,outcome:"dispatched",reason:s.reason??"claimed"}:s.claimed&&!s.runId?{agentId:null,outcome:"halted",reason:s.reason??"claimed-but-no-run"}:{agentId:null,outcome:"halted",reason:s.reason??"not-claimed"}}function sn(s){return{decidedBy:"workflow-dispatcher",decide:()=>({agentId:s.agentId,outcome:s.outcome==="deduped"?"halted":s.outcome,reason:s.outcome==="deduped"?`legacy-dedup: ${s.reason??""}`.trim():s.reason??null})}}function Ge(s,e,t,n,r=Date.now){let o=nn(e,t,r),i=rn(n),a=sn(i),d=Se(s,o,a,r);return $e(s,"workflow",d,i,r),d}var on=4e3,an=8,pe=class{store;runs;nodeId;forwarder;channels;agents;log;actors;tasks;timers;signals;events;renderUserTask;ackTypingTimers=new Map;commitChains=new Map;constructor(e){this.store=e.store,this.runs=e.runs,this.nodeId=e.nodeId,this.forwarder=e.forwarder,this.channels=e.channels,this.agents=e.agents,this.log=e.log??(()=>{}),this.actors=e.actors??new Pe,this.tasks=e.tasks??new V,this.timers=e.timers??new Y({log:t=>this.log(t)}),this.signals=e.signals??new _,this.events=e.events,this.renderUserTask=e.renderUserTask,this.timers.onFire(t=>this.resumeFromTimer(t)),this.signals.subscribe(t=>this.resumeFromSignal(t))}emitRunEvent(e){if(this.events)try{this.events.publish({kind:"run",runId:e.runId,workflowId:e.workflowId,nodeId:e.nodeId,phase:e.phase,status:e.status,note:e.note,homeNode:e.homeNode})}catch{}}async commit(e,t){let r=(this.commitChains.get(e)??Promise.resolve()).then(()=>t(),()=>t());return this.commitChains.set(e,r.then(()=>{},()=>{})),r}emitSignal(e){let t={name:e.name,scope:e.scope??"global",workflowId:e.workflowId??"",payload:e.payload??{},emittedAt:new Date().toISOString()};if(this.signals.emit(t),this.events)try{this.events.publish({kind:"signal",name:t.name,scope:t.scope,workflowId:t.workflowId||void 0,payload:t.payload})}catch{}return t}async resumeFromSignal(e){let t=this.runs.list({limit:500});for(let n of t){if(n.status!=="paused"||!n.pausedAt||n.pausedAt.kind!=="signalWait")continue;let r={name:n.pausedAt.signalName,scope:n.pausedAt.scope,workflowId:n.workflowId,match:n.pausedAt.match??{}};if(!K(r,e))continue;let o=this.store.list().find(i=>i.id===n.workflowId);o&&(await this.commit(n.id,()=>{let i=this.runs.get(n.id);if(!i||i.status!=="paused"||!i.pausedAt||i.pausedAt.kind!=="signalWait"||!K({name:i.pausedAt.signalName,scope:i.pausedAt.scope,workflowId:i.workflowId,match:i.pausedAt.match??{}},e))return;let a=T(o,i.pausedAt.nodeId),d=a?o.edges.filter(g=>g.from===a.id).map(g=>g.to):[],l={receivedAt:new Date().toISOString(),name:e.name,payload:e.payload};this.runs.recordExecution({runId:i.id,entry:{at:l.receivedAt,nodeId:i.pausedAt.nodeId,inputKeys:[],status:"resumed",output:l,idempotencyKey:A(i.id,i.pausedAt.nodeId,`signal:${e.name}:${e.emittedAt}`)},nextPending:d,status:"running",pausedAt:null,context:{...i.context,[i.pausedAt.nodeId]:l}}),this.log(`[workflow:${o.id}] run ${i.id} resumed from signal "${e.name}"`),this.emitRunEvent({runId:i.id,workflowId:o.id,nodeId:i.pausedAt.nodeId,phase:"resumed",status:"running",note:`signal:${e.name}`})}),this.walk(o,n.id,`signal:${e.name}`).catch(i=>this.log(`[workflow:${o.id}] walk-after-signal failed: ${i.message}`)))}}async resumeFromTimer(e){let t=this.store.list().find(n=>n.id===(this.runs.get(e.runId)?.workflowId??""));t&&(await this.commit(e.runId,()=>{let n=this.runs.get(e.runId);if(!n||n.status!=="paused"||!n.pausedAt||n.pausedAt.kind!=="timerWait"||n.pausedAt.nodeId!==e.nodeId)return;let r=T(t,e.nodeId),o=r?t.edges.filter(d=>d.from===r.id).map(d=>d.to):[],i=new Date().toISOString(),a={firedAt:i,scheduledFor:e.fireAt};this.runs.recordExecution({runId:n.id,entry:{at:i,nodeId:e.nodeId,inputKeys:[],status:"resumed",output:a,idempotencyKey:A(n.id,e.nodeId,`timer:${e.id}`)},nextPending:o,status:"running",pausedAt:null,context:{...n.context,[e.nodeId]:a}}),this.log(`[workflow:${t.id}] run ${n.id} resumed from timer "${e.nodeId}" (fired ${i})`),this.emitRunEvent({runId:n.id,workflowId:t.id,nodeId:e.nodeId,phase:"resumed",status:"running",note:`timer:${e.id}`})}),this.walk(t,e.runId,`timer:${e.id}`).catch(n=>this.log(`[workflow:${t.id}] walk-after-timer failed: ${n.message}`)))}async dispatchWorkflow(e){let t=this.store.list().find(i=>i.id===e.workflowId);if(!t)return this.log(`[workflows] dispatchWorkflow: workflow "${e.workflowId}" not found`),{claimed:!1,run:null};let r=t.nodes.find(i=>i.type.startsWith("trigger."))?.config??{},o={source:e.trigger?.source??r.source??"hook",project:e.trigger?.project,repo:e.trigger?.repo,chat:e.trigger?.chat,labels:e.trigger?.labels};return this.dispatchOne(t,e.entityRef,e.event,o)}startChannelAck(e,t){let n=String(t.channel??""),r=String(t.chatId??"");if(!n||!r)return;let o=this.channels[n];if(!o)return;let i=typeof t.accountId=="string"?t.accountId:void 0,a=t.event,d=typeof a?.id=="string"?a.id:a?.id!=null?String(a.id):void 0;if(d&&o.react)try{Promise.resolve(o.react(r,d,"\u{1F440}",i)).catch(()=>{})}catch{}if(this.ackTypingTimers.has(e)||!o.sendTyping)return;let l=()=>{try{Promise.resolve(o.sendTyping(r,i)).catch(()=>{})}catch{}};l();let g=setInterval(l,on);this.ackTypingTimers.set(e,g)}stopChannelAck(e){let t=this.ackTypingTimers.get(e);t&&(clearInterval(t),this.ackTypingTimers.delete(e))}async dispatch(e){let t=this.matchByTrigger(e.trigger,e.fromRemote),r=t.some(a=>a.fanOut)?t:t.slice(0,1),o=[],i=[];for(let a of r){let d=await this.dispatchOne(a,e.entityRef,e.event,e.trigger);d.claimed&&o.push(a),d.run&&i.push(d.run)}return!e.fromRemote&&this.forwarder?.broadcastTrigger&&Promise.resolve(this.forwarder.broadcastTrigger({trigger:e.trigger,entityRef:e.entityRef,event:e.event})).catch(a=>this.log(`[mesh-broadcast] ${a?.message??a}`)),{claimed:o,runs:i}}matchByTrigger(e,t){let n=this.store.list(),r=[];for(let o of n){if(o.state&&o.state!=="active")continue;if(t){if(!o.mesh?.allowRemote)continue;let l=o.mesh.peers;if(l&&l.length>0&&!l.includes(t.peer))continue}let i=o.nodes.find(l=>l.type.startsWith("trigger."));if(!i)continue;let a=i.config;if(a.source!==e.source)continue;let d=a.filter;if(d){if(d.project&&d.project!=="*"&&d.project!==e.project||d.repo&&d.repo!=="*"&&d.repo!==e.repo||d.chat&&d.chat!=="*"&&q(e.source,d.chat)!==q(e.source,e.chat))continue;if(d.labels?.length){let l=new Set(e.labels??[]);if(!d.labels.some(c=>l.has(c)))continue}}r.push(o)}return r.sort((o,i)=>i.priority-o.priority||o.id.localeCompare(i.id))}async dispatchOne(e,t,n,r){let o=await this.dispatchOneLegacy(e,t,n,r);if(ve("workflow")!=="off")try{Ge(Ie(),{workflowId:e.id,eventId:n.id,triggerSource:r.source,project:r.project??null,entityRef:t},JSON.stringify({event:n,trigger:r,entityRef:t}),{claimed:o.claimed,runId:o.run?.id??null})}catch(i){this.log(`[ledger] workflow ${e.id} run ${o.run?.id??"?"} record failed: ${i?.message??i}`)}return o}async dispatchOneLegacy(e,t,n,r){let o=this.runs.getActiveByEntity(t),i=o?this.runs.getHomeNodeByEntity(t):null;if(o&&i&&i!==this.nodeId){if(!this.forwarder)return this.log(`[workflow:${e.id}] run ${o} home'd on "${i}" but no forwarder \u2014 dropping`),{claimed:!1,run:null};try{await this.forwarder.forwardTransition(i,{workflowId:e.id,event:n,entityRef:t})}catch(d){this.log(`[workflow:${e.id}] forward to "${i}" failed: ${d.message}`)}return{claimed:!0,run:null}}let a=o?this.runs.get(o):null;if(a)if(a.status==="paused"&&a.pausedAt){if(a.pausedAt.kind!=="checkpoint")return this.log(`[workflow:${e.id}] run ${a.id} paused on ${a.pausedAt.kind} \u2014 channel event bypasses workflow`),{claimed:!1,run:null};if(!ln(a.pausedAt.resumeMatch,r,n))return this.log(`[workflow:${e.id}] run ${a.id} paused but event doesn't match resumeMatch \u2014 dropping`),{claimed:!1,run:null};let d=T(e,a.pausedAt.nodeId),l=d?e.edges.filter(m=>m.from===d.id).map(m=>m.to):[],g={at:new Date().toISOString(),nodeId:a.pausedAt.nodeId,inputKeys:[],status:"resumed",output:{event:n.payload},idempotencyKey:A(a.id,a.pausedAt.nodeId,`resume:${n.id}`)},c={...a.context,[a.pausedAt.nodeId]:{event:n.payload}},p=a.pausedAt.checkpointName,f=this.runs.recordExecution({runId:a.id,entry:g,nextPending:l,status:"running",pausedAt:null,context:c});f&&(a=f),this.log(`[workflow:${e.id}] run ${a.id} resumed from checkpoint "${p}"`),r.source.endsWith("-message")&&this.startChannelAck(a.id,n.payload)}else return a.status==="running"?(this.log(`[workflow:${e.id}] run ${a.id} already running; dropping concurrent event ${n.id}`),{claimed:!0,run:null}):(this.log(`[workflow:${e.id}] run ${a.id} is ${a.status}; dropping event ${n.id}`),{claimed:!1,run:null});else{let d=H(e);if(!d)return this.log(`[workflow:${e.id}] no trigger node found`),{claimed:!1,run:null};a=this.runs.create({workflowId:e.id,initialPending:d.pending,entityRef:t,initialContext:{[d.triggerId]:n.payload}}),this.log(`[workflow:${e.id}] run ${a.id} created from trigger "${d.triggerId}" for ${t.id}`),this.emitRunEvent({runId:a.id,workflowId:e.id,phase:"created",status:a.status,homeNode:a.homeNode}),r.source.endsWith("-message")&&this.startChannelAck(a.id,n.payload)}return this.walk(e,a.id,n.id),{claimed:!0,run:a}}async walk(e,t,n){try{await this.walkInner(e,t,n)}finally{this.stopChannelAck(t)}}async walkInner(e,t,n){let r=this.runs.get(t);if(r)for(;r.status==="running"&&r.pending.length>0;){let o=r.pending.slice(0,an);await Promise.allSettled(o.map(a=>this.executeNodeAndCommit(e,t,a,n)));let i=this.runs.get(t);if(!i||(r=i,r.status!=="running"))return}}async executeNodeAndCommit(e,t,n,r){let o=A(t,n,r),i=await this.commit(t,()=>{let p=this.runs.get(t);if(!p)return{kind:"done"};if(p.status!=="running")return{kind:"done"};let f=T(e,n);if(!f)return this.log(`[workflow:${e.id}] missing node "${n}" \u2014 marking run failed`),this.runs.recordExecution({runId:t,entry:{at:new Date().toISOString(),nodeId:n,inputKeys:[],status:"failed",idempotencyKey:o,note:"node definition missing from workflow"},nextPending:p.pending.filter(w=>w!==n),status:"failed"}),{kind:"done"};let m=le(f.type);return m?p.history.some(w=>w.idempotencyKey===o)?(this.runs.recordExecution({runId:t,entry:{at:new Date().toISOString(),nodeId:n,inputKeys:[],status:"skipped",idempotencyKey:o+"_dedup",note:"duplicate execution dropped"},nextPending:p.pending.filter(w=>w!==n)}),{kind:"done"}):{kind:"go",run:p,node:f,handler:m}:(this.log(`[workflow:${e.id}] no handler for node type "${f.type}"`),this.runs.recordExecution({runId:t,entry:{at:new Date().toISOString(),nodeId:n,inputKeys:[],status:"failed",idempotencyKey:o,note:`no handler for node type "${f.type}"`},nextPending:p.pending.filter(w=>w!==n),status:"failed"}),{kind:"done"})});if(i.kind==="done")return;let{run:a,node:d,handler:l}=i,g=e.edges.filter(p=>p.to===n).map(p=>p.from),c;try{c=await l({workflow:e,run:a,node:d,channels:this.channels,agents:this.agents,actors:this.actors,tasks:this.tasks,forwardChannelSend:this.forwarder?.forwardChannelSend?.bind(this.forwarder),log:this.log})}catch(p){this.log(`[workflow:${e.id}] handler "${d.type}" threw: ${p.message}`),c={error:p.message}}await this.commit(t,async()=>{let p=this.runs.get(t);if(!p)return;let f=new Date().toISOString(),m=p.pending.filter(h=>h!==n);if(c.error){let h=p.status==="running"?"failed":void 0;this.runs.recordExecution({runId:t,entry:{at:f,nodeId:n,inputKeys:g,status:"failed",idempotencyKey:o,note:c.error.slice(0,200)},nextPending:m,status:h}),this.emitRunEvent({runId:t,workflowId:e.id,nodeId:n,phase:"failed",status:h??p.status,note:c.error.slice(0,200)});return}if(c.paused&&c.pausedAt){let h=c.pausedAt,P=null;if(c.spawnChild&&h.kind==="subProcess"){if(P=await this.spawnChild({parent:p,parentNodeId:n,childWorkflowId:c.spawnChild.workflowId,input:c.spawnChild.input}),!P){this.runs.recordExecution({runId:t,entry:{at:f,nodeId:n,inputKeys:g,status:"failed",idempotencyKey:o,note:`subProcess: child workflow "${c.spawnChild.workflowId}" not found`},nextPending:m,status:"failed"});return}h={...h,childRunId:P.id}}if(this.runs.recordExecution({runId:t,entry:{at:f,nodeId:n,inputKeys:g,status:"paused",idempotencyKey:o},nextPending:m,status:"paused",pausedAt:h}),this.emitRunEvent({runId:t,workflowId:e.id,nodeId:n,phase:"paused",status:"paused",note:h.kind}),P&&this.kickChildWalk(P),h.kind==="timerWait")try{this.timers.schedule({runId:t,workflowId:e.id,nodeId:h.nodeId,fireAt:h.fireAt,cancelKey:`${t}:${h.nodeId}`})}catch(S){this.log(`[workflow:${e.id}] timer schedule failed: ${S.message}`)}if(h.kind==="userTask"){let S=this.tasks.get(h.taskId);if(S&&this.events)try{this.events.publish({kind:"task",taskId:S.id,workflowId:e.id,runId:t,phase:"created",title:S.title,assignedTo:S.assignedTo})}catch{}if(S&&this.renderUserTask)try{await this.renderUserTask(S)}catch(O){this.log(`[workflow:${e.id}] userTask render failed: ${O.message}`)}}return}let w=c.output??{},v={...p.context,[n]:w},{nextPending:tt}=ie({workflow:e,fromNodeId:n,selectedPort:c.port}),G=[],F={...p.joinCounters??{}};for(let h of tt){let P=T(e,h);if(!(P?.type==="gateway.parallel"&&String(P.config?.mode??"fanOut")==="join")){G.push(h);continue}let O=F[h]??[];O.includes(n)||O.push(n),F[h]=O;let st=e.edges.filter(ot=>ot.to===h).length;O.length>=st&&(G.push(h),delete F[h])}let nt=[...m,...G],L=d.type==="end",rt=p.status==="running"?L?String(d.config.status??"completed"):"running":void 0,x=this.runs.recordExecution({runId:t,entry:{at:f,nodeId:n,inputKeys:g,status:"ok",output:w,idempotencyKey:o},nextPending:L?[]:nt,status:rt,context:v,joinCounters:F});this.emitRunEvent({runId:t,workflowId:e.id,nodeId:n,phase:L?"completed":"ok",status:x?.status??p.status}),c.emitSignal&&this.emitSignal({name:c.emitSignal.name,scope:c.emitSignal.scope,workflowId:e.id,payload:c.emitSignal.payload}),L&&x&&x.parentRunId&&x.parentNodeId&&this.resumeParent({parentRunId:x.parentRunId,parentNodeId:x.parentNodeId,childRun:x}).catch(h=>this.log(`[workflow:${e.id}] resumeParent failed: ${h.message}`))})}async spawnChild(e){let t=this.store.list().find(a=>a.id===e.childWorkflowId);if(!t)return null;let n=H(t);if(!n)return this.log(`[workflow:${t.id}] no trigger node \u2014 cannot spawn as child`),null;let r={...e.input};r[n.triggerId]={...r[n.triggerId]??{},parentRunId:e.parent.id,parentNodeId:e.parentNodeId};let o={backend:"agentx-internal",id:`subprocess:${e.parent.id}:${e.parentNodeId}`},i=this.runs.create({workflowId:t.id,initialPending:n.pending,entityRef:o,initialContext:r,parentRunId:e.parent.id,parentNodeId:e.parentNodeId,rootRunId:e.parent.rootRunId??e.parent.id,depth:(e.parent.depth??0)+1});return this.log(`[workflow:${t.id}] child run ${i.id} spawned from ${e.parent.id}/${e.parentNodeId} (depth ${i.depth})`),i}kickChildWalk(e){let t=this.store.list().find(n=>n.id===e.workflowId);t&&this.walk(t,e.id,`spawn:${e.parentRunId}:${e.parentNodeId}`).catch(n=>this.log(`[workflow:${t.id}] child walk failed: ${n.message}`))}async resumeParent(e){let t=this.runs.get(e.parentRunId);if(!t)return;let n=this.store.list().find(r=>r.id===t.workflowId);n&&(await this.commit(e.parentRunId,()=>{let r=this.runs.get(e.parentRunId);if(!r||r.status!=="paused"||!r.pausedAt||r.pausedAt.kind!=="subProcess"||r.pausedAt.nodeId!==e.parentNodeId||r.pausedAt.childRunId!==e.childRun.id)return;let o=T(n,e.parentNodeId),i=o?n.edges.filter(d=>d.from===o.id).map(d=>d.to):[],a={childRunId:e.childRun.id,status:e.childRun.status,output:dn(e.childRun)};this.runs.recordExecution({runId:r.id,entry:{at:new Date().toISOString(),nodeId:e.parentNodeId,inputKeys:[],status:"resumed",output:a,idempotencyKey:A(r.id,e.parentNodeId,`child:${e.childRun.id}`)},nextPending:i,status:"running",pausedAt:null,context:{...r.context,[e.parentNodeId]:a}}),this.log(`[workflow:${n.id}] parent run ${r.id} resumed from subProcess child ${e.childRun.id}`),this.emitRunEvent({runId:r.id,workflowId:n.id,nodeId:e.parentNodeId,phase:"resumed",status:"running",note:`child:${e.childRun.id}`})}),this.walk(n,e.parentRunId,`child:${e.childRun.id}`))}async submitTask(e,t,n){let r=this.tasks.get(e);if(!r)return{ok:!1,error:`task not found: ${e}`};if(r.status!=="open")return{ok:!1,error:`task is ${r.status}`};let o=Je(r.form,t);if(!o.ok)return{ok:!1,error:"form validation failed",fieldErrors:o.errors};let i=this.runs.get(r.runId);if(!i)return{ok:!1,error:`run ${r.runId} not found`};let a=this.store.list().find(l=>l.id===i.workflowId);if(!a)return{ok:!1,error:`workflow ${i.workflowId} not found`};let d=await this.commit(r.runId,()=>{let l=this.runs.get(r.runId);if(!l||l.status!=="paused")return{ok:!1,error:`run ${r.runId} is not paused`};if(!l.pausedAt||l.pausedAt.kind!=="userTask"||l.pausedAt.taskId!==e)return{ok:!1,error:`run ${r.runId} is not waiting on task ${e}`};let g=T(a,r.nodeId),c=g?a.edges.filter(f=>f.from===g.id).map(f=>f.to):[],p={submittedBy:n,submittedAt:new Date().toISOString(),values:o.values,action:t.action};if(this.runs.recordExecution({runId:l.id,entry:{at:new Date().toISOString(),nodeId:r.nodeId,inputKeys:[],status:"resumed",output:p,idempotencyKey:A(l.id,r.nodeId,`task:${e}:${t.action}`)},nextPending:c,status:"running",pausedAt:null,context:{...l.context,[r.nodeId]:p}}),this.tasks.save({...r,status:"completed",submittedBy:n,submittedAt:p.submittedAt,submittedValues:o.values,submittedAction:t.action}),this.log(`[workflow:${a.id}] run ${l.id} resumed from userTask ${e}`),this.emitRunEvent({runId:l.id,workflowId:a.id,nodeId:r.nodeId,phase:"resumed",status:"running",note:`task:${e}`}),this.events)try{this.events.publish({kind:"task",taskId:e,workflowId:a.id,runId:l.id,phase:"submitted",submittedBy:n,title:r.title,assignedTo:r.assignedTo})}catch{}return{ok:!0,runId:l.id}});return d.ok&&this.walk(a,r.runId,`task:${e}`),d}};function dn(s){for(let e=s.history.length-1;e>=0;e--){let t=s.history[e];if(t.status==="ok"&&t.output&&Object.keys(t.output).length>0)return t.output}return{}}function ln(s,e,t){let n=o=>{let i=s[o];if(i===void 0||i===""||i==="*")return!0;if(Array.isArray(i)){let a=new Set(e.labels??[]);return i.some(d=>a.has(String(d)))}return o==="chat"?q(e.source,String(i))===q(e.source,e.chat):e[o]===i};if(!n("source")||!n("project")||!n("repo")||!n("chat"))return!1;let r=s.eventIdLike;return!(typeof r=="string"&&r&&!t.id.includes(r))}function q(s,e){return e==null?"":s==="whatsapp-message"?e.replace(/@s\.whatsapp\.net$|@g\.us$/i,"").replace(/[\s+()]/g,""):e}function cn(s){return{"pre:channel-message":async e=>{let t=e.msg;if(!t)return{};let n=un(t.channel);if(!n)return{};let r=t.group?.id??t.sender.id,o={backend:t.channel,id:`${t.channel}:${r}`},{claimed:i}=await s.dispatch({trigger:{source:n,chat:r},entityRef:o,event:{id:`${t.channel}:${t.accountId}:${t.id}`,payload:pn(t)}});return i.length===0?{}:i.every(d=>d.nodes.find(g=>g.type.startsWith("trigger."))?.config?.passthrough===!0)?{}:{blocked:!0,message:`handled by workflow${i.length>1?"s":""}: ${i.map(d=>d.id).join(", ")}`}},"on:gitlab-issue":async e=>{let t=e.project,n=e.iid,r=e.issueEvent;if(!t||n===void 0)return{};let o=Array.isArray(r?.object_attributes?.labels)?r.object_attributes.labels.map(d=>typeof d=="string"?d:d?.title).filter(Boolean):r?.labels?.map(d=>d?.title)??[],i=r?.assignees??r?.object_attributes?.assignee_ids??[],a={backend:"gitlab",id:`${t}#${n}`};return await s.dispatch({trigger:{source:"gitlab-issue",project:t,labels:o},entityRef:a,event:{id:`gitlab-issue:${t}:${n}:${r?.object_attributes?.updated_at||r?.object_attributes?.action||"evt"}`,payload:{issue:{iid:n,title:r?.object_attributes?.title,description:r?.object_attributes?.description,url:r?.object_attributes?.url,action:r?.object_attributes?.action,labels:o,assignees:i},project:t,channel:"gitlab",chatId:`${t}:issue:${n}`}}}),{}},"on:gitlab-pipeline":async e=>{let t=e.project,n=e.pipelineId,r=e.status,o=e.ref;if(!t||!r)return{};let a=e.raw?.merge_request?.iid;if(!a)return{};let d={backend:"gitlab",id:`${t}!${a}`};return await s.dispatch({trigger:{source:"gitlab-pipeline",project:t},entityRef:d,event:{id:`gitlab-pipeline:${t}:${n}:${r}`,payload:{pipeline:{id:n,status:r,ref:o},project:t,channel:"gitlab",chatId:`${t}:merge_request:${a}`}}}),{}}}}function un(s){switch(s){case"telegram":return"telegram-message";case"whatsapp":return"whatsapp-message";case"discord":return"discord-message";case"slack":return"slack-message";default:return null}}function pn(s){let e=s.group?.id??s.sender.id;return{channel:s.channel,chatId:e,accountId:s.accountId,text:s.text,fromJid:s.sender.id,sender:{id:s.sender.id,name:s.sender.name,username:s.sender.username},contact:s.channelMeta?.facts?{facts:s.channelMeta.facts}:void 0,group:s.group?{id:s.group.id,name:s.group.name}:void 0,channelMeta:s.channelMeta,replyTo:s.replyTo,replyToText:s.replyToText,media:s.media,event:{id:s.id,timestamp:s.timestamp?.toISOString?.()??new Date().toISOString()}}}function gn(s){let e=s.store.list(),t=0,n=0;for(let r of e){if(r.state&&r.state!=="active"){s.log(`[workflows] ${r.id} state=${r.state} \u2014 skipping trigger registration`);continue}let o=r.nodes.find(i=>i.type.startsWith("trigger."));if(o){if(o.type==="trigger.cron"){let i=o.config;if(!i.spec){s.log(`[workflows] ${r.id} trigger.cron missing config.spec \u2014 skipping`);continue}mn({workflowId:r.id,triggerNodeId:o.id,spec:i.spec,timezone:i.timezone??"UTC"},s.dispatcher,s.log),t++}else if(o.type==="trigger.hook"){let i=o.config;if(!i.event||!i.event.startsWith("on:")){s.log(`[workflows] ${r.id} trigger.hook config.event must start with "on:" \u2014 skipping`);continue}s.hooks.registerHandler(i.event,`workflows:${r.id}`,async a=>{try{let d=fn(r.id,i.event,a);await s.dispatcher.dispatchWorkflow({workflowId:r.id,entityRef:{backend:"hook",id:d},event:{id:`hook:${i.event}:${Date.now().toString(36)}`,payload:{hookEvent:i.event,...a}}})}catch(d){s.log(`[workflows] ${r.id} hook dispatch failed: ${d.message}`)}return{}},60),n++}}}return{cronTimers:t,hookSubscribers:n}}function fn(s,e,t){let n=typeof t.project=="string"?t.project:"",r=t.iid!=null?String(t.iid):"";if(e==="on:gitlab-issue"&&n&&r)return`${s}:${e}:${n}#${r}`;if(e==="on:gitlab-mr"&&n&&r)return`${s}:${e}:${n}!${r}`;if(e==="on:gitlab-pipeline"&&n){let o=t.pipelineId!=null?String(t.pipelineId):"";if(o)return`${s}:${e}:${n}@pipeline:${o}`}return`${s}:${e}:${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function mn(s,e,t){let n=()=>{let r;try{r=Re(s.spec,new Date,s.timezone)}catch(i){t(`[workflows] ${s.workflowId} cron spec invalid: ${i.message}`);return}let o=Math.max(1e3,r.getTime()-Date.now());setTimeout(()=>{(async()=>{let i=`cron:${s.workflowId}:${r.toISOString()}`;try{await e.dispatchWorkflow({workflowId:s.workflowId,trigger:{source:"cron"},entityRef:{backend:"cron",id:`${s.workflowId}@${r.toISOString()}`},event:{id:i,payload:{now:r.toISOString(),spec:s.spec,workflowId:s.workflowId}}})}catch(a){t(`[workflows] ${s.workflowId} cron dispatch failed: ${a.message}`)}finally{n()}})()},o)};n()}import{readFileSync as fe,writeFileSync as et,existsSync as me,readdirSync as Rn,statSync as An}from"fs";import{resolve as he,join as Tn}from"path";import{existsSync as Ve,mkdirSync as yn,readFileSync as wn,writeFileSync as Ye}from"fs";import{dirname as kn,resolve as Ze}from"path";import{z as y}from"zod";var bn=y.object({type:y.enum(["gitlab","github"]),host:y.string().optional(),project:y.string(),iid:y.number().int().positive(),url:y.string()}),In=y.object({id:y.string(),title:y.string(),description:y.string().optional(),assignee:y.string().optional(),labels:y.array(y.string()).default([]),milestone:y.string().optional(),status:y.enum(["todo","doing","blocked","done"]).default("todo"),priority:y.number().int().optional(),estimatedSeconds:y.number().int().optional(),source:bn.optional(),importedAt:y.string().optional(),createdAt:y.string(),updatedAt:y.string(),blocker:y.string().optional(),doneNote:y.string().optional()}),vn=y.object({version:y.literal(1),items:y.array(In).default([])}),z=class{constructor(e){this.path=e}jsonPath(){return Ze(process.cwd(),this.path).replace(/\.md$/i,".json")}mdPath(){return Ze(process.cwd(),this.path).replace(/\.json$/i,".md")}exists(){return Ve(this.jsonPath())}load(){let e=this.jsonPath();if(!Ve(e))return{version:1,items:[]};let t=wn(e,"utf-8");try{return vn.parse(JSON.parse(t))}catch(n){throw new Error(`Backlog file invalid (${e}): ${n.message}`)}}save(e){let t=this.jsonPath();yn(kn(t),{recursive:!0}),Ye(t,JSON.stringify(e,null,2)+`
8
+ `),Ye(this.mdPath(),this.toMarkdown(e))}list(){return this.load().items}findById(e){return this.list().find(t=>t.id===e)}add(e){let t=this.load();if(t.items.some(o=>o.id===e.id))throw new Error(`backlog item ${e.id} already exists`);let n=new Date().toISOString(),r={...e,labels:e.labels??[],status:e.status??"todo",createdAt:e.createdAt??n,updatedAt:n};return t.items.push(r),this.save(t),r}addMany(e){let t=this.load(),n=new Set(t.items.map(i=>i.id)),r=new Date().toISOString(),o=[];for(let i of e){if(n.has(i.id))continue;let a={...i,labels:i.labels??[],status:i.status??"todo",createdAt:i.createdAt??r,updatedAt:r};t.items.push(a),o.push(a),n.add(a.id)}return o.length&&this.save(t),o}update(e,t){let n=this.load(),r=n.items.findIndex(i=>i.id===e);if(r<0)throw new Error(`backlog item ${e} not found`);let o={...n.items[r],...t,id:n.items[r].id,createdAt:n.items[r].createdAt,updatedAt:new Date().toISOString()};return n.items[r]=o,this.save(n),o}remove(e){let t=this.load(),n=t.items.length;return t.items=t.items.filter(r=>r.id!==e),t.items.length===n?!1:(this.save(t),!0)}toMarkdown(e){let t=["# Backlog","","_Generated from `backlog.json`. Do not edit by hand \u2014 use `agentx backlog` commands._",""],n={doing:[],blocked:[],todo:[],done:[]};for(let o of e.items)n[o.status].push(o);let r=[["doing","Doing"],["blocked","Blocked"],["todo","To Do"],["done","Done"]];for(let[o,i]of r)if(n[o].length){t.push(`## ${i}`,"");for(let a of n[o]){let d=o==="done"?"x":" ",l=a.assignee?`@${a.assignee} `:"",g=a.estimatedSeconds?` [time: ${Math.round(a.estimatedSeconds/60)}m]`:"",c=a.source?` (${a.source.type}: ${a.source.project}#${a.source.iid})`:"";t.push(`- [${d}] ${l}${a.title}${g}${c}`),a.source?.url&&t.push(` - <${a.source.url}>`),a.labels.length&&t.push(` - labels: ${a.labels.join(", ")}`),a.milestone&&t.push(` - milestone: ${a.milestone}`),a.blocker&&t.push(` - BLOCKED: ${a.blocker}`)}t.push("")}return t.join(`
9
+ `)}};function Yr(s){return`${s.type}:${s.project}:${s.iid}`}function Xe(s,e,t){let n=[];if(e.type==="gitlab"){let r=t.channels.gitlab?.agentMappings??[];for(let o of s){let i=r.find(a=>a.agentId===o);i?.gitlabUsernames?.length?n.push(i.gitlabUsernames[0]):n.push(o)}}else if(e.type==="github"){let r=t.channels.github?.agentMappings??[];for(let o of s){let i=r.find(a=>a.agentId===o);i?.githubUsernames?.length?n.push(i.githubUsernames[0]):n.push(o)}}return n}async function ge(s,e,t,n=()=>{}){return s.source?s.source.type==="gitlab"?Sn(s.source,e,t,n):s.source.type==="github"?$n(s.source,e,t,n):{ok:!1,error:`unknown source.type ${s.source.type}`,attempts:[]}:{ok:!0,attempts:[]}}async function Sn(s,e,t,n){let r=t.channels.gitlab,o=r?.token,i=r?.host||(s.host?`https://${s.host}`:void 0);if(!o||!i)return{ok:!1,error:"gitlab token/host not configured",attempts:[]};let a=[],d=async(f,m={})=>fetch(`${i}/api/v4${f}`,{...m,headers:{"PRIVATE-TOKEN":o,"Content-Type":"application/json",...m.headers||{}}}),l=encodeURIComponent(s.project),g;e.assigneeUsernames!==void 0&&(g=(await Promise.all(e.assigneeUsernames.map(async m=>{try{let w=await fetch(`${i}/api/v4/users?username=${encodeURIComponent(m)}`,{headers:{"PRIVATE-TOKEN":o}});if(!w.ok)return null;let v=await w.json();return Array.isArray(v)&&v[0]?.id?v[0].id:null}catch{return null}}))).filter(m=>typeof m=="number"));let c;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")c=0;else try{let f=await d(`/projects/${l}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);if(f.ok){let m=await f.json();Array.isArray(m)&&m[0]?.id&&(c=m[0].id)}}catch(f){n(`[backlog-sync] milestone lookup failed: ${f.message}`)}let p={};if(e.title!==void 0&&(p.title=e.title),e.description!==void 0&&(p.description=e.description),e.labels!==void 0&&(p.labels=e.labels.join(",")),e.addLabels?.length&&(p.add_labels=e.addLabels.join(",")),e.removeLabels?.length&&(p.remove_labels=e.removeLabels.join(",")),g!==void 0&&(p.assignee_ids=g),c!==void 0&&(p.milestone_id=c),e.state&&(p.state_event=e.state==="closed"?"close":"reopen"),Object.keys(p).length)try{let f=await d(`/projects/${l}/issues/${s.iid}`,{method:"PUT",body:JSON.stringify(p)});if(a.push({kind:"PUT issue",ok:f.ok,status:f.status}),!f.ok){let m=await f.text().catch(()=>"");return{ok:!1,attempts:a,error:`PUT issue ${f.status}: ${m.slice(0,200)}`,url:s.url}}}catch(f){return a.push({kind:"PUT issue",ok:!1,error:f.message}),{ok:!1,attempts:a,error:f.message,url:s.url}}if(e.note)try{let f=await d(`/projects/${l}/issues/${s.iid}/notes`,{method:"POST",body:JSON.stringify({body:e.note})});a.push({kind:"POST note",ok:f.ok,status:f.status})}catch(f){a.push({kind:"POST note",ok:!1,error:f.message})}return{ok:a.every(f=>f.ok),attempts:a,url:s.url}}async function $n(s,e,t,n){let o=t.channels.github?.token;if(!o)return{ok:!1,error:"github token not configured",attempts:[]};let i=[],a=async(p,f={})=>fetch(`https://api.github.com${p}`,{...f,headers:{Authorization:`Bearer ${o}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28",...f.headers||{}}}),d=s.project,l;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")l=null;else try{let p=await a(`/repos/${d}/milestones?state=all&per_page=100`);if(p.ok){let f=await p.json(),m=Array.isArray(f)?f.find(w=>w.title===e.milestoneTitle):null;m?.number&&(l=m.number)}}catch(p){n(`[backlog-sync] github milestone lookup failed: ${p.message}`)}let g;if(e.labels!==void 0)g=e.labels;else if(e.addLabels?.length||e.removeLabels?.length)try{let p=await a(`/repos/${d}/issues/${s.iid}`);if(p.ok){let f=await p.json(),m=Array.isArray(f.labels)?f.labels.map(v=>typeof v=="string"?v:v.name):[],w=new Set([...m,...e.addLabels??[]]);for(let v of e.removeLabels??[])w.delete(v);g=[...w]}}catch(p){n(`[backlog-sync] github label fetch failed: ${p.message}`)}let c={};if(e.title!==void 0&&(c.title=e.title),e.description!==void 0&&(c.body=e.description),g!==void 0&&(c.labels=g),e.assigneeUsernames!==void 0&&(c.assignees=e.assigneeUsernames),l!==void 0&&(c.milestone=l),e.state&&(c.state=e.state),Object.keys(c).length)try{let p=await a(`/repos/${d}/issues/${s.iid}`,{method:"PATCH",body:JSON.stringify(c)});if(i.push({kind:"PATCH issue",ok:p.ok,status:p.status}),!p.ok){let f=await p.text().catch(()=>"");return{ok:!1,attempts:i,error:`PATCH issue ${p.status}: ${f.slice(0,200)}`,url:s.url}}}catch(p){return i.push({kind:"PATCH issue",ok:!1,error:p.message}),{ok:!1,attempts:i,error:p.message,url:s.url}}if(e.note)try{let p=await a(`/repos/${d}/issues/${s.iid}/comments`,{method:"POST",body:JSON.stringify({body:e.note})});i.push({kind:"POST comment",ok:p.ok,status:p.status})}catch(p){i.push({kind:"POST comment",ok:!1,error:p.message})}return{ok:i.every(p=>p.ok),attempts:i,url:s.url}}var ye=/^(\s*)-\s*\[( |x|X)\]\s*(.*)$/,J=/@([a-z0-9_-]+)/i,Qe=/\[time:\s*([0-9hm\s]+)\]/i;function Pn(s){let e=s.match(/(\d+)\s*h/i),t=s.match(/(\d+)\s*m/i);return(e?parseInt(e[1],10)*3600:0)+(t?parseInt(t[1],10)*60:0)}var we=class{constructor(e,t,n=()=>{}){this.path=e;this.daemon=t;this.log=n;this.store=new z(this.path)}type="backlog";capabilities={listAll:!0,create:!1,transition:!1,labels:!0,search:!1};store;getStore(){return this.store}readMd(){let e=he(process.cwd(),this.path);return me(e)?fe(e,"utf-8").split(`
10
+ `):[]}writeMd(e){let t=he(process.cwd(),this.path);et(t,e.join(`
11
+ `))}async listOpen(e){if(this.store.exists())return this.store.list().filter(o=>o.status!=="done"&&(!o.assignee||o.assignee.toLowerCase()===e.toLowerCase())).map(o=>this.toWorkItem(o));let t=this.readMd(),n=[];for(let r=0;r<t.length;r++){let o=t[r].match(ye);if(!o||o[2].toLowerCase()==="x")continue;let a=o[3],d=a.match(J);if(d&&d[1].toLowerCase()!==e.toLowerCase())continue;let l=a.match(Qe),g=a.replace(J,"").replace(Qe,"").trim();n.push({id:`backlog:${r}`,title:g||`Task at line ${r+1}`,assignee:d?d[1]:void 0,estimatedSeconds:l?Pn(l[1]):void 0,priority:r})}return n}async listAll(e={}){return this.store.exists()?this.store.list().map(t=>this.toWorkItem(t)):[]}async claim(e,t){if(!this.store.exists())return;let n=this.store.findById(t);if(!n)return;let r=this.store.update(t,{assignee:n.assignee||e,status:"doing"});if(r.source&&this.daemon){let o=Xe([r.assignee||e],r.source,this.daemon);ge(r,{assigneeUsernames:o,addLabels:["Doing"],removeLabels:["To Do"]},this.daemon,this.log).catch(i=>this.log(`[backlog-sync] claim failed for ${t}: ${i?.message??i}`))}}async report(e,t){if(this.store.exists()&&this.store.findById(e)){let a={};t.status==="done"?a.status="done":t.status==="blocked"?(a.status="blocked",a.blocker=t.blocker||t.note||void 0):t.status==="in-progress"&&(a.status="doing"),t.timeSeconds&&(a.estimatedSeconds=t.timeSeconds);let d=this.store.update(e,a);if(d.source&&this.daemon){let l={};t.status==="done"?(l.addLabels=["Done"],l.removeLabels=["Doing"]):t.status==="blocked"&&(l.addLabels=["Blocked"]),t.note&&(l.note=t.note),Object.keys(l).length&&ge(d,l,this.daemon,this.log).catch(g=>this.log(`[backlog-sync] report failed for ${e}: ${g?.message??g}`))}return}if(!e.startsWith("backlog:"))throw new Error(`not a backlog id: ${e}`);let n=parseInt(e.slice(8),10),r=this.readMd(),o=r[n];if(!o)throw new Error(`backlog line ${n} missing`);if(!o.match(ye))throw new Error(`backlog line ${n} not a checkbox`);if(t.status==="done"){r[n]=o.replace(/- \[ \]/,"- [x]");let a=t.timeSeconds?` <!-- done by agent, ${Math.round(t.timeSeconds/60)}m -->`:" <!-- done by agent -->";r.splice(n+1,0,a)}else t.status==="blocked"?r.splice(n+1,0,` <!-- BLOCKED: ${t.blocker||t.note||"?"} -->`):t.note&&r.splice(n+1,0,` <!-- ${t.note.replace(/-->/g,"\u2014 >")} -->`);this.writeMd(r)}toWorkItem(e){let t={todo:"todo",doing:"doing",blocked:"onhold",done:"done"}[e.status];return{id:e.id,title:e.title,description:e.description,assignee:e.assignee,estimatedSeconds:e.estimatedSeconds,priority:e.priority,labels:e.labels,stage:t,milestone:e.milestone,url:e.source?.url,updatedAt:e.updatedAt,state:e.status==="done"?"closed":"opened"}}},ke=class{constructor(e,t){this.root=e;this.glob=t}type="wiki";capabilities={listAll:!1,create:!1,transition:!1,labels:!1,search:!1};walk(e,t){if(me(e))for(let n of Rn(e)){let r=Tn(e,n);An(r).isDirectory()?this.walk(r,t):n.endsWith(".md")&&t.push(r)}}async listOpen(e){let t=[];this.walk(he(process.cwd(),this.root),t);let n=[];for(let r of t){let o=fe(r,"utf-8").split(`
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
+ `);t.status==="done"&&i[r]&&(i[r]=i[r].replace(/- \[ \]/,"- [x]"),et(o,i.join(`
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 rs(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,cn as j,gn as k,z as l,Yr as m,Xe as n,ge as o,be as p,rs as q};
15
+ //# sourceMappingURL=chunk-E4ZZILAK.js.map