import type { ProviderResumeCapability } from '../providers/contracts.js';
import type { ChatMessageKind } from '../providers/chat-message-normalization.js';
import type { ChatBubbleState } from '../types.js';
import type { InteractivePrompt } from '../providers/types/interactive-prompt.js';
import { sanitizeSpawnEnv } from './spawn-env.js';
export interface CliChatMessage {
    role: string;
    content: any;
    timestamp?: number;
    receivedAt?: number;
    kind?: ChatMessageKind;
    id?: string;
    index?: number;
    providerUnitKey?: string;
    bubbleId?: string;
    bubbleState?: ChatBubbleState;
    _turnKey?: string;
    meta?: Record<string, unknown>;
    senderName?: string;
    [key: string]: any;
}
export interface CliSessionStatus {
    status: 'idle' | 'generating' | 'waiting_approval' | 'error' | 'stopped' | 'starting';
    messages: CliChatMessage[];
    workingDir: string;
    activeModal: {
        message: string;
        buttons: string[];
    } | null;
    /**
     * Monotonic counter identifying which approval *entry* the current modal
     * belongs to. Bumped by the FSM on every fresh waiting_approval entry.
     * Consumers (e.g. auto-approval) use it to distinguish a genuinely new
     * approval from the same approval re-observed across TUI paint flaps —
     * two distinct approvals can carry identical message/button text, so the
     * seq is the only reliable discriminator.
     */
    approvalEntrySeq?: number;
    /**
     * The approval entry seq that the engine's last resolveModal() handled. When
     * `lastResolvedEntrySeq >= approvalEntrySeq` (and approvalEntrySeq > 0) it is positive
     * evidence that the current/latest approval entry was resolved through ADHDev (auto-approve
     * fire, dashboard / mesh_approve, or dev-cli-debug — all route through resolveModal). The
     * completion finalization gate uses this to avoid confirming a waiting_approval→idle
     * transition for which no resolution actually occurred (a false idle: the spec's text-based
     * approval→idle rule tripped while the modal is still on screen).
     */
    lastResolvedEntrySeq?: number;
    activeInteractivePrompt?: InteractivePrompt | null;
    pendingOutboundCount?: number;
    pendingOutboundMessages?: Array<{
        id: string;
        role: 'user';
        content: string;
        queuedAt: number;
        source: string;
    }>;
    errorMessage?: string;
    errorReason?: string;
    providerSessionId?: string;
    /**
     * Spec/FSM adapters only (SpecCliAdapter): true once the driver has observed
     * its first non-initial idle state — the prompt is genuinely drawn. The
     * legacy ProviderCliAdapter never sets it (undefined). CliProviderInstance
     * uses it to re-arm the queue-claim agent:ready on the first genuine ready,
     * independent of the boot-time starting→idle one-shot (which is consumed too
     * early for specs whose initial state already reports status 'idle', e.g.
     * antigravity-cli — without the re-arm the worker never claims its queued
     * task and the coordinator relaunch-loops).
     */
    fsmReadySeen?: boolean;
    /**
     * Timestamp (ms) of the most recent raw PTY output chunk. Advances on every
     * byte the process emits, including tool/build output that produces no
     * parsed assistant text. Liveness watchdogs use this to distinguish a real
     * stall (no output at all) from an active turn whose assistant buffer is
     * momentarily static while a tool runs.
     */
    lastOutputAt?: number;
    /**
     * Timestamp (ms) of the most recent *visible* terminal screen change.
     * Stricter than lastOutputAt — only advances when the rendered screen
     * content actually differs, so repeated keepalive bytes do not register as
     * progress. Preferred liveness signal for the no-progress watchdog.
     */
    lastScreenChangeAt?: number;
    bufferState?: {
        responseBuffer?: {
            truncated: boolean;
            droppedChars: number;
            maxChars: number;
        };
        recentOutputBuffer?: {
            truncated: boolean;
            droppedChars: number;
            maxChars: number;
        };
        accumulatedBuffer?: {
            truncated: boolean;
            droppedChars: number;
            maxChars: number;
        };
        accumulatedRawBuffer?: {
            truncated: boolean;
            droppedChars: number;
            maxChars: number;
        };
    };
}
export interface ParsedSession {
    status: string;
    messages: any[];
    modal: {
        message: string;
        buttons: string[];
    } | null;
    parsedStatus: string | null;
    errorMessage?: string;
    errorReason?: string;
    providerSessionId?: string;
    transcriptAuthority?: 'provider' | 'daemon';
    coverage?: 'full' | 'tail' | 'current-turn';
}
export interface CliScripts {
    /**
     * Optional state factory. Called once per CLI session start (or script reload).
     * The returned object is passed as the first argument to detectStatus, parseApproval,
     * and parseSession on every invocation, allowing scripts to maintain per-session state
     * (e.g. last-seen status, approval fingerprints, stability counters).
     *
     * Scripts that don't define createState() receive null as the state argument,
     * making this change fully backward compatible.
     */
    createState?: () => unknown;
    parseSession?: (state: unknown, input: CliScriptInput & {
        tail?: string;
        tailScreen?: CliScreenSnapshot;
    }) => ParsedSession | null;
    detectStatus?: (state: unknown, input: CliStatusInput) => string | null;
    parseApproval?: (state: unknown, input: CliApprovalInput) => {
        message: string;
        buttons: string[];
    } | null;
    resolveAction?: (data: any) => string;
    [name: string]: ((state: unknown, input: any) => any) | ((data: any) => any) | (() => unknown) | undefined;
}
export interface CliScreenLine {
    index: number;
    fromTop: number;
    fromBottom: number;
    text: string;
    trimmed: string;
    isEmpty: boolean;
}
export interface CliScreenSnapshot {
    text: string;
    lineCount: number;
    lines: CliScreenLine[];
    nonEmptyLines: CliScreenLine[];
    firstNonEmptyLineIndex: number;
    lastNonEmptyLineIndex: number;
    firstNonEmptyLine: CliScreenLine | null;
    lastNonEmptyLine: CliScreenLine | null;
    promptLineIndex: number;
    promptLine: CliScreenLine | null;
    linesAbovePrompt: CliScreenLine[];
    linesBelowPrompt: CliScreenLine[];
}
export interface CliScriptInput {
    buffer: string;
    rawBuffer: string;
    recentBuffer: string;
    screenText: string;
    workspace?: string;
    workingDir?: string;
    providerSessionId?: string;
    historySessionId?: string;
    screen: CliScreenSnapshot;
    bufferScreen: CliScreenSnapshot;
    recentScreen: CliScreenSnapshot;
    messages: CliChatMessage[];
    partialResponse: string;
    isWaitingForResponse?: boolean;
    promptText?: string;
    settings?: Record<string, any>;
    args?: Record<string, any>;
    spawnAt?: number;
}
export interface CliStatusInput {
    tail: string;
    screenText?: string;
    rawBuffer?: string;
    isWaitingForResponse?: boolean;
    screen: CliScreenSnapshot;
    tailScreen: CliScreenSnapshot;
}
export interface CliApprovalInput {
    buffer: string;
    screenText?: string;
    rawBuffer?: string;
    tail: string;
    screen: CliScreenSnapshot;
    bufferScreen: CliScreenSnapshot;
    tailScreen: CliScreenSnapshot;
}
export interface CliTraceEntry {
    id: number;
    at: number;
    type: string;
    status: CliSessionStatus['status'];
    isWaitingForResponse: boolean;
    activeModal: {
        message: string;
        buttons: string[];
    } | null;
    payload: Record<string, any>;
}
export interface CliProviderModule {
    type: string;
    name: string;
    category: 'cli';
    binary: string;
    approvalKeys?: Record<number, string>;
    sendDelayMs?: number;
    /** Wall-clock budget (ms) for a single provider script invocation. Default 50. Range 1..5000.
     *  Exceeding the budget records `timedOut: true` on the invocation trace and emits a
     *  throttled WARN — it does NOT abort the script (Node CJS can't interrupt sync code). */
    scriptCallBudgetMs?: number;
    sendKey?: string;
    submitStrategy?: 'wait_for_echo' | 'immediate';
    /** Require the typed prompt to be visible on the PTY screen before sending Enter. */
    requirePromptEchoBeforeSubmit?: boolean;
    /** Allow sending another prompt while the CLI is still generating so users can intervene mid-turn. */
    allowInputDuringGeneration?: boolean;
    /** When true, only transition to idle after the parsed transcript includes a final standard assistant message. */
    requiresFinalAssistantBeforeIdle?: boolean;
    /** When true, allow providers to augment stale snapshot data before parse. Reserved for future use. */
    augmentStaleSnapshot?: boolean;
    /** When provider-owned, daemon treats provider parser output as canonical transcript authority. */
    transcriptAuthority?: 'provider' | 'daemon';
    /** Full context lets provider-owned parsers canonicalize retained history instead of daemon prefix stitching. */
    transcriptContext?: 'full' | 'tail';
    /** v1 declarative tui block — used by CliScriptRunner to synthesize SDK helpers (declarativeDetectStatus, declarativeParseApproval). */
    tui?: Record<string, unknown>;
    scripts?: CliScripts;
    spawn: {
        command: string;
        args: string[];
        shell: boolean;
        env: Record<string, string>;
    };
    timeouts?: {
        ptyFlush?: number;
        dialogAccept?: number;
        approvalCooldown?: number;
        generatingIdle?: number;
        idleFinish?: number;
        idleFinishConfirm?: number;
        statusActivityHold?: number;
        maxResponse?: number;
        shutdownGrace?: number;
        outputSettle?: number;
    };
    resume?: ProviderResumeCapability;
    _resolvedVersion?: string | null;
    _resolvedOs?: string | null;
    _resolvedProviderDir?: string | null;
    _resolvedScriptDir?: string | null;
    _resolvedScriptsPath?: string | null;
    _resolvedScriptsSource?: string | null;
    _versionWarning?: string | null;
}
/**
 * Stateful, transcript-oriented terminal cell accumulator.
 *
 * CLI transcript parsing must not consume raw PTY append text for user-visible
 * readback: CLIs rewrite prompts/status/tool lines with CR, BS, CSI cursor
 * motion and erase-line. This accumulator preserves parser state across chunks
 * and mutates rendered cells before exposing plain transcript text. It is a
 * deliberately small terminal model for readback buffers; live UI rendering still
 * uses TerminalScreen's ghostty/xterm backend.
 */
