UNPKG

framework

Version:

The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.

53 lines 2.44 kB
/** * One `execFile`-backed CLI runner, configured per binary. * * `git` and `gh` were each wrapped by hand — the same dynamic import, the same promise * around `execFile`, the same `String(stdout)` — differing only in the binary, the timeout * and how a failure is reported. Those are the parameters; the wrapper is not worth writing * twice, and it was written five times. */ /** * A CLI killed for outrunning its timeout, as opposed to one the tool itself rejected (#997). * * `execFile` SIGTERMs on timeout, and a killed `git push` usually writes nothing to stderr, so * without this the failure surfaces as a bare "Command failed: git push ..." that reads like a * rejected push. */ export class CliTimeoutError extends Error { bin; args; timeoutMs; /** Brand, so a value that crossed a module boundary is still recognisable. */ timedOut = true; constructor(bin, args, timeoutMs) { super(`${bin} ${args.join(' ')} timed out after ${timeoutMs}ms`); this.bin = bin; this.args = args; this.timeoutMs = timeoutMs; this.name = 'CliTimeoutError'; } } /** True when a {@link CliRunner} rejection is a timeout kill rather than a non-zero exit (#997). */ export function isCliTimeout(err) { return err instanceof Error && err.timedOut === true; } /** Build a {@link CliRunner} for one binary. */ export function cliRunner(opts) { return async (args, cwd) => { const { execFile } = await import('node:child_process'); const timeoutMs = typeof opts.timeoutMs === 'function' ? opts.timeoutMs(args) : opts.timeoutMs; return new Promise((resolvePromise, rejectPromise) => { execFile(opts.bin, args, { cwd, timeout: timeoutMs, ...(opts.maxBuffer !== undefined ? { maxBuffer: opts.maxBuffer } : {}) }, (err, stdout, stderr) => { if (!err) return resolvePromise(String(stdout)); // execFile kills on both timeout and a maxBuffer overrun; only the latter carries ENOBUFS. const killed = err.killed === true; if (killed && err.code !== 'ENOBUFS') { return rejectPromise(new CliTimeoutError(opts.bin, args, timeoutMs)); } rejectPromise(opts.preferStderr ? new Error(String(stderr).trim() || err.message) : err); }); }); }; } //# sourceMappingURL=cli-exec.js.map