/**
 * @fileoverview tmux session manager for persistent Claude sessions.
 *
 * This module provides the TmuxManager class which creates and manages
 * tmux sessions that wrap Claude CLI processes. tmux provides:
 *
 * - **Persistence**: Sessions survive server restarts and disconnects
 * - **Ghost recovery**: Orphaned sessions are discovered and reattached on startup
 * - **Resource tracking**: Memory, CPU, and child process stats per session
 * - **Reliable input**: `send-keys -l` sends literal text in a single command
 * - **Teammate support**: Immutable pane IDs enable targeting individual teammates
 *
 * tmux sessions are named `codeman-{sessionId}` and stored in ~/.codeman/mux-sessions.json.
 *
 * Key features:
 * - `send-keys 'text' Enter` sends literal text in a single command
 * - `list-sessions -F` provides structured queries
 * - `display-message -p '#{pane_pid}'` for reliable PID discovery
 * - Single server architecture
 *
 * @module tmux-manager
 */
import { EventEmitter } from 'node:events';
import { ProcessStats, PersistedRespawnConfig, type PaneInfo, type CodexConfig } from './types.js';
import type { TerminalMultiplexer, MuxSession, MuxSessionWithStats, CreateSessionOptions, RespawnPaneOptions } from './mux-interface.js';
/** Claude Code native macOS recommendation for avoiding low nofile startup failures. */
export declare const CLAUDE_CODE_NOFILE_LIMIT = 2147483646;
/**
 * 构建 pane 启动前的 nofile 修复命令。
 *
 * macOS launchd/tmux 组合有时会让 pane 继承 256 的 soft nofile；
 * 新版 Claude Code 会在这种环境下直接退出。这里避免使用 $变量
 * 或命令替换，因为 fullCmd 目前经由双引号 bash -c 传递，外层
 * shell 会提前展开它们。
 */
export declare function buildNofileLimitCommand(targetLimit?: number): string;
/**
 * Parse the output of `tmux list-panes -a -F '#{session_name}|#{pane_pid}'`
 * into a Map of session-name → pane pid. Exported for unit testing.
 *
 * - Skips empty lines and lines without the separator.
 * - Skips entries with a non-numeric pid or empty name.
 */
export declare function parsePaneList(output: string): Map<string, number>;
/**
 * Resolve a target pane id from `tmux list-panes -F '#{pane_id}:#{pane_active}'`.
 * Prefers the active pane and falls back to the first valid pane.
 */
export declare function resolveTmuxPaneTarget(muxName: string, paneTarget?: string): string | null;
/**
 * Pick the active pane id from `tmux list-panes -F '#{pane_id}:#{pane_active}'`
 * output (lines like `%0:1`). Returns the pane id whose active flag is 1.
 */
export declare function resolveActivePaneTarget(output: string): string | null;
export declare function formatPaneSnapshot(lines: string[], geometry: {
    cols: number;
    rows: number;
    cursorX: number;
    cursorY: number;
}): string;
/**
 * Build the codex CLI command with appropriate flags.
 *
 * Codeman launches Codex's native TUI and handles replay/scrollback by
 * stripping destructive terminal sequences before xterm.js sees them.
 */
export declare function buildCodexCommand(config?: CodexConfig): string;
/**
 * Manages tmux sessions that wrap Claude CLI or shell processes.
 *
 * Implements the TerminalMultiplexer interface.
 *
 * @example
 * ```typescript
 * const manager = new TmuxManager();
 *
 * // Create a tmux session for Claude
 * const session = await manager.createSession({ sessionId, workingDir: '/project', mode: 'claude' });
 *
 * // Send input (single command, no delay!)
 * manager.sendInput(sessionId, '/clear\r');
 *
 * // Kill when done
 * await manager.killSession(sessionId);
 * ```
 */