export declare class TerminalTranscriptAccumulator {
    private lines;
    private row;
    private col;
    private savedCursor;
    private pendingEscape;
    append(data: string): string;
    reset(): void;
    getText(): string;
    private ensureRow;
    private writeControlOrChar;
    private consumeEscape;
    private applyCsi;
}
export declare function sanitizeTerminalText(str: string): string;
/** Named PTY keys the send-keys tool accepts (closed enum). */
export type MeshSendKeyName = 'ENTER' | 'ESC' | 'CTRL_C' | 'UP' | 'DOWN' | 'LEFT' | 'RIGHT' | 'TAB' | 'BACKSPACE';
/** Exact terminal byte sequence for each named key. */
export declare const MESH_SEND_KEY_ENCODING: Record<MeshSendKeyName, string>;
export declare const MESH_DESTRUCTIVE_KEYS: ReadonlySet<MeshSendKeyName>;
export type MeshSendKeyItem = {
    text: string;
} | {
    key: MeshSendKeyName;
};
export interface MeshSendKeysEncodeResult {
    /** The concatenated byte sequence to write to the PTY (single atomic write). */
    sequence: string;
    /** Named keys present, in order (for audit — text bodies are NOT recorded). */
    keys: MeshSendKeyName[];
    /** True if any item is a destructive key (CTRL_C / ESC). */
    hasDestructive: boolean;
    /** True if the sequence submits (ends with an ENTER/CR) — informational. */
    submits: boolean;
}
/** Per-call limits (auditability + safety — no unbounded blast). */
export declare const MESH_SEND_KEYS_MAX_ITEMS = 64;
export declare const MESH_SEND_KEYS_MAX_TEXT_BYTES = 4096;
/**
 * Validate + encode a structured key sequence into the exact bytes to write.
 * Throws on an invalid key name, an over-limit item count, or an over-limit
 * total text byte length. text+ENTER (or any text followed by ENTER) is encoded
 * as ONE contiguous string so the caller can submit it in a single atomic write
 * — no interleaving between the text and its submit key.
 */
