agentix-cli 0.20.0 → 0.21.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-57MG4LBM.js → agent-I3ILI3MO.js} +2 -2
- package/dist/{board-dashboard-HXDOYGIG.js → board-dashboard-ASI6MDKX.js} +339 -97
- package/dist/board-dashboard-ASI6MDKX.js.map +1 -0
- package/dist/{chunk-WFHIIVLL.js → chunk-2B2DIQKD.js} +75 -51
- package/dist/chunk-2B2DIQKD.js.map +1 -0
- package/dist/{chunk-MBOLXKA2.js → chunk-5GDCJ2SF.js} +13 -6
- package/dist/chunk-5GDCJ2SF.js.map +1 -0
- package/dist/{chunk-23AUU4S2.js → chunk-5XZ73VM4.js} +38 -38
- package/dist/chunk-5XZ73VM4.js.map +1 -0
- package/dist/{chunk-DLVOHCTA.js → chunk-AANSVC5A.js} +2 -2
- package/dist/{chunk-TC3BSUP7.js → chunk-AGINLNAW.js} +2 -2
- package/dist/{chunk-6B74TO2J.js → chunk-BLRLUF2H.js} +2 -2
- package/dist/chunk-EQNM3TOF.js +15 -0
- package/dist/chunk-EQNM3TOF.js.map +1 -0
- package/dist/{chunk-WPPUOTY6.js → chunk-FUYZUGNQ.js} +2 -2
- package/dist/chunk-GSX4NK2N.js +2 -0
- package/dist/chunk-GSX4NK2N.js.map +1 -0
- package/dist/chunk-GV7S5BAX.js +2 -0
- package/dist/chunk-GV7S5BAX.js.map +1 -0
- package/dist/{chunk-7GVXCOLO.js → chunk-IFQQVDM6.js} +85 -83
- package/dist/chunk-IFQQVDM6.js.map +1 -0
- package/dist/{chunk-QW2OYR3N.js → chunk-K6MC66D6.js} +2 -2
- package/dist/chunk-SZDACK6O.js +2 -0
- package/dist/chunk-SZDACK6O.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{config-QXWKEQON.js → config-RWHSEE4N.js} +2 -2
- package/dist/config-mutator-JKCNCY2F.js +2 -0
- package/dist/doctor-KWN7NUFQ.js +2 -0
- package/dist/index.js +1 -1
- package/dist/program-JEKM7SCS.js +2 -0
- package/dist/{registry-HM4ELSXS.js → registry-EGKDMVSP.js} +2 -2
- package/dist/runner-BFYDWPUO.js +2 -0
- package/dist/scheduler-ED4FCI2Y.js +2 -0
- package/dist/scheduler-ED4FCI2Y.js.map +1 -0
- package/dist/store-I3HEWVLQ.js +2 -0
- package/dist/store-I3HEWVLQ.js.map +1 -0
- package/dist/types-Y6ZCZ52Z.js +2 -0
- package/dist/types-Y6ZCZ52Z.js.map +1 -0
- package/dist/web/workflow-editor.global.js +12 -10
- package/dist/web/workflow-editor.global.js.map +1 -1
- package/package.json +1 -1
- package/dist/board-dashboard-HXDOYGIG.js.map +0 -1
- package/dist/chunk-23AUU4S2.js.map +0 -1
- package/dist/chunk-7GVXCOLO.js.map +0 -1
- package/dist/chunk-E4ZZILAK.js +0 -15
- package/dist/chunk-E4ZZILAK.js.map +0 -1
- package/dist/chunk-MBOLXKA2.js.map +0 -1
- package/dist/chunk-WFHIIVLL.js.map +0 -1
- package/dist/config-mutator-53XGR2NT.js +0 -2
- package/dist/doctor-SEOUFHSL.js +0 -2
- package/dist/program-WWCXMRU2.js +0 -2
- package/dist/scheduler-XVFIK4XH.js +0 -2
- /package/dist/{agent-57MG4LBM.js.map → agent-I3ILI3MO.js.map} +0 -0
- /package/dist/{chunk-DLVOHCTA.js.map → chunk-AANSVC5A.js.map} +0 -0
- /package/dist/{chunk-TC3BSUP7.js.map → chunk-AGINLNAW.js.map} +0 -0
- /package/dist/{chunk-6B74TO2J.js.map → chunk-BLRLUF2H.js.map} +0 -0
- /package/dist/{chunk-WPPUOTY6.js.map → chunk-FUYZUGNQ.js.map} +0 -0
- /package/dist/{chunk-QW2OYR3N.js.map → chunk-K6MC66D6.js.map} +0 -0
- /package/dist/{config-QXWKEQON.js.map → config-RWHSEE4N.js.map} +0 -0
- /package/dist/{config-mutator-53XGR2NT.js.map → config-mutator-JKCNCY2F.js.map} +0 -0
- /package/dist/{doctor-SEOUFHSL.js.map → doctor-KWN7NUFQ.js.map} +0 -0
- /package/dist/{program-WWCXMRU2.js.map → program-JEKM7SCS.js.map} +0 -0
- /package/dist/{registry-HM4ELSXS.js.map → registry-EGKDMVSP.js.map} +0 -0
- /package/dist/{scheduler-XVFIK4XH.js.map → runner-BFYDWPUO.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{c as m,d as $}from"./chunk-
|
|
1
|
+
import{c as m,d as $}from"./chunk-5GDCJ2SF.js";import{readFileSync as S,writeFileSync as x,existsSync as b}from"fs";import{resolve as f}from"path";function P(r){if(r)return f(r);let e=[f(process.cwd(),"agentx.json"),f(process.cwd(),".agentx/config.json")];for(let n of e)if(b(n))return n;return e[0]}function w(r){return JSON.parse(JSON.stringify(r))}async function v(r){try{let e=await fetch(`${r.replace(/\/$/,"")}/reload`,{method:"POST",signal:AbortSignal.timeout(3e3)});return e.ok?{ok:!0}:{ok:!1,reason:`HTTP ${e.status}`}}catch(e){return{ok:!1,reason:e?.cause?.code||e?.message||"unreachable"}}}async function T(r,e={}){let{validate:n=!0,dryRun:t=!1,reload:s=!0,configPath:u,daemonUrl:c}=e,o=P(u);if(!b(o))return{success:!1,path:o,error:`Config not found at ${o}. Run \`agentx init\` first.`};let d;try{d=S(o,"utf-8")}catch(a){return{success:!1,path:o,error:`Cannot read ${o}: ${a.message}`}}let g;try{g=JSON.parse(d)}catch(a){return{success:!1,path:o,error:`Invalid JSON in ${o}: ${a.message}`}}let i=w(g);try{await r(i)}catch(a){return{success:!1,path:o,error:`Mutator threw: ${a.message}`}}if(n){let a=$(i),l=m.safeParse(a);if(!l.success){let k=l.error.issues.map(y=>` ${y.path.join(".")||"<root>"}: ${y.message}`).join(`
|
|
2
2
|
`);return{success:!1,path:o,error:`Validation failed:
|
|
3
3
|
${k}`,after:i}}}if(t)return{success:!0,path:o,after:i,dryRun:!0};try{x(o,JSON.stringify(i,null,2)+`
|
|
4
4
|
`)}catch(a){return{success:!1,path:o,error:`Write failed: ${a.message}`,after:i}}let p=!1,h;if(s){let a=c||O(i),l=await v(a);l.ok?p=!0:h=l.reason}return{success:!0,path:o,after:i,reloaded:p,reloadSkipped:h}}function O(r){let e=r?.node?.bind;if(!e)return"http://127.0.0.1:18800";let[n,t]=e.split(":");return`http://${n==="0.0.0.0"||n==="::"?"127.0.0.1":n}:${t}`}function J(r,e,n){let t=e.split("."),s=r;for(let u=0;u<t.length-1;u++){let c=t[u];(s[c]===void 0||s[c]===null)&&(s[c]={}),s=s[c]}s[t[t.length-1]]=n}function N(r,e){let n=e.split("."),t=r;for(let s of n){if(t==null)return;t=t[s]}return t}function j(r,e){let n=e.split("."),t=r;for(let s=0;s<n.length-1;s++){if(t==null)return;t=t[n[s]]}t!=null&&delete t[n[n.length-1]]}export{T as a,J as b,N as c,j as d};
|
|
5
|
-
//# sourceMappingURL=chunk-
|
|
5
|
+
//# sourceMappingURL=chunk-AANSVC5A.js.map
|
|
@@ -48,7 +48,7 @@ The "modified" field is optional and can contain updated values to pass forward.
|
|
|
48
48
|
... (output truncated)`:i;return s.exitCode!==0?{tool_use_id:e.id,content:`Command exited with code ${s.exitCode}:
|
|
49
49
|
${l}`,is_error:!0}:{tool_use_id:e.id,content:l||"(no output)"}}async editFile(e){let t=String(e.input.path||""),o=e.input.edits,n=pe.resolve(this.cwd,t);if(!o||o.length===0)return{tool_use_id:e.id,content:"No edits provided.",is_error:!0};let s=await N.checkFileWrite(t);if(s==="deny")return{tool_use_id:e.id,content:`File write blocked by permissions: ${t}`,is_error:!0};if(s==="skip")return{tool_use_id:e.id,content:`File write skipped (plan mode): ${t}`};if(d.has("pre:file-write")){let a=await d.execute("pre:file-write",{event:"pre:file-write",file:n,cwd:this.cwd});if(a.blocked)return{tool_use_id:e.id,content:a.message||`File edit blocked by pre:file-write hook: ${t}`,is_error:!0}}let i=await ee.readFile(n,"utf8"),l=[];for(let a of o)i.includes(a.old_text)?(i=i.replace(a.old_text,a.new_text),l.push(`Replaced: "${a.old_text.slice(0,40)}..."`)):l.push(`Not found: "${a.old_text.slice(0,40)}..."`);return this.options.dryRun||await ee.writeFile(n,i,"utf8"),d.has("post:file-write")&&await d.execute("post:file-write",{event:"post:file-write",file:n,fileContent:i,cwd:this.cwd}),{tool_use_id:e.id,content:`Edited ${t}:
|
|
50
50
|
${l.join(`
|
|
51
|
-
`)}`}}async createFiles(e){let t=e.input,o=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${o.length} file(s) for creation.`,files:o}}async spawnAgent(e){let t=String(e.input.agent_id||""),o=String(e.input.prompt||""),n=Number(e.input.timeout_seconds)||300;if(!t||!o)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-WV7QKQ3L.js"),{getGlobalRegistry:i}=await import("./registry-
|
|
51
|
+
`)}`}}async createFiles(e){let t=e.input,o=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${o.length} file(s) for creation.`,files:o}}async spawnAgent(e){let t=String(e.input.agent_id||""),o=String(e.input.prompt||""),n=Number(e.input.timeout_seconds)||300;if(!t||!o)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-WV7QKQ3L.js"),{getGlobalRegistry:i}=await import("./registry-EGKDMVSP.js"),l=i();if(!l)return{tool_use_id:e.id,content:"Sub-agent spawning requires the daemon to be running.",is_error:!0};let p=await new s(l).spawn({targetAgentId:t,prompt:o,parentAgentId:"orchestrator",timeout:n*1e3});return p.success?{tool_use_id:e.id,content:`Sub-agent "${t}" completed (${Math.round(p.duration/1e3)}s):
|
|
52
52
|
|
|
53
53
|
${p.content}`}:{tool_use_id:e.id,content:`Sub-agent "${t}" failed: ${p.error}`,is_error:!0}}catch(s){return{tool_use_id:e.id,content:`Failed to spawn sub-agent: ${s.message}`,is_error:!0}}}async askUser(e){let t=String(e.input.question||""),o=e.input.options,n=t;return o?.length&&(n+=`
|
|
54
54
|
Options: ${o.join(", ")}`),{tool_use_id:e.id,content:"Question sent to user.",followUp:n}}};async function Re(r){let{provider:e,systemPrompt:t,messages:o,providerOptions:n,cwd:s,maxIterations:i=20,enabledTools:l,interactive:a=!0,overwrite:p=!1,dryRun:c=!1,onProgress:u}=r;if(!e.generateRaw)return et(r);let y=new te(s,{interactive:a,overwrite:p,dryRun:c}),k=he(l),A=o.filter(v=>v.role!=="system").map(v=>({role:v.role,content:v.content})),F=[],C=0,T="",I,O=0;for(;O<i;){O++,u?.({type:"iteration_start",iteration:O}),x.step(O,`Agentic loop iteration (${k.length} tools available)`);let v;try{v=await e.generateRaw(A,t,k,n)}catch(w){if(w.message?.includes("not available"))return et(r);throw w}C+=v.usage.input_tokens+v.usage.output_tokens;for(let w of v.content)w.type==="text"&&(T+=w.text,u?.({type:"text_delta",text:w.text}));if(v.stop_reason==="end_turn"||v.stop_reason==="max_tokens")break;if(v.stop_reason==="tool_use"){let w=v.content.filter(_=>_.type==="tool_use");if(w.length===0)break;A.push({role:"assistant",content:v.content});let E=[];for(let _ of w){u?.({type:"tool_call",name:_.name,id:_.id,input:_.input}),x.step(O,`Tool call: ${_.name}`);let b=await y.execute({name:_.name,id:_.id,input:_.input});u?.({type:"tool_result",name:_.name,id:_.id,content:b.content.slice(0,200),is_error:b.is_error}),b.files?.length&&(F.push(...b.files),u?.({type:"files_created",files:b.files})),b.followUp&&(I=b.followUp),E.push({type:"tool_result",tool_use_id:b.tool_use_id,content:b.content,is_error:b.is_error})}if(A.push({role:"user",content:E}),I)break;continue}break}return u?.({type:"complete",iterations:O,totalTokens:C}),{files:F,content:T,followUp:I,tokensUsed:C,iterations:O}}async function et(r){let{provider:e,systemPrompt:t,messages:o,providerOptions:n,maxIterations:s=5}=r,l=[{role:"system",content:t+`
|
|
@@ -115,4 +115,4 @@ ${r.projectInstructions}`),r.memoryContext&&o.push(r.memoryContext),o.push(`# Ou
|
|
|
115
115
|
Generate output appropriate for: ${e}. Use the \`create_files\` tool to output all files.`),o.join(`
|
|
116
116
|
|
|
117
117
|
`)}export{je as a,$t as b,Mt as c,Ue as d,De as e,Ne as f,Le as g,_e as h,V as i,Se as j,re as k,Q as l,ut as m,X as n,ht as o,d as p,ze as q,Ke as r,Pe as s,ie as t,N as u,Z as v,Xe as w,Te as x,Ce as y,te as z,tt as A,Cn as B,Tn as C};
|
|
118
|
-
//# sourceMappingURL=chunk-
|
|
118
|
+
//# sourceMappingURL=chunk-AGINLNAW.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{f as Dt,g as Nt,i as Lt,j as Bt,k as Gt,q as Ft}from"./chunk-E4ZZILAK.js";import{b as Ut}from"./chunk-ZE2YFX4K.js";import{A as Pt,B as Et,h as xt,n as At,o as Ye}from"./chunk-TC3BSUP7.js";import{b as St}from"./chunk-SFQUP3BP.js";import{a as E,b as Ot,c as F,d as H,f as Qe}from"./chunk-QW2OYR3N.js";import{e as Ve,f as jt}from"./chunk-MBOLXKA2.js";import{e as Mt,f as X,g as Rt,i as _t}from"./chunk-23AUU4S2.js";import{a as Ct}from"./chunk-5F3J55LG.js";import{c as _}from"./chunk-4MREHZP5.js";import{a as pe}from"./chunk-VJUTQAPJ.js";import{a as It,d as Tt}from"./chunk-DJEZ2HVU.js";import{e as z}from"./chunk-DSYKYZMT.js";import{b as ue}from"./chunk-4YCH6IZV.js";var Qn={name:"agentx",version:"0.1.0"},Zn="2024-11-05",es={tools:{},elicitation:{form:{}}},ts=0;async function Ht(c,e){let t=++ts;return q({jsonrpc:"2.0",id:`elicit-${t}`,method:"elicitation/create",params:{mode:"form",message:c,requestedSchema:e}}),new Promise(n=>{se.set(`elicit-${t}`,s=>{s?.action==="accept"&&s.content?n(s.content):n(null)}),setTimeout(()=>{se.has(`elicit-${t}`)&&(se.delete(`elicit-${t}`),n(null))},6e4)})}var se=new Map,P=process.env.AGENTX_DAEMON_URL||"http://localhost:19900",ns=/\x1B\[[0-9;]*[A-Za-z]/g;function Z(c){return c.replace(ns,"")}var ss=[{name:"agentx_generate",description:"Generate code, components, pages, APIs, documents, tests, workflows, schemas, emails, diagrams, and more using AI. Understands the project's tech stack, schemas, and skills automatically.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what to generate (e.g., 'a responsive pricing card', 'REST API for users', 'GitHub Actions CI pipeline')"},type:{type:"string",description:"Output type: component, page, api, website, document, script, config, skill, media, report, test, workflow, schema, email, diagram, auto",default:"auto"},output_dir:{type:"string",description:"Optional output directory (relative to project root)"},cwd:{type:"string",description:"Project working directory (defaults to current directory)"}},required:["task"]}},{name:"agentx_inspect",description:"Analyze a project and return its tech stack, frameworks, databases, schemas, installed skills, and dependencies. Use this to understand a project before generating code.",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Project working directory (defaults to current directory)"}}}},{name:"agentx_skill_match",description:"Find installed skills that are relevant to a given task description. Returns matched skills with relevance scores.",inputSchema:{type:"object",properties:{task:{type:"string",description:"The task to match skills against"},cwd:{type:"string",description:"Project working directory"}},required:["task"]}},{name:"agentx_detect_output_type",description:"Auto-detect the best output type for a given task description based on keyword analysis.",inputSchema:{type:"object",properties:{task:{type:"string",description:"The task description to analyze"}},required:["task"]}},{name:"agentx_send",description:"Low-level outbound send when you ALREADY have a channel-native chatId (Telegram numeric chat id, GitLab 'group/project:issue:123', WhatsApp '+phone@s.whatsapp.net'). For sending to another agent by name, use agentx_send_agent instead. For sending to a human contact by name, use agentx_send_contact instead.",inputSchema:{type:"object",properties:{channel:{type:"string",description:"Target channel: telegram, whatsapp, gitlab, discord"},chatId:{type:"string",description:'Chat ID. Telegram: numeric ("-1001234567890"). GitLab: "group/project:issue:123". WhatsApp: "+phone@s.whatsapp.net".'},text:{type:"string",description:"Message text to send"},agentId:{type:"string",description:"Agent ID to send as (determines bot account on Telegram, GitLab token, etc.)"}},required:["channel","chatId","text"]}},{name:"agentx_send_agent",description:"Send a message to ANOTHER AGENT by exact agentId \u2014 uses the AgentX A2A mesh (or local registry when the agent lives on this daemon). This is the deterministic path for agent-to-agent communication; it never falls through to a contact lookup, so an unknown agentId returns 404 with the list of known agents instead of silently sending to a similarly-named human. Use this when the target is a registered agent.",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Exact agentId of the target agent (e.g. 'clawd', 'atlas'). Must match an agent in this daemon's registry or in a healthy mesh peer's directory."},text:{type:"string",description:"Message to send to the target agent"},senderAgentId:{type:"string",description:"Optional. The agentId on whose behalf this call is being made. Recorded in route_traces and (with A2A protocolVersion >= 2) validated by the receiving daemon."}},required:["agentId","text"]}},{name:"agentx_recent",description:"Read the most recent messages from a chat across ALL agents that have sessions for it. Returns inbound + each agent's replies in chronological order, so you can see what's actually been said in a Telegram chat / GitLab thread / WhatsApp DM regardless of which agent recorded it. Use this BEFORE speculating about what was sent \u2014 the cx/devops/marketing thread on 2026-04-29 about a Nadia/CX bot mixup would have been resolved in one call instead of three agents speculating. Bounded by sinceISO (default: last 24h) and limit (default: 30, max: 200).",inputSchema:{type:"object",properties:{channel:{type:"string",description:"Channel name. Examples: telegram, whatsapp, gitlab, github, discord, cron, api, a2a."},chatId:{type:"string",description:'Channel-native chat id. Telegram: numeric (e.g. "1816212449" for a DM, "-1001234567890" for a group). GitLab: "group/project:issue:123". WhatsApp: "+phone@s.whatsapp.net".'},sinceISO:{type:"string",description:"Optional ISO timestamp lower bound. Defaults to 24h ago."},limit:{type:"number",description:"Optional cap on returned messages. Default 30, max 200."}},required:["channel","chatId"]}},{name:"agentx_send_contact",description:"Send a message to a HUMAN CONTACT by name. Resolves through .agentx/contacts.json (id \u2192 exact alias \u2192 fuzzy substring). Refuses fuzzy matches without confirmed:true so the agent must ask the user to disambiguate before sending. Refuses when the name also matches a registered agent (use agentx_send_agent for those). Use this when the target is a person, not a bot.",inputSchema:{type:"object",properties:{contactName:{type:"string",description:"Free-form contact name. Tried as id first, then alias, then fuzzy substring."},text:{type:"string",description:"Message to send to the contact"},channel:{type:"string",description:"Optional explicit channel (telegram | whatsapp | gitlab | discord). Defaults to the first channel configured for the contact."},confirmed:{type:"boolean",description:"Pass true ONLY after the user has confirmed a fuzzy match. Without it, fuzzy matches return 409 with the candidate so you can ask the user."},agentId:{type:"string",description:"Optional agent identity used for the outbound send (determines bot account / token)."}},required:["contactName","text"]}},{name:"agentx_task",description:"Send a task to a specific agent on the daemon. The agent processes it and returns a response. Use to delegate work to specialized agents.",inputSchema:{type:"object",properties:{agent:{type:"string",description:"Agent ID to send the task to"},message:{type:"string",description:"Task message for the agent"}},required:["agent","message"]}},{name:"agentx_agents",description:"List all agents registered on the daemon with their status (active tasks, total tasks, errors, tier).",inputSchema:{type:"object",properties:{}}},{name:"agentx_health",description:"Get the daemon health status including node info, agents, crons, mesh peers, and uptime.",inputSchema:{type:"object",properties:{}}},{name:"agentx_crons",description:"List cron jobs and their health. Shows healthy, failing, disabled counts and per-job status with consecutive error counts.",inputSchema:{type:"object",properties:{}}},{name:"agentx_debug",description:"Toggle debug mode on the daemon. Enable verbose logging for specific categories (webhook, agent, channel, cron, mesh, context, memory, all) or disable it.",inputSchema:{type:"object",properties:{action:{type:"string",description:'"on", "off", or "status"',default:"status"},categories:{type:"string",description:'Comma-separated categories to enable (e.g. "webhook,agent"). Only used with action=on.'}}}},{name:"agentx_wiki_query",description:"Query the agentx institutional wiki: a cross-agent knowledge base organized by article type (person, project, place, concept, event, decision, pattern). Use this BEFORE grep/memory-search when the question is about who / what happened / what we decided / how we do something. The query walks the catalog + wikilink graph and returns a synthesized answer with citations.",inputSchema:{type:"object",properties:{question:{type:"string",description:"The question to answer from the wiki, in natural language."},agent:{type:"string",description:"Which agent's wiki to query (default: first agent with a catalog). Each agent has its own wiki dir under .agentx/wiki/agents/<id>/"},wiki_dir:{type:"string",description:"Wiki root dir (default: <cwd>/.agentx/wiki)."},max_hops:{type:"number",description:"Wikilink hops from candidates (default 2, max 3).",default:2}},required:["question"]}},{name:"agentx_wiki_patch",description:"Edit a single wiki article via an LLM-applied instruction and write the result. Use this for targeted fixes, additions, or clarifications to an existing article when you already know what's wrong. For brand-new articles, use `agentx_wiki_interview` instead.",inputSchema:{type:"object",properties:{agent:{type:"string",description:"Agent ID whose wiki owns the article (required)."},title_or_path:{type:"string",description:"Article title (case-insensitive) or relative path like 'people/anis.md'."},instruction:{type:"string",description:"Plain-English edit instruction (e.g. 'Add a section on the KSA Supabase rollout'). The LLM makes the minimum edit that satisfies it."},model:{type:"string",description:"Claude model for the patch (default: sonnet).",default:"sonnet"},dry_run:{type:"boolean",description:"Preview the patched body without writing.",default:!1}},required:["agent","title_or_path","instruction"]}},{name:"agentx_wiki_interview",description:"Run a scripted wiki interview \u2014 synthesize ONE typed article from a list of Q&A answers, and save it. Non-interactive: caller supplies the answers upfront. Use for capturing tacit knowledge (person/project/decision/pattern/...) that never hit a channel. For editing an existing article, use `agentx_wiki_patch`.",inputSchema:{type:"object",properties:{agent:{type:"string",description:"Agent ID that will own the new article (required)."},topic:{type:"string",description:"What the article is about \u2014 e.g. 'MTGL deployment procedure', 'Yousef Al-Fahad', 'Hackathonat KSA migration'."},type:{type:"string",description:"Article type: person | project | place | concept | event | decision | pattern"},answers:{type:"array",description:"Answers to the type-specific question bank (one per question, in order). Empty string = skip that question. Final entry is typically 'save'.",items:{type:"string"}},model:{type:"string",description:"Synthesis model (default: sonnet).",default:"sonnet"},commit:{type:"boolean",description:"Write the article (true) or just preview (false).",default:!0}},required:["agent","topic","type","answers"]}},{name:"agentx_graph_review",description:"Triage pending intent-graph classifications via the configured review agent. The review agent sees each pending classification, may call `wiki query` for institutional context, and decides approve/reject/skip. Structural changes (new org, new unit) gate here; leaf additions auto-approve without this step.",inputSchema:{type:"object",properties:{max:{type:"number",description:"Cap reviews this run (default 20).",default:20},dry_run:{type:"boolean",description:"Show decisions but don't apply approvals/rejections.",default:!1},agent:{type:"string",description:"Override the review agent (defaults to graph.reviewAgent or graph.draftAgent)."}}}}];async function is(c,e){let t=e.cwd||process.cwd();switch(c){case"agentx_generate":{let n=e.task,s=e.type||"auto",i=e.output_dir,r=await Et({task:n,outputType:s,outputDir:i,cwd:t,overwrite:!0,dryRun:!1,context7:!0,interactive:!1,maxSteps:5}),o=[];return r.content&&o.push(r.content),r.files.written.length&&o.push(`
|
|
1
|
+
import{f as Dt,g as Nt,i as Lt,j as Bt,k as Gt,q as Ft}from"./chunk-EQNM3TOF.js";import{b as Ut}from"./chunk-ZE2YFX4K.js";import{A as Pt,B as Et,h as xt,n as At,o as Ye}from"./chunk-AGINLNAW.js";import{b as St}from"./chunk-SFQUP3BP.js";import{a as E,b as Ot,c as F,d as H,f as Qe}from"./chunk-K6MC66D6.js";import{e as Ve,f as jt}from"./chunk-5GDCJ2SF.js";import{e as Mt,f as X,g as Rt,i as _t}from"./chunk-5XZ73VM4.js";import{a as Ct}from"./chunk-5F3J55LG.js";import{c as _}from"./chunk-4MREHZP5.js";import{a as pe}from"./chunk-VJUTQAPJ.js";import{a as It,d as Tt}from"./chunk-DJEZ2HVU.js";import{e as z}from"./chunk-DSYKYZMT.js";import{b as ue}from"./chunk-4YCH6IZV.js";var Qn={name:"agentx",version:"0.1.0"},Zn="2024-11-05",es={tools:{},elicitation:{form:{}}},ts=0;async function Ht(c,e){let t=++ts;return q({jsonrpc:"2.0",id:`elicit-${t}`,method:"elicitation/create",params:{mode:"form",message:c,requestedSchema:e}}),new Promise(n=>{se.set(`elicit-${t}`,s=>{s?.action==="accept"&&s.content?n(s.content):n(null)}),setTimeout(()=>{se.has(`elicit-${t}`)&&(se.delete(`elicit-${t}`),n(null))},6e4)})}var se=new Map,P=process.env.AGENTX_DAEMON_URL||"http://localhost:19900",ns=/\x1B\[[0-9;]*[A-Za-z]/g;function Z(c){return c.replace(ns,"")}var ss=[{name:"agentx_generate",description:"Generate code, components, pages, APIs, documents, tests, workflows, schemas, emails, diagrams, and more using AI. Understands the project's tech stack, schemas, and skills automatically.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what to generate (e.g., 'a responsive pricing card', 'REST API for users', 'GitHub Actions CI pipeline')"},type:{type:"string",description:"Output type: component, page, api, website, document, script, config, skill, media, report, test, workflow, schema, email, diagram, auto",default:"auto"},output_dir:{type:"string",description:"Optional output directory (relative to project root)"},cwd:{type:"string",description:"Project working directory (defaults to current directory)"}},required:["task"]}},{name:"agentx_inspect",description:"Analyze a project and return its tech stack, frameworks, databases, schemas, installed skills, and dependencies. Use this to understand a project before generating code.",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Project working directory (defaults to current directory)"}}}},{name:"agentx_skill_match",description:"Find installed skills that are relevant to a given task description. Returns matched skills with relevance scores.",inputSchema:{type:"object",properties:{task:{type:"string",description:"The task to match skills against"},cwd:{type:"string",description:"Project working directory"}},required:["task"]}},{name:"agentx_detect_output_type",description:"Auto-detect the best output type for a given task description based on keyword analysis.",inputSchema:{type:"object",properties:{task:{type:"string",description:"The task description to analyze"}},required:["task"]}},{name:"agentx_send",description:"Low-level outbound send when you ALREADY have a channel-native chatId (Telegram numeric chat id, GitLab 'group/project:issue:123', WhatsApp '+phone@s.whatsapp.net'). For sending to another agent by name, use agentx_send_agent instead. For sending to a human contact by name, use agentx_send_contact instead.",inputSchema:{type:"object",properties:{channel:{type:"string",description:"Target channel: telegram, whatsapp, gitlab, discord"},chatId:{type:"string",description:'Chat ID. Telegram: numeric ("-1001234567890"). GitLab: "group/project:issue:123". WhatsApp: "+phone@s.whatsapp.net".'},text:{type:"string",description:"Message text to send"},agentId:{type:"string",description:"Agent ID to send as (determines bot account on Telegram, GitLab token, etc.)"}},required:["channel","chatId","text"]}},{name:"agentx_send_agent",description:"Send a message to ANOTHER AGENT by exact agentId \u2014 uses the AgentX A2A mesh (or local registry when the agent lives on this daemon). This is the deterministic path for agent-to-agent communication; it never falls through to a contact lookup, so an unknown agentId returns 404 with the list of known agents instead of silently sending to a similarly-named human. Use this when the target is a registered agent.",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Exact agentId of the target agent (e.g. 'clawd', 'atlas'). Must match an agent in this daemon's registry or in a healthy mesh peer's directory."},text:{type:"string",description:"Message to send to the target agent"},senderAgentId:{type:"string",description:"Optional. The agentId on whose behalf this call is being made. Recorded in route_traces and (with A2A protocolVersion >= 2) validated by the receiving daemon."}},required:["agentId","text"]}},{name:"agentx_recent",description:"Read the most recent messages from a chat across ALL agents that have sessions for it. Returns inbound + each agent's replies in chronological order, so you can see what's actually been said in a Telegram chat / GitLab thread / WhatsApp DM regardless of which agent recorded it. Use this BEFORE speculating about what was sent \u2014 the cx/devops/marketing thread on 2026-04-29 about a Nadia/CX bot mixup would have been resolved in one call instead of three agents speculating. Bounded by sinceISO (default: last 24h) and limit (default: 30, max: 200).",inputSchema:{type:"object",properties:{channel:{type:"string",description:"Channel name. Examples: telegram, whatsapp, gitlab, github, discord, cron, api, a2a."},chatId:{type:"string",description:'Channel-native chat id. Telegram: numeric (e.g. "1816212449" for a DM, "-1001234567890" for a group). GitLab: "group/project:issue:123". WhatsApp: "+phone@s.whatsapp.net".'},sinceISO:{type:"string",description:"Optional ISO timestamp lower bound. Defaults to 24h ago."},limit:{type:"number",description:"Optional cap on returned messages. Default 30, max 200."}},required:["channel","chatId"]}},{name:"agentx_send_contact",description:"Send a message to a HUMAN CONTACT by name. Resolves through .agentx/contacts.json (id \u2192 exact alias \u2192 fuzzy substring). Refuses fuzzy matches without confirmed:true so the agent must ask the user to disambiguate before sending. Refuses when the name also matches a registered agent (use agentx_send_agent for those). Use this when the target is a person, not a bot.",inputSchema:{type:"object",properties:{contactName:{type:"string",description:"Free-form contact name. Tried as id first, then alias, then fuzzy substring."},text:{type:"string",description:"Message to send to the contact"},channel:{type:"string",description:"Optional explicit channel (telegram | whatsapp | gitlab | discord). Defaults to the first channel configured for the contact."},confirmed:{type:"boolean",description:"Pass true ONLY after the user has confirmed a fuzzy match. Without it, fuzzy matches return 409 with the candidate so you can ask the user."},agentId:{type:"string",description:"Optional agent identity used for the outbound send (determines bot account / token)."}},required:["contactName","text"]}},{name:"agentx_task",description:"Send a task to a specific agent on the daemon. The agent processes it and returns a response. Use to delegate work to specialized agents.",inputSchema:{type:"object",properties:{agent:{type:"string",description:"Agent ID to send the task to"},message:{type:"string",description:"Task message for the agent"}},required:["agent","message"]}},{name:"agentx_agents",description:"List all agents registered on the daemon with their status (active tasks, total tasks, errors, tier).",inputSchema:{type:"object",properties:{}}},{name:"agentx_health",description:"Get the daemon health status including node info, agents, crons, mesh peers, and uptime.",inputSchema:{type:"object",properties:{}}},{name:"agentx_crons",description:"List cron jobs and their health. Shows healthy, failing, disabled counts and per-job status with consecutive error counts.",inputSchema:{type:"object",properties:{}}},{name:"agentx_debug",description:"Toggle debug mode on the daemon. Enable verbose logging for specific categories (webhook, agent, channel, cron, mesh, context, memory, all) or disable it.",inputSchema:{type:"object",properties:{action:{type:"string",description:'"on", "off", or "status"',default:"status"},categories:{type:"string",description:'Comma-separated categories to enable (e.g. "webhook,agent"). Only used with action=on.'}}}},{name:"agentx_wiki_query",description:"Query the agentx institutional wiki: a cross-agent knowledge base organized by article type (person, project, place, concept, event, decision, pattern). Use this BEFORE grep/memory-search when the question is about who / what happened / what we decided / how we do something. The query walks the catalog + wikilink graph and returns a synthesized answer with citations.",inputSchema:{type:"object",properties:{question:{type:"string",description:"The question to answer from the wiki, in natural language."},agent:{type:"string",description:"Which agent's wiki to query (default: first agent with a catalog). Each agent has its own wiki dir under .agentx/wiki/agents/<id>/"},wiki_dir:{type:"string",description:"Wiki root dir (default: <cwd>/.agentx/wiki)."},max_hops:{type:"number",description:"Wikilink hops from candidates (default 2, max 3).",default:2}},required:["question"]}},{name:"agentx_wiki_patch",description:"Edit a single wiki article via an LLM-applied instruction and write the result. Use this for targeted fixes, additions, or clarifications to an existing article when you already know what's wrong. For brand-new articles, use `agentx_wiki_interview` instead.",inputSchema:{type:"object",properties:{agent:{type:"string",description:"Agent ID whose wiki owns the article (required)."},title_or_path:{type:"string",description:"Article title (case-insensitive) or relative path like 'people/anis.md'."},instruction:{type:"string",description:"Plain-English edit instruction (e.g. 'Add a section on the KSA Supabase rollout'). The LLM makes the minimum edit that satisfies it."},model:{type:"string",description:"Claude model for the patch (default: sonnet).",default:"sonnet"},dry_run:{type:"boolean",description:"Preview the patched body without writing.",default:!1}},required:["agent","title_or_path","instruction"]}},{name:"agentx_wiki_interview",description:"Run a scripted wiki interview \u2014 synthesize ONE typed article from a list of Q&A answers, and save it. Non-interactive: caller supplies the answers upfront. Use for capturing tacit knowledge (person/project/decision/pattern/...) that never hit a channel. For editing an existing article, use `agentx_wiki_patch`.",inputSchema:{type:"object",properties:{agent:{type:"string",description:"Agent ID that will own the new article (required)."},topic:{type:"string",description:"What the article is about \u2014 e.g. 'MTGL deployment procedure', 'Yousef Al-Fahad', 'Hackathonat KSA migration'."},type:{type:"string",description:"Article type: person | project | place | concept | event | decision | pattern"},answers:{type:"array",description:"Answers to the type-specific question bank (one per question, in order). Empty string = skip that question. Final entry is typically 'save'.",items:{type:"string"}},model:{type:"string",description:"Synthesis model (default: sonnet).",default:"sonnet"},commit:{type:"boolean",description:"Write the article (true) or just preview (false).",default:!0}},required:["agent","topic","type","answers"]}},{name:"agentx_graph_review",description:"Triage pending intent-graph classifications via the configured review agent. The review agent sees each pending classification, may call `wiki query` for institutional context, and decides approve/reject/skip. Structural changes (new org, new unit) gate here; leaf additions auto-approve without this step.",inputSchema:{type:"object",properties:{max:{type:"number",description:"Cap reviews this run (default 20).",default:20},dry_run:{type:"boolean",description:"Show decisions but don't apply approvals/rejections.",default:!1},agent:{type:"string",description:"Override the review agent (defaults to graph.reviewAgent or graph.draftAgent)."}}}}];async function is(c,e){let t=e.cwd||process.cwd();switch(c){case"agentx_generate":{let n=e.task,s=e.type||"auto",i=e.output_dir,r=await Et({task:n,outputType:s,outputDir:i,cwd:t,overwrite:!0,dryRun:!1,context7:!0,interactive:!1,maxSteps:5}),o=[];return r.content&&o.push(r.content),r.files.written.length&&o.push(`
|
|
2
2
|
Created ${r.files.written.length} file(s):
|
|
3
3
|
${r.files.written.map(a=>` - ${a}`).join(`
|
|
4
4
|
`)}`),r.files.skipped.length&&o.push(`
|
|
@@ -740,4 +740,4 @@ ${d.slice(-10).join(`
|
|
|
740
740
|
`),t.end()}else{let p=await this.registry.execute({agentId:o,message:g+l.content,context:{channel:"api",sender:"openai-compat"}}),u=p.error||p.content||"",f=Math.ceil(u.length/4);this.json(t,200,{id:`chatcmpl-${Date.now().toString(36)}`,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:o,choices:[{index:0,message:{role:"assistant",content:u},finish_reason:"stop"}],usage:{prompt_tokens:Math.ceil(l.content.length/4),completion_tokens:f,total_tokens:Math.ceil(l.content.length/4)+f}})}}json(e,t,n){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(n,null,2))}resolveTodayUsage(){let e=Nn();if(e==="json")return this.registry.getTodayUsage();let t=Dn(this.db);return e==="sqlite"||Object.keys(t.agents).length>0?t:this.registry.getTodayUsage()}installAgentMemorySurface(){for(let e of this.registry.list()){let t=e.workspace;if(!(!t||!he(t)))try{let n=B(t,".claude","skills");Kn(n,{recursive:!0});let s=B(n,Hn);he(s)||(qn(s,Wn),this.log(` memory-skill: installed remember.md \u2192 ${e.id}`)),this.agentMemory.syncToWorkspace(e.id,t)}catch(n){this.log(` memory-skill: ${e.id} install failed \u2014 ${n?.message??n}`)}}}installAgentMcpConfig(){for(let[e,t]of Object.entries(this.config.agents)){let n=t.workspace;if(!n||!he(n))continue;let s=t.mcp??{};try{switch(Fn(n,s)){case"installed":this.log(` mcp: installed ${Object.keys(s).length} server(s) \u2192 ${e}`);break;case"updated":this.log(` mcp: updated .mcp.json (${Object.keys(s).length} server(s)) \u2192 ${e}`);break;case"removed":this.log(` mcp: removed managed .mcp.json (config now empty) \u2192 ${e}`);break;case"skipped-operator-owned":Object.keys(s).length>0&&this.log(` mcp: ${e} has operator-owned .mcp.json \u2014 skipping (delete file or marker to let agentx manage)`);break;case"noop":break}}catch(i){this.log(` mcp: ${e} install failed \u2014 ${i?.message??i}`)}}}workspaceFor(e){for(let t of this.registry.list())if(t.id===e)return t.workspace;return null}async handleMemoryApi(e,t,n,s){let i=this.agentMemory;if(e.method==="GET"&&n==="/api/memory"){let a=s.searchParams.get("agent")||"";return a?(this.json(t,200,{agent:a,memories:i.list(a),index:i.indexMarkdown(a)}),!0):(this.json(t,400,{error:"missing agent query param"}),!0)}let r=e.method==="GET"&&n.match(/^\/api\/memory\/([^\/?]+)$/);if(r){let a=s.searchParams.get("agent")||"";if(!a)return this.json(t,400,{error:"missing agent query param"}),!0;let l=i.get(a,decodeURIComponent(r[1]));return l?(this.json(t,200,{memory:l}),!0):(this.json(t,404,{error:"no such memory"}),!0)}if(e.method==="POST"&&n==="/api/memory"){let a;try{a=await Y(e)}catch(f){return this.json(t,400,{error:"invalid JSON body",message:f.message}),!0}let l=typeof a?.agentId=="string"?a.agentId:"",d=typeof a?.type=="string"?a.type:"",g=typeof a?.name=="string"?a.name:"",h=typeof a?.description=="string"?a.description:"",p=typeof a?.body=="string"?a.body:"",u=a?.append===!0;if(!l||!d||!g||!h||!p)return this.json(t,400,{error:"required fields: agentId, type, name, description, body"}),!0;try{let f=p;if(u){let b=i.get(l,g);b&&(f=`${b.body.trimEnd()}
|
|
741
741
|
|
|
742
742
|
${p.trim()}`)}let m=i.save({agentId:l,type:d,name:g,description:h,body:f}),y=this.workspaceFor(l);if(y)try{i.syncToWorkspace(l,y)}catch{}this.json(t,200,{ok:!0,memory:m,syncedToWorkspace:!!y})}catch(f){this.json(t,400,{error:f?.message||"save failed"})}return!0}let o=e.method==="DELETE"&&n.match(/^\/api\/memory\/([^\/?]+)$/);if(o){let a=s.searchParams.get("agent")||"";if(!a)return this.json(t,400,{error:"missing agent query param"}),!0;if(!i.remove(a,decodeURIComponent(o[1])))return this.json(t,404,{error:"no such memory"}),!0;let d=this.workspaceFor(a);if(d)try{i.syncToWorkspace(a,d)}catch{}return this.json(t,200,{ok:!0}),!0}return!1}async handleTaskApi(e,t,n){let s=this.workflowDispatcher;if(!s)return!1;let{formSubmissionSchema:i}=await import("./types-ZRLHHCGB.js");if(e.method==="GET"&&(n==="/api/workflows/tasks"||n.startsWith("/api/workflows/tasks?"))){let d=new URL(e.url||"/","http://_").searchParams.get("actor")||void 0,g=d?s.tasks.listForActor(d):s.tasks.listOpen();return this.json(t,200,{tasks:g}),!0}let o=n.replace(/^\/api\/workflows\/tasks/,"").match(/^\/([^\/?]+)(\/submit)?$/);if(!o)return!1;let a=decodeURIComponent(o[1]);if(o[2]){if(e.method!=="POST")return this.json(t,405,{error:"method not allowed"}),!0;let l;try{l=await Y(e)}catch(u){return this.json(t,400,{error:"invalid JSON body",message:u.message}),!0}let d=l&&typeof l=="object"&&"submission"in l?l.submission:l,g=i.safeParse(d);if(!g.success)return this.json(t,400,{error:"invalid submission",issues:g.error.issues.map(u=>({path:u.path.join("."),message:u.message}))}),!0;let h=typeof l?.submittedBy=="string"?l.submittedBy:"anonymous",p=await s.submitTask(a,g.data,h);return p.ok?(this.json(t,200,{ok:!0,runId:p.runId}),!0):(this.json(t,400,{error:p.error,fieldErrors:p.fieldErrors}),!0)}if(e.method==="GET"){let l=s.tasks.get(a);return l?(this.json(t,200,{task:l}),!0):(this.json(t,404,{error:"task not found"}),!0)}return!1}async handleWorkflowEvent(e,t){if(!this.workflowDispatcher){this.json(t,503,{error:"workflow engine not enabled on this node"});return}let n;try{n=await Y(e)}catch(a){this.json(t,400,{error:"invalid JSON body",message:a.message});return}let s=n?.payload??n,i=s?.event,r=s?.entityRef;if(!i?.id||!r?.backend||!r?.id){this.json(t,400,{error:"missing event or entityRef"});return}let o=n?.kind;try{if(o==="trigger"&&s.trigger){let h=typeof n?.fromPeer=="string"?n.fromPeer:"unknown";this.log(`[workflows/mesh] received trigger from "${h}" source="${s.trigger.source}" chat="${s.trigger.chat??"*"}"`);let p=await this.workflowDispatcher.dispatch({trigger:s.trigger,entityRef:r,event:i,fromRemote:{peer:h}});this.log(`[workflows/mesh] dispatched broadcast: matched=${p.claimed.length} ${p.claimed.length?`(${p.claimed.map(u=>u.id).join(", ")})`:"[none \u2014 no workflow with mesh.allowRemote matched]"}`),this.json(t,202,{ok:!0,mode:"trigger-broadcast",matched:p.claimed.map(u=>u.id)});return}let d=(s.workflowId?this.workflowStore?.get(s.workflowId):null)?.nodes.find(h=>h.type.startsWith("trigger."))?.config??{},g={source:String(d.source??"hook"),project:d.filter?.project,repo:d.filter?.repo,chat:d.filter?.chat,labels:d.filter?.labels};await this.workflowDispatcher.dispatch({trigger:g,entityRef:r,event:i}),this.json(t,202,{ok:!0})}catch(a){this.log(`[workflows] /workflow/event failed: ${a.message}`),this.json(t,500,{error:a.message})}}async handleChannelSend(e,t){let n;try{n=await Y(e)}catch(a){this.json(t,400,{error:"invalid JSON body",message:a.message});return}let s=String(n?.channel??""),i=String(n?.chatId??""),r=String(n?.text??"");if(!s||!i||!r){this.json(t,400,{error:"channel, chatId, and text are required"});return}if(!this.router.getChannel(s)){this.json(t,404,{error:`channel "${s}" not hosted on this node`});return}try{let a=await this.router.sendOutbound({channel:s,chatId:i,text:r,accountId:typeof n.accountId=="string"?n.accountId:void 0,parseMode:typeof n.parseMode=="string"?n.parseMode:void 0,replyTo:typeof n.replyTo=="string"?n.replyTo:void 0});this.json(t,200,{ok:!0,messageId:a??null})}catch(a){this.log(`[mesh] /channel/send "${s}" failed: ${a.message}`),this.json(t,500,{error:a.message})}}async handleChannelChats(e,t,n={}){let s=new Set,i=[],r=[],o=(l,d)=>{let g=0;for(let h of l)!h.id||s.has(h.id)||(s.add(h.id),i.push({...h,source:d}),g++);g>0&&r.push(`${d}:${g}`)},a=this.router.getChannel(t);if(a?.listKnownChats)try{o(a.listKnownChats(),"local")}catch{}else if(a?.listChats)try{o(a.listChats().map(l=>({id:l.jid,name:l.name,kind:l.isGroup?"group":"dm"})),"local")}catch{}if(!n.localOnly&&this.mesh){let l=this.mesh.directory().filter(d=>d.healthy&&d.channels?.includes(t));await Promise.allSettled(l.map(async d=>{try{let g=await fetch(`${d.peerUrl}/channels/${encodeURIComponent(t)}/chats?local=1`,{signal:AbortSignal.timeout(5e3)});if(!g.ok)return;let h=await g.json();Array.isArray(h.chats)&&o(h.chats.map(p=>({id:p.id,name:p.name,kind:p.kind??"dm",accountId:p.accountId})),`mesh:${d.peer}`)}catch{}}))}this.json(e,200,{channel:t,source:r.join(", ")||"none",chats:i})}async handleWorkflowManualRun(e,t,n){if(!this.workflowDispatcher||!this.workflowStore){this.json(t,503,{error:"workflow engine not enabled on this node"});return}let s=this.workflowStore.get(n);if(!s){this.json(t,404,{error:`unknown workflow "${n}"`});return}let i=s.nodes.find(u=>u.type.startsWith("trigger."));if(!i){this.json(t,400,{error:`workflow "${n}" has no trigger node`});return}let r;try{r=await Y(e)}catch{r={}}let o=!!r?.force,a=r?.payload||{};if(i.type!=="trigger.manual"&&!o){this.json(t,409,{error:`workflow "${n}" trigger is "${i.type}"`,hint:'pass { "force": true } to fire anyway with a synthesized event (for testing)'});return}let l=i.config??{},d=o?String(l.source??"manual"):"manual",g=String(a.entityId||a.chatId||`manual-${Date.now().toString(36)}`),h={backend:o&&l.source?"channel":"manual",id:g},p=`manual:${n}:${g}:${Date.now()}`;try{let f=(await this.workflowDispatcher.dispatch({trigger:o?{source:d,project:l.filter?.project,repo:l.filter?.repo,chat:l.filter?.chat,labels:l.filter?.labels}:{source:"manual"},entityRef:h,event:{id:p,payload:a}})).runs[0]?.id;this.json(t,f?200:202,{ok:!0,runId:f,entityRef:h,source:d,force:o})}catch(u){this.log(`[workflows] manual run "${n}" failed: ${u.message}`),this.json(t,500,{error:u.message})}}};function Wi(c){if(typeof c!="string")return"";let e=c.trim();if(!e)return"";let t=e.match(/^[^.!?\n]+[.!?]?/),n=(t?t[0]:e).trim();return n.length>140?n.slice(0,137)+"\u2026":n}function Y(c){return new Promise((e,t)=>{let n="";c.setEncoding("utf8"),c.on("data",s=>{n+=s}),c.on("end",()=>{try{e(n?JSON.parse(n):{})}catch(s){t(s)}}),c.on("error",t)})}function Ji(c){let e=c;return e=e.replace(/```[\s\S]*?```/g,". "),e=e.replace(/`[^`]*`/g,""),e=e.replace(/\*\*(.*?)\*\*/g,"$1"),e=e.replace(/__(.*?)__/g,"$1"),e=e.replace(/\*([^*]+)\*/g,"$1"),e=e.replace(/_([^_]+)_/g,"$1"),e=e.replace(/~~(.*?)~~/g,"$1"),e=e.replace(/\[([^\]]+)\]\([^)]+\)/g,"$1"),e=e.replace(/!\[([^\]]*)\]\([^)]+\)/g,"image$1 "),e=e.replace(/^#{1,6}\s+/gm,""),e=e.replace(/^[\s]*[-*+]\s+/gm,". "),e=e.replace(/^[\s]*\d+\.\s+/gm,". "),e=e.replace(/^[-=_]{3,}$/gm,""),e=e.replace(/^>\s*/gm,""),e=e.replace(/https?:\/\/\S+/g,"link"),e=e.replace(/\/\w+(\/\w+)+/g,t=>t.split("/").filter(Boolean).join(" slash ")),e=e.replace(/&/g," and "),e=e.replace(/@/g," at "),e=e.replace(/=>/g," returns "),e=e.replace(/->/g," to "),e=e.replace(/\|/g," or "),e=e.replace(/\be\.g\./gi,"for example"),e=e.replace(/\bi\.e\./gi,"that is"),e=e.replace(/\betc\./gi,"etcetera"),e=e.replace(/\bvs\.?\b/gi,"versus"),e=e.replace(/\n{2,}/g,". "),e=e.replace(/\n/g," "),e=e.replace(/\s+/g," "),e=e.replace(/\.\s*\./g,"."),e=e.replace(/\s+([.,!?])/g,"$1"),e=e.trim().replace(/^[.,:;]+\s*/,""),e.length>800&&(e=e.slice(0,800).replace(/\s+\S*$/,"")+"..."),e}function zi(c,e){let t=["model","workspace","tier","permissionMode","mcpServers"],n=new Set,s=new Set([...Object.keys(c),...Object.keys(e)]);for(let i of s){let r=c[i],o=e[i];if(!r||!o){n.add("add/remove");continue}for(let a of t)JSON.stringify(r[a])!==JSON.stringify(o[a])&&n.add(`${i}.${a}`)}return Array.from(n).slice(0,6)}async function M(c){return new Promise((e,t)=>{let n="";c.on("data",s=>n+=s.toString()),c.on("end",()=>{try{e(n?JSON.parse(n):{})}catch{e({})}}),c.on("error",t)})}function Bc(c){typeof c=="string"&&(pe.error(c),process.exit(1)),c instanceof Error&&(pe.error(c.message),process.exit(1)),pe.error("Something went wrong. Please try again."),process.exit(1)}import $t from"path";import Vn from"fs-extra";function Hc(){let c=[];try{let e=import.meta.dirname;e&&(c.push($t.resolve(e,"..","package.json")),c.push($t.resolve(e,"package.json")))}catch{}c.push($t.resolve(process.cwd(),"package.json"));for(let e of c)try{if(Vn.existsSync(e)){let t=Vn.readJSONSync(e);if(t&&t.name)return t}}catch{}return{name:"agentix-cli",version:"0.0.0"}}export{Zi as a,ee as b,me as c,oe as d,K as e,ve as f,En as g,pt as h,Yn as i,Bc as j,Hc as k};
|
|
743
|
-
//# sourceMappingURL=chunk-
|
|
743
|
+
//# sourceMappingURL=chunk-BLRLUF2H.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import{c as V}from"./chunk-N67JZAXU.js";import{b as Y}from"./chunk-AFRHKA7B.js";import{a as Te,b as Pe}from"./chunk-EW27SCCC.js";import{a as ve,c as Se,d as $e,e as Re}from"./chunk-K6MC66D6.js";import{e as Ae}from"./chunk-CDNWCYF7.js";import{c as Ie}from"./chunk-4MREHZP5.js";import{existsSync as I,mkdirSync as kt,readdirSync as Ce,readFileSync as X,unlinkSync as Q,writeFileSync as bt}from"fs";import{resolve as R,relative as ee}from"path";import{z as u}from"zod";var it=u.enum(["trigger.channel","trigger.manual","trigger.cron","trigger.hook","trigger.form","agent","transform","branch","gateway.parallel","rule","action.send","action.createIssue","action.setLabel","action.readLabel","action.react","action.editMessage","action.logTime","action.callHTTP","action.run","userTask","subProcess","signal.emit","signal.wait","timer.boundary","checkpoint","end"]),at=u.enum(["equals","contains","matches","exists"]),dt=u.object({kind:at,params:u.record(u.unknown()).default({})}),xe=u.object({id:u.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_-]*$/,"node id must be identifier-safe"),type:it,config:u.record(u.unknown()).default({}),position:u.object({x:u.number(),y:u.number()}).optional()}),je=u.object({from:u.string(),fromPort:u.string().optional(),to:u.string(),toPort:u.string().optional(),label:u.string().optional()}),j=u.object({id:u.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"workflow id must be lower-kebab"),version:u.literal(2).default(2),title:u.string().min(1),description:u.string().optional(),state:u.enum(["active","disabled","quarantined"]).default("active"),priority:u.number().int().default(0),fanOut:u.boolean().default(!1),nodes:u.array(xe).refine(s=>s.length>0,{message:"workflow must have at least one node"}),edges:u.array(je).default([]),envAllow:u.array(u.string()).default([]),retention:u.object({maxRuns:u.number().int().positive().default(500),maxDays:u.number().int().positive().default(90)}).default({maxRuns:500,maxDays:90}),maxChildDepth:u.number().int().positive().default(5),mesh:u.object({allowRemote:u.boolean().default(!1),peers:u.array(u.string()).optional()}).default({allowRemote:!1}),created:u.string().optional(),updated:u.string().optional()});function Z(s){let e=[],t=new Map(s.nodes.map(i=>[i.id,i])),n=s.nodes.filter(i=>i.type.startsWith("trigger."));n.length===0&&e.push("workflow must have exactly one trigger.* node (found 0)"),n.length>1&&e.push(`workflow has ${n.length} trigger.* nodes; v1 supports exactly one`);for(let i of s.edges)t.has(i.from)||e.push(`edge references missing node: from="${i.from}"`),t.has(i.to)||e.push(`edge references missing node: to="${i.to}"`);let r=n[0];if(r){let i=new Map;for(let l of s.edges)i.has(l.from)||i.set(l.from,[]),i.get(l.from).push(l.to);let a=new Set,d=[r.id];for(;d.length;){let l=d.pop();if(!a.has(l)){a.add(l);for(let g of i.get(l)??[])d.push(g)}}for(let l of s.nodes)a.has(l.id)||e.push(`node "${l.id}" is unreachable from trigger "${r.id}"`);s.nodes.some(l=>a.has(l.id)&<(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 w(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]=w(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"?tn(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=w(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=w(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=w(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=w(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=w(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=w(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=w(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=w(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=w(s.node.config,s.run.context,{envAllow:s.workflow.envAllow}),t=String(e.actionId??e.id??"");if(!t)return{error:`action.run "${s.node.id}" needs actionId`};let n=e.inputs&&typeof e.inputs=="object"?e.inputs:{},{ActionStore:r}=await import("./store-I3HEWVLQ.js"),{runAction:o}=await import("./runner-BFYDWPUO.js"),i=new r().get(t);if(!i)return{error:`action.run "${s.node.id}": no action "${t}" in registry`};try{let a=await o(i,n),d={ok:a.ok,output:a.output,status:a.status,durationMs:a.durationMs};return a.errors!==void 0&&(d.errors=a.errors),a.ok?{output:d}:{output:d,error:`action "${t}" failed (status=${a.status})`}}catch(a){return{error:`action.run failed: ${a.message}`}}},Kt=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:w(e.template,t,{envAllow:s.workflow.envAllow})}:{output:{}}},qt=async s=>{let e=s.node.config,t=w(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=zt(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 zt(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 Jt=async s=>{let e=s.node.config,t=w(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]=w(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}}},Gt=D,Vt=async s=>{let e=s.node.config,t=w(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}}},Yt=async s=>{let e=s.node.config,t=w(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}}},Zt=async s=>{let e=s.node.config,t=w(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)`}},Xt=async()=>({output:{}}),Qt=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(!en(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 en(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":Gt,agent:Wt,branch:Nt,transform:Kt,"gateway.parallel":Xt,rule:Qt,"action.send":Ot,"action.createIssue":Et,"action.setLabel":_t,"action.readLabel":Ft,"action.react":Lt,"action.editMessage":Ut,"action.logTime":Mt,"action.callHTTP":Ht,"action.run":Bt,userTask:qt,subProcess:Jt,"signal.emit":Vt,"signal.wait":Yt,"timer.boundary":Zt,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 tn(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=nn(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 nn(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 rn(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 sn(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 on(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=rn(e,t,r),i=sn(n),a=on(i),d=Se(s,o,a,r);return $e(s,"workflow",d,i,r),d}var an=4e3,dn=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,an);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(!cn(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,dn);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(k=>k!==n),status:"failed"}),{kind:"done"};let m=le(f.type);return m?p.history.some(k=>k.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(k=>k!==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(k=>k!==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 k=c.output??{},v={...p.context,[n]:k},{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:k,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:ln(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 ln(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 cn(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 un(s){return{"pre:channel-message":async e=>{let t=e.msg;if(!t)return{};let n=pn(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:gn(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 pn(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 gn(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 fn(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}hn({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=mn(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 mn(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 hn(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 An,statSync as Tn}from"fs";import{resolve as he,join as Pn}from"path";import{existsSync as Ve,mkdirSync as wn,readFileSync as kn,writeFileSync as Ye}from"fs";import{dirname as bn,resolve as Ze}from"path";import{z as y}from"zod";var In=y.object({type:y.enum(["gitlab","github"]),host:y.string().optional(),project:y.string(),iid:y.number().int().positive(),url:y.string()}),vn=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:In.optional(),importedAt:y.string().optional(),createdAt:y.string(),updatedAt:y.string(),blocker:y.string().optional(),doneNote:y.string().optional()}),Sn=y.object({version:y.literal(1),items:y.array(vn).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=kn(e,"utf-8");try{return Sn.parse(JSON.parse(t))}catch(n){throw new Error(`Backlog file invalid (${e}): ${n.message}`)}}save(e){let t=this.jsonPath();wn(bn(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 Zr(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"?$n(s.source,e,t,n):s.source.type==="github"?Rn(s.source,e,t,n):{ok:!1,error:`unknown source.type ${s.source.type}`,attempts:[]}:{ok:!0,attempts:[]}}async function $n(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 k=await fetch(`${i}/api/v4/users?username=${encodeURIComponent(m)}`,{headers:{"PRIVATE-TOKEN":o}});if(!k.ok)return null;let v=await k.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 Rn(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(k=>k.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):[],k=new Set([...m,...e.addLabels??[]]);for(let v of e.removeLabels??[])k.delete(v);g=[...k]}}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 xn(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?xn(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 An(e)){let r=Pn(e,n);Tn(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 ss(s,e,t){let n=s.workSource;switch(n.type){case"backlog":return new we(n.path,e,t);case"wiki":return new ke(n.path,n.glob);case"gitlab":{let r=e.channels.gitlab;if(!r?.token)throw new Error("business.workSource.type=gitlab requires channels.gitlab.token");let o={};for(let a of r.agentMappings)a.gitlabUsernames.length&&(o[a.agentId]=a.gitlabUsernames);let i=n.projects.length?n.projects:r.routes.map(a=>a.project);return new be(r.host,r.token,i,o,t)}}}export{j as a,Z as b,b as c,U as d,wt as e,te as f,re as g,oe as h,pe as i,un as j,fn as k,z as l,Zr as m,Xe as n,ge as o,be as p,ss as q};
|
|
15
|
+
//# sourceMappingURL=chunk-EQNM3TOF.js.map
|