import type { SessionBackend, SpawnOpts, SessionProbe } from './types.js';
/**
 * TmuxBackend — session backend using tmux for process persistence.
 *
 * Architecture: pty-under-tmux.
 *   - A node-pty process runs `tmux new-session` or `tmux attach-session`
 *   - All output flows through the pty (onData/onExit work unchanged)
 *   - kill() only detaches (kills the pty viewer), tmux session survives
 *   - destroySession() kills the tmux session (for explicit /close)
 *
 * Naming: tmux sessions are named `bmx-<sessionId.slice(0,8)>`.
 */
export declare class TmuxBackend implements SessionBackend {
    private process;
    private readonly sessionName;
    private readonly ownsSession;
    private reattaching;
    /** Tmux pane target when in adopt mode (e.g. "0:2.0") — set by attachToExisting.
     *  When non-null, ALL pane-scoped tmux commands (send-keys / paste-buffer /
     *  copy-mode / list-panes) must address this pane explicitly; using
     *  `this.sessionName` would either resolve nothing (the name is synthetic
     *  in adopt mode) or fall through to whichever pane tmux happens to have
     *  active, which is exactly the bug we're avoiding. */
    private adoptedPaneTarget;
    constructor(sessionName: string, opts?: {
        ownsSession?: boolean;
    });
    /** Target string to use for pane-scoped tmux commands. In adopt mode this
     *  is the real pane address ("0:2.0"); otherwise the bmx-* session name. */
    private get cmdTarget();
    /**
     * Check if tmux is usable — runs a functional probe (start + kill a
     * disposable server), not just `tmux -V`. Same probe as config.ts so
     * backend selection and runtime guard agree.
     */
    static isAvailable(): boolean;
    /** Derive tmux session name from a session UUID. */
    static sessionName(sessionId: string): string;
    /** Check if a named tmux session exists. */
    static hasSession(name: string): boolean;
    /**
     * Tri-state existence probe. `tmux has-session` exits 0 when the session
     * exists and exits 1 (clean status, no signal) when the server answered but
     * the session is absent — including "no server running", which means every
     * pane is genuinely gone. That is an authoritative 'missing'. Anything else —
     * a timeout (signal/killed) or a spawn failure (binary not on PATH → ENOENT,
     * not executable → EACCES; neither carries a numeric exit status) — means we
     * never got an answer → 'unknown', so a flaky/unavailable tmux can't be
     * mistaken for a gone session.
     *
     * Uses execFileSync (NOT a shell string): running tmux directly keeps a
     * missing/unrunnable binary as ENOENT/EACCES. A shell would instead surface
     * those as its own clean exits 127/126, which this classifier would wrongly
     * read as 'missing' and then drive a destructive restore-time close.
     */
    static probeSession(name: string): SessionProbe;
    /** Kill a named tmux session (no-op if it doesn't exist). */
    static killSession(name: string): void;
    /** List all botmux tmux sessions (bmx-* prefix). */
    static listBotmuxSessions(): string[];
    spawn(bin: string, args: string[], opts: SpawnOpts): void;
    /** Whether the last spawn() re-attached to an existing tmux session. */
    get isReattach(): boolean;
    /** Claude Code session JSONL path — set by worker for claude-code sessions so
     *  the claude-code adapter can verify paste+Enter submissions via file growth. */
    claudeJsonlPath?: string;
    /** PID of the spawned Claude Code child — used by the claude-code adapter to
     *  follow Claude's authoritative session id via ~/.claude/sessions/<pid>.json. */
    cliPid?: number;
    /** Working directory the CLI was spawned in — cross-checked against the pid
     *  file's cwd field so a recycled PID can't mislead the resolver. */
    cliCwd?: string;
    write(data: string): void;
    /**
     * Send text literally to the tmux pane via `tmux send-keys -l`.
     * Uses execFileSync (no shell) so arbitrary text is safe — no escaping needed.
     * For multiline text, use pasteText() instead (send-keys -l sends \n as Enter).
     */
    sendText(text: string): void;
    /** Send special keys (Enter, Escape, C-c, etc.) to the tmux pane. */
    sendSpecialKeys(...keys: string[]): void;
    /**
     * Enter copy-mode on the pane (`-e` makes it auto-exit when scrolled back to
     * the bottom). Lets us use tmux's own scrollback even when the running app
     * is in the alternate screen buffer (Claude Code, vim, etc.).
     */
    enterCopyMode(): void;
    /** Send a copy-mode X-command (e.g. 'halfpage-up', 'halfpage-down', 'cancel'). */
    sendCopyModeCommand(xCommand: string): void;
    /**
     * Paste text into the tmux pane via load-buffer + paste-buffer.
     * The -p flag asks tmux to insert bracketed-paste markers
     * (\e[200~ … \e[201~) when the application has requested bracketed paste,
     * so TUI apps (CoCo/Ink, etc.) can detect paste boundaries reliably.
     * Safe for multiline content (unlike sendText where \n becomes Enter).
     */
    pasteText(text: string): void;
    private exitCopyModeIfNeeded;
    resize(cols: number, rows: number): void;
    /** Must be called AFTER spawn(). Callbacks registered before spawn are silently lost. */
    onData(cb: (data: string) => void): void;
    /** Must be called AFTER spawn(). Callbacks registered before spawn are silently lost. */
    onExit(cb: (code: number | null, signal: string | null) => void): void;
    getChildPid(): number | null;
    /** Detach only — kills the pty viewer but leaves tmux session alive. */
    kill(): void;
    /** Kill the tmux session permanently. Called on explicit /close. */
    destroySession(): void;
    /**
     * Attach to an existing user tmux pane (not a bmx-* session).
     * Used by adopt mode — Botmux observes an already-running CLI.
     *
     * Zooms the target pane so only it is visible (hides other panes in the window).
     * The zoom is undone when the backend is killed (detach/disconnect).
     */
    attachToExisting(tmuxTarget: string, opts: SpawnOpts): void;
    getAttachInfo(): {
        type: "tmux";
        sessionName: string;
    };
}
/**
 * Build the `KEY=VAL` argv slice passed to `/usr/bin/env`. Only forwards the
 * keys in `BOTMUX_INJECTED_ENV_KEYS` and only when the value is defined —
 * `IS_SANDBOX` for instance is only set when the daemon is running as root.
 * Pure function for unit-testing without spawning tmux.
 */
