import { Client } from 'ssh2'; import type { CommandResult } from '../../domain/command/command-result.js'; import type { CommandSpec } from '../../domain/command/command-spec.js'; import type { CommandRunner, DisconnectListener } from '../../domain/ports/command-runner.js'; import type { Logger } from '../../domain/ports/logger.js'; import type { SshAuthConfig } from '../../domain/config/plugin-config.js'; export interface SshConnectionConfig { readonly host: string; readonly port: number; readonly user: string; readonly auth: SshAuthConfig; readonly connectTimeoutMs: number; readonly keepaliveIntervalMs: number; /** Idle disconnect: 0 = never disconnect (default). > 0 = close after that many ms of no commands. */ readonly idleDisconnectMs: number; } export interface SshCommandRunnerDeps { readonly logger: Logger; readonly sshConfig: SshConnectionConfig; readonly clientFactory?: () => Client; readonly readKey?: (path: string) => Buffer; } export declare class SshCommandRunner implements CommandRunner { private readonly deps; private client; private connecting; private idleHandle; private readonly listeners; private readonly clientFactory; private readonly readKey; constructor(deps: SshCommandRunnerDeps); connect(): Promise; run(spec: CommandSpec): Promise; /** * Tear down the current SSH client. Used when an exec-level error indicates * the connection itself is no longer usable. Synchronously nulls the client * reference so concurrent run() calls don't grab a poisoned client, fires * onDisconnect listeners directly (the natural 'close' event handler would * otherwise no-op because we already cleared this.client), and ends the * transport. */ private recycleClient; disconnect(): Promise; onDisconnect(listener: DisconnectListener): () => void; private armIdleTimer; private cancelIdleTimer; private openClient; private attachLifecycleListeners; private buildConnectConfig; }