@agimon-ai/workflow-mcp 0.3.0 → 0.3.1
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 +1 -1
- package/dist/cli.mjs +1 -1
- package/package.json +5 -5
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.
|
|
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.0`;const u=`WORKFLOW_STATUS_FILE`,ee={readStdin:oe,readStatusFile:se,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
|
|
3
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}ie(r.error)||r.terminationReason!==`model_stop`||await e.writeStatusFile(t)}}function ne(e){try{let t=JSON.parse(e);return ae(t)?{conversationId:typeof t.conversationId==`string`?t.conversationId:void 0,transcriptPath:d(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 d(e){return typeof e==`string`&&e.trim().length>0?e:null}function ie(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}}const ce=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={readStdin:_,readStatusFile:v,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
|
|
4
4
|
`,`utf8`)},workflowStatusFile:process.env[m]},h={readStdin:_,readStatusFile:v,writeSessionBinding:async(e,t)=>{await(0,n.writeFile)(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[m]};async function fe(e=h){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=he(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 pe(e=de){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=ge(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`)return;let i=_e(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i)return;let a=r.background_tasks.length>0,o=r.session_crons.length>0;if(a){e.writeStdout?.(me(`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`));return}o||await e.writeStatusFile(t)}function me(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}function he(e){try{let t=JSON.parse(e);return g(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 ge(e){try{let t=JSON.parse(e);if(!g(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 _e(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 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 v(e){try{return await(0,n.readFile)(e,`utf8`)}catch{return null}}const ve=new s.Command(`claude-session-start-hook`).description(`Claude Code SessionStart hook: binds ${m} to the root Claude session id`).action(async()=>{await fe()}),ye=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 pe()}),y=`WORKFLOW_STATUS_FILE`,b=`session_meta`,be=[`sub_agent`,`subagent`],xe=new Set([`in_progress`,`inProgress`,`running`,`pending_init`,`pendingInit`]),Se=new Set([`collabAgentToolCall`,`commandExecution`,`dynamicToolCall`,`imageGeneration`,`local_shell_call`,`mcpToolCall`]),Ce={readStdin:M,readStatusFile:N,readTranscriptHead:P,readTranscriptState:F,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await(0,n.writeFile)(e,`YES
|
|
5
5
|
`,`utf8`)},workflowStatusFile:process.env[y]},x={readStdin:M,readStatusFile:N,writeSessionBinding:async(e,t)=>{await(0,n.writeFile)(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[y]};async function S(e=x){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)return;let i=await e.readStatusFile(t);i===null||i.trim().length>0||await e.writeSessionBinding(t,r.session_id)}async function C(e=Ce){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=D(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`||r.stop_hook_active&&!r.hasTaskRegistry)return;let i=k(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i)return;let a=O(r.transcript_path);if(!a)return;let o=await T(e,a),s=o.sessionMeta;if(!s||r.session_id&&s.id&&r.session_id!==s.id||A(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?.(w(`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 w(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}async function T(e,t){return e.readTranscriptState?e.readTranscriptState(t):e.readTranscriptHead===P?F(t):{sessionMeta:await e.readTranscriptHead(t),hasPendingWork:!1}}function E(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 D(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: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 k(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 A(e){return typeof e==`string`?e.startsWith(`subagent_`)||e.startsWith(`internal_`):j(e)?be.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=we(t);n&&(s||=Te(n),Ee(n,r),De(n,a))}}finally{n.close(),t.destroy()}return{sessionMeta:s,hasPendingWork:r.size>0||Array.from(a.values()).some(R)}}function we(e){try{let t=JSON.parse(e);return j(t)?t:null}catch{return null}}function Te(e){return e.type===b?e.payload??null:e.item?.type===b?e.item.payload??null:null}function Ee(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||!Se.has(i)||(R(n.status)?t.add(r):t.delete(r))}function De(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&&xe.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 Oe=new s.Command(`codex-session-start-hook`).description(`Codex session-start hook: binds ${y} to the first workflow Codex session id`).action(async()=>{await S()}),ke=new s.Command(`codex-stop-hook`).description(`Codex stop hook: reads stop-hook JSON on stdin and marks ${y} when the root session ends`).action(async()=>{await C()}),V=`list-crons`;function Ae(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 je=Ae(),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 Me(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 Ne=Me(),Pe=()=>{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 Fe(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 Ie(e){let t=Pe();if(!t)return async()=>{};let n=Fe(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 Le(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 Re(e){try{await e()}catch{}}const ze=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 Ie(t.serviceName);try{let r=t.type.toLowerCase();r===`stdio`?await Le(new e.t(e.n()),n):(console.error(`Unknown transport type: ${r}. Use: stdio`),process.exit(1))}catch(e){await Re(n),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),G=`recover-workflow`;function Be(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 Ve=Be(),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 He(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 Ue(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 We(t={}){let n=t.createService??(()=>new e.i),r=t.exit??(e=>process.exit(e)),i=t.launchBackgroundRun??He,a=t.registerBackgroundChild??Ue,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 Ge=We(),Q=`schedule-cron`;function Ke(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 qe=Ke(),$=`stop-workflow`;function Je(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 Ye=Je();async function Xe(){let e=new s.Command;e.name(`workflow-mcp`).description(`MCP server for running GitHub Actions workflows locally`).version(l),e.addCommand(je),e.addCommand(Ne),e.addCommand(ue),e.addCommand(ce),e.addCommand(ve),e.addCommand(ye),e.addCommand(Oe),e.addCommand(ke),e.addCommand(ze),e.addCommand(Ve),e.addCommand(Ge),e.addCommand(qe),e.addCommand(Ye),await e.parseAsync(process.argv)}Xe().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 f}from"@agimon-ai/foundation-process-registry";import{createInterface as re}from"node:readline";import{Command as p,InvalidArgumentError as m}from"commander";var ie=`0.
|
|
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 f}from"@agimon-ai/foundation-process-registry";import{createInterface as re}from"node:readline";import{Command as p,InvalidArgumentError as m}from"commander";var ie=`0.3.0`;const h=`WORKFLOW_STATUS_FILE`,ae={readStdin:g,readStatusFile:fe,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await d(e,`YES
|
|
3
3
|
`,`utf8`)},workflowStatusFile:process.env[h]};async function oe(e=ae){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=se(n);if(!r?.conversationId)return;let i=await e.readStatusFile(t);if(!(i===null||i.trim()===`YES`)){if(!r.fullyIdle){e.writeStdout?.(ce(`In-progress work is still running. Continue the execution loop until background tasks finish.`));return}ue(r.error)||r.terminationReason!==`model_stop`||await e.writeStatusFile(t)}}function se(e){try{let t=JSON.parse(e);return de(t)?{conversationId:typeof t.conversationId==`string`?t.conversationId:void 0,transcriptPath:le(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 ce(e){return`${JSON.stringify({decision:`continue`,reason:e})}\n`}function le(e){return typeof e==`string`&&e.trim().length>0?e:null}function ue(e){return typeof e==`string`&&e.trim().length>0}function de(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 fe(e){try{return await u(e,`utf8`)}catch{return null}}const pe=new p(`antigravity-stop-hook`).description(`Antigravity stop hook: reads Stop hook JSON on stdin and marks ${h} when the execution is fully idle`).action(async()=>{await oe()});var _=class extends Error{constructor(e,t,n={},r){super(e,r),this.code=t,this.context=n,this.name=`WorkflowCommandError`}};const v=`check-codex-quota`;function me(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(v).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 _(`Codex quota is blocking work at ${e.blockingLimit.limitId}/${e.blockingLimit.window}.`,`CODEX_QUOTA_BLOCKED`,{command:v,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 _?e:new _(`Error checking Codex quota.`,`CHECK_CODEX_QUOTA_COMMAND_FAILED`,{command:v},{cause:e});i(`${t.message} [${t.code}]`,t),r(1)}})}const he=me(),y=`WORKFLOW_STATUS_FILE`,ge={readStdin:x,readStatusFile:S,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await d(e,`YES
|
|
4
4
|
`,`utf8`)},workflowStatusFile:process.env[y]},_e={readStdin:x,readStatusFile:S,writeSessionBinding:async(e,t)=>{await d(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[y]};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=Ce(await e.readStatusFile(t));if(!r.session_id||r.session_id!==i)return;let a=r.background_tasks.length>0,o=r.session_crons.length>0;if(a){e.writeStdout?.(be(`In-progress work is still running. Wait for spawned agents and running tool calls to finish before ending the turn.`));return}o||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 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 Se(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 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 u(e,`utf8`)}catch{return null}}const we=new p(`claude-session-start-hook`).description(`Claude Code SessionStart hook: binds ${y} to the root Claude session id`).action(async()=>{await ve()}),C=new p(`claude-stop-hook`).description(`Claude Code stop hook: reads Stop hook JSON on stdin and marks ${y} when the root session is complete`).action(async()=>{await ye()}),w=`WORKFLOW_STATUS_FILE`,T=`session_meta`,E=[`sub_agent`,`subagent`],D=new Set([`in_progress`,`inProgress`,`running`,`pending_init`,`pendingInit`]),O=new Set([`collabAgentToolCall`,`commandExecution`,`dynamicToolCall`,`imageGeneration`,`local_shell_call`,`mcpToolCall`]),k={readStdin:M,readStatusFile:N,readTranscriptHead:P,readTranscriptState:F,writeStdout:e=>{process.stdout.write(e)},writeStatusFile:async e=>{await d(e,`YES
|
|
5
5
|
`,`utf8`)},workflowStatusFile:process.env[w]},Te={readStdin:M,readStatusFile:N,writeSessionBinding:async(e,t)=>{await d(e,`${JSON.stringify({sessionId:t})}\n`,`utf8`)},workflowStatusFile:process.env[w]};async function Ee(e=Te){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=Ae(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 De(e=k){let t=e.workflowStatusFile;if(!t)return;let n=await e.readStdin();if(n.trim().length===0)return;let r=je(n);if(!r||r.hook_event_name&&r.hook_event_name!==`Stop`||r.stop_hook_active&&!r.hasTaskRegistry)return;let i=Me(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 ke(e,a),s=o.sessionMeta;if(!s||r.session_id&&s.id&&r.session_id!==s.id||Ne(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?.(Oe(`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 Oe(e){return`${JSON.stringify({decision:`block`,reason:e,suppressOutput:!0})}\n`}async function ke(e,t){return e.readTranscriptState?e.readTranscriptState(t):e.readTranscriptHead===P?F(t):{sessionMeta:await e.readTranscriptHead(t),hasPendingWork:!1}}function Ae(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 je(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 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 Ne(e){return typeof e==`string`?e.startsWith(`subagent_`)||e.startsWith(`internal_`):j(e)?E.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 u(e,`utf8`)}catch{return null}}async function P(e){return(await F(e)).sessionMeta}async function F(e){let t=ne(e,{encoding:`utf8`}),n=re({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=Pe(t);n&&(a||=Fe(n),Ie(n,r),Le(n,i))}}finally{n.close(),t.destroy()}return{sessionMeta:a,hasPendingWork:r.size>0||Array.from(i.values()).some(R)}}function Pe(e){try{let t=JSON.parse(e);return j(t)?t:null}catch{return null}}function Fe(e){return e.type===T?e.payload??null:e.item?.type===T?e.item.payload??null:null}function Ie(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||!O.has(i)||(R(n.status)?t.add(r):t.delete(r))}function Le(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&&D.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 Re=new p(`codex-session-start-hook`).description(`Codex session-start hook: binds ${w} to the first workflow Codex session id`).action(async()=>{await Ee()}),ze=new p(`codex-stop-hook`).description(`Codex stop hook: reads stop-hook JSON on stdin and marks ${w} when the root session ends`).action(async()=>{await De()}),V=`list-crons`;function Be(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 _(`Error listing cron jobs.`,`LIST_CRONS_COMMAND_FAILED`,{command:V},{cause:e});r(`${t.message} [${t.code}]`,t),n(1)}})}const Ve=Be(),H=`list-workflow-statuses`;function U(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw new m(`Expected a positive integer.`);return t}function He(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 _(`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 Ue=He(),We=()=>{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 Ge(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 Ke(e){let t=We();if(!t)return async()=>{};let n=Ge(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 qe(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 Je(e){try{await e()}catch{}}const Ye=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 Ke(e.serviceName);try{let n=e.type.toLowerCase();n===`stdio`?await qe(new c(i()),t):(console.error(`Unknown transport type: ${n}. Use: stdio`),process.exit(1))}catch(e){await Je(t),console.error(`Failed to start MCP server:`,e),process.exit(1)}}),G=`recover-workflow`;function Xe(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 _(`Error recovering workflow.`,`RECOVER_WORKFLOW_FAILED`,{command:G,runKey:e,workspace:i.workspace},{cause:t});r(`${a.message} [${a.code}]`,a),n(1)}})}const Ze=Xe(),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 _(`Conflicting runner selectors.`,q,{cliAgent:e.cliAgent,command:K,runner:e.runner});return e.runner??e.cliAgent}function Qe(e,t){let n=process.argv[1];if(!n)throw new _(`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 $e(e,t){if(process.env[J]!==`1`)return async()=>{};let n=new f(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 et(e={}){let t=e.createService??(()=>new n),r=e.exit??(e=>process.exit(e)),i=e.launchBackgroundRun??Qe,a=e.registerBackgroundChild??$e,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 _?t:new _(`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 tt=et(),Q=`schedule-cron`;function nt(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 _?t:new _(`Error scheduling cron job.`,`SCHEDULE_CRON_COMMAND_FAILED`,{command:Q,name:e},{cause:t});a(`${n.message} [${n.code}]`,n),i(1)}})}const rt=nt(),$=`stop-workflow`;function it(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 _(`Error requesting workflow stop.`,`STOP_WORKFLOW_FAILED`,{command:$,runKey:e,workspace:a.workspace},{cause:t});r(`${i.message} [${i.code}]`,i),n(1)}})}const at=it();async function ot(){let e=new p;e.name(`workflow-mcp`).description(`MCP server for running GitHub Actions workflows locally`).version(ie),e.addCommand(Ve),e.addCommand(Ue),e.addCommand(he),e.addCommand(pe),e.addCommand(we),e.addCommand(C),e.addCommand(Re),e.addCommand(ze),e.addCommand(Ye),e.addCommand(Ze),e.addCommand(tt),e.addCommand(rt),e.addCommand(at),await e.parseAsync(process.argv)}ot().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.
|
|
3
|
+
"version": "0.3.1",
|
|
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-
|
|
40
|
-
"@agimon-ai/foundation-
|
|
41
|
-
"@agimon-ai/foundation-validator": "0.7.
|
|
42
|
-
"@agimon-ai/log-sink-mcp": "0.10.
|
|
39
|
+
"@agimon-ai/foundation-port-registry": "0.10.1",
|
|
40
|
+
"@agimon-ai/foundation-process-registry": "0.10.1",
|
|
41
|
+
"@agimon-ai/foundation-validator": "0.7.1",
|
|
42
|
+
"@agimon-ai/log-sink-mcp": "0.10.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/js-yaml": "4.0.9",
|