@agimon-ai/workflow-mcp 0.3.2 → 0.3.3

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/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./stdio-CMbfCrs1.cjs`);let t=require(`node:child_process`),n=require(`node:fs/promises`),r=require(`node:path`),i=require(`node:fs`),a=require(`@agimon-ai/foundation-process-registry`),o=require(`node:readline`),s=require(`commander`),c=require(`node:module`);var l=`0.3.1`;const u=`WORKFLOW_STATUS_FILE`,ee={readStdin:se,readStatusFile:ce,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
3
- `,`utf8`)},workflowStatusFile:process.env[u]};async function te(e=ee){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ne(n);if(!r?.conversationId)return;let i=await e.readStatusFile(t);if(!(i===null||i.trim()===`YES`)){if(!r.fullyIdle){e.writeStdout?.(re(`In-progress work is still running. Continue the execution loop until background tasks finish.`));return}ae(r.error)||r.terminationReason!==`model_stop`||await e.writeStatusFile(t)}}function ne(e){try{let t=JSON.parse(e);return oe(t)?{conversationId:typeof t.conversationId==`string`?t.conversationId:void 0,transcriptPath:ie(t.transcriptPath),terminationReason:typeof t.terminationReason==`string`?t.terminationReason:void 0,error:typeof t.error==`string`?t.error:void 0,fullyIdle:t.fullyIdle===!0}:null}catch{return null}}function re(e){return`${JSON.stringify({decision:`continue`,reason:e})}\n`}function ie(e){return typeof e==`string`&&e.trim().length>0?e:null}function ae(e){return typeof e==`string`&&e.trim().length>0}function oe(e){return typeof e==`object`&&!!e}async function se(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function ce(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}const d=new s.Command(`antigravity-stop-hook`).description(`Antigravity stop hook: reads Stop hook JSON on stdin and marks ${u} when the execution is fully idle`).action(async()=>{await te()});var f=class extends Error{constructor(e,t,n={},r){super(e,r),this.code=t,this.context=n,this.name=`WorkflowCommandError`}};const p=`check-codex-quota`;function le(t={}){let n=t.createService??(()=>new e.a),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command(p).description(`Check whether Codex quota is currently blocking new work`).action(async()=>{try{let e=await n().getQuotaStatus();if(a(`${JSON.stringify({blockingLimit:e?.blockingLimit??null,planType:e?.planType??null},null,2)}\n`),e?.blockingLimit){let t=new f(`Codex quota is blocking work at ${e.blockingLimit.limitId}/${e.blockingLimit.window}.`,`CODEX_QUOTA_BLOCKED`,{command:p,limitId:e.blockingLimit.limitId,limitName:e.blockingLimit.limitName,window:e.blockingLimit.window});i(`${t.message} [${t.code}]`,t),r(2);return}r(0)}catch(e){let t=e instanceof f?e:new f(`Error checking Codex quota.`,`CHECK_CODEX_QUOTA_COMMAND_FAILED`,{command:p},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const ue=le(),m=`WORKFLOW_STATUS_FILE`,de=new Set([`aborted`,`cancelled`,`canceled`,`completed`,`crashed`,`done`,`error`,`failed`,`killed`,`not_running`,`retired`,`settled`,`stopped`,`success`,`succeeded`]),fe={readStdin:g,readStatusFile:_,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
4
- `,`utf8`)},workflowStatusFile:process.env[m]},pe={readStdin:g,readStatusFile:_,writeSessionBinding:async(e,t)=>{await(0,n.writeFile)(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[m]};async function me(e=pe){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=_e(n);if(!r?.session_id||r.hook_event_name&&r.hook_event_name!==`SessionStart`)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function he(e=fe){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ve(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`)return;let i=xe(await e.readStatusFile(t));if(!(!r.session_id||r.session_id!==i)){if(r.background_tasks.some(ye)){e.writeStdout?.(ge(`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`));return}await e.writeStatusFile(t)}}function ge(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}function _e(e){try{let t=JSON.parse(e);return h(t)?{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function ve(e){try{let t=JSON.parse(e);if(!h(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:[],r=Array.isArray(t.session_crons)?t.session_crons:[];return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r}}catch{return null}}function ye(e){if(!h(e))return!0;let t=be(e.status);return!t||!de.has(t)}function be(e){return typeof e==`string`&&e.trim().length>0?e.trim().toLowerCase().replaceAll(`-`,`_`):null}function xe(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function h(e){return typeof e==`object`&&!!e}async function g(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function _(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}const Se=new s.Command(`claude-session-start-hook`).description(`Claude Code SessionStart hook: binds ${m} to the root Claude session id`).action(async()=>{await me()}),Ce=new s.Command(`claude-stop-hook`).description(`Claude Code stop hook: reads Stop hook JSON on stdin and marks ${m} when the root session is complete`).action(async()=>{await he()}),v=`WORKFLOW_STATUS_FILE`,y=`session_meta`,we=[`sub_agent`,`subagent`],b=new Set([`in_progress`,`inProgress`,`running`,`pending_init`,`pendingInit`]),x=new Set([`collabAgentToolCall`,`commandExecution`,`dynamicToolCall`,`imageGeneration`,`local_shell_call`,`mcpToolCall`]),S={readStdin:M,readStatusFile:N,readTranscriptHead:P,readTranscriptState:F,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
5
- `,`utf8`)},workflowStatusFile:process.env[v]},C={readStdin:M,readStatusFile:N,writeSessionBinding:async(e,t)=>{await(0,n.writeFile)(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[v]};async function w(e=C){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=O(n);if(!r?.session_id)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function T(e=S){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=k(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`||r.stop_hook_active&&!r.hasTaskRegistry)return;let i=Te(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i)return;let a=A(r.transcript_path);if(!a)return;let o=await D(e,a),s=o.sessionMeta;if(!s||r.session_id&&s.id&&r.session_id!==s.id||Ee(s.source))return;let c=r.hasTaskRegistry&&(r.background_tasks?.length??0)>0,l=r.hasTaskRegistry&&(r.session_crons?.length??0)>0;if(c||!r.hasTaskRegistry&&o.hasPendingWork){e.writeStdout?.(E(`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`));return}l||await e.writeStatusFile(t)}function E(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}async function D(e,t){return e.readTranscriptState?e.readTranscriptState(t):e.readTranscriptHead===P?F(t):{sessionMeta:await e.readTranscriptHead(t),hasPendingWork:!1}}function O(e){try{let t=JSON.parse(e);return j(t)?{session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function k(e){try{let t=JSON.parse(e);if(!j(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:void 0,r=Array.isArray(t.session_crons)?t.session_crons:void 0;return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,transcript_path:A(t.transcript_path),stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r,hasTaskRegistry:n!==void 0||r!==void 0}}catch{return null}}function A(e){return typeof e==`string`&&e.trim().length>0?e:null}function Te(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function Ee(e){return typeof e==`string`?e.startsWith(`subagent_`)||e.startsWith(`internal_`):j(e)?we.some(t=>t in e):!1}function j(e){return typeof e==`object`&&!!e}async function M(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function N(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}async function P(e){return(await F(e)).sessionMeta}async function F(e){let t=(0,i.createReadStream)(e,{encoding:`utf8`}),n=(0,o.createInterface)({input:t,crlfDelay:1/0}),r=new Set,a=new Map,s=null;try{for await(let e of n){let t=e.trim();if(t.length===0)continue;let n=De(t);n&&(s||=Oe(n),ke(n,r),Ae(n,a))}}finally{n.close(),t.destroy()}return{sessionMeta:s,hasPendingWork:r.size>0||Array.from(a.values()).some(R)}}function De(e){try{let t=JSON.parse(e);return j(t)?t:null}catch{return null}}function Oe(e){return e.type===y?e.payload??null:e.item?.type===y?e.item.payload??null:null}function ke(e,t){let n=z(e,[`payload`,`item`])??z(e,[`item`,`payload`,`item`]);if(!n)return;let r=B(n.id),i=B(n.type);!r||!i||!x.has(i)||(R(n.status)?t.add(r):t.delete(r))}function Ae(e,t){let n=z(e,[`payload`])??z(e,[`item`,`payload`]);if(!n||!B(n.type)?.startsWith(`collab_`))return;I(t,B(n.new_thread_id),n.status),I(t,B(n.receiver_thread_id),n.status);let r=z(n,[`statuses`]);if(r)for(let[e,n]of Object.entries(r))I(t,e,n)}function I(e,t,n){let r=L(n);!t||!r||e.set(t,r)}function L(e){if(typeof e==`string`)return e;if(!j(e))return null;let[t]=Object.keys(e);return t??null}function R(e){let t=typeof e==`string`?e:L(e);return t!==null&&b.has(t)}function z(e,t){let n=e;for(let e of t){if(!j(n))return null;n=n[e]}return j(n)?n:null}function B(e){return typeof e==`string`&&e.length>0?e:void 0}const je=new s.Command(`codex-session-start-hook`).description(`Codex session-start hook: binds ${v} to the first workflow Codex session id`).action(async()=>{await w()}),Me=new s.Command(`codex-stop-hook`).description(`Codex stop hook: reads stop-hook JSON on stdin and marks ${v} when the root session ends`).action(async()=>{await T()}),V=`list-crons`;function Ne(t={}){let n=t.createService??(()=>new e.s),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command(V).description(`List cron jobs scheduled via workflow-mcp`).action(async()=>{try{let e=await n().list();a(`${JSON.stringify(e,null,2)}\n`),r(0)}catch(e){let t=new f(`Error listing cron jobs.`,`LIST_CRONS_COMMAND_FAILED`,{command:V},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const Pe=Ne(),H=`list-workflow-statuses`;function U(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw new s.InvalidArgumentError(`Expected a positive integer.`);return t}function Fe(t={}){let n=t.createRegistry??(()=>new e.o),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command(H).description(`List tracked workflow runs and their current stages`).option(`--page <number>`,`Page number to return`,U,1).option(`--page-size <number>`,`Number of workflow runs per page`,U,20).option(`-w, --workspace <name>`,`Filter workflow runs by workspace`,`all`).action(async e=>{try{let t=n(),i=e.workspace===`all`?void 0:e.workspace,o=await t.listRunsPage({page:e.page,pageSize:e.pageSize,workspace:i});a(`${JSON.stringify(o,null,2)}\n`),r(0)}catch(t){let n=new f(`Error listing workflow statuses.`,`LIST_WORKFLOW_STATUSES_FAILED`,{command:H,workspace:e.workspace??`all`},{cause:t});i(`${n.message} [${n.code}]`,n),r(1)}})}const Ie=Fe(),Le=()=>{try{return(0,c.createRequire)(require(`url`).pathToFileURL(__filename).href)(`@agimon-ai/foundation-process-registry`)}catch{return null}};function W(e,t){for(let n of e){if(n==null||typeof n!=`object`&&typeof n!=`function`)continue;let e=n;for(let n of t){let t=e[n];if(typeof t==`function`)return t}}return null}function Re(e){let t=[e];if(e&&typeof e==`object`){let n=e.default;if(n&&(t.push(n),typeof n==`function`))try{t.push(new n)}catch{}}return t}async function ze(e){let t=Le();if(!t)return async()=>{};let n=Re(t),r=W(n,[`registerProcess`,`register`,`registerProcessInstance`]),i=W(n,[`unregisterProcess`,`unregister`,`releaseProcess`]);if(!r)return async()=>{};try{await Promise.resolve(r({name:e,pid:process.pid,command:process.argv.join(` `)}))}catch{return async()=>{}}return i?async()=>{await Promise.resolve(i({name:e,pid:process.pid}))}:async()=>{}}async function Be(e,t){await e.start();let n=async n=>{console.error(`\\nReceived ${n}, shutting down gracefully...`);let r=0;try{await e.stop()}catch(e){console.error(`Error during shutdown:`,e),r=1}try{await t()}catch(e){console.error(`Error during resource cleanup:`,e),r=1}process.exit(r)};process.on(`SIGINT`,()=>{n(`SIGINT`)}),process.on(`SIGTERM`,()=>{n(`SIGTERM`)})}async function Ve(e){try{await e()}catch{}}const He=new s.Command(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--service-name <name>`,`Service name for registry tracking`,`workflow-mcp`).action(async t=>{let n=await ze(t.serviceName);try{let r=t.type.toLowerCase();r===`stdio`?await Be(new e.t(e.n()),n):(console.error(`Unknown transport type: ${r}. Use: stdio`),process.exit(1))}catch(e){await Ve(n),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),G=`recover-workflow`;function Ue(t={}){let n=t.createService??(()=>new e.r),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t));return new s.Command(G).description(`Recover a failed workflow run from the local workflow registry`).argument(`<run-key>`,`Failed workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the failed workflow run`,`default`).option(`-j, --job <name>`,`Override the job to recover from`).option(`--runner <runner>`,`Override the runner key for step command maps`).option(`--dry-run`,`Print recovery steps without executing`).action(async(e,t)=>{try{r((await n().recover({dryRun:t.dryRun,job:t.job,runKey:e,runner:t.runner,workspace:t.workspace})).exitCode)}catch(n){let a=new f(`Error recovering workflow.`,`RECOVER_WORKFLOW_FAILED`,{command:G,runKey:e,workspace:t.workspace},{cause:n});i(`${a.message} [${a.code}]`,a),r(1)}})}const We=Ue(),K=`run-workflow`,q=`RUN_WORKFLOW_COMMAND_FAILED`,J=`WORKFLOW_MCP_BACKGROUND_CHILD`,Y=`workflow-mcp-background-run`;function X(e){if(!e||e.length===0)return;let t={};for(let n of e){let[e,...r]=n.split(`=`);t[e]=r.join(`=`)}return Object.keys(t).length>0?t:void 0}function Z(e){if(e.runner&&e.cliAgent&&e.runner!==e.cliAgent)throw new f(`Conflicting runner selectors.`,q,{cliAgent:e.cliAgent,command:K,runner:e.runner});return e.runner??e.cliAgent}function Ge(e,n){let r=process.argv[1];if(!r)throw new f(`Unable to determine the workflow-mcp CLI entry point for background execution.`,`RUN_WORKFLOW_BACKGROUND_LAUNCH_FAILED`,{command:K,workflow:e,workspace:n.workspace});let i=[r,`run-workflow`,e];n.job&&i.push(`--job`,n.job);for(let e of n.input??[])i.push(`--input`,e);for(let e of n.env??[])i.push(`--env`,e);n.secretFile&&i.push(`--secret-file`,n.secretFile),n.dryRun&&i.push(`--dry-run`),n.continueOnError&&i.push(`--continue-on-error`),n.keepWorktree&&i.push(`--keep-worktree`);let a=Z(n);a&&i.push(`--runner`,a),n.prompt&&i.push(`--prompt`,n.prompt),n.name&&i.push(`--name`,n.name),n.workspace&&i.push(`--workspace`,n.workspace);let o=(0,t.spawn)(process.execPath,i,{detached:!0,env:{...process.env,[J]:`1`},stdio:`ignore`});return o.unref(),o.pid}async function Ke(e,t){if(process.env[J]!==`1`)return async()=>{};let n=new a.ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH),i=(0,r.resolve)(process.cwd()),o=process.env.NODE_ENV??`development`;return(await n.registerProcess({repositoryPath:i,serviceName:Y,serviceType:`tool`,environment:o,pid:process.pid,command:process.argv.join(` `),args:process.argv.slice(2),metadata:{workflow:e,workspace:t.workspace,job:t.job,name:t.name,runner:t.runner??t.cliAgent},force:!0})).success?async()=>{let e=await n.releaseProcess({repositoryPath:i,serviceName:Y,serviceType:`tool`,environment:o,pid:process.pid,kill:!1,releasePort:!1,force:!0});if(!e.success&&!e.error?.includes(`No matching process entry`))throw Error(e.error??`Failed to release workflow background process`)}:async()=>{}}function qe(t={}){let n=t.createService??(()=>new e.i),r=t.exit??(e=>process.exit(e)),i=t.launchBackgroundRun??Ge,a=t.registerBackgroundChild??Ke,o=t.logError??((e,t)=>console.error(e,t)),c=t.logInfo??(e=>process.stdout.write(`${e}\n`));return new s.Command(K).description(`Run a GitHub Actions workflow file locally on macOS`).argument(`<workflow>`,`Path to the workflow YAML file`).option(`-j, --job <name>`,`Run only this job (and its dependencies)`).option(`-i, --input <key=value...>`,`Set workflow_dispatch input (repeatable)`).option(`-e, --env <key=value...>`,`Set extra environment variable (repeatable)`).option(`--secret-file <path>`,`Load secrets from a dotenv-style file`).option(`--dry-run`,`Print steps without executing`).option(`--continue-on-error`,`Continue past step failures`).option(`--runner <runner>`,`Preferred runner key for step command maps`).option(`--cli-agent <agent>`,`Deprecated alias for --runner`).option(`-p, --prompt <text>`,`User prompt for user_prompt trigger workflows`).option(`-n, --name <name>`,`Name for the workflow run context directory`).option(`-w, --workspace <name>`,`Workspace for workflow registry storage`).option(`--keep-worktree`,`Keep worktree on completion (skip merge and cleanup for retry)`).option(`--skip-launch`,`Skip launch-command delegation (used by inner invocations)`).option(`-b, --background`,`Run the workflow in a detached background process`).action(async(e,t)=>{try{if(t.background){let n=i(e,t);c(`Started workflow in background${n?` (PID: ${n})`:``}`),r(0);return}let o=await a(e,t),s=n();try{let n=Z(t),i=await s.run({cliAgent:t.cliAgent,runner:n,workflowPath:e,job:t.job,inputs:X(t.input),env:X(t.env),secretFile:t.secretFile,dryRun:t.dryRun,continueOnError:t.continueOnError,keepWorktree:t.keepWorktree,prompt:t.prompt,name:t.name,workspace:t.workspace,skipLaunch:t.skipLaunch});await o(),r(i.exitCode)}catch(e){throw await o(),e}}catch(n){let i=n instanceof f?n:new f(`Error executing run-workflow.`,q,{background:!!t.background,command:K,workflow:e,workspace:t.workspace},{cause:n});o(`${i.message} [${i.code}]`,i),r(1)}})}const Je=qe(),Q=`schedule-cron`;function Ye(t={}){let n=t.createService??(()=>new e.s),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(`${e}\n`));return new s.Command(Q).description(`Schedule a headless Claude Code or Codex CLI run via system crontab`).argument(`<name>`,`Unique name for this cron job`).option(`-d, --cwd <path>`,`Working directory for the CLI run`,process.cwd()).option(`-c, --cli <cli>`,`CLI to use: claude or codex`,e.c).option(`-p, --prompt <text>`,`Prompt to pass to the CLI`).option(`-f, --prompt-file <path>`,`Path to a file whose content is used as the prompt (read at cron execution time)`).option(`-s, --schedule <cron>`,`Cron expression (e.g., "*/10 * * * *")`).option(`-i, --interval-minutes <minutes>`,`Run every N minutes (alternative to --schedule)`).action(async(t,o)=>{try{let i=e.l.parse({name:t,cwd:o.cwd??process.cwd(),cli:o.cli??`claude`,prompt:o.prompt,promptFile:o.promptFile,schedule:o.schedule,intervalMinutes:o.intervalMinutes?Number.parseInt(o.intervalMinutes,10):void 0}),s=await n().schedule(i);a(`Scheduled cron job "${s.name}" with schedule: ${s.schedule}`),a(`CLI: ${s.cli} | CWD: ${s.cwd}`),s.prompt&&a(`Prompt: ${s.prompt}`),r(0)}catch(e){let n=e instanceof f?e:new f(`Error scheduling cron job.`,`SCHEDULE_CRON_COMMAND_FAILED`,{command:Q,name:t},{cause:e});i(`${n.message} [${n.code}]`,n),r(1)}})}const Xe=Ye(),$=`stop-workflow`;function Ze(t={}){let n=t.createRegistry??(()=>new e.o),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command($).description(`Request a running workflow to stop gracefully`).argument(`<run-key>`,`Running workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the running workflow`,`default`).option(`-r, --reason <text>`,`Optional stop reason to record`).action(async(e,t)=>{try{let i=n(),o=await i.requestStop(t.workspace,e,t.reason);a(`${JSON.stringify({reason:o.reason,requestedAt:o.requestedAt,runKey:e,workspace:i.resolveWorkspace(t.workspace)},null,2)}\n`),r(0)}catch(n){let a=new f(`Error requesting workflow stop.`,`STOP_WORKFLOW_FAILED`,{command:$,runKey:e,workspace:t.workspace},{cause:n});i(`${a.message} [${a.code}]`,a),r(1)}})}const Qe=Ze();async function $e(){let e=new s.Command;e.name(`workflow-mcp`).description(`MCP server for running GitHub Actions workflows locally`).version(l),e.addCommand(Pe),e.addCommand(Ie),e.addCommand(ue),e.addCommand(d),e.addCommand(Se),e.addCommand(Ce),e.addCommand(je),e.addCommand(Me),e.addCommand(He),e.addCommand(We),e.addCommand(Je),e.addCommand(Xe),e.addCommand(Qe),await e.parseAsync(process.argv)}$e().catch(e=>{console.error(`[CLI_STARTUP_ERROR] workflow-mcp startup failed:`,e),process.exit(1)});
2
+ const e=require(`./stdio-CMbfCrs1.cjs`);let t=require(`node:child_process`),n=require(`node:fs/promises`),r=require(`node:path`),i=require(`node:fs`),a=require(`@agimon-ai/foundation-process-registry`),o=require(`node:readline`),s=require(`commander`),c=require(`node:module`);var l=`0.3.2`;const u=`WORKFLOW_STATUS_FILE`,ee=(0,r.join)(process.cwd(),`tmp`,`antigravity-stop-hook.json`),d=`In-progress work is still running. Continue the execution loop until background tasks finish.`,f={readStdin:oe,readStatusFile:se,writeDebugLog:async e=>{await h(ee,e)},writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
3
+ `,`utf8`)},workflowStatusFile:process.env[u]};async function te(e=f){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ne(n);if(!r?.conversationId){await m(e,n,r,{decision:`ignore`,reason:r?`missing conversation id`:`invalid stop hook JSON`});return}let i=await e.readStatusFile(t);if(i===null||i.trim()===`YES`){await m(e,n,r,{decision:`ignore`,reason:i===null?`missing workflow status file`:`workflow status file already completed`});return}if(!r.fullyIdle){e.writeStdout?.(re(d)),await m(e,n,r,{decision:`continue`,reason:d});return}if(p(r.error)||r.terminationReason!==`model_stop`){await m(e,n,r,{decision:`ignore`,reason:p(r.error)?`stop hook reported an error`:`unsupported termination reason: ${r.terminationReason??`missing`}`});return}await e.writeStatusFile(t),await m(e,n,r,{decision:`complete`})}function ne(e){try{let t=JSON.parse(e);return ae(t)?{conversationId:typeof t.conversationId==`string`?t.conversationId:void 0,transcriptPath:ie(t.transcriptPath),terminationReason:typeof t.terminationReason==`string`?t.terminationReason:void 0,error:typeof t.error==`string`?t.error:void 0,fullyIdle:t.fullyIdle===!0}:null}catch{return null}}function re(e){return`${JSON.stringify({decision:`continue`,reason:e})}\n`}function ie(e){return typeof e==`string`&&e.trim().length>0?e:null}function p(e){return typeof e==`string`&&e.trim().length>0}function ae(e){return typeof e==`object`&&!!e}async function oe(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function se(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}async function m(e,t,n,r){try{await e.writeDebugLog?.({timestamp:new Date().toISOString(),rawInput:t,input:n,decision:r})}catch{}}async function h(e,t){let i=await ce(e);i.push(t),await(0,n.mkdir)((0,r.dirname)(e),{recursive:!0}),await(0,n.writeFile)(e,`${JSON.stringify(i.slice(-50),null,2)}\n`,`utf8`)}async function ce(e){try{let t=JSON.parse(await(0,n.readFile)(e,`utf8`));return Array.isArray(t)?t:[]}catch{return[]}}const le=new s.Command(`antigravity-stop-hook`).description(`Antigravity stop hook: reads Stop hook JSON on stdin and marks ${u} when the execution is fully idle`).action(async()=>{await te()});var g=class extends Error{constructor(e,t,n={},r){super(e,r),this.code=t,this.context=n,this.name=`WorkflowCommandError`}};const _=`check-codex-quota`;function ue(t={}){let n=t.createService??(()=>new e.a),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command(_).description(`Check whether Codex quota is currently blocking new work`).action(async()=>{try{let e=await n().getQuotaStatus();if(a(`${JSON.stringify({blockingLimit:e?.blockingLimit??null,planType:e?.planType??null},null,2)}\n`),e?.blockingLimit){let t=new g(`Codex quota is blocking work at ${e.blockingLimit.limitId}/${e.blockingLimit.window}.`,`CODEX_QUOTA_BLOCKED`,{command:_,limitId:e.blockingLimit.limitId,limitName:e.blockingLimit.limitName,window:e.blockingLimit.window});i(`${t.message} [${t.code}]`,t),r(2);return}r(0)}catch(e){let t=e instanceof g?e:new g(`Error checking Codex quota.`,`CHECK_CODEX_QUOTA_COMMAND_FAILED`,{command:_},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const de=ue(),v=`WORKFLOW_STATUS_FILE`,fe=(0,r.join)(process.cwd(),`tmp`,`claude-stop-hook.json`),y=`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`,pe=new Set([`aborted`,`cancelled`,`canceled`,`completed`,`crashed`,`done`,`error`,`failed`,`killed`,`not_running`,`retired`,`settled`,`stopped`,`success`,`succeeded`]),me={readStdin:x,readStatusFile:S,writeDebugLog:async e=>{await we(fe,e)},writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
4
+ `,`utf8`)},workflowStatusFile:process.env[v]},he={readStdin:x,readStatusFile:S,writeSessionBinding:async(e,t)=>{await(0,n.writeFile)(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[v]};async function ge(e=he){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ye(n);if(!r?.session_id||r.hook_event_name&&r.hook_event_name!==`SessionStart`)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function _e(e=me){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=be(n);if(!r){await C(e,n,null,{decision:`ignore`,reason:`invalid stop hook JSON`});return}if(r.hook_event_name&&r.hook_event_name!==`Stop`){await C(e,n,r,{decision:`ignore`,reason:`unsupported hook event: ${r.hook_event_name}`});return}let i=Ce(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i){await C(e,n,r,{decision:`ignore`,reason:`stop hook session is not bound to the workflow status file`});return}if(r.background_tasks.some(xe)){e.writeStdout?.(ve(y)),await C(e,n,r,{decision:`block`,reason:y});return}await e.writeStatusFile(t),await C(e,n,r,{decision:`complete`})}function ve(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}function ye(e){try{let t=JSON.parse(e);return b(t)?{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function be(e){try{let t=JSON.parse(e);if(!b(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:[],r=Array.isArray(t.session_crons)?t.session_crons:[];return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r}}catch{return null}}function xe(e){if(!b(e))return!0;let t=Se(e.status);return!t||!pe.has(t)}function Se(e){return typeof e==`string`&&e.trim().length>0?e.trim().toLowerCase().replaceAll(`-`,`_`):null}function Ce(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function b(e){return typeof e==`object`&&!!e}async function x(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function S(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}async function C(e,t,n,r){try{await e.writeDebugLog?.({timestamp:new Date().toISOString(),rawInput:t,input:n,decision:r})}catch{}}async function we(e,t){let i=await Te(e);i.push(t),await(0,n.mkdir)((0,r.dirname)(e),{recursive:!0}),await(0,n.writeFile)(e,`${JSON.stringify(i.slice(-50),null,2)}\n`,`utf8`)}async function Te(e){try{let t=JSON.parse(await(0,n.readFile)(e,`utf8`));return Array.isArray(t)?t:[]}catch{return[]}}const Ee=new s.Command(`claude-session-start-hook`).description(`Claude Code SessionStart hook: binds ${v} to the root Claude session id`).action(async()=>{await ge()}),De=new s.Command(`claude-stop-hook`).description(`Claude Code stop hook: reads Stop hook JSON on stdin and marks ${v} when the root session is complete`).action(async()=>{await _e()}),w=`WORKFLOW_STATUS_FILE`,T=(0,r.join)(process.cwd(),`tmp`,`codex-stop-hook.json`),E=`session_meta`,D=`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`,Oe=[`sub_agent`,`subagent`],ke=new Set([`in_progress`,`inProgress`,`running`,`pending_init`,`pendingInit`]),Ae=new Set([`collabAgentToolCall`,`commandExecution`,`dynamicToolCall`,`imageGeneration`,`local_shell_call`,`mcpToolCall`]),je={readStdin:A,readStatusFile:j,readTranscriptHead:N,readTranscriptState:P,writeDebugLog:async e=>{await Ve(T,e)},writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
5
+ `,`utf8`)},workflowStatusFile:process.env[w]},Me={readStdin:A,readStatusFile:j,writeSessionBinding:async(e,t)=>{await(0,n.writeFile)(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[w]};async function Ne(e=Me){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Le(n);if(!r?.session_id)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function Pe(e=je){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Re(n);if(!r){await M(e,n,null,{decision:`ignore`,reason:`invalid stop hook JSON`});return}if(r.hook_event_name&&r.hook_event_name!==`Stop`){await M(e,n,r,{decision:`ignore`,reason:`unsupported hook event: ${r.hook_event_name}`});return}if(r.stop_hook_active&&!r.hasTaskRegistry){await M(e,n,r,{decision:`ignore`,reason:`recursive stop hook without task registry`});return}let i=ze(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i){await M(e,n,r,{decision:`ignore`,reason:`stop hook session is not bound to the workflow status file`});return}let a=O(r.transcript_path);if(!a){await M(e,n,r,{decision:`ignore`,reason:`missing transcript path`});return}let o=await Ie(e,a),s=o.sessionMeta;if(!s){await M(e,n,r,{decision:`ignore`,reason:`missing transcript session metadata`});return}if(r.session_id&&s.id&&r.session_id!==s.id){await M(e,n,r,{decision:`ignore`,reason:`stop hook session does not match transcript session`});return}if(Be(s.source)){await M(e,n,r,{decision:`ignore`,reason:`transcript session is a subagent`});return}let c=r.hasTaskRegistry&&(r.background_tasks?.length??0)>0,l=r.hasTaskRegistry&&(r.session_crons?.length??0)>0;if(c||!r.hasTaskRegistry&&o.hasPendingWork){e.writeStdout?.(Fe(D)),await M(e,n,r,{decision:`block`,reason:D});return}if(l){await M(e,n,r,{decision:`ignore`,reason:`session crons are still scheduled`});return}await e.writeStatusFile(t),await M(e,n,r,{decision:`complete`})}function Fe(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}async function Ie(e,t){return e.readTranscriptState?e.readTranscriptState(t):e.readTranscriptHead===N?P(t):{sessionMeta:await e.readTranscriptHead(t),hasPendingWork:!1}}function Le(e){try{let t=JSON.parse(e);return k(t)?{session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function Re(e){try{let t=JSON.parse(e);if(!k(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:void 0,r=Array.isArray(t.session_crons)?t.session_crons:void 0;return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,transcript_path:O(t.transcript_path),stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r,hasTaskRegistry:n!==void 0||r!==void 0}}catch{return null}}function O(e){return typeof e==`string`&&e.trim().length>0?e:null}function ze(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function Be(e){return typeof e==`string`?e.startsWith(`subagent_`)||e.startsWith(`internal_`):k(e)?Oe.some(t=>t in e):!1}function k(e){return typeof e==`object`&&!!e}async function A(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function j(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}async function M(e,t,n,r){try{await e.writeDebugLog?.({timestamp:new Date().toISOString(),rawInput:t,input:n,decision:r})}catch{}}async function Ve(e,t){let i=await He(e);i.push(t),await(0,n.mkdir)((0,r.dirname)(e),{recursive:!0}),await(0,n.writeFile)(e,`${JSON.stringify(i.slice(-50),null,2)}\n`,`utf8`)}async function He(e){try{let t=JSON.parse(await(0,n.readFile)(e,`utf8`));return Array.isArray(t)?t:[]}catch{return[]}}async function N(e){return(await P(e)).sessionMeta}async function P(e){let t=(0,i.createReadStream)(e,{encoding:`utf8`}),n=(0,o.createInterface)({input:t,crlfDelay:1/0}),r=new Set,a=new Map,s=null;try{for await(let e of n){let t=e.trim();if(t.length===0)continue;let n=Ue(t);n&&(s||=We(n),Ge(n,r),Ke(n,a))}}finally{n.close(),t.destroy()}return{sessionMeta:s,hasPendingWork:r.size>0||Array.from(a.values()).some(L)}}function Ue(e){try{let t=JSON.parse(e);return k(t)?t:null}catch{return null}}function We(e){return e.type===E?e.payload??null:e.item?.type===E?e.item.payload??null:null}function Ge(e,t){let n=R(e,[`payload`,`item`])??R(e,[`item`,`payload`,`item`]);if(!n)return;let r=z(n.id),i=z(n.type);!r||!i||!Ae.has(i)||(L(n.status)?t.add(r):t.delete(r))}function Ke(e,t){let n=R(e,[`payload`])??R(e,[`item`,`payload`]);if(!n||!z(n.type)?.startsWith(`collab_`))return;F(t,z(n.new_thread_id),n.status),F(t,z(n.receiver_thread_id),n.status);let r=R(n,[`statuses`]);if(r)for(let[e,n]of Object.entries(r))F(t,e,n)}function F(e,t,n){let r=I(n);!t||!r||e.set(t,r)}function I(e){if(typeof e==`string`)return e;if(!k(e))return null;let[t]=Object.keys(e);return t??null}function L(e){let t=typeof e==`string`?e:I(e);return t!==null&&ke.has(t)}function R(e,t){let n=e;for(let e of t){if(!k(n))return null;n=n[e]}return k(n)?n:null}function z(e){return typeof e==`string`&&e.length>0?e:void 0}const qe=new s.Command(`codex-session-start-hook`).description(`Codex session-start hook: binds ${w} to the first workflow Codex session id`).action(async()=>{await Ne()}),Je=new s.Command(`codex-stop-hook`).description(`Codex stop hook: reads stop-hook JSON on stdin and marks ${w} when the root session ends`).action(async()=>{await Pe()}),B=`list-crons`;function Ye(t={}){let n=t.createService??(()=>new e.s),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command(B).description(`List cron jobs scheduled via workflow-mcp`).action(async()=>{try{let e=await n().list();a(`${JSON.stringify(e,null,2)}\n`),r(0)}catch(e){let t=new g(`Error listing cron jobs.`,`LIST_CRONS_COMMAND_FAILED`,{command:B},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const Xe=Ye(),V=`list-workflow-statuses`;function H(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw new s.InvalidArgumentError(`Expected a positive integer.`);return t}function Ze(t={}){let n=t.createRegistry??(()=>new e.o),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command(V).description(`List tracked workflow runs and their current stages`).option(`--page <number>`,`Page number to return`,H,1).option(`--page-size <number>`,`Number of workflow runs per page`,H,20).option(`-w, --workspace <name>`,`Filter workflow runs by workspace`,`all`).action(async e=>{try{let t=n(),i=e.workspace===`all`?void 0:e.workspace,o=await t.listRunsPage({page:e.page,pageSize:e.pageSize,workspace:i});a(`${JSON.stringify(o,null,2)}\n`),r(0)}catch(t){let n=new g(`Error listing workflow statuses.`,`LIST_WORKFLOW_STATUSES_FAILED`,{command:V,workspace:e.workspace??`all`},{cause:t});i(`${n.message} [${n.code}]`,n),r(1)}})}const Qe=Ze(),$e=()=>{try{return(0,c.createRequire)(require(`url`).pathToFileURL(__filename).href)(`@agimon-ai/foundation-process-registry`)}catch{return null}};function U(e,t){for(let n of e){if(n==null||typeof n!=`object`&&typeof n!=`function`)continue;let e=n;for(let n of t){let t=e[n];if(typeof t==`function`)return t}}return null}function et(e){let t=[e];if(e&&typeof e==`object`){let n=e.default;if(n&&(t.push(n),typeof n==`function`))try{t.push(new n)}catch{}}return t}async function tt(e){let t=$e();if(!t)return async()=>{};let n=et(t),r=U(n,[`registerProcess`,`register`,`registerProcessInstance`]),i=U(n,[`unregisterProcess`,`unregister`,`releaseProcess`]);if(!r)return async()=>{};try{await Promise.resolve(r({name:e,pid:process.pid,command:process.argv.join(` `)}))}catch{return async()=>{}}return i?async()=>{await Promise.resolve(i({name:e,pid:process.pid}))}:async()=>{}}async function nt(e,t){await e.start();let n=async n=>{console.error(`\\nReceived ${n}, shutting down gracefully...`);let r=0;try{await e.stop()}catch(e){console.error(`Error during shutdown:`,e),r=1}try{await t()}catch(e){console.error(`Error during resource cleanup:`,e),r=1}process.exit(r)};process.on(`SIGINT`,()=>{n(`SIGINT`)}),process.on(`SIGTERM`,()=>{n(`SIGTERM`)})}async function rt(e){try{await e()}catch{}}const it=new s.Command(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--service-name <name>`,`Service name for registry tracking`,`workflow-mcp`).action(async t=>{let n=await tt(t.serviceName);try{let r=t.type.toLowerCase();r===`stdio`?await nt(new e.t(e.n()),n):(console.error(`Unknown transport type: ${r}. Use: stdio`),process.exit(1))}catch(e){await rt(n),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),W=`recover-workflow`;function at(t={}){let n=t.createService??(()=>new e.r),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t));return new s.Command(W).description(`Recover a failed workflow run from the local workflow registry`).argument(`<run-key>`,`Failed workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the failed workflow run`,`default`).option(`-j, --job <name>`,`Override the job to recover from`).option(`--runner <runner>`,`Override the runner key for step command maps`).option(`--dry-run`,`Print recovery steps without executing`).action(async(e,t)=>{try{r((await n().recover({dryRun:t.dryRun,job:t.job,runKey:e,runner:t.runner,workspace:t.workspace})).exitCode)}catch(n){let a=new g(`Error recovering workflow.`,`RECOVER_WORKFLOW_FAILED`,{command:W,runKey:e,workspace:t.workspace},{cause:n});i(`${a.message} [${a.code}]`,a),r(1)}})}const ot=at(),G=`run-workflow`,K=`RUN_WORKFLOW_COMMAND_FAILED`,q=`WORKFLOW_MCP_BACKGROUND_CHILD`,J=`workflow-mcp-background-run`;function Y(e){if(!e||e.length===0)return;let t={};for(let n of e){let[e,...r]=n.split(`=`);t[e]=r.join(`=`)}return Object.keys(t).length>0?t:void 0}function X(e){if(e.runner&&e.cliAgent&&e.runner!==e.cliAgent)throw new g(`Conflicting runner selectors.`,K,{cliAgent:e.cliAgent,command:G,runner:e.runner});return e.runner??e.cliAgent}function Z(e,n){let r=process.argv[1];if(!r)throw new g(`Unable to determine the workflow-mcp CLI entry point for background execution.`,`RUN_WORKFLOW_BACKGROUND_LAUNCH_FAILED`,{command:G,workflow:e,workspace:n.workspace});let i=[r,`run-workflow`,e];n.job&&i.push(`--job`,n.job);for(let e of n.input??[])i.push(`--input`,e);for(let e of n.env??[])i.push(`--env`,e);n.secretFile&&i.push(`--secret-file`,n.secretFile),n.dryRun&&i.push(`--dry-run`),n.continueOnError&&i.push(`--continue-on-error`),n.keepWorktree&&i.push(`--keep-worktree`);let a=X(n);a&&i.push(`--runner`,a),n.prompt&&i.push(`--prompt`,n.prompt),n.name&&i.push(`--name`,n.name),n.workspace&&i.push(`--workspace`,n.workspace);let o=(0,t.spawn)(process.execPath,i,{detached:!0,env:{...process.env,[q]:`1`},stdio:`ignore`});return o.unref(),o.pid}async function st(e,t){if(process.env[q]!==`1`)return async()=>{};let n=new a.ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH),i=(0,r.resolve)(process.cwd()),o=process.env.NODE_ENV??`development`;return(await n.registerProcess({repositoryPath:i,serviceName:J,serviceType:`tool`,environment:o,pid:process.pid,command:process.argv.join(` `),args:process.argv.slice(2),metadata:{workflow:e,workspace:t.workspace,job:t.job,name:t.name,runner:t.runner??t.cliAgent},force:!0})).success?async()=>{let e=await n.releaseProcess({repositoryPath:i,serviceName:J,serviceType:`tool`,environment:o,pid:process.pid,kill:!1,releasePort:!1,force:!0});if(!e.success&&!e.error?.includes(`No matching process entry`))throw Error(e.error??`Failed to release workflow background process`)}:async()=>{}}function ct(t={}){let n=t.createService??(()=>new e.i),r=t.exit??(e=>process.exit(e)),i=t.launchBackgroundRun??Z,a=t.registerBackgroundChild??st,o=t.logError??((e,t)=>console.error(e,t)),c=t.logInfo??(e=>process.stdout.write(`${e}\n`));return new s.Command(G).description(`Run a GitHub Actions workflow file locally on macOS`).argument(`<workflow>`,`Path to the workflow YAML file`).option(`-j, --job <name>`,`Run only this job (and its dependencies)`).option(`-i, --input <key=value...>`,`Set workflow_dispatch input (repeatable)`).option(`-e, --env <key=value...>`,`Set extra environment variable (repeatable)`).option(`--secret-file <path>`,`Load secrets from a dotenv-style file`).option(`--dry-run`,`Print steps without executing`).option(`--continue-on-error`,`Continue past step failures`).option(`--runner <runner>`,`Preferred runner key for step command maps`).option(`--cli-agent <agent>`,`Deprecated alias for --runner`).option(`-p, --prompt <text>`,`User prompt for user_prompt trigger workflows`).option(`-n, --name <name>`,`Name for the workflow run context directory`).option(`-w, --workspace <name>`,`Workspace for workflow registry storage`).option(`--keep-worktree`,`Keep worktree on completion (skip merge and cleanup for retry)`).option(`--skip-launch`,`Skip launch-command delegation (used by inner invocations)`).option(`-b, --background`,`Run the workflow in a detached background process`).action(async(e,t)=>{try{if(t.background){let n=i(e,t);c(`Started workflow in background${n?` (PID: ${n})`:``}`),r(0);return}let o=await a(e,t),s=n();try{let n=X(t),i=await s.run({cliAgent:t.cliAgent,runner:n,workflowPath:e,job:t.job,inputs:Y(t.input),env:Y(t.env),secretFile:t.secretFile,dryRun:t.dryRun,continueOnError:t.continueOnError,keepWorktree:t.keepWorktree,prompt:t.prompt,name:t.name,workspace:t.workspace,skipLaunch:t.skipLaunch});await o(),r(i.exitCode)}catch(e){throw await o(),e}}catch(n){let i=n instanceof g?n:new g(`Error executing run-workflow.`,K,{background:!!t.background,command:G,workflow:e,workspace:t.workspace},{cause:n});o(`${i.message} [${i.code}]`,i),r(1)}})}const lt=ct(),Q=`schedule-cron`;function ut(t={}){let n=t.createService??(()=>new e.s),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(`${e}\n`));return new s.Command(Q).description(`Schedule a headless Claude Code or Codex CLI run via system crontab`).argument(`<name>`,`Unique name for this cron job`).option(`-d, --cwd <path>`,`Working directory for the CLI run`,process.cwd()).option(`-c, --cli <cli>`,`CLI to use: claude or codex`,e.c).option(`-p, --prompt <text>`,`Prompt to pass to the CLI`).option(`-f, --prompt-file <path>`,`Path to a file whose content is used as the prompt (read at cron execution time)`).option(`-s, --schedule <cron>`,`Cron expression (e.g., "*/10 * * * *")`).option(`-i, --interval-minutes <minutes>`,`Run every N minutes (alternative to --schedule)`).action(async(t,o)=>{try{let i=e.l.parse({name:t,cwd:o.cwd??process.cwd(),cli:o.cli??`claude`,prompt:o.prompt,promptFile:o.promptFile,schedule:o.schedule,intervalMinutes:o.intervalMinutes?Number.parseInt(o.intervalMinutes,10):void 0}),s=await n().schedule(i);a(`Scheduled cron job "${s.name}" with schedule: ${s.schedule}`),a(`CLI: ${s.cli} | CWD: ${s.cwd}`),s.prompt&&a(`Prompt: ${s.prompt}`),r(0)}catch(e){let n=e instanceof g?e:new g(`Error scheduling cron job.`,`SCHEDULE_CRON_COMMAND_FAILED`,{command:Q,name:t},{cause:e});i(`${n.message} [${n.code}]`,n),r(1)}})}const dt=ut(),$=`stop-workflow`;function ft(t={}){let n=t.createRegistry??(()=>new e.o),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new s.Command($).description(`Request a running workflow to stop gracefully`).argument(`<run-key>`,`Running workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the running workflow`,`default`).option(`-r, --reason <text>`,`Optional stop reason to record`).action(async(e,t)=>{try{let i=n(),o=await i.requestStop(t.workspace,e,t.reason);a(`${JSON.stringify({reason:o.reason,requestedAt:o.requestedAt,runKey:e,workspace:i.resolveWorkspace(t.workspace)},null,2)}\n`),r(0)}catch(n){let a=new g(`Error requesting workflow stop.`,`STOP_WORKFLOW_FAILED`,{command:$,runKey:e,workspace:t.workspace},{cause:n});i(`${a.message} [${a.code}]`,a),r(1)}})}const pt=ft();async function mt(){let e=new s.Command;e.name(`workflow-mcp`).description(`MCP server for running GitHub Actions workflows locally`).version(l),e.addCommand(Xe),e.addCommand(Qe),e.addCommand(de),e.addCommand(le),e.addCommand(Ee),e.addCommand(De),e.addCommand(qe),e.addCommand(Je),e.addCommand(it),e.addCommand(ot),e.addCommand(lt),e.addCommand(dt),e.addCommand(pt),await e.parseAsync(process.argv)}mt().catch(e=>{console.error(`[CLI_STARTUP_ERROR] workflow-mcp startup failed:`,e),process.exit(1)});
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c}from"./stdio-k5DKbtyw.mjs";import{createRequire as l}from"node:module";import{spawn as ee}from"node:child_process";import{readFile as u,writeFile as d}from"node:fs/promises";import{resolve as te}from"node:path";import{createReadStream as ne}from"node:fs";import{ProcessRegistryService as re}from"@agimon-ai/foundation-process-registry";import{createInterface as f}from"node:readline";import{Command as p,InvalidArgumentError as ie}from"commander";var ae=`0.3.1`;const m=`WORKFLOW_STATUS_FILE`,oe={readStdin:_,readStatusFile:de,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await d(e,`YES
3
- `,`utf8`)},workflowStatusFile:process.env[m]};async function se(e=oe){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ce(n);if(!r?.conversationId)return;let i=await e.readStatusFile(t);if(!(i===null||i.trim()===`YES`)){if(!r.fullyIdle){e.writeStdout?.(le(`In-progress work is still running. Continue the execution loop until background tasks finish.`));return}h(r.error)||r.terminationReason!==`model_stop`||await e.writeStatusFile(t)}}function ce(e){try{let t=JSON.parse(e);return g(t)?{conversationId:typeof t.conversationId==`string`?t.conversationId:void 0,transcriptPath:ue(t.transcriptPath),terminationReason:typeof t.terminationReason==`string`?t.terminationReason:void 0,error:typeof t.error==`string`?t.error:void 0,fullyIdle:t.fullyIdle===!0}:null}catch{return null}}function le(e){return`${JSON.stringify({decision:`continue`,reason:e})}\n`}function ue(e){return typeof e==`string`&&e.trim().length>0?e:null}function h(e){return typeof e==`string`&&e.trim().length>0}function g(e){return typeof e==`object`&&!!e}async function _(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function de(e){try{return await u(e,`utf8`)}catch{return null}}const fe=new p(`antigravity-stop-hook`).description(`Antigravity stop hook: reads Stop hook JSON on stdin and marks ${m} when the execution is fully idle`).action(async()=>{await se()});var v=class extends Error{constructor(e,t,n={},r){super(e,r),this.code=t,this.context=n,this.name=`WorkflowCommandError`}};const y=`check-codex-quota`;function pe(t={}){let n=t.createService??(()=>new e),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new p(y).description(`Check whether Codex quota is currently blocking new work`).action(async()=>{try{let e=await n().getQuotaStatus();if(a(`${JSON.stringify({blockingLimit:e?.blockingLimit??null,planType:e?.planType??null},null,2)}\n`),e?.blockingLimit){let t=new v(`Codex quota is blocking work at ${e.blockingLimit.limitId}/${e.blockingLimit.window}.`,`CODEX_QUOTA_BLOCKED`,{command:y,limitId:e.blockingLimit.limitId,limitName:e.blockingLimit.limitName,window:e.blockingLimit.window});i(`${t.message} [${t.code}]`,t),r(2);return}r(0)}catch(e){let t=e instanceof v?e:new v(`Error checking Codex quota.`,`CHECK_CODEX_QUOTA_COMMAND_FAILED`,{command:y},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const me=pe(),b=`WORKFLOW_STATUS_FILE`,he=new Set([`aborted`,`cancelled`,`canceled`,`completed`,`crashed`,`done`,`error`,`failed`,`killed`,`not_running`,`retired`,`settled`,`stopped`,`success`,`succeeded`]),ge={readStdin:S,readStatusFile:C,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await d(e,`YES
4
- `,`utf8`)},workflowStatusFile:process.env[b]},_e={readStdin:S,readStatusFile:C,writeSessionBinding:async(e,t)=>{await d(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[b]};async function ve(e=_e){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=xe(n);if(!r?.session_id||r.hook_event_name&&r.hook_event_name!==`SessionStart`)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function ye(e=ge){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Se(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`)return;let i=Te(await e.readStatusFile(t));if(!(!r.session_id||r.session_id!==i)){if(r.background_tasks.some(Ce)){e.writeStdout?.(be(`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`));return}await e.writeStatusFile(t)}}function be(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}function xe(e){try{let t=JSON.parse(e);return x(t)?{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function Se(e){try{let t=JSON.parse(e);if(!x(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:[],r=Array.isArray(t.session_crons)?t.session_crons:[];return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r}}catch{return null}}function Ce(e){if(!x(e))return!0;let t=we(e.status);return!t||!he.has(t)}function we(e){return typeof e==`string`&&e.trim().length>0?e.trim().toLowerCase().replaceAll(`-`,`_`):null}function Te(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function x(e){return typeof e==`object`&&!!e}async function S(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function C(e){try{return await u(e,`utf8`)}catch{return null}}const w=new p(`claude-session-start-hook`).description(`Claude Code SessionStart hook: binds ${b} to the root Claude session id`).action(async()=>{await ve()}),T=new p(`claude-stop-hook`).description(`Claude Code stop hook: reads Stop hook JSON on stdin and marks ${b} when the root session is complete`).action(async()=>{await ye()}),E=`WORKFLOW_STATUS_FILE`,D=`session_meta`,O=[`sub_agent`,`subagent`],Ee=new Set([`in_progress`,`inProgress`,`running`,`pending_init`,`pendingInit`]),De=new Set([`collabAgentToolCall`,`commandExecution`,`dynamicToolCall`,`imageGeneration`,`local_shell_call`,`mcpToolCall`]),Oe={readStdin:j,readStatusFile:M,readTranscriptHead:N,readTranscriptState:P,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await d(e,`YES
5
- `,`utf8`)},workflowStatusFile:process.env[E]},ke={readStdin:j,readStatusFile:M,writeSessionBinding:async(e,t)=>{await d(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[E]};async function Ae(e=ke){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Pe(n);if(!r?.session_id)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function je(e=Oe){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Fe(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`||r.stop_hook_active&&!r.hasTaskRegistry)return;let i=Ie(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i)return;let a=k(r.transcript_path);if(!a)return;let o=await Ne(e,a),s=o.sessionMeta;if(!s||r.session_id&&s.id&&r.session_id!==s.id||Le(s.source))return;let c=r.hasTaskRegistry&&(r.background_tasks?.length??0)>0,l=r.hasTaskRegistry&&(r.session_crons?.length??0)>0;if(c||!r.hasTaskRegistry&&o.hasPendingWork){e.writeStdout?.(Me(`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`));return}l||await e.writeStatusFile(t)}function Me(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}async function Ne(e,t){return e.readTranscriptState?e.readTranscriptState(t):e.readTranscriptHead===N?P(t):{sessionMeta:await e.readTranscriptHead(t),hasPendingWork:!1}}function Pe(e){try{let t=JSON.parse(e);return A(t)?{session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function Fe(e){try{let t=JSON.parse(e);if(!A(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:void 0,r=Array.isArray(t.session_crons)?t.session_crons:void 0;return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,transcript_path:k(t.transcript_path),stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r,hasTaskRegistry:n!==void 0||r!==void 0}}catch{return null}}function k(e){return typeof e==`string`&&e.trim().length>0?e:null}function Ie(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function Le(e){return typeof e==`string`?e.startsWith(`subagent_`)||e.startsWith(`internal_`):A(e)?O.some(t=>t in e):!1}function A(e){return typeof e==`object`&&!!e}async function j(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function M(e){try{return await u(e,`utf8`)}catch{return null}}async function N(e){return(await P(e)).sessionMeta}async function P(e){let t=ne(e,{encoding:`utf8`}),n=f({input:t,crlfDelay:1/0}),r=new Set,i=new Map,a=null;try{for await(let e of n){let t=e.trim();if(t.length===0)continue;let n=Re(t);n&&(a||=ze(n),F(n,r),Be(n,i))}}finally{n.close(),t.destroy()}return{sessionMeta:a,hasPendingWork:r.size>0||Array.from(i.values()).some(R)}}function Re(e){try{let t=JSON.parse(e);return A(t)?t:null}catch{return null}}function ze(e){return e.type===D?e.payload??null:e.item?.type===D?e.item.payload??null:null}function F(e,t){let n=z(e,[`payload`,`item`])??z(e,[`item`,`payload`,`item`]);if(!n)return;let r=B(n.id),i=B(n.type);!r||!i||!De.has(i)||(R(n.status)?t.add(r):t.delete(r))}function Be(e,t){let n=z(e,[`payload`])??z(e,[`item`,`payload`]);if(!n||!B(n.type)?.startsWith(`collab_`))return;I(t,B(n.new_thread_id),n.status),I(t,B(n.receiver_thread_id),n.status);let r=z(n,[`statuses`]);if(r)for(let[e,n]of Object.entries(r))I(t,e,n)}function I(e,t,n){let r=L(n);!t||!r||e.set(t,r)}function L(e){if(typeof e==`string`)return e;if(!A(e))return null;let[t]=Object.keys(e);return t??null}function R(e){let t=typeof e==`string`?e:L(e);return t!==null&&Ee.has(t)}function z(e,t){let n=e;for(let e of t){if(!A(n))return null;n=n[e]}return A(n)?n:null}function B(e){return typeof e==`string`&&e.length>0?e:void 0}const Ve=new p(`codex-session-start-hook`).description(`Codex session-start hook: binds ${E} to the first workflow Codex session id`).action(async()=>{await Ae()}),He=new p(`codex-stop-hook`).description(`Codex stop hook: reads stop-hook JSON on stdin and marks ${E} when the root session ends`).action(async()=>{await je()}),V=`list-crons`;function Ue(e={}){let t=e.createService??(()=>new s),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t)),i=e.writeStdout??(e=>process.stdout.write(e));return new p(V).description(`List cron jobs scheduled via workflow-mcp`).action(async()=>{try{let e=await t().list();i(`${JSON.stringify(e,null,2)}\n`),n(0)}catch(e){let t=new v(`Error listing cron jobs.`,`LIST_CRONS_COMMAND_FAILED`,{command:V},{cause:e});r(`${t.message} [${t.code}]`,t),n(1)}})}const We=Ue(),H=`list-workflow-statuses`;function U(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw new ie(`Expected a positive integer.`);return t}function Ge(e={}){let t=e.createRegistry??(()=>new a),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t)),i=e.writeStdout??(e=>process.stdout.write(e));return new p(H).description(`List tracked workflow runs and their current stages`).option(`--page <number>`,`Page number to return`,U,1).option(`--page-size <number>`,`Number of workflow runs per page`,U,20).option(`-w, --workspace <name>`,`Filter workflow runs by workspace`,`all`).action(async e=>{try{let r=t(),a=e.workspace===`all`?void 0:e.workspace,o=await r.listRunsPage({page:e.page,pageSize:e.pageSize,workspace:a});i(`${JSON.stringify(o,null,2)}\n`),n(0)}catch(t){let i=new v(`Error listing workflow statuses.`,`LIST_WORKFLOW_STATUSES_FAILED`,{command:H,workspace:e.workspace??`all`},{cause:t});r(`${i.message} [${i.code}]`,i),n(1)}})}const Ke=Ge(),qe=()=>{try{return l(import.meta.url)(`@agimon-ai/foundation-process-registry`)}catch{return null}};function W(e,t){for(let n of e){if(n==null||typeof n!=`object`&&typeof n!=`function`)continue;let e=n;for(let n of t){let t=e[n];if(typeof t==`function`)return t}}return null}function Je(e){let t=[e];if(e&&typeof e==`object`){let n=e.default;if(n&&(t.push(n),typeof n==`function`))try{t.push(new n)}catch{}}return t}async function Ye(e){let t=qe();if(!t)return async()=>{};let n=Je(t),r=W(n,[`registerProcess`,`register`,`registerProcessInstance`]),i=W(n,[`unregisterProcess`,`unregister`,`releaseProcess`]);if(!r)return async()=>{};try{await Promise.resolve(r({name:e,pid:process.pid,command:process.argv.join(` `)}))}catch{return async()=>{}}return i?async()=>{await Promise.resolve(i({name:e,pid:process.pid}))}:async()=>{}}async function Xe(e,t){await e.start();let n=async n=>{console.error(`\\nReceived ${n}, shutting down gracefully...`);let r=0;try{await e.stop()}catch(e){console.error(`Error during shutdown:`,e),r=1}try{await t()}catch(e){console.error(`Error during resource cleanup:`,e),r=1}process.exit(r)};process.on(`SIGINT`,()=>{n(`SIGINT`)}),process.on(`SIGTERM`,()=>{n(`SIGTERM`)})}async function Ze(e){try{await e()}catch{}}const Qe=new p(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--service-name <name>`,`Service name for registry tracking`,`workflow-mcp`).action(async e=>{let t=await Ye(e.serviceName);try{let n=e.type.toLowerCase();n===`stdio`?await Xe(new c(i()),t):(console.error(`Unknown transport type: ${n}. Use: stdio`),process.exit(1))}catch(e){await Ze(t),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),G=`recover-workflow`;function $e(e={}){let t=e.createService??(()=>new o),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t));return new p(G).description(`Recover a failed workflow run from the local workflow registry`).argument(`<run-key>`,`Failed workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the failed workflow run`,`default`).option(`-j, --job <name>`,`Override the job to recover from`).option(`--runner <runner>`,`Override the runner key for step command maps`).option(`--dry-run`,`Print recovery steps without executing`).action(async(e,i)=>{try{n((await t().recover({dryRun:i.dryRun,job:i.job,runKey:e,runner:i.runner,workspace:i.workspace})).exitCode)}catch(t){let a=new v(`Error recovering workflow.`,`RECOVER_WORKFLOW_FAILED`,{command:G,runKey:e,workspace:i.workspace},{cause:t});r(`${a.message} [${a.code}]`,a),n(1)}})}const et=$e(),K=`run-workflow`,q=`RUN_WORKFLOW_COMMAND_FAILED`,J=`WORKFLOW_MCP_BACKGROUND_CHILD`,Y=`workflow-mcp-background-run`;function X(e){if(!e||e.length===0)return;let t={};for(let n of e){let[e,...r]=n.split(`=`);t[e]=r.join(`=`)}return Object.keys(t).length>0?t:void 0}function Z(e){if(e.runner&&e.cliAgent&&e.runner!==e.cliAgent)throw new v(`Conflicting runner selectors.`,q,{cliAgent:e.cliAgent,command:K,runner:e.runner});return e.runner??e.cliAgent}function tt(e,t){let n=process.argv[1];if(!n)throw new v(`Unable to determine the workflow-mcp CLI entry point for background execution.`,`RUN_WORKFLOW_BACKGROUND_LAUNCH_FAILED`,{command:K,workflow:e,workspace:t.workspace});let r=[n,`run-workflow`,e];t.job&&r.push(`--job`,t.job);for(let e of t.input??[])r.push(`--input`,e);for(let e of t.env??[])r.push(`--env`,e);t.secretFile&&r.push(`--secret-file`,t.secretFile),t.dryRun&&r.push(`--dry-run`),t.continueOnError&&r.push(`--continue-on-error`),t.keepWorktree&&r.push(`--keep-worktree`);let i=Z(t);i&&r.push(`--runner`,i),t.prompt&&r.push(`--prompt`,t.prompt),t.name&&r.push(`--name`,t.name),t.workspace&&r.push(`--workspace`,t.workspace);let a=ee(process.execPath,r,{detached:!0,env:{...process.env,[J]:`1`},stdio:`ignore`});return a.unref(),a.pid}async function nt(e,t){if(process.env[J]!==`1`)return async()=>{};let n=new re(process.env.PROCESS_REGISTRY_PATH),r=te(process.cwd()),i=process.env.NODE_ENV??`development`;return(await n.registerProcess({repositoryPath:r,serviceName:Y,serviceType:`tool`,environment:i,pid:process.pid,command:process.argv.join(` `),args:process.argv.slice(2),metadata:{workflow:e,workspace:t.workspace,job:t.job,name:t.name,runner:t.runner??t.cliAgent},force:!0})).success?async()=>{let e=await n.releaseProcess({repositoryPath:r,serviceName:Y,serviceType:`tool`,environment:i,pid:process.pid,kill:!1,releasePort:!1,force:!0});if(!e.success&&!e.error?.includes(`No matching process entry`))throw Error(e.error??`Failed to release workflow background process`)}:async()=>{}}function rt(e={}){let t=e.createService??(()=>new n),r=e.exit??(e=>process.exit(e)),i=e.launchBackgroundRun??tt,a=e.registerBackgroundChild??nt,o=e.logError??((e,t)=>console.error(e,t)),s=e.logInfo??(e=>process.stdout.write(`${e}\n`));return new p(K).description(`Run a GitHub Actions workflow file locally on macOS`).argument(`<workflow>`,`Path to the workflow YAML file`).option(`-j, --job <name>`,`Run only this job (and its dependencies)`).option(`-i, --input <key=value...>`,`Set workflow_dispatch input (repeatable)`).option(`-e, --env <key=value...>`,`Set extra environment variable (repeatable)`).option(`--secret-file <path>`,`Load secrets from a dotenv-style file`).option(`--dry-run`,`Print steps without executing`).option(`--continue-on-error`,`Continue past step failures`).option(`--runner <runner>`,`Preferred runner key for step command maps`).option(`--cli-agent <agent>`,`Deprecated alias for --runner`).option(`-p, --prompt <text>`,`User prompt for user_prompt trigger workflows`).option(`-n, --name <name>`,`Name for the workflow run context directory`).option(`-w, --workspace <name>`,`Workspace for workflow registry storage`).option(`--keep-worktree`,`Keep worktree on completion (skip merge and cleanup for retry)`).option(`--skip-launch`,`Skip launch-command delegation (used by inner invocations)`).option(`-b, --background`,`Run the workflow in a detached background process`).action(async(e,n)=>{try{if(n.background){let t=i(e,n);s(`Started workflow in background${t?` (PID: ${t})`:``}`),r(0);return}let o=await a(e,n),c=t();try{let t=Z(n),i=await c.run({cliAgent:n.cliAgent,runner:t,workflowPath:e,job:n.job,inputs:X(n.input),env:X(n.env),secretFile:n.secretFile,dryRun:n.dryRun,continueOnError:n.continueOnError,keepWorktree:n.keepWorktree,prompt:n.prompt,name:n.name,workspace:n.workspace,skipLaunch:n.skipLaunch});await o(),r(i.exitCode)}catch(e){throw await o(),e}}catch(t){let i=t instanceof v?t:new v(`Error executing run-workflow.`,q,{background:!!n.background,command:K,workflow:e,workspace:n.workspace},{cause:t});o(`${i.message} [${i.code}]`,i),r(1)}})}const it=rt(),Q=`schedule-cron`;function at(e={}){let n=e.createService??(()=>new s),i=e.exit??(e=>process.exit(e)),a=e.logError??((e,t)=>console.error(e,t)),o=e.writeStdout??(e=>process.stdout.write(`${e}\n`));return new p(Q).description(`Schedule a headless Claude Code or Codex CLI run via system crontab`).argument(`<name>`,`Unique name for this cron job`).option(`-d, --cwd <path>`,`Working directory for the CLI run`,process.cwd()).option(`-c, --cli <cli>`,`CLI to use: claude or codex`,t).option(`-p, --prompt <text>`,`Prompt to pass to the CLI`).option(`-f, --prompt-file <path>`,`Path to a file whose content is used as the prompt (read at cron execution time)`).option(`-s, --schedule <cron>`,`Cron expression (e.g., "*/10 * * * *")`).option(`-i, --interval-minutes <minutes>`,`Run every N minutes (alternative to --schedule)`).action(async(e,t)=>{try{let a=r.parse({name:e,cwd:t.cwd??process.cwd(),cli:t.cli??`claude`,prompt:t.prompt,promptFile:t.promptFile,schedule:t.schedule,intervalMinutes:t.intervalMinutes?Number.parseInt(t.intervalMinutes,10):void 0}),s=await n().schedule(a);o(`Scheduled cron job "${s.name}" with schedule: ${s.schedule}`),o(`CLI: ${s.cli} | CWD: ${s.cwd}`),s.prompt&&o(`Prompt: ${s.prompt}`),i(0)}catch(t){let n=t instanceof v?t:new v(`Error scheduling cron job.`,`SCHEDULE_CRON_COMMAND_FAILED`,{command:Q,name:e},{cause:t});a(`${n.message} [${n.code}]`,n),i(1)}})}const ot=at(),$=`stop-workflow`;function st(e={}){let t=e.createRegistry??(()=>new a),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t)),i=e.writeStdout??(e=>process.stdout.write(e));return new p($).description(`Request a running workflow to stop gracefully`).argument(`<run-key>`,`Running workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the running workflow`,`default`).option(`-r, --reason <text>`,`Optional stop reason to record`).action(async(e,a)=>{try{let r=t(),o=await r.requestStop(a.workspace,e,a.reason);i(`${JSON.stringify({reason:o.reason,requestedAt:o.requestedAt,runKey:e,workspace:r.resolveWorkspace(a.workspace)},null,2)}\n`),n(0)}catch(t){let i=new v(`Error requesting workflow stop.`,`STOP_WORKFLOW_FAILED`,{command:$,runKey:e,workspace:a.workspace},{cause:t});r(`${i.message} [${i.code}]`,i),n(1)}})}const ct=st();async function lt(){let e=new p;e.name(`workflow-mcp`).description(`MCP server for running GitHub Actions workflows locally`).version(ae),e.addCommand(We),e.addCommand(Ke),e.addCommand(me),e.addCommand(fe),e.addCommand(w),e.addCommand(T),e.addCommand(Ve),e.addCommand(He),e.addCommand(Qe),e.addCommand(et),e.addCommand(it),e.addCommand(ot),e.addCommand(ct),await e.parseAsync(process.argv)}lt().catch(e=>{console.error(`[CLI_STARTUP_ERROR] workflow-mcp startup failed:`,e),process.exit(1)});export{};
2
+ import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c}from"./stdio-k5DKbtyw.mjs";import{createRequire as l}from"node:module";import{spawn as ee}from"node:child_process";import{mkdir as u,readFile as d,writeFile as f}from"node:fs/promises";import{dirname as p,join as m,resolve as te}from"node:path";import{createReadStream as ne}from"node:fs";import{ProcessRegistryService as re}from"@agimon-ai/foundation-process-registry";import{createInterface as ie}from"node:readline";import{Command as h,InvalidArgumentError as ae}from"commander";var oe=`0.3.2`;const g=`WORKFLOW_STATUS_FILE`,se=m(process.cwd(),`tmp`,`antigravity-stop-hook.json`),_=`In-progress work is still running. Continue the execution loop until background tasks finish.`,ce={readStdin:me,readStatusFile:he,writeDebugLog:async e=>{await ge(se,e)},writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await f(e,`YES
3
+ `,`utf8`)},workflowStatusFile:process.env[g]};async function le(e=ce){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ue(n);if(!r?.conversationId){await y(e,n,r,{decision:`ignore`,reason:r?`missing conversation id`:`invalid stop hook JSON`});return}let i=await e.readStatusFile(t);if(i===null||i.trim()===`YES`){await y(e,n,r,{decision:`ignore`,reason:i===null?`missing workflow status file`:`workflow status file already completed`});return}if(!r.fullyIdle){e.writeStdout?.(de(_)),await y(e,n,r,{decision:`continue`,reason:_});return}if(v(r.error)||r.terminationReason!==`model_stop`){await y(e,n,r,{decision:`ignore`,reason:v(r.error)?`stop hook reported an error`:`unsupported termination reason: ${r.terminationReason??`missing`}`});return}await e.writeStatusFile(t),await y(e,n,r,{decision:`complete`})}function ue(e){try{let t=JSON.parse(e);return pe(t)?{conversationId:typeof t.conversationId==`string`?t.conversationId:void 0,transcriptPath:fe(t.transcriptPath),terminationReason:typeof t.terminationReason==`string`?t.terminationReason:void 0,error:typeof t.error==`string`?t.error:void 0,fullyIdle:t.fullyIdle===!0}:null}catch{return null}}function de(e){return`${JSON.stringify({decision:`continue`,reason:e})}\n`}function fe(e){return typeof e==`string`&&e.trim().length>0?e:null}function v(e){return typeof e==`string`&&e.trim().length>0}function pe(e){return typeof e==`object`&&!!e}async function me(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function he(e){try{return await d(e,`utf8`)}catch{return null}}async function y(e,t,n,r){try{await e.writeDebugLog?.({timestamp:new Date().toISOString(),rawInput:t,input:n,decision:r})}catch{}}async function ge(e,t){let n=await _e(e);n.push(t),await u(p(e),{recursive:!0}),await f(e,`${JSON.stringify(n.slice(-50),null,2)}\n`,`utf8`)}async function _e(e){try{let t=JSON.parse(await d(e,`utf8`));return Array.isArray(t)?t:[]}catch{return[]}}const ve=new h(`antigravity-stop-hook`).description(`Antigravity stop hook: reads Stop hook JSON on stdin and marks ${g} when the execution is fully idle`).action(async()=>{await le()});var b=class extends Error{constructor(e,t,n={},r){super(e,r),this.code=t,this.context=n,this.name=`WorkflowCommandError`}};const x=`check-codex-quota`;function ye(t={}){let n=t.createService??(()=>new e),r=t.exit??(e=>process.exit(e)),i=t.logError??((e,t)=>console.error(e,t)),a=t.writeStdout??(e=>process.stdout.write(e));return new h(x).description(`Check whether Codex quota is currently blocking new work`).action(async()=>{try{let e=await n().getQuotaStatus();if(a(`${JSON.stringify({blockingLimit:e?.blockingLimit??null,planType:e?.planType??null},null,2)}\n`),e?.blockingLimit){let t=new b(`Codex quota is blocking work at ${e.blockingLimit.limitId}/${e.blockingLimit.window}.`,`CODEX_QUOTA_BLOCKED`,{command:x,limitId:e.blockingLimit.limitId,limitName:e.blockingLimit.limitName,window:e.blockingLimit.window});i(`${t.message} [${t.code}]`,t),r(2);return}r(0)}catch(e){let t=e instanceof b?e:new b(`Error checking Codex quota.`,`CHECK_CODEX_QUOTA_COMMAND_FAILED`,{command:x},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const be=ye(),S=`WORKFLOW_STATUS_FILE`,xe=m(process.cwd(),`tmp`,`claude-stop-hook.json`),C=`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`,Se=new Set([`aborted`,`cancelled`,`canceled`,`completed`,`crashed`,`done`,`error`,`failed`,`killed`,`not_running`,`retired`,`settled`,`stopped`,`success`,`succeeded`]),Ce={readStdin:T,readStatusFile:E,writeDebugLog:async e=>{await Ne(xe,e)},writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await f(e,`YES
4
+ `,`utf8`)},workflowStatusFile:process.env[S]},we={readStdin:T,readStatusFile:E,writeSessionBinding:async(e,t)=>{await f(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[S]};async function Te(e=we){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Oe(n);if(!r?.session_id||r.hook_event_name&&r.hook_event_name!==`SessionStart`)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function Ee(e=Ce){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ke(n);if(!r){await D(e,n,null,{decision:`ignore`,reason:`invalid stop hook JSON`});return}if(r.hook_event_name&&r.hook_event_name!==`Stop`){await D(e,n,r,{decision:`ignore`,reason:`unsupported hook event: ${r.hook_event_name}`});return}let i=Me(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i){await D(e,n,r,{decision:`ignore`,reason:`stop hook session is not bound to the workflow status file`});return}if(r.background_tasks.some(Ae)){e.writeStdout?.(De(C)),await D(e,n,r,{decision:`block`,reason:C});return}await e.writeStatusFile(t),await D(e,n,r,{decision:`complete`})}function De(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}function Oe(e){try{let t=JSON.parse(e);return w(t)?{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function ke(e){try{let t=JSON.parse(e);if(!w(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:[],r=Array.isArray(t.session_crons)?t.session_crons:[];return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r}}catch{return null}}function Ae(e){if(!w(e))return!0;let t=je(e.status);return!t||!Se.has(t)}function je(e){return typeof e==`string`&&e.trim().length>0?e.trim().toLowerCase().replaceAll(`-`,`_`):null}function Me(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function w(e){return typeof e==`object`&&!!e}async function T(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function E(e){try{return await d(e,`utf8`)}catch{return null}}async function D(e,t,n,r){try{await e.writeDebugLog?.({timestamp:new Date().toISOString(),rawInput:t,input:n,decision:r})}catch{}}async function Ne(e,t){let n=await Pe(e);n.push(t),await u(p(e),{recursive:!0}),await f(e,`${JSON.stringify(n.slice(-50),null,2)}\n`,`utf8`)}async function Pe(e){try{let t=JSON.parse(await d(e,`utf8`));return Array.isArray(t)?t:[]}catch{return[]}}const Fe=new h(`claude-session-start-hook`).description(`Claude Code SessionStart hook: binds ${S} to the root Claude session id`).action(async()=>{await Te()}),Ie=new h(`claude-stop-hook`).description(`Claude Code stop hook: reads Stop hook JSON on stdin and marks ${S} when the root session is complete`).action(async()=>{await Ee()}),O=`WORKFLOW_STATUS_FILE`,Le=m(process.cwd(),`tmp`,`codex-stop-hook.json`),k=`session_meta`,Re=`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`,ze=[`sub_agent`,`subagent`],Be=new Set([`in_progress`,`inProgress`,`running`,`pending_init`,`pendingInit`]),Ve=new Set([`collabAgentToolCall`,`commandExecution`,`dynamicToolCall`,`imageGeneration`,`local_shell_call`,`mcpToolCall`]),He={readStdin:M,readStatusFile:N,readTranscriptHead:F,readTranscriptState:I,writeDebugLog:async e=>{await Qe(Le,e)},writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await f(e,`YES
5
+ `,`utf8`)},workflowStatusFile:process.env[O]},Ue={readStdin:M,readStatusFile:N,writeSessionBinding:async(e,t)=>{await f(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[O]};async function We(e=Ue){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Je(n);if(!r?.session_id)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function Ge(e=He){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Ye(n);if(!r){await P(e,n,null,{decision:`ignore`,reason:`invalid stop hook JSON`});return}if(r.hook_event_name&&r.hook_event_name!==`Stop`){await P(e,n,r,{decision:`ignore`,reason:`unsupported hook event: ${r.hook_event_name}`});return}if(r.stop_hook_active&&!r.hasTaskRegistry){await P(e,n,r,{decision:`ignore`,reason:`recursive stop hook without task registry`});return}let i=Xe(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i){await P(e,n,r,{decision:`ignore`,reason:`stop hook session is not bound to the workflow status file`});return}let a=A(r.transcript_path);if(!a){await P(e,n,r,{decision:`ignore`,reason:`missing transcript path`});return}let o=await qe(e,a),s=o.sessionMeta;if(!s){await P(e,n,r,{decision:`ignore`,reason:`missing transcript session metadata`});return}if(r.session_id&&s.id&&r.session_id!==s.id){await P(e,n,r,{decision:`ignore`,reason:`stop hook session does not match transcript session`});return}if(Ze(s.source)){await P(e,n,r,{decision:`ignore`,reason:`transcript session is a subagent`});return}let c=r.hasTaskRegistry&&(r.background_tasks?.length??0)>0,l=r.hasTaskRegistry&&(r.session_crons?.length??0)>0;if(c||!r.hasTaskRegistry&&o.hasPendingWork){e.writeStdout?.(Ke(Re)),await P(e,n,r,{decision:`block`,reason:Re});return}if(l){await P(e,n,r,{decision:`ignore`,reason:`session crons are still scheduled`});return}await e.writeStatusFile(t),await P(e,n,r,{decision:`complete`})}function Ke(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}async function qe(e,t){return e.readTranscriptState?e.readTranscriptState(t):e.readTranscriptHead===F?I(t):{sessionMeta:await e.readTranscriptHead(t),hasPendingWork:!1}}function Je(e){try{let t=JSON.parse(e);return j(t)?{session_id:typeof t.session_id==`string`?t.session_id:void 0}:null}catch{return null}}function Ye(e){try{let t=JSON.parse(e);if(!j(t))return null;let n=Array.isArray(t.background_tasks)?t.background_tasks:void 0,r=Array.isArray(t.session_crons)?t.session_crons:void 0;return{hook_event_name:typeof t.hook_event_name==`string`?t.hook_event_name:void 0,session_id:typeof t.session_id==`string`?t.session_id:void 0,transcript_path:A(t.transcript_path),stop_hook_active:t.stop_hook_active===!0,background_tasks:n,session_crons:r,hasTaskRegistry:n!==void 0||r!==void 0}}catch{return null}}function A(e){return typeof e==`string`&&e.trim().length>0?e:null}function Xe(e){if(!e)return null;let t=e.trim();if(!t||t===`YES`)return null;try{let e=JSON.parse(t);return typeof e.sessionId==`string`&&e.sessionId.length>0?e.sessionId:null}catch{return null}}function Ze(e){return typeof e==`string`?e.startsWith(`subagent_`)||e.startsWith(`internal_`):j(e)?ze.some(t=>t in e):!1}function j(e){return typeof e==`object`&&!!e}async function M(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(String(t)));return Buffer.concat(e).toString(`utf8`)}async function N(e){try{return await d(e,`utf8`)}catch{return null}}async function P(e,t,n,r){try{await e.writeDebugLog?.({timestamp:new Date().toISOString(),rawInput:t,input:n,decision:r})}catch{}}async function Qe(e,t){let n=await $e(e);n.push(t),await u(p(e),{recursive:!0}),await f(e,`${JSON.stringify(n.slice(-50),null,2)}\n`,`utf8`)}async function $e(e){try{let t=JSON.parse(await d(e,`utf8`));return Array.isArray(t)?t:[]}catch{return[]}}async function F(e){return(await I(e)).sessionMeta}async function I(e){let t=ne(e,{encoding:`utf8`}),n=ie({input:t,crlfDelay:1/0}),r=new Set,i=new Map,a=null;try{for await(let e of n){let t=e.trim();if(t.length===0)continue;let n=et(t);n&&(a||=tt(n),nt(n,r),rt(n,i))}}finally{n.close(),t.destroy()}return{sessionMeta:a,hasPendingWork:r.size>0||Array.from(i.values()).some(z)}}function et(e){try{let t=JSON.parse(e);return j(t)?t:null}catch{return null}}function tt(e){return e.type===k?e.payload??null:e.item?.type===k?e.item.payload??null:null}function nt(e,t){let n=B(e,[`payload`,`item`])??B(e,[`item`,`payload`,`item`]);if(!n)return;let r=V(n.id),i=V(n.type);!r||!i||!Ve.has(i)||(z(n.status)?t.add(r):t.delete(r))}function rt(e,t){let n=B(e,[`payload`])??B(e,[`item`,`payload`]);if(!n||!V(n.type)?.startsWith(`collab_`))return;L(t,V(n.new_thread_id),n.status),L(t,V(n.receiver_thread_id),n.status);let r=B(n,[`statuses`]);if(r)for(let[e,n]of Object.entries(r))L(t,e,n)}function L(e,t,n){let r=R(n);!t||!r||e.set(t,r)}function R(e){if(typeof e==`string`)return e;if(!j(e))return null;let[t]=Object.keys(e);return t??null}function z(e){let t=typeof e==`string`?e:R(e);return t!==null&&Be.has(t)}function B(e,t){let n=e;for(let e of t){if(!j(n))return null;n=n[e]}return j(n)?n:null}function V(e){return typeof e==`string`&&e.length>0?e:void 0}const it=new h(`codex-session-start-hook`).description(`Codex session-start hook: binds ${O} to the first workflow Codex session id`).action(async()=>{await We()}),at=new h(`codex-stop-hook`).description(`Codex stop hook: reads stop-hook JSON on stdin and marks ${O} when the root session ends`).action(async()=>{await Ge()}),H=`list-crons`;function ot(e={}){let t=e.createService??(()=>new s),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t)),i=e.writeStdout??(e=>process.stdout.write(e));return new h(H).description(`List cron jobs scheduled via workflow-mcp`).action(async()=>{try{let e=await t().list();i(`${JSON.stringify(e,null,2)}\n`),n(0)}catch(e){let t=new b(`Error listing cron jobs.`,`LIST_CRONS_COMMAND_FAILED`,{command:H},{cause:e});r(`${t.message} [${t.code}]`,t),n(1)}})}const st=ot(),U=`list-workflow-statuses`;function W(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw new ae(`Expected a positive integer.`);return t}function ct(e={}){let t=e.createRegistry??(()=>new a),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t)),i=e.writeStdout??(e=>process.stdout.write(e));return new h(U).description(`List tracked workflow runs and their current stages`).option(`--page <number>`,`Page number to return`,W,1).option(`--page-size <number>`,`Number of workflow runs per page`,W,20).option(`-w, --workspace <name>`,`Filter workflow runs by workspace`,`all`).action(async e=>{try{let r=t(),a=e.workspace===`all`?void 0:e.workspace,o=await r.listRunsPage({page:e.page,pageSize:e.pageSize,workspace:a});i(`${JSON.stringify(o,null,2)}\n`),n(0)}catch(t){let i=new b(`Error listing workflow statuses.`,`LIST_WORKFLOW_STATUSES_FAILED`,{command:U,workspace:e.workspace??`all`},{cause:t});r(`${i.message} [${i.code}]`,i),n(1)}})}const lt=ct(),ut=()=>{try{return l(import.meta.url)(`@agimon-ai/foundation-process-registry`)}catch{return null}};function G(e,t){for(let n of e){if(n==null||typeof n!=`object`&&typeof n!=`function`)continue;let e=n;for(let n of t){let t=e[n];if(typeof t==`function`)return t}}return null}function dt(e){let t=[e];if(e&&typeof e==`object`){let n=e.default;if(n&&(t.push(n),typeof n==`function`))try{t.push(new n)}catch{}}return t}async function ft(e){let t=ut();if(!t)return async()=>{};let n=dt(t),r=G(n,[`registerProcess`,`register`,`registerProcessInstance`]),i=G(n,[`unregisterProcess`,`unregister`,`releaseProcess`]);if(!r)return async()=>{};try{await Promise.resolve(r({name:e,pid:process.pid,command:process.argv.join(` `)}))}catch{return async()=>{}}return i?async()=>{await Promise.resolve(i({name:e,pid:process.pid}))}:async()=>{}}async function pt(e,t){await e.start();let n=async n=>{console.error(`\\nReceived ${n}, shutting down gracefully...`);let r=0;try{await e.stop()}catch(e){console.error(`Error during shutdown:`,e),r=1}try{await t()}catch(e){console.error(`Error during resource cleanup:`,e),r=1}process.exit(r)};process.on(`SIGINT`,()=>{n(`SIGINT`)}),process.on(`SIGTERM`,()=>{n(`SIGTERM`)})}async function mt(e){try{await e()}catch{}}const ht=new h(`mcp-serve`).description(`Start MCP server with specified transport`).option(`-t, --type <type>`,`Transport type: stdio`,`stdio`).option(`--service-name <name>`,`Service name for registry tracking`,`workflow-mcp`).action(async e=>{let t=await ft(e.serviceName);try{let n=e.type.toLowerCase();n===`stdio`?await pt(new c(i()),t):(console.error(`Unknown transport type: ${n}. Use: stdio`),process.exit(1))}catch(e){await mt(t),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),K=`recover-workflow`;function gt(e={}){let t=e.createService??(()=>new o),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t));return new h(K).description(`Recover a failed workflow run from the local workflow registry`).argument(`<run-key>`,`Failed workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the failed workflow run`,`default`).option(`-j, --job <name>`,`Override the job to recover from`).option(`--runner <runner>`,`Override the runner key for step command maps`).option(`--dry-run`,`Print recovery steps without executing`).action(async(e,i)=>{try{n((await t().recover({dryRun:i.dryRun,job:i.job,runKey:e,runner:i.runner,workspace:i.workspace})).exitCode)}catch(t){let a=new b(`Error recovering workflow.`,`RECOVER_WORKFLOW_FAILED`,{command:K,runKey:e,workspace:i.workspace},{cause:t});r(`${a.message} [${a.code}]`,a),n(1)}})}const _t=gt(),q=`run-workflow`,J=`RUN_WORKFLOW_COMMAND_FAILED`,Y=`WORKFLOW_MCP_BACKGROUND_CHILD`,X=`workflow-mcp-background-run`;function Z(e){if(!e||e.length===0)return;let t={};for(let n of e){let[e,...r]=n.split(`=`);t[e]=r.join(`=`)}return Object.keys(t).length>0?t:void 0}function Q(e){if(e.runner&&e.cliAgent&&e.runner!==e.cliAgent)throw new b(`Conflicting runner selectors.`,J,{cliAgent:e.cliAgent,command:q,runner:e.runner});return e.runner??e.cliAgent}function vt(e,t){let n=process.argv[1];if(!n)throw new b(`Unable to determine the workflow-mcp CLI entry point for background execution.`,`RUN_WORKFLOW_BACKGROUND_LAUNCH_FAILED`,{command:q,workflow:e,workspace:t.workspace});let r=[n,`run-workflow`,e];t.job&&r.push(`--job`,t.job);for(let e of t.input??[])r.push(`--input`,e);for(let e of t.env??[])r.push(`--env`,e);t.secretFile&&r.push(`--secret-file`,t.secretFile),t.dryRun&&r.push(`--dry-run`),t.continueOnError&&r.push(`--continue-on-error`),t.keepWorktree&&r.push(`--keep-worktree`);let i=Q(t);i&&r.push(`--runner`,i),t.prompt&&r.push(`--prompt`,t.prompt),t.name&&r.push(`--name`,t.name),t.workspace&&r.push(`--workspace`,t.workspace);let a=ee(process.execPath,r,{detached:!0,env:{...process.env,[Y]:`1`},stdio:`ignore`});return a.unref(),a.pid}async function yt(e,t){if(process.env[Y]!==`1`)return async()=>{};let n=new re(process.env.PROCESS_REGISTRY_PATH),r=te(process.cwd()),i=process.env.NODE_ENV??`development`;return(await n.registerProcess({repositoryPath:r,serviceName:X,serviceType:`tool`,environment:i,pid:process.pid,command:process.argv.join(` `),args:process.argv.slice(2),metadata:{workflow:e,workspace:t.workspace,job:t.job,name:t.name,runner:t.runner??t.cliAgent},force:!0})).success?async()=>{let e=await n.releaseProcess({repositoryPath:r,serviceName:X,serviceType:`tool`,environment:i,pid:process.pid,kill:!1,releasePort:!1,force:!0});if(!e.success&&!e.error?.includes(`No matching process entry`))throw Error(e.error??`Failed to release workflow background process`)}:async()=>{}}function bt(e={}){let t=e.createService??(()=>new n),r=e.exit??(e=>process.exit(e)),i=e.launchBackgroundRun??vt,a=e.registerBackgroundChild??yt,o=e.logError??((e,t)=>console.error(e,t)),s=e.logInfo??(e=>process.stdout.write(`${e}\n`));return new h(q).description(`Run a GitHub Actions workflow file locally on macOS`).argument(`<workflow>`,`Path to the workflow YAML file`).option(`-j, --job <name>`,`Run only this job (and its dependencies)`).option(`-i, --input <key=value...>`,`Set workflow_dispatch input (repeatable)`).option(`-e, --env <key=value...>`,`Set extra environment variable (repeatable)`).option(`--secret-file <path>`,`Load secrets from a dotenv-style file`).option(`--dry-run`,`Print steps without executing`).option(`--continue-on-error`,`Continue past step failures`).option(`--runner <runner>`,`Preferred runner key for step command maps`).option(`--cli-agent <agent>`,`Deprecated alias for --runner`).option(`-p, --prompt <text>`,`User prompt for user_prompt trigger workflows`).option(`-n, --name <name>`,`Name for the workflow run context directory`).option(`-w, --workspace <name>`,`Workspace for workflow registry storage`).option(`--keep-worktree`,`Keep worktree on completion (skip merge and cleanup for retry)`).option(`--skip-launch`,`Skip launch-command delegation (used by inner invocations)`).option(`-b, --background`,`Run the workflow in a detached background process`).action(async(e,n)=>{try{if(n.background){let t=i(e,n);s(`Started workflow in background${t?` (PID: ${t})`:``}`),r(0);return}let o=await a(e,n),c=t();try{let t=Q(n),i=await c.run({cliAgent:n.cliAgent,runner:t,workflowPath:e,job:n.job,inputs:Z(n.input),env:Z(n.env),secretFile:n.secretFile,dryRun:n.dryRun,continueOnError:n.continueOnError,keepWorktree:n.keepWorktree,prompt:n.prompt,name:n.name,workspace:n.workspace,skipLaunch:n.skipLaunch});await o(),r(i.exitCode)}catch(e){throw await o(),e}}catch(t){let i=t instanceof b?t:new b(`Error executing run-workflow.`,J,{background:!!n.background,command:q,workflow:e,workspace:n.workspace},{cause:t});o(`${i.message} [${i.code}]`,i),r(1)}})}const xt=bt(),$=`schedule-cron`;function St(e={}){let n=e.createService??(()=>new s),i=e.exit??(e=>process.exit(e)),a=e.logError??((e,t)=>console.error(e,t)),o=e.writeStdout??(e=>process.stdout.write(`${e}\n`));return new h($).description(`Schedule a headless Claude Code or Codex CLI run via system crontab`).argument(`<name>`,`Unique name for this cron job`).option(`-d, --cwd <path>`,`Working directory for the CLI run`,process.cwd()).option(`-c, --cli <cli>`,`CLI to use: claude or codex`,t).option(`-p, --prompt <text>`,`Prompt to pass to the CLI`).option(`-f, --prompt-file <path>`,`Path to a file whose content is used as the prompt (read at cron execution time)`).option(`-s, --schedule <cron>`,`Cron expression (e.g., "*/10 * * * *")`).option(`-i, --interval-minutes <minutes>`,`Run every N minutes (alternative to --schedule)`).action(async(e,t)=>{try{let a=r.parse({name:e,cwd:t.cwd??process.cwd(),cli:t.cli??`claude`,prompt:t.prompt,promptFile:t.promptFile,schedule:t.schedule,intervalMinutes:t.intervalMinutes?Number.parseInt(t.intervalMinutes,10):void 0}),s=await n().schedule(a);o(`Scheduled cron job "${s.name}" with schedule: ${s.schedule}`),o(`CLI: ${s.cli} | CWD: ${s.cwd}`),s.prompt&&o(`Prompt: ${s.prompt}`),i(0)}catch(t){let n=t instanceof b?t:new b(`Error scheduling cron job.`,`SCHEDULE_CRON_COMMAND_FAILED`,{command:$,name:e},{cause:t});a(`${n.message} [${n.code}]`,n),i(1)}})}const Ct=St(),wt=`stop-workflow`;function Tt(e={}){let t=e.createRegistry??(()=>new a),n=e.exit??(e=>process.exit(e)),r=e.logError??((e,t)=>console.error(e,t)),i=e.writeStdout??(e=>process.stdout.write(e));return new h(wt).description(`Request a running workflow to stop gracefully`).argument(`<run-key>`,`Running workflow run key`).option(`-w, --workspace <name>`,`Workspace containing the running workflow`,`default`).option(`-r, --reason <text>`,`Optional stop reason to record`).action(async(e,a)=>{try{let r=t(),o=await r.requestStop(a.workspace,e,a.reason);i(`${JSON.stringify({reason:o.reason,requestedAt:o.requestedAt,runKey:e,workspace:r.resolveWorkspace(a.workspace)},null,2)}\n`),n(0)}catch(t){let i=new b(`Error requesting workflow stop.`,`STOP_WORKFLOW_FAILED`,{command:wt,runKey:e,workspace:a.workspace},{cause:t});r(`${i.message} [${i.code}]`,i),n(1)}})}const Et=Tt();async function Dt(){let e=new h;e.name(`workflow-mcp`).description(`MCP server for running GitHub Actions workflows locally`).version(oe),e.addCommand(st),e.addCommand(lt),e.addCommand(be),e.addCommand(ve),e.addCommand(Fe),e.addCommand(Ie),e.addCommand(it),e.addCommand(at),e.addCommand(ht),e.addCommand(_t),e.addCommand(xt),e.addCommand(Ct),e.addCommand(Et),await e.parseAsync(process.argv)}Dt().catch(e=>{console.error(`[CLI_STARTUP_ERROR] workflow-mcp startup failed:`,e),process.exit(1)});export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/workflow-mcp",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "MCP server for running GitHub Actions workflows locally",
5
5
  "keywords": [
6
6
  "mcp",
@@ -36,10 +36,10 @@
36
36
  "commander": "14.0.3",
37
37
  "js-yaml": "4.1.1",
38
38
  "zod": "4.4.1",
39
- "@agimon-ai/foundation-process-registry": "0.10.2",
40
- "@agimon-ai/foundation-port-registry": "0.10.2",
41
- "@agimon-ai/log-sink-mcp": "0.10.2",
42
- "@agimon-ai/foundation-validator": "0.7.2"
39
+ "@agimon-ai/foundation-validator": "0.7.3",
40
+ "@agimon-ai/foundation-port-registry": "0.10.3",
41
+ "@agimon-ai/foundation-process-registry": "0.10.3",
42
+ "@agimon-ai/log-sink-mcp": "0.10.3"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/js-yaml": "4.0.9",