/**
 * Parse a stream of concatenated JSON objects (e.g. govulncheck's
 * pretty-printed `-json` output, where each top-level object spans many
 * lines and isn't single-line ndjson). Walks the input character by
 * character, tracking brace depth while ignoring braces inside string
 * literals and respecting backslash escapes. Each balanced `{...}` block
 * gets handed to `JSON.parse`; parse failures are dropped silently so
 * non-JSON noise (banner lines, trailing whitespace) doesn't poison the
 * stream.
 */
export declare function parseJsonStream(raw: string): unknown[];
/** Run a command and return stdout. Returns empty string on failure. */
export declare function run(cmd: string, cwd: string, timeoutMs?: number): string;
/**
 * Run a binary directly (NO shell) and return stdout, or '' on failure.
 *
 * Synchronous sibling of `runDetached` for single-binary tools that must
 * stay on a synchronous call path (e.g. the memoized `gatherGitleaksResult`).
 * Because there's no shell, there are no cross-platform quoting hazards:
 * pass the resolved binary path plus an args array and Node hands them to
 * the OS verbatim. This is the portable replacement for building a shell
 * string with single-quotes + `2>/dev/null` — both of which are POSIX-only
 * and break under Windows' cmd.exe (single-quotes don't quote; the
 * redirect writes a stray `nul` file instead of discarding stderr).
 */
export declare function runFileSync(file: string, args: string[], cwd: string, timeoutMs?: number): string;
/** Run a command and return the exit code. */
export declare function runExitCode(cmd: string, cwd: string, timeoutMs?: number): number;
/** Run a command and parse stdout as JSON. Returns null on failure. */
export declare function runJSON<T>(cmd: string, cwd: string, timeoutMs?: number): T | null;
/** Count lines in command output. */
export declare function countLines(cmd: string, cwd: string): number;
/**
 * Cross-platform "where is this binary on PATH?" resolver. Returns the
 * absolute path of the first match, or null.
 *
 * Pure-Node: walks `process.env.PATH` entries and checks each candidate
 * with `fs`, honoring `%PATHEXT%` on Windows. This replaces the prior
 * `which <binary> 2>/dev/null` shell probe, which silently
 * false-negatived EVERY tool on Windows — cmd.exe has no `which` (it's
 * `where`), and `2>/dev/null` is a POSIX redirect that writes a stray
 * `nul` file rather than discarding stderr. The shell probe is also
 * unnecessary: PATH resolution is a filesystem walk that Node can do
 * directly, with no subprocess to spawn.
 */
export declare function resolveOnPath(binary: string): string | null;
/** Resolve `binary` against an explicit list of directories, honoring
 *  `%PATHEXT%` on Windows. Returns the first matching absolute path, or
 *  null. Used for system probe dirs and user-configured tool paths so
 *  they match `git.exe` / `tool.cmd` on Windows the same way a PATH
 *  walk does. */
export declare function resolveInDirs(binary: string, dirs: string[]): string | null;
/** Check if a command is available on PATH (cross-platform). */
export declare function commandExists(cmd: string, _cwd?: string): boolean;
/** Check if a file exists relative to cwd. */
export declare function fileExists(cwd: string, ...paths: string[]): boolean;
/**
 * Outcome of a `runDetached` invocation.
 *  - `code` is the child's exit status, `null` if the timeout fired.
 *  - `timedOut` is true when the process group was killed by our timer.
 *  - `stdout`/`stderr` are the captured output up to the kill / exit.
 */
export interface DetachedRunOutcome {
    stdout: string;
    stderr: string;
    code: number | null;
    timedOut: boolean;
}
/**
 * Run a command in its OWN process group and SIGKILL the whole group on
 * timeout. Solves the orphan-grandchild leak that `execSync(..., {timeout})`
 * has: when execSync's timer fires, it sends SIGTERM to the immediate child,
 * but if that child has already spawned grandchildren (e.g. `osv-scanner fix`
 * → `npm install` → its own subprocesses), the grandchildren stay alive,
 * orphaned to PID 1. They keep eating CPU/memory until they finish or the
 * shell exits.
 *
 * Discovered during 2.4.5 pre-ship regression on dxkit-on-dxkit (10k.1.5c):
 * each `dxkit vulnerabilities` run on a slow target was leaving 1-3 orphan
 * `osv-scanner fix` processes behind, surviving past the dxkit invocation
 * and slowing subsequent steps. Pre-fix, repeated runs accumulated leaks.
 *
 * Mechanism:
 *   - `spawn(cmd, args, { detached: true })` puts the child in its own
 *     process group (its PGID = its PID).
 *   - On timeout, `process.kill(-child.pid, 'SIGKILL')` — the negative PID
 *     means "send to every process in the group", taking grandchildren too.
 *   - We never call `child.unref()` so the parent keeps reference to the
 *     child; the parent shell waits for completion as expected.
 *
 * Returns captured stdout/stderr regardless of how the run ended (timeout
 * still hands back whatever the tool wrote before being killed). Callers
 * that need to distinguish "timeout vs clean exit" check `outcome.timedOut`.
 *
 * Use this whenever a tool may spawn its own subprocesses AND the timeout
 * is short enough that it could fire mid-grandchild. For pure single-binary
 * tools (gitleaks, semgrep), `run()` / `execSync` is fine — no grandchildren
 * means no leak risk.
 */
export declare function runDetached(cmd: string, args: string[], opts: {
    cwd: string;
    timeoutMs: number;
}): Promise<DetachedRunOutcome>;
//# sourceMappingURL=runner.d.ts.map