export declare function buildBotmuxEnvAssignments(env: NodeJS.ProcessEnv | undefined): string[];
/**
 * Default wrapper script for `<shell> -c`. Sees argv as:
 *   $0 = '_' (placeholder), $1 = cwd, $2..N = KEY=VAL... bin args...
 *
 * The `cd` step makes the CLI's cwd survive a wayward `cd` in the user's
 * rcfile. The `unset` step removes bare creds the pane inherited from the tmux
 * server's global env (REDACTED_ENV_UNSET_CLAUSE). The `exec /usr/bin/env` step
 * injects botmux's per-bot/per-session overrides AFTER rcfile load so they
 * can't be shadowed by leftover exports.
 *
 * POSIX-syntax (works in bash/zsh/sh); fish/csh/nu users get remapped to
 * bash/zsh/sh by resolveUserShell() so they hit the same SCRIPT path.
 */
export declare const SHELL_WRAPPER_SCRIPT: string;
/**
 * Debug variant of the wrapper script — same prelude, but the CLI runs as
 * a *child* (no `exec`) and the wrapper hands off to an interactive shell
 * once the CLI exits. Useful for diagnosing missing PATH / NVM / pnpm /
 * mise shims in the user's rcfile: hit Ctrl-C in the web terminal, land
 * in `<shell> -i`, run `echo $PATH` / `which node` / etc.
 *
 * Enabled with `BOTMUX_DEBUG_KEEP_SHELL=1` at daemon-start time.
 *
 * `shellPath` is single-quoted into the script with `'` escaped, so it's
 * safe for paths containing spaces or quotes. Caller has already verified
 * it via accessSync().
 */
export declare function buildDebugKeepShellScript(shellPath: string): string;
export type ShellKind = 'bash' | 'zsh' | 'sh';
export interface ShellSpec {
    /** Absolute path to the shell binary. */
    shell: string;
    /** Rcfile-loading flags (`-i`, `-l -i`, or empty) — caller appends
     *  `-c <SCRIPT> _ <cwd> KEY=VAL... bin args...` after these. */
    flags: string[];
}
/**
 * Pick a shell to wrap the CLI launch in, returning the binary path plus the
 * exact argv flags needed for its rcfiles to load. Tries `$SHELL` first, then
 * `/bin/zsh` → `/bin/bash` → `/bin/sh`.
 *
 * If `$SHELL` is fish/nu/csh/etc., emits a warning and falls back to a POSIX
 * shell — our wrapper SCRIPT is POSIX-syntax and would break under fish. The
 * user can still configure their CLI's PATH/etc. inside the fallback shell's
 * rcfile if needed; the alternative (run their fish rcfile under a POSIX
 * harness) does not work.
 *
 * Always returns a usable ShellSpec — the last-resort `/bin/sh` fallback is
 * close enough to universal that surfacing an error here would do more harm
 * than good. If `/bin/sh` is also missing, tmux's own spawn will fail with
 * a clear message.
 */
export declare function resolveUserShell(env?: NodeJS.ProcessEnv): ShellSpec;
//# sourceMappingURL=tmux-backend.d.ts.map