import { type SandboxPolicy } from "./sandbox.js"; import { type ToolOperations } from "../tools/operations.js"; /** * A live Node.js debugging session driven over the V8 inspector protocol * (Chrome DevTools Protocol). The program runs under `node --inspect-brk` * bound to loopback on a random port; this class connects, sets breakpoints, * steps, and reads real runtime state — so the agent can see the value that * broke instead of guessing from source and print-and-rerun loops. * * Node only, no new dependency: Node 22+ ships both the inspector and a global * WebSocket. `.ts` files work when run by Node's own type stripping, which * keeps line numbers; loaders that transpile (tsx, ts-node) shift lines. */ export type PauseOnExceptions = "none" | "uncaught" | "all"; export interface DebugLaunchOptions { cwd: string; program: string; args?: readonly string[]; nodeArgs?: readonly string[]; pauseOnExceptions?: PauseOnExceptions; breakpoints?: ReadonlyArray<{ file: string; line: number; condition?: string; }>; sandboxPolicy?: SandboxPolicy; ops?: ToolOperations; /** How long to wait for the inspector to come up. */ startTimeoutMs?: number; } export type StopState = { kind: "paused"; } | { kind: "exited"; code: number | null; } | { kind: "running"; }; interface RemoteObject { type: string; subtype?: string; className?: string; value?: unknown; unserializableValue?: string; description?: string; objectId?: string; preview?: ObjectPreview; } interface ObjectPreview { type: string; subtype?: string; description?: string; overflow: boolean; properties: Array<{ name: string; type: string; value?: string; subtype?: string; }>; entries?: Array<{ key?: ObjectPreview; value: ObjectPreview; }>; } interface Breakpoint { id: string; /** The URL-pattern breakpoint first, then one per script bound by exact URL. */ cdpIds: string[]; /** The pattern the first CDP breakpoint was set with. */ urlRegex: string; /** The target file, comparable with `samePath`. */ target: string; /** As the caller wrote it, for display. */ file: string; line: number; condition?: string; boundLines: number[]; } /** One-line rendering of a value the inspector returned. */ export declare function formatRemoteObject(object: RemoteObject): string; /** File path for an inspector script URL, or undefined for node: internals and evals. */ export declare function urlToPath(url: string): string | undefined; export declare class NodeDebugSession { /** The cwd as the program was launched in it. */ private readonly launchCwd; /** `launchCwd` fully resolved, for displaying paths relative to it. */ private readonly cwd; private readonly child; private readonly socket; private readonly pending; private readonly scripts; private readonly breakpoints; private readonly stopWaiters; /** In-flight exact-URL breakpoint bindings (see `bindToScript`). */ private readonly binding; private nextMessageId; private nextBreakpoint; private paused; private exitCode; private output; private outputDropped; private outputRead; private constructor(); /** Start `node --inspect-brk `, attach, set breakpoints, run to the first stop. */ static launch(options: DebugLaunchOptions): Promise; private connect; private initialize; private onMessage; private send; private appendOutput; private markExited; private wakeStopWaiters; get isPaused(): boolean; get hasExited(): boolean; state(): StopState; /** Wait until the program pauses or exits, up to `timeoutMs`. */ waitForStop(timeoutMs: number, signal?: AbortSignal): Promise; /** Resume (or step) and wait for the next stop. */ resume(how: "continue" | "step_over" | "step_into" | "step_out", timeoutMs: number, signal?: AbortSignal): Promise; pause(timeoutMs: number, signal?: AbortSignal): Promise; setBreakpoint(file: string, line: number, condition?: string): Promise; /** * Also bind `bp` by the exact URL of a loaded script that is the target file * but that the URL pattern missed — Node can name a script in a spelling no * path form predicts (Windows short names, drive-letter case, URL encoding). * The file itself, resolved on disk, decides whether it is the same script. */ private bindToScript; removeBreakpoint(id: string): Promise; listBreakpoints(): Breakpoint[]; private frame; private frameLocation; /** `#0 parseUser (src/user.ts:12:5)` lines, innermost first. */ stack(limit?: number): string; /** Source lines around a frame's position, the current line marked. */ sourceSnippet(index?: number, context?: number): string; /** Visible variables of a frame, scope by scope, innermost first. */ variables(index?: number): Promise; /** Evaluate in a paused frame, or in the global context while running. */ evaluate(expression: string, index?: number): Promise; /** Why and where the program is paused. */ pauseSummary(): string; /** Program output since the last call. */ readNewOutput(): string; /** Kill the program and close the connection. Safe to call twice. */ stop(): void; } export {};