import { spawn, spawnSync, type StdioOptions } from "node:child_process"; export interface RunTrackedOptions { cwd?: string; env?: NodeJS.ProcessEnv; encoding?: BufferEncoding; timeout?: number; input?: string; maxBuffer?: number; windowsHide?: boolean; stdio?: StdioOptions; /** Override the platform; for tests. Defaults to `process.platform`. */ platform?: NodeJS.Platform; } export interface RunTrackedResult { status: number | null; stdout: string; stderr: string; /** The argv actually spawned, after platform wrapping. */ argv: string[]; /** The cwd passed to runTracked, if any. undefined means the command inherited the process CWD. */ cwd?: string; /** Elapsed wall-clock time in milliseconds for the spawned command. */ duration_ms: number; error?: Error; /** * The signal that killed the child, or `null` when it exited on its own. * * Reported, never DISCRIMINATED on by callers that need to know WHY a child * died: a deadline miss, a `maxBuffer` overflow and an external `kill` all * set it. The `error.code` (`ETIMEDOUT` / `ENOBUFS`) is what separates those * three; `signal` is the residue that names an external kill once they are * ruled out. */ signal?: string | null; } /** * Quote a single argv token for embedding into the `cmd.exe /d /s /c "..."` * command line used by `wrapForWindowsBatch`. * * Two layers of neutralization apply — both are required; this is the * CVE-2024-27980 lesson (see the block comment above): * * 1. **argv-parser layer**: wrap the token in double-quotes and double any * embedded `"` — this is what makes the eventual `.cmd`/`.bat` process * see the intended single argv value (doubled double-quotes are a * literal `"` under that parser's rules). * 2. **cmd.exe line-scan layer**: caret-escape `& | < > ^` wherever they * appear (even inside the double-quoted region from step 1) — cmd.exe * applies its own metacharacter scan to the *entire* `/d /s /c` line * before the argv-parser layer ever runs, and quotes do not block that * scan (the root cause of CVE-2024-27980). * * `%` cannot be neutralized this way: cmd.exe's percent-expansion of * `%VAR%` runs at yet another stage that caret-escaping does not reliably * suppress across cmd.exe's quirky invocation-shape-dependent rules (a * documented residual gap in Node core's own upstream fix for the same CVE * class). Rather than emit an escape that looks safe but can still be * defeated, this throws a clear error for any argument containing `%` * destined for a `.cmd`/`.bat` shim — callers must avoid routing a raw `%` * through this path (e.g. resolve/expand it before calling, or avoid the * shim). * * **Do not use this for shell-interpreter command strings.** For that context * (where the entire command is a shell string interpreted by cmd.exe before any * argv parser runs), use `quoteForShellInterpreterCmd` instead. */ export declare function quoteForCmd(arg: string): string; /** * Quote a single argv token for embedding inside a shell command line that is * rendered as one string: `cmd.exe` * double-quote doubling on Windows, POSIX single-quote escaping elsewhere. * Shared by command-rendering consumers in both orchestrators. */ export declare function shellQuote(arg: string, platform?: NodeJS.Platform): string; export declare function toPromptPathToken(value: string): string; /** * Quote a single argv token for a *rendered command line* that this tool * hands a host agent to run verbatim — the host may paste it into posix sh, * PowerShell, or cmd.exe, and this function does not know which. Double * quotes protect a token containing a space or shell metacharacter in all * three dialects, provided embedded double quotes are escaped, so: quote * whenever any character falls outside `PROMPT_COMMAND_SAFE_CHARS`, escaping * embedded `"` as `\"`. * * Target: safe to paste into posix sh, PowerShell, and cmd. */ export declare function quotePromptCommandArg(value: string): string; /** * Render an argv array into a single command-line string safe to paste into * posix sh, PowerShell, or cmd.exe — for step prompts and `allowed_commands` * a host agent is told to run verbatim, never for actually spawning a * process (that path is `runTracked`/`resolveExecArgv`, argv-only). * Normalizes path-like Windows tokens to forward slashes first * (`toPromptPathToken`) since `\` is an escape character in some of those * dialects, then quotes each token per `quotePromptCommandArg`. */ export declare function renderPromptCommand(argv: readonly string[]): string; export declare function coerceJsonObjectArg>(value: T | string | undefined, label: string): T; /** * On Windows, package-manager shims (`npm`/`npx`/`pnpm`/`yarn`) are `.cmd` * batch files that `spawn` cannot launch without a shell. Map them to their * `.cmd` form so the batch-wrapping path below applies. Anything already * carrying an executable extension is returned unchanged. */ export declare function platformCommand(command: string, platform?: NodeJS.Platform): string; /** * Quote a single argv token for embedding in a full command-line *string* * that `cmd.exe /c` will interpret as a shell command. * * **Context:** this is the *shell-interpreter* quoting context — the entire * command is one string seen by `cmd.exe` before any argv parser runs. In * this context metacharacters (`^&|<>%"`) must be caret-escaped. Safe * single-token characters pass through unquoted. * * **Do not confuse with `quoteForCmd`**, which is the *argv-parser* context * used by `wrapForWindowsBatch`. The difference: * * - `quoteForCmd` (argv-parser): wraps in double-quotes and doubles internal * `"` → `""`. Used in `cmd.exe /d /s /c "prog arg"` where cmd.exe's own * argv parser processes the quoted string. * * - `quoteForShellInterpreterCmd` (shell-interpreter): caret-escapes * metacharacters. Used when building an inline shell command string passed * to `cmd.exe /c`, e.g. the opencode launcher's `cmd.exe /c ""`. * * Canonical owner of this charset — the opencode launcher * (`resolveOpenCodeSpawnCommand`) imports it instead of carrying its own copy. */ export declare function quoteForShellInterpreterCmd(value: string): string; /** * Resolve a logical argv into the concrete `[command, ...args]` that should be * spawned on this platform, applying package-manager shim mapping and Windows * batch wrapping. Exposed for callers that spawn asynchronously and only need * the resolved argv. */ export declare function resolveExecArgv(argv: string[], options?: { platform?: NodeJS.Platform; }): string[]; /** * Strip audit-tools' wrapper-only control variables from a child environment. * Always operates on an explicit copy so the original is never mutated. When * `base` is undefined, falls back to `process.env`. */ export declare function stripAuditToolsControlEnv(base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv; /** Run a command synchronously. argv[0] is the command, the rest are args. */ export declare function runTracked(argv: string[], options?: RunTrackedOptions): RunTrackedResult; /** * Async twin of {@link runTracked}: same argv resolution, control-env scrub, and * result shape, driven by {@link spawnHidden} instead of `spawnSync`. Analyzer * acquisition runs HERE rather than on the synchronous runner because a * synchronous child blocks the event loop for the whole spawn — which starves * every `setInterval` liveness heartbeat in the process (the advance * heartbeat, and each held file lock's mtime heartbeat), so one stalled * `npx --version` probe classified a LIVE lock stale and stole it mid-flight. * Awaited by the acquisition engine, the binary resolver, and every closing / * required-test spawn; never mixed with {@link runTracked} in one call path. * * DEADLINE AND OVERFLOW ARE CLASSIFIED, not left as a bare signal. `spawnSync` * reports an over-deadline child as `ETIMEDOUT` and an over-`maxBuffer` child * as `ENOBUFS`, and callers discriminate on those codes precisely because * `signal` conflates them with an external `kill`. Node's own `timeout` option * on the async path would surface both as an ordinary SIGTERM close and throw * that distinction away, so this runner enforces BOTH bounds itself and stamps * the same two codes — one classification serves both twins, and the bounds * themselves are measured the same way (`maxBuffer` PER STREAM, as `spawnSync` * measures it) so the two twins cannot disagree about which children overflow. */ export declare function runTrackedAsync(argv: string[], options?: RunTrackedOptions): Promise; /** * `child_process.spawnSync` with `windowsHide` forced on. A windowless parent * (node launched by an IDE/agent) spawning a console child (git, sqlite3, …) pops * a console window on win32 unless suppressed — the many direct git spawns across * the remediate git-worktree machinery would otherwise each flash one. Thin * passthrough otherwise; callers keep their exact args/options and, via the * `typeof spawnSync` cast, its full encoding-based overloads (so `.stdout` stays * `string` under `{ encoding: "utf8" }`). `windowsHide` is forced last so it * always wins (no caller wants a visible window). */ export declare const spawnSyncHidden: typeof spawnSync; /** * Async twin of {@link spawnSyncHidden}: `child_process.spawn` with `windowsHide` * forced on. Same rationale — a windowless parent (node under an IDE/agent) * spawning a console child pops a console window on win32 unless suppressed. Thin * passthrough otherwise; callers keep their exact args/options and, via the * `typeof spawn` cast, its full overload set. `windowsHide` is forced last so it * always wins (no caller wants a visible window). */ export declare const spawnHidden: typeof spawn; //# sourceMappingURL=exec.d.ts.map