import { type ResolveShellOpts, type ShellResolution } from "./shell.js"; export interface PersistentRunResult { exitCode: number | "TIMEOUT"; output: string; /** Timeout/abort only: true when the command was stopped and the shell kept its state. */ shellKept?: boolean; } interface Snapshot { cwd: string | null; env: string; } /** Single-quote for bash. */ export declare function shellQuote(value: string): string; /** * Split a state file (`pwd -P` line, then `export -p`) into cwd + env script. * Variables the new shell must own (PWD, OLDPWD, SHLVL) are dropped. */ export declare function parseStateSnapshot(text: string): Snapshot | null; /** Restore script: env first (its PWD is filtered), then cd, then report where we landed. */ export declare function buildRestoreScript(snapshot: Snapshot): string; export declare class PersistentShell { private readonly cwd; private readonly env; private readonly maxOutputBytes; private readonly shellOpts?; private readonly launch?; private child; /** The shell's own `$$`, used to stop just its command. */ private shellPid; private busy; private stateDir; /** * One-line notes about restarts, kept until `takeRestartNote()` so a helper * run (e.g. a guard's `pwd`) cannot swallow the note meant for the model. */ private pendingNotes; /** Bumped by kill(): a run cut short by an explicit kill must not restart the shell. */ private generation; constructor(cwd: string, env: NodeJS.ProcessEnv, maxOutputBytes: number, shellOpts?: ResolveShellOpts | undefined, launch?: ShellResolution | undefined); /** * Consume the note(s) for the model about shell restarts since the last * call, e.g. `[Shell exited with code 3, so it was restarted; restored * working directory /x and exported environment variables. …]`. */ takeRestartNote(): string | undefined; /** True while a previous persistent command is still running. */ get isBusy(): boolean; /** Private 0700 temp dir holding the state snapshot; null if unavailable. */ private get statePath(); private readSnapshot; private spawnChild; /** Spawn a shell, install the interrupt trap and learn its pid. */ private startShell; /** * Replace a dead (or killed) shell with a fresh one restored from the * snapshot taken after the last completed command. Returns the one-line * note for the tool result: `[Shell , so it was restarted; . * ]`. */ private restart; /** * The shell's own pid, if it is a real descendant of the spawned process * (inside a Linux sandbox's pid namespace `$$` is not a host pid). Never on * Windows, where MSYS pids are not native pids. */ private verifiedShellPid; private hardKill; /** * Write one script and wait for its sentinel. `run()` passes a signal and * gets the stop-the-command-not-the-shell interrupt; setup scripts don't. */ private send; /** * Run one command in the session shell. Serialized by the tool's sequential * execution mode; a concurrent call while busy is rejected defensively. */ run(command: string, timeoutMs: number, signal: AbortSignal, onChunk?: (text: string) => void): Promise; /** Kill the session shell and drop its saved state; the next run() starts fresh. */ kill(): void; } export {};