export declare function encodeMeshSendKeys(items: MeshSendKeyItem[]): MeshSendKeysEncodeResult;
/**
 * MESH-READ-TERMINAL (feature 2): result of a byte-bounded, bottom-tail terminal
 * screen truncation. The bound is in BYTES (UTF-8), not characters, because a
 * screen full of multi-byte glyphs can blow past an MCP payload cap even when the
 * character count looks safe. The bottom (tail) of the screen is preserved — the
 * prompt, an active modal and the most recent output all live at the bottom — so
 * a truncated read still shows the coordinator the actionable frame.
 */
export interface ByteTailTruncation {
    text: string;
    truncated: boolean;
    /** UTF-8 byte length of the full input before truncation. */
    originalBytes: number;
    /** UTF-8 byte length of the returned (possibly truncated) text. */
    returnedBytes: number;
}
/**
 * Truncate `text` to at most `maxBytes` UTF-8 bytes, preserving whole lines from
 * the BOTTOM up (the prompt/modal/recent output). Never splits a line and never
 * splits a UTF-8 code point (whole-line granularity guarantees valid UTF-8). If
 * even the single last line exceeds the bound, that line is hard-clipped on a
 * safe UTF-8 boundary from its END so the tail is still returned intact-ish.
 */
export declare function truncateToByteTailByLine(text: string, maxBytes: number): ByteTailTruncation;
export declare function listCliScriptNames(scripts: CliScripts | undefined): string[];
export declare function buildCliScreenSnapshot(text: string): CliScreenSnapshot;
export declare const buildCliSpawnEnv: typeof sanitizeSpawnEnv;
export declare function computeTerminalQueryTail(buffer: string): string;
export declare function findBinary(name: string): string;
export declare function isScriptBinary(binaryPath: string): boolean;
export declare function looksLikeMachOOrElf(filePath: string): boolean;
export declare function shSingleQuote(arg: string): string;
export declare function estimatePromptDisplayLines(text: string, cols?: number): number;
export declare function extractPromptRetrySnippet(text: string): string;
export declare function normalizePromptText(text: string): string;
export declare function compactPromptText(text: string): string;
export declare function promptLikelyVisible(screenText: string, promptSnippet: string): boolean;
export declare function normalizeScreenSnapshot(text: string): string;
export declare function normalizeComparableMessageContent(text: string): string;
export declare function trimPromptEchoPrefix(text: string, promptText?: string | null): string;
export declare function getLastUserPromptText(messages: Array<{
    role?: string;
    content?: string;
}> | null | undefined): string;
export declare function normalizeCliProviderForRuntime(raw: unknown): {
    patterns: {
        approval: RegExp[];
    };
};
