Files
united-workforce/packages/workflow-util-agent/src/spawn-cli.ts
T
xingyue ecc348f182 feat(agent): add command config to hermes/cursor agents + explicit env inheritance
- HermesAgentConfig.command: override hermes CLI path (default: "hermes")
- CursorAgentConfig.command: override cursor-agent CLI path (default: "cursor-agent")
- spawnCli: explicit env: process.env for clarity and future extensibility
- bundle-entry: read WORKFLOW_CURSOR_COMMAND from env
2026-05-12 12:49:28 +08:00

72 lines
1.9 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,
env: process.env,
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 }));
});
});
}