agentix-cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-RDVGL2TW.js +2 -0
- package/dist/audit-Z47AQFFD.js +3 -0
- package/dist/audit-Z47AQFFD.js.map +1 -0
- package/dist/{board-dashboard-CXIVJKDP.js → board-dashboard-KX2CNOSY.js} +44 -44
- package/dist/board-dashboard-KX2CNOSY.js.map +1 -0
- package/dist/{chunk-EKTPCSN4.js → chunk-4ITQP3XL.js} +2 -2
- package/dist/chunk-53NRX2NA.js +2 -0
- package/dist/chunk-53NRX2NA.js.map +1 -0
- package/dist/{chunk-5WNGHDFC.js → chunk-ASSJ4Z6Z.js} +11 -11
- package/dist/{chunk-5WNGHDFC.js.map → chunk-ASSJ4Z6Z.js.map} +1 -1
- package/dist/chunk-BLUXL6HR.js +854 -0
- package/dist/chunk-BLUXL6HR.js.map +1 -0
- package/dist/chunk-BTAEYL3P.js +72 -0
- package/dist/chunk-BTAEYL3P.js.map +1 -0
- package/dist/chunk-DJEZ2HVU.js +5 -0
- package/dist/chunk-DJEZ2HVU.js.map +1 -0
- package/dist/{chunk-SRHLXZRF.js → chunk-DSCMCVTV.js} +3 -3
- package/dist/chunk-DSCMCVTV.js.map +1 -0
- package/dist/chunk-HPDHNIA3.js +2 -0
- package/dist/chunk-IM376SD6.js +13 -0
- package/dist/chunk-IM376SD6.js.map +1 -0
- package/dist/chunk-J4WKMKTP.js +5 -0
- package/dist/{chunk-MBEQASP3.js.map → chunk-J4WKMKTP.js.map} +1 -1
- package/dist/chunk-JGXE2YNV.js +46 -0
- package/dist/chunk-JGXE2YNV.js.map +1 -0
- package/dist/{chunk-TT2Q7YMZ.js → chunk-JXEPJ3YD.js} +6 -6
- package/dist/{chunk-TT2Q7YMZ.js.map → chunk-JXEPJ3YD.js.map} +1 -1
- package/dist/chunk-LY7JGDV7.js +6 -0
- package/dist/chunk-LY7JGDV7.js.map +1 -0
- package/dist/chunk-SR3X25TN.js +3 -0
- package/dist/chunk-SR3X25TN.js.map +1 -0
- package/dist/{chunk-63UYRJIC.js → chunk-TRQSP67X.js} +2 -2
- package/dist/chunk-U364GNQX.js +719 -0
- package/dist/chunk-U364GNQX.js.map +1 -0
- package/dist/chunk-VJUTQAPJ.js +2 -0
- package/dist/chunk-VJUTQAPJ.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{compaction-X46EQEPS.js → compaction-S5H6DTOR.js} +4 -4
- package/dist/config-UOHEG4BW.js +2 -0
- package/dist/config-mutator-KSEBWKJH.js +2 -0
- package/dist/{context-planner-G2J7FNNU.js → context-planner-2RGHJHSO.js} +3 -3
- package/dist/debug-TGAP7E7W.js +2 -0
- package/dist/discover-OATU7SHI.js +4 -0
- package/dist/discover-OATU7SHI.js.map +1 -0
- package/dist/{editor-chat-R54E65W5.js → editor-chat-FUBQLMAQ.js} +2 -2
- package/dist/heal-YP7QI7D3.js +2 -0
- package/dist/{inbox-L5ZZ623Y.js → inbox-O5UB3YQN.js} +2 -2
- package/dist/index.d.ts +462 -22
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/{ingest-whatsapp-NS4OWDOU.js → ingest-whatsapp-C3O5UPBX.js} +2 -2
- package/dist/loader-BGWA7IRY.js +2 -0
- package/dist/loader-LBHKSXBK.js +2 -0
- package/dist/memory-extract-KKPKAOPH.js +2 -0
- package/dist/{processes-XF5CV4LK.js → processes-7W27G3J3.js} +2 -2
- package/dist/program-2MDELQLX.js +2 -0
- package/dist/providers-WCQSKTNP.js +2 -0
- package/dist/query-FZAL7AQD.js +2 -0
- package/dist/recipes-LZ56TA3X.js +2 -0
- package/dist/registry-ONJSILH4.js +2 -0
- package/dist/scheduler-XRM2RJIV.js +2 -0
- package/dist/{slack-PSQLVTGB.js → slack-D27BE37Q.js} +2 -2
- package/dist/store-4UCO56K2.js +2 -0
- package/dist/{subagent-2SJHSSJS.js → subagent-EPOT3QDM.js} +2 -2
- package/dist/{task-store-NM7VKNLE.js → task-store-3NUWLYRY.js} +2 -2
- package/dist/{telegram-W4SLFMNY.js → telegram-UWV67KWG.js} +2 -2
- package/dist/timers-QB4KYNAE.js +2 -0
- package/dist/types-ECMEC5BZ.js +2 -0
- package/dist/types-TTB6DJUE.js +2 -0
- package/dist/{usage-dashboard-AXPXB2KP.js → usage-dashboard-FQGPPABD.js} +2 -2
- package/dist/web/workflow-editor.global.js +35 -12
- package/dist/web/workflow-editor.global.js.map +1 -1
- package/dist/{whatsapp-DCHRBRVV.js → whatsapp-KJ2NRKKQ.js} +2 -2
- package/dist/{whatsapp-state-6D6FHHD2.js → whatsapp-state-3ZVQ6MQD.js} +2 -2
- package/dist/{wiki-UDPYFJBL.js → wiki-OUYKM7MB.js} +2 -2
- package/dist/wiki-OUYKM7MB.js.map +1 -0
- package/dist/workspace-setup-6GDBEORT.js +2 -0
- package/dist/workspace-setup-6GDBEORT.js.map +1 -0
- package/package.json +11 -1
- package/dist/agent-4AOMVXRJ.js +0 -2
- package/dist/board-dashboard-CXIVJKDP.js.map +0 -1
- package/dist/chunk-4HP6UC2X.js +0 -13
- package/dist/chunk-4HP6UC2X.js.map +0 -1
- package/dist/chunk-ABCHHNG6.js +0 -625
- package/dist/chunk-ABCHHNG6.js.map +0 -1
- package/dist/chunk-FIOB3MEX.js +0 -2
- package/dist/chunk-HCFSHGK4.js +0 -46
- package/dist/chunk-HCFSHGK4.js.map +0 -1
- package/dist/chunk-HHJGKD5B.js +0 -71
- package/dist/chunk-HHJGKD5B.js.map +0 -1
- package/dist/chunk-MBEQASP3.js +0 -5
- package/dist/chunk-MCJUAE6V.js +0 -6
- package/dist/chunk-MCJUAE6V.js.map +0 -1
- package/dist/chunk-SRHLXZRF.js.map +0 -1
- package/dist/chunk-XDJSYQST.js +0 -6
- package/dist/chunk-XDJSYQST.js.map +0 -1
- package/dist/chunk-YPOELN6Z.js +0 -798
- package/dist/chunk-YPOELN6Z.js.map +0 -1
- package/dist/config-KCYHMKCT.js +0 -2
- package/dist/config-mutator-QP4GLBOE.js +0 -2
- package/dist/debug-3MEUO2P2.js +0 -2
- package/dist/heal-JDXUPRET.js +0 -2
- package/dist/loader-PTCXLJEX.js +0 -2
- package/dist/memory-extract-WH4FZ456.js +0 -2
- package/dist/program-FFWEILAS.js +0 -2
- package/dist/providers-AKQ4HTB4.js +0 -2
- package/dist/query-PKGYE5HR.js +0 -2
- package/dist/registry-IFMDJWQ7.js +0 -2
- package/dist/scheduler-63D5KFO7.js +0 -2
- package/dist/store-5MJOO74U.js +0 -2
- package/dist/timers-PCB4ZIBD.js +0 -2
- package/dist/types-C7IFH42Z.js +0 -2
- package/dist/types-OIFU3KSQ.js +0 -2
- package/dist/workspace-setup-C4VB3QZV.js +0 -2
- /package/dist/{agent-4AOMVXRJ.js.map → agent-RDVGL2TW.js.map} +0 -0
- /package/dist/{chunk-EKTPCSN4.js.map → chunk-4ITQP3XL.js.map} +0 -0
- /package/dist/{chunk-FIOB3MEX.js.map → chunk-HPDHNIA3.js.map} +0 -0
- /package/dist/{chunk-63UYRJIC.js.map → chunk-TRQSP67X.js.map} +0 -0
- /package/dist/{compaction-X46EQEPS.js.map → compaction-S5H6DTOR.js.map} +0 -0
- /package/dist/{config-KCYHMKCT.js.map → config-UOHEG4BW.js.map} +0 -0
- /package/dist/{config-mutator-QP4GLBOE.js.map → config-mutator-KSEBWKJH.js.map} +0 -0
- /package/dist/{context-planner-G2J7FNNU.js.map → context-planner-2RGHJHSO.js.map} +0 -0
- /package/dist/{debug-3MEUO2P2.js.map → debug-TGAP7E7W.js.map} +0 -0
- /package/dist/{editor-chat-R54E65W5.js.map → editor-chat-FUBQLMAQ.js.map} +0 -0
- /package/dist/{heal-JDXUPRET.js.map → heal-YP7QI7D3.js.map} +0 -0
- /package/dist/{inbox-L5ZZ623Y.js.map → inbox-O5UB3YQN.js.map} +0 -0
- /package/dist/{ingest-whatsapp-NS4OWDOU.js.map → ingest-whatsapp-C3O5UPBX.js.map} +0 -0
- /package/dist/{loader-PTCXLJEX.js.map → loader-BGWA7IRY.js.map} +0 -0
- /package/dist/{memory-extract-WH4FZ456.js.map → loader-LBHKSXBK.js.map} +0 -0
- /package/dist/{program-FFWEILAS.js.map → memory-extract-KKPKAOPH.js.map} +0 -0
- /package/dist/{processes-XF5CV4LK.js.map → processes-7W27G3J3.js.map} +0 -0
- /package/dist/{providers-AKQ4HTB4.js.map → program-2MDELQLX.js.map} +0 -0
- /package/dist/{query-PKGYE5HR.js.map → providers-WCQSKTNP.js.map} +0 -0
- /package/dist/{registry-IFMDJWQ7.js.map → query-FZAL7AQD.js.map} +0 -0
- /package/dist/{scheduler-63D5KFO7.js.map → recipes-LZ56TA3X.js.map} +0 -0
- /package/dist/{store-5MJOO74U.js.map → registry-ONJSILH4.js.map} +0 -0
- /package/dist/{task-store-NM7VKNLE.js.map → scheduler-XRM2RJIV.js.map} +0 -0
- /package/dist/{slack-PSQLVTGB.js.map → slack-D27BE37Q.js.map} +0 -0
- /package/dist/{timers-PCB4ZIBD.js.map → store-4UCO56K2.js.map} +0 -0
- /package/dist/{subagent-2SJHSSJS.js.map → subagent-EPOT3QDM.js.map} +0 -0
- /package/dist/{types-C7IFH42Z.js.map → task-store-3NUWLYRY.js.map} +0 -0
- /package/dist/{telegram-W4SLFMNY.js.map → telegram-UWV67KWG.js.map} +0 -0
- /package/dist/{types-OIFU3KSQ.js.map → timers-QB4KYNAE.js.map} +0 -0
- /package/dist/{wiki-UDPYFJBL.js.map → types-ECMEC5BZ.js.map} +0 -0
- /package/dist/{workspace-setup-C4VB3QZV.js.map → types-TTB6DJUE.js.map} +0 -0
- /package/dist/{usage-dashboard-AXPXB2KP.js.map → usage-dashboard-FQGPPABD.js.map} +0 -0
- /package/dist/{whatsapp-DCHRBRVV.js.map → whatsapp-KJ2NRKKQ.js.map} +0 -0
- /package/dist/{whatsapp-state-6D6FHHD2.js.map → whatsapp-state-3ZVQ6MQD.js.map} +0 -0
package/dist/chunk-4HP6UC2X.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import{a as le}from"./chunk-SRHLXZRF.js";import{c as U}from"./chunk-N67JZAXU.js";import{e as ce}from"./chunk-CDNWCYF7.js";import{b as L}from"./chunk-AFRHKA7B.js";import{a as ue,b as pe}from"./chunk-EW27SCCC.js";import{existsSync as N,mkdirSync as ze,readdirSync as he,readFileSync as H,unlinkSync as Be,writeFileSync as Je}from"fs";import{resolve as j,relative as Ge}from"path";import{z as c}from"zod";var Oe=c.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"]),_e=c.enum(["equals","contains","matches","exists"]),Ce=c.object({kind:_e,params:c.record(c.unknown()).default({})}),ge=c.object({id:c.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_-]*$/,"node id must be identifier-safe"),type:Oe,config:c.record(c.unknown()).default({}),position:c.object({x:c.number(),y:c.number()}).optional()}),fe=c.object({from:c.string(),fromPort:c.string().optional(),to:c.string(),toPort:c.string().optional(),label:c.string().optional()}),v=c.object({id:c.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"workflow id must be lower-kebab"),version:c.literal(2).default(2),title:c.string().min(1),description:c.string().optional(),priority:c.number().int().default(0),fanOut:c.boolean().default(!1),nodes:c.array(ge).refine(s=>s.length>0,{message:"workflow must have at least one node"}),edges:c.array(fe).default([]),envAllow:c.array(c.string()).default([]),retention:c.object({maxRuns:c.number().int().positive().default(500),maxDays:c.number().int().positive().default(90)}).default({maxRuns:500,maxDays:90}),maxChildDepth:c.number().int().positive().default(5),mesh:c.object({allowRemote:c.boolean().default(!1),peers:c.array(c.string()).optional()}).default({allowRemote:!1}),created:c.string().optional(),updated:c.string().optional()});function M(s){let e=[],t=new Map(s.nodes.map(o=>[o.id,o])),r=s.nodes.filter(o=>o.type.startsWith("trigger."));r.length===0&&e.push("workflow must have exactly one trigger.* node (found 0)"),r.length>1&&e.push(`workflow has ${r.length} trigger.* nodes; v1 supports exactly one`);for(let o of s.edges)t.has(o.from)||e.push(`edge references missing node: from="${o.from}"`),t.has(o.to)||e.push(`edge references missing node: to="${o.to}"`);let n=r[0];if(n){let o=new Map;for(let l of s.edges)o.has(l.from)||o.set(l.from,[]),o.get(l.from).push(l.to);let a=new Set,d=[n.id];for(;d.length;){let l=d.pop();if(!a.has(l)){a.add(l);for(let u of o.get(l)??[])d.push(u)}}for(let l of s.nodes)a.has(l.id)||e.push(`node "${l.id}" is unreachable from trigger "${n.id}"`);s.nodes.some(l=>a.has(l.id)&&De(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 o of s.nodes){if(o.type!=="branch"&&o.type!=="rule")continue;let a=o.type==="branch"?o.config.cases??[]:(o.config.rules??[]).filter(p=>typeof p.to=="string"),d=o.type==="branch"?o.config.default:o.config.default?.to,l=new Set(a.map(p=>p.to));d&&l.add(d);let u=s.edges.filter(p=>p.from===o.id);for(let p of u){let m=p.fromPort??"";l.has(m)||e.push(`${o.type} "${o.id}" has outgoing edge with port "${m}" not declared in cases or default`)}}let i=Ue(s);for(let o of i)e.push(`cycle without agent/checkpoint: ${o.join(" -> ")}`);return e}function De(s){return s==="end"||s==="checkpoint"||s==="userTask"||s==="subProcess"||s==="signal.wait"||s==="timer.boundary"}function Fe(s){return s==="agent"||s==="checkpoint"||s==="userTask"||s==="subProcess"||s==="signal.wait"||s==="timer.boundary"}function Ue(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])),r=[],n=new Map,i=[],o=a=>{if(n.get(a)===1){let d=i.indexOf(a);if(d>=0){let l=i.slice(d).concat(a);l.some(p=>{let m=t.get(p)?.type;return m?Fe(m):!1})||r.push(l)}return}if(n.get(a)!==2){n.set(a,1),i.push(a);for(let d of e.get(a)??[])o(d);i.pop(),n.set(a,2)}};for(let a of s.nodes)n.get(a.id)!==2&&o(a.id);return r}var me=c.enum(["running","paused","completed","failed","canceled"]),Le=c.enum(["ok","failed","timeout","skipped","paused","resumed"]),Me=c.object({at:c.string(),nodeId:c.string(),inputKeys:c.array(c.string()).default([]),status:Le,output:c.record(c.unknown()).optional(),idempotencyKey:c.string(),note:c.string().optional()}),He=c.object({backend:c.string(),id:c.string()}),Ke=c.discriminatedUnion("kind",[c.object({kind:c.literal("checkpoint"),nodeId:c.string(),checkpointName:c.string(),resumeMatch:c.record(c.unknown()).default({})}),c.object({kind:c.literal("userTask"),nodeId:c.string(),taskId:c.string(),assignee:c.string(),assignedTo:c.array(c.string()).default([])}),c.object({kind:c.literal("subProcess"),nodeId:c.string(),childRunId:c.string(),childWorkflowId:c.string()}),c.object({kind:c.literal("signalWait"),nodeId:c.string(),signalName:c.string(),match:c.record(c.unknown()).default({}),scope:c.enum(["workflow","global"]).default("workflow")}),c.object({kind:c.literal("timerWait"),nodeId:c.string(),fireAt:c.string()})]),qe=c.object({id:c.string(),workflowId:c.string(),workflowVersion:c.literal(2),homeNode:c.string(),status:me,pausedAt:Ke.optional(),context:c.record(c.record(c.unknown())).default({}),pending:c.array(c.string()).default([]),joinCounters:c.record(c.array(c.string())).default({}),entityRef:He,history:c.array(Me).default([]),parentRunId:c.string().nullable().default(null),parentNodeId:c.string().nullable().default(null),rootRunId:c.string().nullable().default(null),depth:c.number().int().min(0).default(0),createdAt:c.string(),updatedAt:c.string()});var K=class{baseDir;constructor(e={}){this.baseDir=e.baseDir??j(process.cwd(),".agentx/workflows"),ze(this.baseDir,{recursive:!0})}pathFor(e){return j(this.baseDir,`${e}.json`)}list(){if(!N(this.baseDir))return[];let e=[];for(let t of he(this.baseDir,{withFileTypes:!0})){if(!t.isFile()||!t.name.endsWith(".json")||t.name.startsWith("_"))continue;let r=j(this.baseDir,t.name);try{let n=JSON.parse(H(r,"utf-8")),i=v.safeParse(n);i.success&&e.push(i.data)}catch{}}return e.sort((t,r)=>t.id.localeCompare(r.id))}validateAll(){let e=[];if(!N(this.baseDir))return e;for(let t of he(this.baseDir,{withFileTypes:!0})){if(!t.isFile()||!t.name.endsWith(".json")||t.name.startsWith("_"))continue;let r=j(this.baseDir,t.name),n=Ge(this.baseDir,r),i;try{i=JSON.parse(H(r,"utf-8"))}catch(d){e.push({id:t.name.replace(/\.json$/,""),path:n,issues:[`parse error: ${d.message}`],isValid:!1});continue}let o=v.safeParse(i);if(!o.success){let d=o.error.issues.map(l=>`${l.path.join(".")||"<root>"}: ${l.message}`);e.push({id:String(i?.id??t.name.replace(/\.json$/,"")),path:n,issues:d,isValid:!1});continue}let a=M(o.data);e.push({workflow:o.data,issues:a,isValid:a.length===0})}return e}get(e){let t=this.pathFor(e);if(!N(t))return null;try{let r=JSON.parse(H(t,"utf-8")),n=v.safeParse(r);return n.success?n.data:null}catch{return null}}save(e){let t=new Date().toISOString().slice(0,10),r=v.parse({...e,created:e.created||t,updated:t});return Je(this.pathFor(r.id),JSON.stringify(r,null,2)+`
|
|
2
|
-
`),r}delete(e){let t=this.pathFor(e);return N(t)?(Be(t),!0):!1}};import{createHash as Ve,randomUUID as Ze}from"crypto";import{appendFileSync as ye,existsSync as R,mkdirSync as we,readdirSync as ke,readFileSync as q,statSync as be,unlinkSync as Ie,writeFileSync as Ye}from"fs";import{resolve as I}from"path";function Qe(s){return s.replace(/[^a-zA-Z0-9._:#@-]/g,"_").slice(0,200)}function w(s,e,t){return Ve("sha1").update(`${s}|${e}|${t}`).digest("hex").slice(0,16)}var z=class{baseDir;runsDir;indexDir;nodeId;constructor(e){this.baseDir=e.baseDir??I(process.cwd(),".agentx/workflows"),this.runsDir=I(this.baseDir,"_runs"),this.indexDir=I(this.baseDir,"_index"),this.nodeId=e.nodeId,we(this.runsDir,{recursive:!0}),we(this.indexDir,{recursive:!0})}runPath(e){return I(this.runsDir,`${e}.jsonl`)}indexPath(e){return I(this.indexDir,`${e.backend}__${Qe(e.id)}.json`)}create(e){let t=new Date().toISOString(),r=Ze(),n={id:r,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??r,depth:e.depth??0,joinCounters:{},createdAt:t,updatedAt:t};return this.appendSnapshot(n),this.writeIndex(e.entityRef,n.id),n}get(e){let t=this.runPath(e);if(!R(t))return null;let r=q(t,"utf-8").trim();if(!r)return null;let n=null;for(let i of r.split(`
|
|
3
|
-
`)){let o;try{o=JSON.parse(i)}catch{continue}if(o.v===2){if(o.kind==="snapshot")n=o.run;else if(o.kind==="exec"&&n&&n.id===o.runId){let a=n;n={...a,history:[...a.history,o.entry],pending:o.pending,status:o.status??a.status,pausedAt:o.pausedAt===null?void 0:o.pausedAt??a.pausedAt,context:o.context??a.context,joinCounters:o.joinCounters??a.joinCounters,updatedAt:o.entry.at}}}}return n}getActiveByEntity(e){let t=this.indexPath(e);if(!R(t))return null;try{return JSON.parse(q(t,"utf-8")).runId}catch{return null}}getHomeNodeByEntity(e){let t=this.indexPath(e);if(!R(t))return null;try{return JSON.parse(q(t,"utf-8")).homeNode}catch{return null}}recordExecution(e){let t=this.get(e.runId);if(!t)return null;if(t.history.some(i=>i.idempotencyKey===e.entry.idempotencyKey))return t;let r={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};ye(this.runPath(e.runId),JSON.stringify(r)+`
|
|
4
|
-
`);let n=e.status??t.status;return n==="completed"||n==="failed"||n==="canceled"?this.clearIndex(t.entityRef):this.writeIndex(t.entityRef,t.id),this.get(e.runId)}setStatus(e,t){let r=this.get(e);if(!r)return null;let n={...r,status:t,updatedAt:new Date().toISOString()};return this.appendSnapshot(n),t!=="running"&&t!=="paused"&&this.clearIndex(n.entityRef),n}list(e={}){if(!R(this.runsDir))return[];let t=ke(this.runsDir).filter(n=>n.endsWith(".jsonl")).map(n=>({name:n,mtime:be(I(this.runsDir,n)).mtimeMs})).sort((n,i)=>i.mtime-n.mtime),r=[];for(let n of t){let i=this.get(n.name.replace(/\.jsonl$/,""));if(i&&!(e.workflowId&&i.workflowId!==e.workflowId)&&(r.push(i),e.limit&&r.length>=e.limit))break}return r}prune(e){if(!R(this.runsDir))return 0;let t=Date.now()-e.maxDays*24*60*60*1e3,r=[];for(let i of ke(this.runsDir)){if(!i.endsWith(".jsonl"))continue;let o=I(this.runsDir,i),a=be(o).mtimeMs,d=this.get(i.replace(/\.jsonl$/,""));d&&(d.status==="running"||d.status==="paused"||r.push({file:o,run:d,mtime:a}))}r.sort((i,o)=>o.mtime-i.mtime);let n=0;for(let i=0;i<r.length;i++){let o=r[i],a=o.mtime<t,d=i>=e.maxRuns;if(a||d)try{Ie(o.file),n++}catch{}}return n}appendSnapshot(e){let t={v:2,kind:"snapshot",run:e};ye(this.runPath(e.id),JSON.stringify(t)+`
|
|
5
|
-
`)}writeIndex(e,t){Ye(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(R(t))try{Ie(t)}catch{}}};import{existsSync as Se,mkdirSync as Xe,readFileSync as et,unlinkSync as tt,writeFileSync as nt}from"fs";import{resolve as B}from"path";import{z as $}from"zod";var ve=$.object({version:$.literal(1),nodes:$.record($.object({x:$.number(),y:$.number()}))}),J=class{baseDir;layoutsDir;constructor(e={}){this.baseDir=e.baseDir??B(process.cwd(),".agentx/workflows"),this.layoutsDir=B(this.baseDir,"_layouts"),Xe(this.layoutsDir,{recursive:!0})}pathFor(e){let t=e.replace(/[^a-zA-Z0-9._-]/g,"_");return B(this.layoutsDir,`${t}.json`)}get(e){let t=this.pathFor(e);if(!Se(t))return null;try{let r=ve.safeParse(JSON.parse(et(t,"utf-8")));return r.success?r.data:null}catch{return null}}save(e,t){let r=ve.parse(t);return nt(this.pathFor(e),JSON.stringify(r,null,2)+`
|
|
7
|
-
`),r}sync(e,t){let r=this.get(e);if(!r)return null;let n={};for(let o of t)r.nodes[o]&&(n[o]=r.nodes[o]);let i={version:1,nodes:n};return this.save(e,i)}delete(e){let t=this.pathFor(e);return Se(t)?(tt(t),!0):!1}};function G(s){let{workflow:e,fromNodeId:t,selectedPort:r}=s,n=e.nodes.find(a=>a.id===t);if(!n)return{nextPending:[]};let i=e.edges.filter(a=>a.from===t);return{nextPending:(n.type==="branch"?i.filter(a=>(a.fromPort??"")===(r??"")):i).map(a=>a.to)}}function V(s,e){let t=s.config.cases??[],r=s.config.default??"";for(let n of t)if(rt(n.when,e))return n.to;return r}function rt(s,e){let t=s.params??{},r=String(t.path??""),n=W(e,r);switch(s.kind){case"equals":return n===t.value;case"contains":return typeof n=="string"?n.includes(String(t.value??"")):Array.isArray(n)?n.some(i=>i===t.value):!1;case"matches":{if(typeof n!="string")return!1;try{return new RegExp(String(t.regex??"")).test(n)}catch{return!1}}case"exists":return n!=null&&n!=="";default:return!1}}function W(s,e){if(!e)return;let t=e.split("."),r=s;for(let n of t){if(r==null||typeof r!="object")return;r=r[n]}return r}function E(s){let e=s.nodes.find(r=>r.type.startsWith("trigger."));if(!e)return null;let t=s.edges.filter(r=>r.from===e.id).map(r=>r.to);return{triggerId:e.id,pending:t}}function k(s,e){return s.nodes.find(t=>t.id===e)}function st(s,e,t){let r=s.split(".");if(r[0]==="env"){if(r.length!==2)return"";let i=r[1];if(!t.has(i))return"";let o=process.env[i];return typeof o=="string"?o:""}let n=e;for(let i of r){if(n==null||typeof n!="object")return"";n=n[i]}return n==null?"":typeof n=="object"?JSON.stringify(n):String(n)}function S(s,e,t={}){let r=new Set(t.envAllow||[]);return s.replace(/\{\{\s*([a-zA-Z_][a-zA-Z0-9_.-]*)\s*\}\}/g,(n,i)=>st(i,e,r))}function f(s,e,t={}){let r={};for(let[n,i]of Object.entries(s))typeof i=="string"?r[n]=S(i,e,t):Array.isArray(i)?r[n]=i.map(o=>typeof o=="string"?S(o,e,t):o):i&&typeof i=="object"?r[n]=f(i,e,t):r[n]=i;return r}var T=async s=>({output:s.run.context[s.node.id]??{}}),ot=async s=>{let e=s.node.config,t=String(e.agentId??""),r=String(e.prompt??"");if(!t)return{error:`agent node "${s.node.id}" missing config.agentId`};let n=S(r,s.run.context,{envAllow:s.workflow.envAllow}),i=typeof e.timeoutMinutes=="number"?e.timeoutMinutes:void 0,o=Date.now();try{let a=await s.agents.execute({agentId:t,message:n,workflowRunId:s.run.id,timeoutMinutes:i}),d=Date.now()-o;if(a.error)return s.log(`[node:${s.node.id}] agent "${t}" failed: ${a.error}`),{error:a.error};let u=String(e.resultParser??"noqta-result-token")==="json"?xt(a.content):Ae(a.content);return{output:{reply:a.content,result:u.result,json:u.json,taskId:a.taskId,durationMs:d}}}catch(a){return s.log(`[node:${s.node.id}] agent "${t}" threw: ${a.message}`),{error:a.message}}},it=async s=>{let e=V(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}})},at=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??""),r=String(e.chatId??""),n=String(e.text??"");if(!t||!r){let a=String(s.node.config.chatId??""),d=String(s.node.config.channel??""),l=[];return t||l.push(`channel config="${d}" rendered=""`),r||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 i=Y(s,e.accountId),o=s.channels[t];if(o?.send)try{return{output:{messageId:await o.send({channel:t,chatId:r,text:n,...i?{accountId:i}:{}})??null}}}catch(a){return{error:`action.send failed: ${a.message}`}}if(s.forwardChannelSend)try{return{output:{messageId:(await s.forwardChannelSend({channel:t,chatId:r,text:n,accountId:i})).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)`}},dt=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),r=String(e.project??""),n=String(e.title??""),i=String(e.description??""),o=Array.isArray(e.labels)?e.labels.map(String):[],a=Array.isArray(e.assignees)?e.assignees.map(String):[];if(!r||!n)return{error:`action.createIssue "${s.node.id}" needs project + title`};let d=Q(s),l=s.channels[t];if(!l?.createIssue)return{error:`channel "${t}" does not support createIssue`};try{let u=await l.createIssue({project:r,title:n,description:i,labels:o,assignees:a,agentId:d});return u?{output:{issue:{iid:u.iid,url:u.url,webUrl:u.url}}}:{error:"createIssue returned null (see adapter log)"}}catch(u){return{error:`action.createIssue failed: ${u.message}`}}},lt=async()=>({output:{}}),ct=async s=>{let e=s.node.config,t=String(e.name??s.node.id),r=e.waitFor??{},n=e.resumeMatch??{};return{paused:!0,pausedAt:{kind:"checkpoint",nodeId:s.node.id,checkpointName:t,resumeMatch:{...r,...n}}}},ut=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),r=String(e.project??""),n=String(e.iid??""),i=Array.isArray(e.add)?e.add.map(String):[],o=Array.isArray(e.remove)?e.remove.map(String):[];if(!r||!n)return{error:`action.setLabel "${s.node.id}" needs project + iid (try {{trigger.project}} / {{trigger.issue.iid}})`};if(i.length===0&&o.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=Q(s),l=e.kind==="merge_request"?"merge_request":"issue";return{output:{labels:await a.setLabels({project:r,kind:l,iid:n,add:i,remove:o,agentId:d})??[],add:i,remove:o}}},pt=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),r=String(e.project??""),n=String(e.iid??"");if(!r||!n)return{error:`action.readLabel "${s.node.id}" needs project + iid`};let i=s.channels[t];if(!i?.getLabels)return{error:`channel "${t}" does not support getLabels`};let o=e.kind==="merge_request"?"merge_request":"issue";return{output:{labels:await i.getLabels({project:r,kind:o,iid:n})??[]}}},gt=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??""),r=String(e.chatId??""),n=String(e.messageId??""),i=String(e.emoji??"\u{1F440}");if(!t||!r||!n)return{error:`action.react "${s.node.id}" needs channel + chatId + messageId`};let o=Y(s,e.accountId),a=s.channels[t];if(!a?.react)return{error:`channel "${t}" does not support react`};try{return await a.react(r,n,i,o),{output:{emoji:i}}}catch(d){return{error:`action.react failed: ${d.message}`}}},ft=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??""),r=String(e.chatId??""),n=String(e.messageId??""),i=String(e.text??""),o=e.parseMode?String(e.parseMode):void 0;if(!t||!r||!n||!i)return{error:`action.editMessage "${s.node.id}" needs channel + chatId + messageId + text`};let a=Y(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(r,n,i,o,a)}}}catch(l){return{error:`action.editMessage failed: ${l.message}`}}},mt=async s=>{let e=f(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.channel??"gitlab"),r=String(e.chatId??""),n=Number(e.durationMs??0);if(!r||!n)return{error:`action.logTime "${s.node.id}" needs chatId + durationMs`};let i=s.channels[t];if(!i?.logTimeSpent)return{error:`channel "${t}" does not support logTimeSpent`};let o=Q(s);try{return await i.logTimeSpent(r,n,o),{output:{durationMs:n}}}catch(a){return{error:`action.logTime failed: ${a.message}`}}},ht=async s=>{let e=f(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 r=String(e.method??"POST").toUpperCase(),n=e.headers&&typeof e.headers=="object"?e.headers:{"Content-Type":"application/json"},i;e.body!==void 0&&(i=typeof e.body=="string"?e.body:JSON.stringify(e.body));try{let o=await fetch(t,{method:r,headers:n,body:i}),a=await o.text(),d=a;try{d=JSON.parse(a)}catch{}return{output:{ok:o.ok,status:o.status,body:d}}}catch(o){return{error:`action.callHTTP failed: ${o.message}`}}},yt=async s=>{let e=s.node.config,t=s.run.context;return typeof e.path=="string"&&e.path?{output:{value:W(t,e.path)}}:e.template&&typeof e.template=="object"?{output:f(e.template,t,{envAllow:s.workflow.envAllow})}:{output:{}}},wt=async s=>{let e=s.node.config,t=f(e,s.run.context,{envAllow:s.workflow.envAllow}),r=String(t.assignTo??"");if(!r)return{error:`userTask "${s.node.id}" missing config.assignTo`};let n=ue(r);if(!n)return{error:`userTask "${s.node.id}" assignTo must be "actor:<id>" or "role:<id>", got "${r}"`};let i=e.form??t.form,o=kt(i);if(!o)return{error:`userTask "${s.node.id}" missing or invalid config.form`};let a=String(t.title??o.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(n);if(l.length===0)return{error:`userTask "${s.node.id}" assignee "${r}" resolved to zero actors`};let u=Re(t.dueIn),p=s.tasks.create({runId:s.run.id,workflowId:s.workflow.id,nodeId:s.node.id,title:a,description:d,assignee:r,assignedTo:l,form:o,dueAt:u});return s.log(`[node:${s.node.id}] userTask created ${p.id} for ${r} \u2192 actors [${l.join(", ")}]`),{paused:!0,pausedAt:{kind:"userTask",nodeId:s.node.id,taskId:p.id,assignee:r,assignedTo:l}}};function kt(s){if(!s||typeof s!="object")return null;let e=ce.safeParse(s);return e.success?e.data:null}function Re(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),r=Number(e[2]??0),n=Number(e[3]??0),i=Number(e[4]??0),o=((t*24+r)*60+n)*6e4+i*1e3;if(o>0)return new Date(Date.now()+o).toISOString()}}}}var bt=async s=>{let e=s.node.config,t=f(e,s.run.context,{envAllow:s.workflow.envAllow}),r=String(t.workflowId??"");if(!r)return{error:`subProcess "${s.node.id}" missing config.workflowId`};let n=s.run.depth??0,i=s.workflow.maxChildDepth??5;if(n+1>=i)return{error:`max child workflow depth ${i} exceeded at ${s.workflow.id} \u2192 ${r} (parent depth ${n})`};let o=e.inputMap,a={};if(o==="*")a={...s.run.context};else if(o&&typeof o=="object")for(let[d,l]of Object.entries(o))l&&typeof l=="object"&&!Array.isArray(l)?a[d]=f(l,s.run.context,{envAllow:s.workflow.envAllow}):typeof l=="string"&&(a[d]={value:S(l,s.run.context,{envAllow:s.workflow.envAllow})});return{paused:!0,pausedAt:{kind:"subProcess",nodeId:s.node.id,childRunId:"",childWorkflowId:r},spawnChild:{workflowId:r,input:a}}},It=T,St=async s=>{let e=s.node.config,t=f(e,s.run.context,{envAllow:s.workflow.envAllow}),r=String(t.name??"");if(!r)return{error:`signal.emit "${s.node.id}" missing config.name`};let n=t.scope==="global"?"global":"workflow",i=t.payload&&typeof t.payload=="object"?t.payload:{};return{output:{emittedAt:new Date().toISOString(),name:r,scope:n,payload:i},emitSignal:{name:r,scope:n,payload:i}}},vt=async s=>{let e=s.node.config,t=f(e,s.run.context,{envAllow:s.workflow.envAllow}),r=String(t.name??"");if(!r)return{error:`signal.wait "${s.node.id}" missing config.name`};let n=t.scope==="global"?"global":"workflow",i=e.match&&typeof e.match=="object"?e.match:{};return{paused:!0,pausedAt:{kind:"signalWait",nodeId:s.node.id,signalName:r,match:i,scope:n}}},Rt=async s=>{let e=s.node.config,t=f(e,s.run.context,{envAllow:s.workflow.envAllow}),r=Re(t.after??e.after);return r?{paused:!0,pausedAt:{kind:"timerWait",nodeId:s.node.id,fireAt:r}}:{error:`timer.boundary "${s.node.id}" needs config.after (duration or minutes)`}},$t=async()=>({output:{}}),At=async s=>{let e=s.node.config,r=(Array.isArray(e.inputs)?e.inputs:[]).map(o=>typeof o=="string"?S(o,s.run.context,{envAllow:s.workflow.envAllow}):o),n=Array.isArray(e.rules)?e.rules:[];for(let o of n){let a=Array.isArray(o.when)?o.when:[];if(a.length!==r.length)continue;let d=!0;for(let l=0;l<a.length;l++)if(!Tt(a[l],r[l])){d=!1;break}if(d)return{output:{...o.output??{},matchedPort:o.to??""},port:o.to}}let i=e.default;return{output:{...i?.output??{},matchedPort:i?.to??""},port:i?.to}};function Tt(s,e){if(s==null||s==="*")return!0;let t=String(s),r=typeof e=="number"?e:String(e??""),n=/^(>=|<=|>|<)\s*(-?\d+(?:\.\d+)?)$/.exec(t);if(n){let i=n[1],o=Number(n[2]),a=typeof r=="number"?r:Number(r);if(Number.isNaN(a))return!1;switch(i){case">":return a>o;case"<":return a<o;case">=":return a>=o;case"<=":return a<=o}}if(t.startsWith("!="))return String(r)!==t.slice(2);if(t.startsWith("/")&&t.endsWith("/")&&t.length>2)try{return new RegExp(t.slice(1,-1)).test(String(r))}catch{return!1}return String(r)===t}var $e={"trigger.channel":T,"trigger.manual":T,"trigger.cron":T,"trigger.hook":T,"trigger.form":It,agent:ot,branch:it,transform:yt,"gateway.parallel":$t,rule:At,"action.send":at,"action.createIssue":dt,"action.setLabel":ut,"action.readLabel":pt,"action.react":gt,"action.editMessage":ft,"action.logTime":mt,"action.callHTTP":ht,userTask:wt,subProcess:bt,"signal.emit":St,"signal.wait":vt,"timer.boundary":Rt,checkpoint:ct,end:lt};function Z(s){return $e[s]}function Y(s,e){if(typeof e=="string"&&e)return e;let t=s.workflow.nodes.find(i=>i.type.startsWith("trigger."));if(!t)return;let n=s.run.context[t.id]?.accountId;return typeof n=="string"&&n?n:void 0}function Q(s){for(let e=s.run.history.length-1;e>=0;e--){let t=s.run.history[e],r=s.workflow.nodes.find(n=>n.id===t.nodeId);if(r?.type==="agent")return r.config.agentId??void 0}}function Ae(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 xt(s){let{result:e}=Ae(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 x=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 X(s,e){if(s.name!==e.name||s.scope==="workflow"&&s.workflowId!==e.workflowId)return!1;for(let[t,r]of Object.entries(s.match??{}))if(!(r===void 0||r===""||r==="*")&&e.payload[t]!==r)return!1;return!0}function Te(s,e){let t=[],r={};for(let n of s.fields){let i=e.values[n.key];if(!(i!=null&&i!=="")){n.required?t.push({field:n.key,message:`"${n.label}" is required`}):n.defaultValue!==void 0&&(r[n.key]=n.defaultValue);continue}let a=Pt(n,i);if(a.error){t.push({field:n.key,message:a.error});continue}r[n.key]=a.value}return{ok:t.length===0,errors:t,values:r}}function Pt(s,e){let t=s.label;switch(s.type){case"text":case"long-text":{let r=String(e);return s.validate?.min!==void 0&&r.length<s.validate.min?{error:`"${t}" must be at least ${s.validate.min} characters`}:s.validate?.max!==void 0&&r.length>s.validate.max?{error:`"${t}" must be at most ${s.validate.max} characters`}:s.validate?.pattern&&!new RegExp(s.validate.pattern).test(r)?{error:`"${t}" does not match the expected format`}:{value:r}}case"number":{let r=typeof e=="number"?e:Number(String(e));return Number.isFinite(r)?s.validate?.min!==void 0&&r<s.validate.min?{error:`"${t}" must be at least ${s.validate.min}`}:s.validate?.max!==void 0&&r>s.validate.max?{error:`"${t}" must be at most ${s.validate.max}`}:{value:r}:{error:`"${t}" must be a number`}}case"boolean":{if(typeof e=="boolean")return{value:e};let r=String(e).toLowerCase();return["true","yes","y","1"].includes(r)?{value:!0}:["false","no","n","0"].includes(r)?{value:!1}:{error:`"${t}" must be yes/no`}}case"date":{let r=typeof e=="string"||typeof e=="number"?new Date(e):null;return!r||Number.isNaN(r.getTime())?{error:`"${t}" is not a valid date`}:{value:r.toISOString()}}case"select":{let r=String(e),n=s.options??[];return n.length&&!n.includes(r)?{error:`"${t}" must be one of: ${n.join(", ")}`}:{value:r}}case"multi-select":{let r=Array.isArray(e)?e.map(String):String(e).split(",").map(i=>i.trim()).filter(Boolean),n=s.options??[];if(n.length){let i=r.filter(o=>!n.includes(o));if(i.length)return{error:`"${t}" contains invalid values: ${i.join(", ")}`}}return{value:r}}case"file":return{value:String(e)}}return{error:`unknown field type: ${s.type}`}}var Nt=4e3,ee=class{store;runs;nodeId;forwarder;channels;agents;log;actors;tasks;timers;signals;renderUserTask;ackTypingTimers=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 U,this.timers=e.timers??new L({log:t=>this.log(t)}),this.signals=e.signals??new x,this.renderUserTask=e.renderUserTask,this.timers.onFire(t=>this.resumeFromTimer(t)),this.signals.subscribe(t=>this.resumeFromSignal(t))}emitSignal(e){let t={name:e.name,scope:e.scope??"global",workflowId:e.workflowId??"",payload:e.payload??{},emittedAt:new Date().toISOString()};return this.signals.emit(t),t}async resumeFromSignal(e){let t=this.runs.list({limit:500});for(let r of t){if(r.status!=="paused"||!r.pausedAt||r.pausedAt.kind!=="signalWait")continue;let n={name:r.pausedAt.signalName,scope:r.pausedAt.scope,workflowId:r.workflowId,match:r.pausedAt.match??{}};if(!X(n,e))continue;let i=this.store.list().find(p=>p.id===r.workflowId);if(!i)continue;let o=k(i,r.pausedAt.nodeId),a=o?i.edges.filter(p=>p.from===o.id).map(p=>p.to):[],d={receivedAt:new Date().toISOString(),name:e.name,payload:e.payload},l={at:d.receivedAt,nodeId:r.pausedAt.nodeId,inputKeys:[],status:"resumed",output:d,idempotencyKey:w(r.id,r.pausedAt.nodeId,`signal:${e.name}:${e.emittedAt}`)},u={...r.context,[r.pausedAt.nodeId]:d};this.runs.recordExecution({runId:r.id,entry:l,nextPending:a,status:"running",pausedAt:null,context:u}),this.log(`[workflow:${i.id}] run ${r.id} resumed from signal "${e.name}"`),this.walk(i,r.id,`signal:${e.name}`).catch(p=>this.log(`[workflow:${i.id}] walk-after-signal failed: ${p.message}`))}}async resumeFromTimer(e){let t=this.runs.get(e.runId);if(!t||t.status!=="paused"||!t.pausedAt||t.pausedAt.kind!=="timerWait"||t.pausedAt.nodeId!==e.nodeId)return;let r=this.store.list().find(u=>u.id===t.workflowId);if(!r)return;let n=k(r,e.nodeId),i=n?r.edges.filter(u=>u.from===n.id).map(u=>u.to):[],o=new Date().toISOString(),a={firedAt:o,scheduledFor:e.fireAt},d={at:o,nodeId:e.nodeId,inputKeys:[],status:"resumed",output:a,idempotencyKey:w(t.id,e.nodeId,`timer:${e.id}`)},l={...t.context,[e.nodeId]:a};this.runs.recordExecution({runId:t.id,entry:d,nextPending:i,status:"running",pausedAt:null,context:l}),this.log(`[workflow:${r.id}] run ${t.id} resumed from timer "${e.nodeId}" (fired ${o})`),this.walk(r,t.id,`timer:${e.id}`).catch(u=>this.log(`[workflow:${r.id}] walk-after-timer failed: ${u.message}`))}async dispatchWorkflow(e){let t=this.store.list().find(o=>o.id===e.workflowId);if(!t)return this.log(`[workflows] dispatchWorkflow: workflow "${e.workflowId}" not found`),{claimed:!1,run:null};let n=t.nodes.find(o=>o.type.startsWith("trigger."))?.config??{},i={source:e.trigger?.source??n.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,i)}startChannelAck(e,t){let r=String(t.channel??""),n=String(t.chatId??"");if(!r||!n)return;let i=this.channels[r];if(!i)return;let o=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&&i.react)try{Promise.resolve(i.react(n,d,"\u{1F440}",o)).catch(()=>{})}catch{}if(this.ackTypingTimers.has(e)||!i.sendTyping)return;let l=()=>{try{Promise.resolve(i.sendTyping(n,o)).catch(()=>{})}catch{}};l();let u=setInterval(l,Nt);this.ackTypingTimers.set(e,u)}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),n=t.some(a=>a.fanOut)?t:t.slice(0,1),i=[],o=[];for(let a of n){let d=await this.dispatchOne(a,e.entityRef,e.event,e.trigger);d.claimed&&i.push(a),d.run&&o.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:i,runs:o}}matchByTrigger(e,t){let r=this.store.list(),n=[];for(let i of r){if(t){if(!i.mesh?.allowRemote)continue;let l=i.mesh.peers;if(l&&l.length>0&&!l.includes(t.peer))continue}let o=i.nodes.find(l=>l.type.startsWith("trigger."));if(!o)continue;let a=o.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!=="*"&&O(e.source,d.chat)!==O(e.source,e.chat))continue;if(d.labels?.length){let l=new Set(e.labels??[]);if(!d.labels.some(p=>l.has(p)))continue}}n.push(i)}return n.sort((i,o)=>o.priority-i.priority||i.id.localeCompare(o.id))}async dispatchOne(e,t,r,n){let i=this.runs.getActiveByEntity(t),o=i?this.runs.getHomeNodeByEntity(t):null;if(i&&o&&o!==this.nodeId){if(!this.forwarder)return this.log(`[workflow:${e.id}] run ${i} home'd on "${o}" but no forwarder \u2014 dropping`),{claimed:!1,run:null};try{await this.forwarder.forwardTransition(o,{workflowId:e.id,event:r,entityRef:t})}catch(d){this.log(`[workflow:${e.id}] forward to "${o}" failed: ${d.message}`)}return{claimed:!0,run:null}}let a=i?this.runs.get(i):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(!Wt(a.pausedAt.resumeMatch,n,r))return this.log(`[workflow:${e.id}] run ${a.id} paused but event doesn't match resumeMatch \u2014 dropping`),{claimed:!1,run:null};let d=k(e,a.pausedAt.nodeId),l=d?e.edges.filter(A=>A.from===d.id).map(A=>A.to):[],u={at:new Date().toISOString(),nodeId:a.pausedAt.nodeId,inputKeys:[],status:"resumed",output:{event:r.payload},idempotencyKey:w(a.id,a.pausedAt.nodeId,`resume:${r.id}`)},p={...a.context,[a.pausedAt.nodeId]:{event:r.payload}},m=a.pausedAt.checkpointName,h=this.runs.recordExecution({runId:a.id,entry:u,nextPending:l,status:"running",pausedAt:null,context:p});h&&(a=h),this.log(`[workflow:${e.id}] run ${a.id} resumed from checkpoint "${m}"`),n.source.endsWith("-message")&&this.startChannelAck(a.id,r.payload)}else return a.status==="running"?(this.log(`[workflow:${e.id}] run ${a.id} already running; dropping concurrent event ${r.id}`),{claimed:!0,run:null}):(this.log(`[workflow:${e.id}] run ${a.id} is ${a.status}; dropping event ${r.id}`),{claimed:!1,run:null});else{let d=E(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]:r.payload}}),this.log(`[workflow:${e.id}] run ${a.id} created from trigger "${d.triggerId}" for ${t.id}`),n.source.endsWith("-message")&&this.startChannelAck(a.id,r.payload)}return this.walk(e,a.id,r.id),{claimed:!0,run:a}}async walk(e,t,r){try{await this.walkInner(e,t,r)}finally{this.stopChannelAck(t)}}async walkInner(e,t,r){let n=this.runs.get(t);if(n)for(;n.status==="running"&&n.pending.length>0;){let i=n.pending[0],o=n.pending.slice(1),a=k(e,i);if(!a){this.log(`[workflow:${e.id}] missing node "${i}" \u2014 marking run failed`),this.runs.recordExecution({runId:n.id,entry:{at:new Date().toISOString(),nodeId:i,inputKeys:[],status:"failed",idempotencyKey:w(n.id,i,r),note:"node definition missing from workflow"},nextPending:o,status:"failed"});return}let d=Z(a.type);if(!d){this.log(`[workflow:${e.id}] no handler for node type "${a.type}"`),this.runs.recordExecution({runId:n.id,entry:{at:new Date().toISOString(),nodeId:i,inputKeys:[],status:"failed",idempotencyKey:w(n.id,i,r),note:`no handler for node type "${a.type}"`},nextPending:o,status:"failed"});return}let l=w(n.id,i,r);if(n.history.some(g=>g.idempotencyKey===l)){n=this.runs.recordExecution({runId:n.id,entry:{at:new Date().toISOString(),nodeId:i,inputKeys:[],status:"skipped",idempotencyKey:l+"_dedup",note:"duplicate execution dropped"},nextPending:o})??n;continue}let u=e.edges.filter(g=>g.to===i).map(g=>g.from),p;try{p=await d({workflow:e,run:n,node:a,channels:this.channels,agents:this.agents,actors:this.actors,tasks:this.tasks,forwardChannelSend:this.forwarder?.forwardChannelSend?.bind(this.forwarder),log:this.log})}catch(g){this.log(`[workflow:${e.id}] handler "${a.type}" threw: ${g.message}`),p={error:g.message}}let m=new Date().toISOString();if(p.error){let g={at:m,nodeId:i,inputKeys:u,status:"failed",idempotencyKey:l,note:p.error.slice(0,200)};n=this.runs.recordExecution({runId:n.id,entry:g,nextPending:o,status:"failed"})??n;return}if(p.paused&&p.pausedAt){let g=p.pausedAt,b=null;if(p.spawnChild&&g.kind==="subProcess"){if(b=await this.spawnChild({parent:n,parentNodeId:i,childWorkflowId:p.spawnChild.workflowId,input:p.spawnChild.input}),!b){let y={at:m,nodeId:i,inputKeys:u,status:"failed",idempotencyKey:l,note:`subProcess: child workflow "${p.spawnChild.workflowId}" not found`};n=this.runs.recordExecution({runId:n.id,entry:y,nextPending:o,status:"failed"})??n;return}g={...g,childRunId:b.id}}let de={at:m,nodeId:i,inputKeys:u,status:"paused",idempotencyKey:l};if(n=this.runs.recordExecution({runId:n.id,entry:de,nextPending:o,status:"paused",pausedAt:g})??n,b&&this.kickChildWalk(b),g.kind==="timerWait")try{this.timers.schedule({runId:n.id,workflowId:e.id,nodeId:g.nodeId,fireAt:g.fireAt,cancelKey:`${n.id}:${g.nodeId}`})}catch(y){this.log(`[workflow:${e.id}] timer schedule failed: ${y.message}`)}if(g.kind==="userTask"&&this.renderUserTask){let y=this.tasks.get(g.taskId);if(y)try{await this.renderUserTask(y)}catch(F){this.log(`[workflow:${e.id}] userTask render failed: ${F.message}`)}}return}let h=p.output??{},A={...n.context,[i]:h},{nextPending:Ne}=G({workflow:e,fromNodeId:i,selectedPort:p.port}),C=[],P={...n.joinCounters??{}};for(let g of Ne){let b=k(e,g);if(!(b?.type==="gateway.parallel"&&String(b.config?.mode??"fanOut")==="join")){C.push(g);continue}let y=P[g]??[];y.includes(i)||y.push(i),P[g]=y;let F=e.edges.filter(Ee=>Ee.to===g).length;y.length>=F&&(C.push(g),delete P[g])}let je=[...o,...C],D=a.type==="end",We={at:m,nodeId:i,inputKeys:u,status:"ok",output:h,idempotencyKey:l};if(n=this.runs.recordExecution({runId:n.id,entry:We,nextPending:D?[]:je,status:D?String(a.config.status??"completed"):"running",context:A,joinCounters:P})??n,p.emitSignal&&this.emitSignal({name:p.emitSignal.name,scope:p.emitSignal.scope,workflowId:e.id,payload:p.emitSignal.payload}),D){n.parentRunId&&n.parentNodeId&&this.resumeParent({parentRunId:n.parentRunId,parentNodeId:n.parentNodeId,childRun:n}).catch(g=>this.log(`[workflow:${e.id}] resumeParent failed: ${g.message}`));return}}}async spawnChild(e){let t=this.store.list().find(a=>a.id===e.childWorkflowId);if(!t)return null;let r=E(t);if(!r)return this.log(`[workflow:${t.id}] no trigger node \u2014 cannot spawn as child`),null;let n={...e.input};n[r.triggerId]={...n[r.triggerId]??{},parentRunId:e.parent.id,parentNodeId:e.parentNodeId};let i={backend:"agentx-internal",id:`subprocess:${e.parent.id}:${e.parentNodeId}`},o=this.runs.create({workflowId:t.id,initialPending:r.pending,entityRef:i,initialContext:n,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 ${o.id} spawned from ${e.parent.id}/${e.parentNodeId} (depth ${o.depth})`),o}kickChildWalk(e){let t=this.store.list().find(r=>r.id===e.workflowId);t&&this.walk(t,e.id,`spawn:${e.parentRunId}:${e.parentNodeId}`).catch(r=>this.log(`[workflow:${t.id}] child walk failed: ${r.message}`))}async resumeParent(e){let t=this.runs.get(e.parentRunId);if(!t||t.status!=="paused"||!t.pausedAt||t.pausedAt.kind!=="subProcess"||t.pausedAt.nodeId!==e.parentNodeId||t.pausedAt.childRunId!==e.childRun.id)return;let r=this.store.list().find(l=>l.id===t.workflowId);if(!r)return;let n=k(r,e.parentNodeId),i=n?r.edges.filter(l=>l.from===n.id).map(l=>l.to):[],o={childRunId:e.childRun.id,status:e.childRun.status,output:jt(e.childRun)},a={at:new Date().toISOString(),nodeId:e.parentNodeId,inputKeys:[],status:"resumed",output:o,idempotencyKey:w(t.id,e.parentNodeId,`child:${e.childRun.id}`)},d={...t.context,[e.parentNodeId]:o};this.runs.recordExecution({runId:t.id,entry:a,nextPending:i,status:"running",pausedAt:null,context:d}),this.log(`[workflow:${r.id}] parent run ${t.id} resumed from subProcess child ${e.childRun.id}`),this.walk(r,t.id,`child:${e.childRun.id}`)}async submitTask(e,t,r){let n=this.tasks.get(e);if(!n)return{ok:!1,error:`task not found: ${e}`};if(n.status!=="open")return{ok:!1,error:`task is ${n.status}`};let i=Te(n.form,t);if(!i.ok)return{ok:!1,error:"form validation failed",fieldErrors:i.errors};let o=this.runs.get(n.runId);if(!o||o.status!=="paused")return{ok:!1,error:`run ${n.runId} is not paused`};if(!o.pausedAt||o.pausedAt.kind!=="userTask"||o.pausedAt.taskId!==e)return{ok:!1,error:`run ${n.runId} is not waiting on task ${e}`};let a=this.store.list().find(h=>h.id===o.workflowId);if(!a)return{ok:!1,error:`workflow ${o.workflowId} not found`};let d=k(a,n.nodeId),l=d?a.edges.filter(h=>h.from===d.id).map(h=>h.to):[],u={submittedBy:r,submittedAt:new Date().toISOString(),values:i.values,action:t.action},p={at:new Date().toISOString(),nodeId:n.nodeId,inputKeys:[],status:"resumed",output:u,idempotencyKey:w(o.id,n.nodeId,`task:${e}:${t.action}`)},m={...o.context,[n.nodeId]:u};return this.runs.recordExecution({runId:o.id,entry:p,nextPending:l,status:"running",pausedAt:null,context:m}),this.tasks.save({...n,status:"completed",submittedBy:r,submittedAt:u.submittedAt,submittedValues:i.values,submittedAction:t.action}),this.log(`[workflow:${a.id}] run ${o.id} resumed from userTask ${e}`),this.walk(a,o.id,`task:${e}`),{ok:!0,runId:o.id}}};function jt(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 Wt(s,e,t){let r=i=>{let o=s[i];if(o===void 0||o===""||o==="*")return!0;if(Array.isArray(o)){let a=new Set(e.labels??[]);return o.some(d=>a.has(String(d)))}return i==="chat"?O(e.source,String(o))===O(e.source,e.chat):e[i]===o};if(!r("source")||!r("project")||!r("repo")||!r("chat"))return!1;let n=s.eventIdLike;return!(typeof n=="string"&&n&&!t.id.includes(n))}function O(s,e){return e==null?"":s==="whatsapp-message"?e.replace(/@s\.whatsapp\.net$|@g\.us$/i,"").replace(/[\s+()]/g,""):e}function Et(s){return{"pre:channel-message":async e=>{let t=e.msg;if(!t)return{};let r=Ot(t.channel);if(!r)return{};let n=t.group?.id??t.sender.id,i={backend:t.channel,id:`${t.channel}:${n}`},{claimed:o}=await s.dispatch({trigger:{source:r,chat:n},entityRef:i,event:{id:`${t.channel}:${t.accountId}:${t.id}`,payload:_t(t)}});return o.length===0?{}:o.every(d=>d.nodes.find(u=>u.type.startsWith("trigger."))?.config?.passthrough===!0)?{}:{blocked:!0,message:`handled by workflow${o.length>1?"s":""}: ${o.map(d=>d.id).join(", ")}`}},"on:gitlab-issue":async e=>{let t=e.project,r=e.iid,n=e.issueEvent;if(!t||r===void 0)return{};let i=Array.isArray(n?.object_attributes?.labels)?n.object_attributes.labels.map(d=>typeof d=="string"?d:d?.title).filter(Boolean):n?.labels?.map(d=>d?.title)??[],o=n?.assignees??n?.object_attributes?.assignee_ids??[],a={backend:"gitlab",id:`${t}#${r}`};return await s.dispatch({trigger:{source:"gitlab-issue",project:t,labels:i},entityRef:a,event:{id:`gitlab-issue:${t}:${r}:${n?.object_attributes?.updated_at||n?.object_attributes?.action||"evt"}`,payload:{issue:{iid:r,title:n?.object_attributes?.title,description:n?.object_attributes?.description,url:n?.object_attributes?.url,action:n?.object_attributes?.action,labels:i,assignees:o},project:t,channel:"gitlab",chatId:`${t}:issue:${r}`}}}),{}},"on:gitlab-pipeline":async e=>{let t=e.project,r=e.pipelineId,n=e.status,i=e.ref;if(!t||!n)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}:${r}:${n}`,payload:{pipeline:{id:r,status:n,ref:i},project:t,channel:"gitlab",chatId:`${t}:merge_request:${a}`}}}),{}}}}function Ot(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 _t(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 Ct(s){let e=s.store.list(),t=0,r=0;for(let n of e){let i=n.nodes.find(o=>o.type.startsWith("trigger."));if(i){if(i.type==="trigger.cron"){let o=i.config;if(!o.spec){s.log(`[workflows] ${n.id} trigger.cron missing config.spec \u2014 skipping`);continue}Dt({workflowId:n.id,triggerNodeId:i.id,spec:o.spec,timezone:o.timezone??"UTC"},s.dispatcher,s.log),t++}else if(i.type==="trigger.hook"){let o=i.config;if(!o.event||!o.event.startsWith("on:")){s.log(`[workflows] ${n.id} trigger.hook config.event must start with "on:" \u2014 skipping`);continue}s.hooks.registerHandler(o.event,`workflows:${n.id}`,async a=>{try{await s.dispatcher.dispatchWorkflow({workflowId:n.id,entityRef:{backend:"hook",id:`${n.id}:${o.event}`},event:{id:`hook:${o.event}:${Date.now().toString(36)}`,payload:{hookEvent:o.event,...a}}})}catch(d){s.log(`[workflows] ${n.id} hook dispatch failed: ${d.message}`)}return{}},60),r++}}}return{cronTimers:t,hookSubscribers:r}}function Dt(s,e,t){let r=()=>{let n;try{n=le(s.spec,new Date,s.timezone)}catch(o){t(`[workflows] ${s.workflowId} cron spec invalid: ${o.message}`);return}let i=Math.max(1e3,n.getTime()-Date.now());setTimeout(()=>{(async()=>{let o=`cron:${s.workflowId}:${n.toISOString()}`;try{await e.dispatchWorkflow({workflowId:s.workflowId,trigger:{source:"cron"},entityRef:{backend:"cron",id:`${s.workflowId}@${n.toISOString()}`},event:{id:o,payload:{now:n.toISOString(),spec:s.spec,workflowId:s.workflowId}}})}catch(a){t(`[workflows] ${s.workflowId} cron dispatch failed: ${a.message}`)}finally{r()}})()},i)};r()}import{readFileSync as te,writeFileSync as Pe,existsSync as ne,readdirSync as Ut,statSync as Lt}from"fs";import{resolve as re,join as Mt}from"path";var se=/^(\s*)-\s*\[( |x|X)\]\s*(.*)$/,_=/@([a-z0-9_-]+)/i,xe=/\[time:\s*([0-9hm\s]+)\]/i;function Ht(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 oe=class{constructor(e){this.path=e}type="backlog";capabilities={listAll:!1,create:!1,transition:!1,labels:!1,search:!1};read(){let e=re(process.cwd(),this.path);return ne(e)?te(e,"utf-8").split(`
|
|
8
|
-
`):[]}write(e){let t=re(process.cwd(),this.path);Pe(t,e.join(`
|
|
9
|
-
`))}async listOpen(e){let t=this.read(),r=[];for(let n=0;n<t.length;n++){let i=t[n].match(se);if(!i||i[2].toLowerCase()==="x")continue;let a=i[3],d=a.match(_);if(d&&d[1].toLowerCase()!==e.toLowerCase())continue;let l=a.match(xe),u=a.replace(_,"").replace(xe,"").trim();r.push({id:`backlog:${n}`,title:u||`Task at line ${n+1}`,assignee:d?d[1]:void 0,estimatedSeconds:l?Ht(l[1]):void 0,priority:n})}return r}async claim(e,t){}async report(e,t){if(!e.startsWith("backlog:"))throw new Error(`not a backlog id: ${e}`);let r=parseInt(e.slice(8),10),n=this.read(),i=n[r];if(!i)throw new Error(`backlog line ${r} missing`);if(!i.match(se))throw new Error(`backlog line ${r} not a checkbox`);if(t.status==="done"){n[r]=i.replace(/- \[ \]/,"- [x]");let a=t.timeSeconds?` <!-- done by agent, ${Math.round(t.timeSeconds/60)}m -->`:" <!-- done by agent -->";n.splice(r+1,0,a)}else t.status==="blocked"?n.splice(r+1,0,` <!-- BLOCKED: ${t.blocker||t.note||"?"} -->`):t.note&&n.splice(r+1,0,` <!-- ${t.note.replace(/-->/g,"\u2014 >")} -->`);this.write(n)}},ie=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(ne(e))for(let r of Ut(e)){let n=Mt(e,r);Lt(n).isDirectory()?this.walk(n,t):r.endsWith(".md")&&t.push(n)}}async listOpen(e){let t=[];this.walk(re(process.cwd(),this.root),t);let r=[];for(let n of t){let i=te(n,"utf-8").split(`
|
|
10
|
-
`);for(let o=0;o<i.length;o++){let a=i[o].match(se);if(!a||a[2].toLowerCase()==="x")continue;let d=a[3].match(_);!d||d[1].toLowerCase()!==e.toLowerCase()||r.push({id:`wiki:${n}:${o}`,title:a[3].replace(_,"").trim(),assignee:d[1],priority:o})}}return r}async claim(){}async report(e,t){let r=e.split(":"),n=parseInt(r[r.length-1],10),i=r.slice(1,-1).join(":");if(!ne(i))return;let o=te(i,"utf-8").split(`
|
|
11
|
-
`);t.status==="done"&&o[n]&&(o[n]=o[n].replace(/- \[ \]/,"- [x]"),Pe(i,o.join(`
|
|
12
|
-
`)))}},ae=class{constructor(e,t,r,n,i){this.host=e;this.token=t;this.projects=r;this.agentUsernames=n;this.log=i}type="gitlab";capabilities={listAll:!0,create:!0,transition:!0,labels:!0,search:!0};usernameToAgent(e){for(let[t,r]of Object.entries(this.agentUsernames))if(r.some(n=>n.toLowerCase()===e.toLowerCase()))return t}mapIssue(e,t){let r=e.references?.full?.split("#")[0]||t,n=[],i;Array.isArray(e.labels)&&(e.labels.length&&typeof e.labels[0]=="object"?(i=e.labels.map(l=>({name:l.name,color:l.color,text_color:l.text_color})),n=i.map(l=>l.name)):n=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:${r}: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:n,labelDetails:i,updatedAt:e.updated_at,state:e.state==="closed"?"closed":"opened",milestone:e.milestone?.title||void 0}}async api(e,t={}){let r=await fetch(`${this.host}/api/v4${e}`,{...t,headers:{"PRIVATE-TOKEN":this.token,"Content-Type":"application/json",...t.headers||{}}});if(!r.ok)throw new Error(`GitLab ${r.status}: ${await r.text().catch(()=>"")}`);return r.json()}async listOpen(e){let t=this.agentUsernames[e]||[];if(!t.length)return[];let r=[],n=this.projects.length?this.projects:["__ALL__"];for(let i of t)for(let o of n)try{let a=`assignee_username=${encodeURIComponent(i)}&state=opened&scope=all&per_page=20`,d=o==="__ALL__"?`/issues?${a}`:`/projects/${encodeURIComponent(o)}/issues?${a}`,l=await this.api(d);for(let u of l){let p=this.mapIssue(u,o);p.assignee=e,r.push(p)}}catch(a){this.log(`[business] GitLab listOpen failed for ${i} on ${o}: ${a.message}`)}return r}async claim(e,t){let{project:r,iid:n,type:i}=this.parseId(t),o=`/projects/${encodeURIComponent(r)}/${i==="issue"?"issues":"merge_requests"}/${n}?add_labels=Doing&remove_labels=To Do`;try{await this.api(o,{method:"PUT"})}catch(a){this.log(`[business] claim label update failed: ${a.message}`)}}async report(e,t){let{project:r,iid:n,type:i}=this.parseId(e),o=i==="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(r)}/${o}/${n}/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(r)}/${o}/${n}?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(r)}/${o}/${n}?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(r)}/${o}/${n}/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,r=new Date(Date.now()-t*24*36e5).toISOString(),n=new URLSearchParams,i=e.state??"opened";n.set("state",i),n.set("updated_after",r),n.set("scope","all"),n.set("per_page","100"),n.set("with_labels_details","true"),n.set("order_by","updated_at"),n.set("sort","desc"),e.labels?.length&&n.set("labels",e.labels.join(",")),e.milestone&&n.set("milestone",e.milestone),e.search&&n.set("search",e.search);let o=this.projects.length?this.projects:["__ALL__"],a=[];for(let l of o)try{let u=l==="__ALL__"?`/issues?${n.toString()}`:`/projects/${encodeURIComponent(l)}/issues?${n.toString()}`,p=await this.api(u);for(let m of p)a.push(this.mapIssue(m,l))}catch(u){this.log(`[business] GitLab listAll failed on ${l}: ${u.message}`)}let d=a;if(e.notLabels?.length){let l=new Set(e.notLabels);d=d.filter(u=>!(u.labels||[]).some(p=>l.has(p)))}if(e.withoutScopedPrefix){let l=e.withoutScopedPrefix+"::";d=d.filter(u=>!(u.labels||[]).some(p=>p.startsWith(l)))}return d}async setState(e,t){let{project:r,iid:n,type:i}=this.parseId(e),o=i==="issue"?"issues":"merge_requests";await this.api(`/projects/${encodeURIComponent(r)}/${o}/${n}?state_event=${t}`,{method:"PUT"})}async getItem(e){let{project:t,iid:r}=this.parseId(e);try{let n=await this.api(`/projects/${encodeURIComponent(t)}/issues/${r}?with_labels_details=true`);return{...this.mapIssue(n,t),descriptionHtml:n.description_html||void 0,createdAt:n.created_at,author:n.author?{username:n.author.username,name:n.author.name,avatarUrl:n.author.avatar_url}:void 0,allLabels:Array.isArray(n.labels)?typeof n.labels[0]=="object"?n.labels.map(o=>o.name):n.labels:[]}}catch(n){return this.log(`[board] GitLab getItem failed for ${e}: ${n.message}`),null}}async updateItem(e,t){let{project:r,iid:n}=this.parseId(e),i;t.assigneeUsernames&&(i=(await Promise.all(t.assigneeUsernames.map(async u=>{try{let p=await this.api(`/users?username=${encodeURIComponent(u)}`);return Array.isArray(p)&&p[0]?.id?p[0].id:null}catch{return null}}))).filter(u=>typeof u=="number"));let o;if(t.milestoneTitle!==void 0)if(t.milestoneTitle===null||t.milestoneTitle==="")o=0;else try{let l=await this.api(`/projects/${encodeURIComponent(r)}/milestones?title=${encodeURIComponent(t.milestoneTitle)}`);Array.isArray(l)&&l[0]?.id&&(o=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(",")),i!==void 0&&(a.assignee_ids=i),o!==void 0&&(a.milestone_id=o);let d=await this.api(`/projects/${encodeURIComponent(r)}/issues/${n}`,{method:"PUT",body:JSON.stringify(a)});return this.mapIssue(d,r)}async listMembers(){let e=new Map;for(let t of this.projects)try{let r=await this.api(`/projects/${encodeURIComponent(t)}/members/all?per_page=100`);for(let n of r)n.username&&!e.has(n.username)&&e.set(n.username,{username:n.username,name:n.name,avatarUrl:n.avatar_url})}catch(r){this.log(`[board] listMembers failed for ${t}: ${r.message}`)}return[...e.values()].sort((t,r)=>t.username.localeCompare(r.username))}async listMilestones(){let e=new Map;for(let r of this.projects)try{let n=await this.api(`/projects/${encodeURIComponent(r)}/milestones?per_page=100`);for(let i of n)i.title&&!e.has(i.title)&&e.set(i.title,{id:i.id,title:i.title,state:i.state,dueDate:i.due_date})}catch(n){this.log(`[board] listMilestones failed for ${r}: ${n.message}`)}let t=[...e.values()];return t.sort((r,n)=>r.state!==n.state?r.state==="active"?-1:1:r.title.localeCompare(n.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 r,n=e.assigneeUsernames?.length?e.assigneeUsernames:e.assignee?(this.agentUsernames[e.assignee]||[]).slice(0,1):[];n.length&&(r=(await Promise.all(n.map(async l=>{try{let u=await this.api(`/users?username=${encodeURIComponent(l)}`);return Array.isArray(u)&&u[0]?.id?u[0].id:null}catch(u){return this.log(`[board] user lookup failed for ${l}: ${u.message}`),null}}))).filter(l=>typeof l=="number"));let i;if(e.milestoneTitle)try{let d=await this.api(`/projects/${encodeURIComponent(t)}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);Array.isArray(d)&&d[0]?.id&&(i=d[0].id)}catch(d){this.log(`[board] milestone lookup failed for "${e.milestoneTitle}": ${d.message}`)}let o={title:e.title,description:e.description,labels:(e.labels||[]).join(",")};r?.length&&(o.assignee_ids=r),i!==void 0&&(o.milestone_id=i);let a=await this.api(`/projects/${encodeURIComponent(t)}/issues`,{method:"POST",body:JSON.stringify(o)});return this.mapIssue(a,t)}async transition(e,t,r){await this.transitionMany(e,t?[t]:[],r?[r]:[])}async transitionMany(e,t,r){let{project:n,iid:i,type:o}=this.parseId(e),a=o==="issue"?"issues":"merge_requests",d=new URLSearchParams;t.length&&d.set("add_labels",t.join(",")),r.length&&d.set("remove_labels",r.join(",")),d.toString()&&await this.api(`/projects/${encodeURIComponent(n)}/${a}/${i}?${d.toString()}`,{method:"PUT"})}parseId(e){let r=e.replace(/^gitlab:/,"").split(":"),n=r.pop(),i=r.pop()==="mr"?"mr":"issue";return{project:r.join(":"),type:i,iid:n}}};function Qn(s,e,t){let r=s.workSource;switch(r.type){case"backlog":return new oe(r.path);case"wiki":return new ie(r.path,r.glob);case"gitlab":{let n=e.channels.gitlab;if(!n?.token)throw new Error("business.workSource.type=gitlab requires channels.gitlab.token");let i={};for(let a of n.agentMappings)a.gitlabUsernames.length&&(i[a.agentId]=a.gitlabUsernames);let o=r.projects.length?r.projects:n.routes.map(a=>a.project);return new ae(n.host,n.token,o,i,t)}}}export{v as a,M as b,K as c,z as d,J as e,ee as f,Et as g,Ct as h,ae as i,Qn as j};
|
|
13
|
-
//# sourceMappingURL=chunk-4HP6UC2X.js.map
|