/**
 * Shared subprocess helpers for runtime code paths.
 *
 * Motivation — why NOT use raw `promisify(exec)`:
 *   Node's `exec` with no `timeout` option hangs forever if the child
 *   never exits, and the default `killSignal` is SIGTERM which a stuck
 *   helper can ignore (or be stuck inside an uninterruptible XPC /
 *   kernel call and never receive). When a hung child lives inside a
 *   `Promise.allSettled` branch or blocks a tool-call handler, the
 *   agent's main loop / tool executor deadlocks.
 *
 * Every shell-exec call on the agent's runtime hot path (screenshot,
 * computer_use tool, android_use tool, transcription, etc.) should go
 * through `execWithTimeout` so the child is SIGKILL'd on timeout and
 * the promise always resolves or rejects in bounded time.
 *
 * This module intentionally has no other dependencies so it can be
 * imported from tool executors without pulling in the logger or config.
 */
import { exec, execFile } from "node:child_process";
declare const execAsync: typeof exec.__promisify__;
declare const execFileAsync: typeof execFile.__promisify__;
/** Default per-subprocess timeout. */
export declare const DEFAULT_EXEC_TIMEOUT_MS = 15000;
/** Tight timeout for quick-check helpers (`which`, `pmset`, `pgrep`, …). */
export declare const QUICK_EXEC_TIMEOUT_MS = 5000;
/** Longer timeout for heavy jobs (compiles, ffmpeg multi-pass, large `adb` payloads). */
export declare const HEAVY_EXEC_TIMEOUT_MS = 60000;
export type ExecOptions = Parameters<typeof execAsync>[1];
export type ExecFileOptions = Parameters<typeof execFileAsync>[2];
/**
 * Run a shell command with a hard timeout. On timeout the child is
 * SIGKILL'd and the promise rejects — never hangs forever like raw
 * `promisify(exec)` does when `{ timeout }` is omitted.
 *
 * stdout / stderr are always returned as strings even when the caller
 * passed an options bag that would normally yield Buffers, so call-sites
 * can rely on string methods without narrowing.
 */
export declare function execWithTimeout(command: string, options?: ExecOptions & {
    timeout?: number;
}): Promise<{
    stdout: string;
    stderr: string;
}>;
/**
 * `execFile` variant of {@link execWithTimeout}. Prefer this over `execFile`
 * directly when shell metacharacter handling isn't required — it avoids the
 * quoting pitfalls of shell-string commands while giving the same hard-kill
 * timeout guarantee.
 *
 * Like Node's `execFile`, `timeout` is forwarded via the options bag. The
 * kill signal is always forced to `SIGKILL` (any caller-supplied
 * `killSignal` is overwritten) because hung children blocked in syscalls
 * can ignore SIGTERM indefinitely, which defeats the purpose of this
 * wrapper. Callers that genuinely need a different signal should use
 * Node's `child_process.execFile` directly.
 */
export declare function execFileWithTimeout(file: string, args?: readonly string[], options?: ExecFileOptions & {
    timeout?: number;
}): Promise<{
    stdout: string;
    stderr: string;
}>;
/**
 * Run a command under `sudo` with a hard timeout.
 *
 * - If `password` is provided, pipes it to `sudo -S` via stdin so the
 *   call works even when passwordless sudo (NOPASSWD) is not configured.
 *   `-p ""` suppresses the usual password prompt so stderr stays clean.
 * - If `password` is omitted, falls back to plain `sudo`, which requires
 *   passwordless sudo to already be configured for the current user.
 *
 * Like {@link execFileWithTimeout}, the child is SIGKILL'd on timeout so
 * this never hangs forever even if sudo blocks waiting for a TTY.
 */
export declare function execSudo(args: readonly string[], options?: {
    password?: string;
    timeoutMs?: number;
}): Promise<{
    stdout: string;
    stderr: string;
}>;
/**
 * Race a promise against a wall-clock timeout. Used as a last-resort
 * ceiling around a sequence of calls — individual subprocess timeouts
 * are the primary defence, this is belt-and-suspenders for the cases
 * where multiple hung subprocesses in sequence could add up past the
 * acceptable budget.
 *
 * Note: this only rejects the promise; it does NOT cancel the wrapped
 * work. Pair it with `execWithTimeout` at the leaves so child processes
 * still terminate even if the outer race rejects first.
 */
export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T>;
export {};
//# sourceMappingURL=exec.d.ts.map