export declare class TmuxManager extends EventEmitter implements TerminalMultiplexer {
    readonly backend: "tmux";
    private sessions;
    private readonly tmuxSocket;
    private statsInterval;
    private mouseSyncInterval;
    /** Track last-known pane count per session to avoid unnecessary tmux set-option calls */
    private lastPaneCount;
    private trueColorConfigured;
    constructor();
    /** The dedicated tmux socket all Codeman sessions live on (see {@link TerminalMultiplexer.muxSocket}). */
    get muxSocket(): string;
    private tmux;
    private loadSessions;
    /**
     * Save sessions to disk asynchronously. (NEVER writes in test mode)
     * Uses atomic temp+rename to prevent corruption on crash.
     */
    private saveSessions;
    /**
     * Build the array of environment export commands shared by createSession() and respawnPane().
     * Includes locale, mux markers, session identity, and API URL.
     *
     * User-supplied envOverrides are NOT inlined here — they go through applyEnvOverrides()
     * via `tmux setenv` so secret values (e.g., OPENCODE_API_KEY) never appear in the bash
     * command line (visible in `ps`). This also sidesteps shell-metachar injection via keys.
     */
    private buildEnvExports;
    /**
     * Apply user-supplied env overrides to a tmux session via `tmux setenv`.
     * Values stay off the bash command line (not visible in `ps`), and are inherited
     * by new panes — including `respawn-pane`. Persists at tmux-session level, so
     * Codeman server restarts don't lose the setting as long as the tmux session lives.
     *
     * Key validation is strict (`/^[A-Z_][A-Z0-9_]*$/`) as defense-in-depth against
     * shell-metachar injection even if upstream schema check is bypassed.
     */
    private applyEnvOverrides;
    /**
     * Resolve the CLI binary directory and return the PATH export prefix string.
     * Returns '' if no override is needed (shell mode) or the binary dir is not found.
     * In createSession(), a missing binary dir throws — the caller handles that separately.
     */
    private buildPathExport;
    /**
     * Configure OpenCode-specific environment on a tmux session.
     * Sets sensitive API keys and config content via tmux setenv
     * (not visible in ps output or tmux history, inherited by panes).
     */
    private _configureOpenCode;
    /**
     * Configure Codex-specific environment on a tmux session.
     * Sets OPENAI_API_KEY (and related keys) via tmux setenv so secrets don't
     * appear in the bash command line.
     */
    private _configureCodex;
    /**
     * Creates a new tmux session wrapping Claude CLI or a shell.
     * In test mode: creates an in-memory session only (no real tmux session).
     */
    createSession(options: CreateSessionOptions): Promise<MuxSession>;
    /**
     * Get the PID of the process running in the tmux pane.
     */
    private getPanePid;
    /**
     * Check if a tmux session exists.
     */
    muxSessionExists(muxName: string): boolean;
    /**
     * Check if the pane in a tmux session is dead (command exited but remain-on-exit keeps it).
     * Returns true if the session exists but the pane's command has exited.
     */
    isPaneDead(muxName: string): boolean;
    /**
     * Respawn a dead pane in an existing tmux session.
     * Uses `tmux respawn-pane -k` to restart the command in the same pane,
     * preserving the session and its scrollback buffer.
     */
    respawnPane(options: RespawnPaneOptions): Promise<number | null>;
    private sessionExists;
    private getChildPids;
    private isProcessAlive;
    private verifyProcessesDead;
    /**
     * Kill a tmux session and all its child processes.
     * Uses a 4-strategy approach (children → process group → tmux kill → SIGKILL).
     * In test mode: removes from memory only (no real kill).
     */
    killSession(sessionId: string): Promise<boolean>;
    getSessions(): MuxSession[];
    getSession(sessionId: string): MuxSession | undefined;
    updateSessionName(sessionId: string, name: string): boolean;
    /**
     * Reconcile tracked sessions with actual running tmux sessions.
     */
    reconcileSessions(): Promise<{
        alive: string[];
        dead: string[];
        discovered: string[];
    }>;
    getProcessStats(sessionId: string): Promise<ProcessStats | null>;
    getSessionsWithStats(): Promise<MuxSessionWithStats[]>;
    startStatsCollection(intervalMs?: number): void;
    stopStatsCollection(): void;
    /**
     * Start periodic mouse mode sync for all tracked sessions.
     * Polls pane counts every 5s and toggles mouse on/off as needed.
     * Polls every 5s. On pane count change, toggles mouse on (>1 pane) or off (1 pane).
     * If enableMouseMode/disableMouseMode fails, lastPaneCount is NOT updated so it retries next poll.
     */
    startMouseModeSync(intervalMs?: number): void;
    stopMouseModeSync(): void;
    destroy(): void;
    registerSession(session: MuxSession): void;
    setAttached(sessionId: string, attached: boolean): void;
    updateRespawnConfig(sessionId: string, config: PersistedRespawnConfig | undefined): void;
    clearRespawnConfig(sessionId: string): void;
    updateRalphEnabled(sessionId: string, enabled: boolean): void;
    /**
     * Send input directly to a tmux session using `send-keys`.
     *
     * Uses tmux send-keys for reliable input delivery:
     * - `-l` flag sends literal text (no key interpretation)
     * - `Enter` key is sent as a SEPARATE tmux invocation after a small delay
     * - Ink (Claude CLI) needs text and Enter split to avoid treating Enter as a newline
     */
    sendInput(sessionId: string, input: string): Promise<boolean>;
    /**
     * Enable mouse mode for an existing tmux session.
     * Allows clicking to select panes in agent team split-pane layouts.
     * When mouse mode is on, tmux intercepts mouse events (slow selection, no browser copy).
     */
    enableMouseMode(muxName: string): Promise<boolean>;
    /**
     * Disable mouse mode for an existing tmux session.
     * Restores native xterm.js text selection and browser clipboard copy.
     */
    disableMouseMode(muxName: string): Promise<boolean>;
    /**
     * Sync mouse mode based on pane count: enable if split (>1 pane), disable if single.
     * Called by TeamWatcher when teammates spawn/despawn panes.
     * Uses `tmux list-panes` for bulletproof detection — counts actual panes, not config.
     */
    syncMouseMode(muxName: string): Promise<boolean>;
    /**
     * List all panes in a tmux session.
     * Returns structured info for each pane.
     */
    listPanes(muxName: string): Promise<PaneInfo[]>;
    /**
     * Send input to a specific pane within a tmux session.
     * Uses the same literal text approach as sendInput() but targets a specific pane.
     */
    sendInputToPane(muxName: string, paneTarget: string, input: string): boolean;
    /**
     * Capture the current visible text and SGR styles of a specific pane.
     *
     * `capture-pane -e` is sanitized by `formatPaneSnapshot`: SGR color/style
     * codes are preserved, while cursor/erase/scroll-region controls are stripped
     * before rows are repainted at absolute positions in browser xterm.
     */
    capturePaneBuffer(muxName: string, paneTarget: string): string | null;
    /**
     * Capture the active pane for a tmux session.
     *
     * Pane ids are not stable across respawns or restores, so callers should not
     * assume the first pane remains `%0`.
     */
    captureActivePaneBuffer(muxName: string): string | null;
    /**
     * Start piping pane output to a file using tmux pipe-pane.
     * Only pipes output direction (-O) to avoid echoing input.
     */
    startPipePane(muxName: string, paneTarget: string, outputFile: string): boolean;
    /**
     * Stop piping pane output (calling pipe-pane with no command stops piping).
     */
    stopPipePane(muxName: string, paneTarget: string): boolean;
    getAttachCommand(): string;
    getAttachArgs(muxName: string): string[];
    setManualWindowSize(muxName: string): boolean;
    resizeWindow(muxName: string, cols: number, rows: number): boolean;
    isAvailable(): boolean;
    /**
     * Check if tmux is available on the system.
     */
    static isTmuxAvailable(): boolean;
}
//# sourceMappingURL=tmux-manager.d.ts.map