export interface CommandHandlers { onOutput: (chunk: string, stream: "stdout" | "stderr") => void; onDone: (exitCode: number, durationMs: number) => void; onError: (error: string) => void; } export interface RunningCommand { kill: () => void; } export interface CommandExecutionOptions { /** * Desktop-only path to the signed launcher in Electron extraResources. npm * and source runs resolve their package-relative dist-native copy. */ windowsExecLauncherPath?: string; /** * Absolute epoch-ms instant at which the CALLER will declare this command * timed out (connection.ts arms its own timer). The executor cannot see that * deadline otherwise, and the post-exit drain below would happily push a * command that exited just under the wire past it — the caller would then * report "Command timed out" for work that actually finished in time. Given * the deadline we clamp the drain to end before it. Optional because callers * without a deadline (tests, library embedders) simply get the unclamped * drain; when it IS supplied it is honoured, never merely recorded. */ deadlineMs?: number; /** * Which interpreter to run the command in (protocol ExecShell: "sh" | "bash" | * "cmd" | "powershell"). Omitted = this machine's historical default, which is * what every caller predating the field gets. * * Typed as a plain string because it arrives off a relay frame: planExecShell * validates it against what THIS machine can actually run and refuses anything * else through onError. It is never coerced to the default — running a command * in a language the caller did not ask for is the failure this field exists to * prevent. */ shell?: string | undefined; /** * The filesystem probe planExecShell uses to decide whether the requested * interpreter exists here (`/bin/bash`, `powershell.exe`). Defaults to the real * one; a caller that supplies it is choosing a different answer to "is this * interpreter present", nothing more. * * It exists because it is the ONLY way the PowerShell half of this file can be * exercised off Windows. `plan.clixmlStderr` — which decides whether stderr * goes through the CLIXML decoder at all — can only be true when planning says * powershell.exe is present, so without this seam the decoder wiring here (the * emitStderr funnel, the pre-handshake replay, the flush before settle) was * asserted by comments alone and CI would have passed with any of it deleted. * It changes no decision on a real machine: nobody in the product passes it. */ shellExists?: (candidate: string) => boolean; } export declare function executeCommand(command: string, cwd: string | undefined, env: Record | undefined, handlers: CommandHandlers, options?: CommandExecutionOptions): RunningCommand;