This repository has been archived on 2026-06-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
workflow/packages/workflow-util-agent/src/spawn-cli.ts
T
xiaoju e9e4960714 refactor(workflow): migrate downstream packages to workflow-runtime (Phase 2+3)
- Verify createWorkflow in runtime has zero I/O imports
- Migrate agent-cursor, agent-hermes to pure workflow-runtime dependency
- Migrate agent-llm, util-agent, templates to dual dependency
  (runtime for types, engine for CAS/merkle/buildDescriptor)
- All 377 tests passing

Refs #121, relates #123 #124
2026-05-08 06:33:52 +00:00

71 lines
1.8 KiB
TypeScript

import { spawn } from "node:child_process";
import { err, ok, type Result } from "@uncaged/workflow-runtime";
export type SpawnCliError =
| { kind: "non_zero_exit"; exitCode: number | null; stdout: string; stderr: string }
| { kind: "timeout" }
| { kind: "spawn_failed"; message: string };
export type SpawnCliConfig = {
cwd: string | null;
timeoutMs: number | null;
};
export type SpawnCliResult = Result<string, SpawnCliError>;
export function spawnCli(
command: string,
args: string[],
options: SpawnCliConfig,
): Promise<SpawnCliResult> {
return new Promise((resolve) => {
const child = spawn(command, args, {
cwd: options.cwd === null ? undefined : options.cwd,
shell: false,
stdio: ["ignore", "pipe", "pipe"],
});
let stdout = "";
let stderr = "";
child.stdout?.on("data", (chunk: Buffer) => {
stdout += chunk.toString();
});
child.stderr?.on("data", (chunk: Buffer) => {
stderr += chunk.toString();
});
let timedOut = false;
let timeoutId: ReturnType<typeof setTimeout> | null = null;
if (options.timeoutMs !== null) {
timeoutId = setTimeout(() => {
timedOut = true;
child.kill("SIGTERM");
}, options.timeoutMs);
}
child.on("error", (cause) => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
}
const message = cause instanceof Error ? cause.message : String(cause);
resolve(err({ kind: "spawn_failed", message }));
});
child.on("close", (code) => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
}
if (timedOut) {
resolve(err({ kind: "timeout" }));
return;
}
if (code === 0) {
resolve(ok(stdout));
return;
}
resolve(err({ kind: "non_zero_exit", exitCode: code, stdout, stderr }));
});
});
}