import { CDPClient } from '../cdp.js';
import type { BrowserProfile, ConnectionKey } from '../types.js';
import { shellQuote } from '../../ssh-exec.js';
export { shellQuote };
export interface SSHConnection {
    cdp: CDPClient;
    port: number;
    pid: number;
    cleanup: () => void;
}
/**
 * Which shell dialect the *remote* host speaks. Selected per-endpoint via the
 * `&os=windows` query param on an `ssh://` target. POSIX is the default — the
 * historical behavior for macOS/Linux remotes. Windows remotes run OpenSSH
 * Server with cmd.exe as the default shell, so the launch/teardown command
 * strings differ (no `&` backgrounding, no `lsof`, `.exe` instead of `.app`).
 */
export type RemoteOs = 'windows' | 'posix';
export interface SSHConnectOptions {
    /**
     * Attach to a browser another device already declared (identity-bearing or
     * a fungible name we don't declare here). Do not launch a fresh remote
     * chrome-data, and do not kill that browser when the tunnel closes — it
     * holds the logins the caller is trying to reach.
     */
    persistRemote?: boolean;
}
/** Lifecycle for a registry-driven tunnel vs a profile the daemon launched. */
export declare function persistRemoteLifecycle(persistRemote: boolean): {
    launchRemote: boolean;
    killOnCleanup: boolean;
};
export declare function connectSSH(endpoint: string, profile: BrowserProfile, 
/**
 * Runtime key (`<profile>@<device>`) this connection is stored under. It
 * keys the tunnel's runtime record; `profile.name` is the bare, user-facing
 * name and appears only in messages (RUSH-2709).
 */
key: ConnectionKey, opts?: SSHConnectOptions): Promise<SSHConnection>;
/**
 * Wrap a PowerShell script as a `-EncodedCommand` invocation. Base64 of the
 * UTF-16LE bytes is a single quote-free token, so it rides through Node spawn
 * → Windows sshd → cmd.exe with zero escaping hazards (hand-quoted
 * `powershell -Command "…"` is fragile the moment a path or URL is involved).
 */
export declare function encodePowerShell(script: string): string;
/**
 * The PowerShell that launches the browser on a Windows remote. Three hard
 * requirements shaped this:
 *   1. The browser must OUTLIVE the ssh session. Windows OpenSSH terminates
 *      the session's job tree on disconnect, which reaps both `start /B` and
 *      `Start-Process` children (verified against a real box). A scheduled
 *      task runs under the Task Scheduler service, so the process survives
 *      after we drop the ssh connection and reconnect over the CDP tunnel.
 *   2. The browser must run in the user's INTERACTIVE session. The previous
 *      WMI `Win32_Process.Create` launch also survived disconnect, but it
 *      spawned Edge in session 0 (the services session): the CDP socket bound
 *      and accepted, yet the DevTools server never initialized — every
 *      /json/version probe hung forever and DevToolsActivePort was never
 *      written (verified against a real box, Edg/150). A scheduled task
 *      registered and started by the logged-on user runs in that user's
 *      interactive session, where DevTools comes up normally.
 *   3. A distinct `--user-data-dir` so a fresh instance bound to the debugging
 *      port comes up even when the user already has Edge open.
 * CreateProcess ignores App Paths, so we resolve the real `.exe` from the
 * registry at runtime rather than relying on a bare `msedge` name. The task is
 * unregistered immediately after start — the browser keeps running; nothing
 * lingers in the scheduler.
 */
export declare function buildWindowsLaunchScript(browserType: string, port: number, customBinary?: string): string;
/**
 * The PowerShell that kills whatever holds the CDP port on a Windows remote.
 * Tree-kill (`taskkill /T`), not `Stop-Process`: Chromium is multi-process, and
 * killing only the port-owning main process orphans its children. The orphans
 * keep the profile's SingletonLock, so every later launch against the same
 * `--user-data-dir` delegates to the zombie tree, exits, and never binds the
 * CDP port — `browser start --device` then fails until someone hand-cleans the
 * box (found live on win-mini by the #561 e2e suite).
 */
export declare function buildWindowsKillScript(port: number): string;
/**
 * Build the remote command that launches the browser detached with a CDP port.
 * POSIX backgrounds the `.app` binary with `… &`; Windows resolves the exe and
 * starts it via an interactive one-shot scheduled task (encoded PowerShell)
 * so it survives the ssh session AND serves CDP (session 0 never does).
 */
export declare function buildLaunchCmd(remoteOs: RemoteOs, browserType: string, port: number, customBinary?: string): string;
/**
 * Build the remote command that kills whatever holds the CDP port.
 * POSIX uses `lsof`+`kill`; Windows uses encoded PowerShell
 * (Get-NetTCPConnection → Stop-Process).
 */
export declare function buildKillCmd(remoteOs: RemoteOs, port: number): string;
export declare function ensureRemoteBrowser(user: string, host: string, browserType: string, port: number, remoteOs: RemoteOs, customBinary?: string): Promise<void>;
export declare function restartRemoteBrowser(user: string, host: string, browserType: string, port: number, remoteOs: RemoteOs, customBinary?: string): Promise<void>;
/**
 * Kill the remote browser holding the CDP port. Invoked on stop/cleanup so the
 * task-launched (Windows) / detached (posix) browser process is not orphaned when
 * the ssh tunnel is torn down — killing only the tunnel left it running on
 * win-mini after every `browser stop`. Best-effort: never rejects.
 */
export declare function killRemoteBrowser(user: string, host: string, remoteOs: RemoteOs, port: number): Promise<void>;
/**
 * Identify whether a pid listening on our target local port is an SSH
 * tunnel WE would have spawned for `host:remotePort`. Used so that two
 * agents-browser invocations of the same SSH profile share a tunnel
 * rather than failing the second one with "port in use".
 *
 * Best-effort match against the ssh -L command line via `ps`. If we
 * can't read the cmd or the args don't look like ours, treat as not-ours.
 *
 * Windows has no `ps`, so the POSIX branch below always throws there and every
 * reuse check returned false — the second invocation to the same host:port then
 * failed "port in use". On win32 we instead reuse the netstat -ano + tasklist
 * occupant lookup (getPortOccupant): the tunnel binds `remotePort` locally
 * (localPort === remotePort in the caller), so the pid holding that port is our
 * ssh.exe. tasklist only exposes the image name, not the full command line, so
 * we can't match host/remotePort as tightly as the POSIX branch — an ssh
 * process on our exact local port is our tunnel in practice.
 */
export declare function isOwnTunnel(pid: number, host: string, remotePort: number): boolean;
