/**
 * CliProviderInstance — Runtime instance for CLI Provider
 *
 * Lifecycle layer on top of ProviderCliAdapter.
 * collectCliData() + status transition logic from daemon-status.ts moved here.
 */
import { type ProviderModule, type InputEnvelope } from './contracts.js';
import type { ProviderInstance, ProviderState, InstanceContext, HotChatSessionState, SessionModalState } from './provider-instance.js';
import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
import type { MeshSendKeyItem, MeshSendKeyName } from '../cli-adapters/provider-cli-shared.js';
import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
import type { ChatMessage } from '../types.js';
export { buildCliStructuredInputPrompt } from './cli-provider-input-prompt.js';
export { buildIncrementalHistoryAppendMessages } from './cli-provider-history-dedup.js';
export { computeTurnAnchoredDurationMs, getForcedNewSessionScriptName, waitForCliAdapterReady, } from './cli-provider-status-helpers.js';
export declare class CliProviderInstance implements ProviderInstance {
    private provider;
    private workingDir;
    private cliArgs;
    readonly type: string;
    readonly category: "cli";
    /**
     * Quiet period an approval modal's signature must be stable before
     * auto-approve sends the approve key. Guards against firing on a prompt
     * that is still streaming into the PTY (the "resolves too fast" symptom):
     * while the modal text/buttons are still changing, every frame yields a
     * new signature and the settle clock restarts. Once the prompt finishes
     * rendering the signature holds and the key is sent after this window.
     * Bounded + small so genuine approvals stay timely. The FSM is already
     * authoritative over the `waiting_approval` state; this only delays the
     * keystroke until the modal *content* has settled.
     */
    private static readonly AUTO_APPROVE_SETTLE_MS;
    /**
     * APPROVAL-INBOX-BLINDSPOT (Fix A): how long after a LOCAL auto-approve fire the mesh
     * event forwarder still treats the modal as "being resolved locally" and suppresses the
     * coordinator notification. Chosen to comfortably cover the resolveModal → PTY absorb →
     * status-leaves-approval round trip (incl. the win32 CR-resend loop) while staying short
     * enough that a modal which auto-approve fired at but did NOT resolve re-surfaces to the
     * coordinator on the next event. Aligned with the adapter's own approval cooldown scale.
     */
    private static readonly APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS;
    /**
     * Busy-side hysteresis for the settle gate. A momentary `generating` flip
     * while the SAME approval modal's button block is still on screen (its
     * question line scrolled out of the captured frame, only the buttons + a
     * residual `esc to interrupt` spinner remain) briefly reports
     * status!=waiting_approval. Without hysteresis that flip wipes the settle
     * clock, and the modal→generating→modal flap restarts the 600ms window
     * every time so auto-approve never fires. We keep the in-progress settle
     * gate warm across an inactive blip up to this bound; only once the modal
     * has genuinely stayed gone this long (a real resolution → idle) is the
     * gate cleared. Bounded so a genuinely new, later approval still re-settles
     * from scratch rather than firing on a stale timestamp.
     */
    private static readonly AUTO_APPROVE_GATE_HYSTERESIS_MS;
    /**
     * AUTOAPPROVE-FLAP-RECUR (Fix B): extended busy-side continuity window for a
     * DELEGATED-WORKER auto-approve episode that is genuinely still cycling.
     *
     * The default AUTO_APPROVE_GATE_HYSTERESIS_MS (1500) absorbs a *momentary*
     * `generating` blip. But a delegated worker running a Bash approval observed
     * the FSM cycle the FULL state waiting_approval → busy → waiting_approval on a
     * 2–5s period (the button set scrolls in/out AND the modal question repaints,
     * so the adapter genuinely reports status=generating for whole seconds between
     * approval frames). Each busy phase outran the 1500ms hysteresis, so the
     * settle clock was WIPED (the genuine-resolution branch), the 600ms settle
     * window never accumulated across the flap, resolveModal never fired
     * (resolveModal count 0), and the mask-stall clock instead tripped at 4500ms →
     * coordinator nudge → the flap the coordinator observed.
     *
     * A genuine resolution and a flap both start with a busy phase; they diverge
     * only in whether waiting_approval RETURNS. So we cannot simply lengthen the
     * blanket hysteresis (that would make every real resolution hold the gate
     * open for seconds). Instead this longer window applies ONLY while an active
     * mask episode is alive (autoApproveMaskSince > 0) AND the session is a
     * delegated worker — i.e. exactly the never-resolving-flap case. A foreground
     * / attended session keeps the tight 1500ms window unchanged. The mask-stall
     * bound below still caps the episode, so a worker whose approval truly never
     * returns is surfaced to the coordinator within AUTO_APPROVE_MASK_STALL_MS
     * rather than held forever.
     *
     * INVARIANT (do not regress the ordering): this window must fully BRIDGE a
     * single busy phase, and the mask-stall bound below must in turn exceed it —
     * AUTO_APPROVE_MASK_STALL_MS > AUTO_APPROVE_FLAP_CONTINUITY_MS + max_busy_phase
     * + AUTO_APPROVE_SETTLE_MS. Observed flap geometry (delegated-worker Bash
     * approval): approval frames last ~1.5s, busy phases (modal=none) last
     * ~4.3–4.5s. With the old 4000ms this window was SHORTER than a busy phase, so
     * the settle clock was torn down every cycle and never accrued 600ms while the
     * 4500ms mask-stall tripped INSIDE the first busy phase → a stalled-approval
     * nudge leaked to the coordinator. 6000ms bridges the ~4.5s busy phase with
     * margin so the returning approval frame survives to resume its settle clock.
     */
    private static readonly AUTO_APPROVE_FLAP_CONTINUITY_MS;
    /**
     * STATUS-MISMATCH: upper bound on how long the auto-approve→`generating` SURFACE
     * mask may hide a worker's `waiting_approval` (status + activeModal) before we give
     * up and surface the real prompt. The mask exists because auto-approve is expected
     * to resolve the modal momentarily; but if it STALLS without ever calling
     * resolveModal — the modal signature never settles for AUTO_APPROVE_SETTLE_MS (a
     * perpetually-flapping/streaming prompt), no concrete modal is ever captured, or the
     * modal is a picker/non-affirmative we never auto-pick — the mask would persist
     * forever and read_chat / mesh_status / the dashboard would NEVER see the pending
     * approval (the coordinator cannot mesh_approve what it cannot see). Once an episode
     * exceeds this bound we stop masking. Generously larger than
     * AUTO_APPROVE_SETTLE_MS (600) + AUTO_APPROVE_GATE_HYSTERESIS_MS (1500) so a
     * legitimately slow-settling / blip-flapping prompt is never unmasked early; a
     * genuine never-resolving stall surfaces within this window. The settle gate keeps
     * running underneath, so a prompt that finally stabilises still auto-approves, and
     * mesh_approve (raw FSM, unmasked) works throughout.
     *
     * INVARIANT (do not regress): must be STRICTLY GREATER than
     * AUTO_APPROVE_FLAP_CONTINUITY_MS + max_busy_phase + AUTO_APPROVE_SETTLE_MS so
     * that during a flap the settle clock (which FLAP_CONTINUITY keeps alive across
     * each busy phase) gets to accrue its 600ms on the RETURNING approval frame
     * before this stall bound can trip. Observed geometry — worker: approval ~1.5s,
     * busy ~4.3–4.5s; coordinator self-session: approval ~1.5s, busy ~2.85s. Both
     * now use the extended window (isAutonomousMeshSession covers worker +
     * meshCoordinatorFor). Worst case: CONTINUITY(6000) + busy(~4.5s) + SETTLE(600)
     * = ~11100ms, so the stall bound must exceed that. 10500ms satisfies the invariant
     * for coordinator (6000 + 2850 + 600 = 9450 < 10500) and was previously 9000ms
     * (which failed for a worker busy phase of 4.5s: 6000+4500+600=11100 > 9000).
     * the old 4500ms tripped inside the very first busy phase (while modal=none, so
     * the nudge was NOT deferred) and leaked to the coordinator.
     */
    private static readonly AUTO_APPROVE_MASK_STALL_MS;
    /**
     * AUTOAPPROVE-FLAP-INBOX-MISSING: sticky-approval overlay window. Same time-tick
     * hold idea as the FALSE-IDLE completion gate — an approval signal that was
     * DOMINANT within this recent window is re-presented across a momentary busy blip
     * instead of collapsing.
     *
     * RCA (live 2026-07-13): a claude-cli worker sitting at a Bash approval modal
     * ("Do you want to proceed? ❯1.Yes") flaps waiting_approval↔busy on a ~2-3s period.
     * The spec `approval→busy` transition fires whenever the footer/modal approval
     * markers momentarily drop out of their parsed sections while the PRIOR command's
     * residual spinner text ("✳ Checking vendor drift…") still matches the busy regex.
     * On the busy frame the adapter reports status='generating', activeModal=null. That
     * corrupts THREE consumers at once: (1) mesh_active_work samples 'generating' →
     * collectPendingApprovals never sees 'awaiting_approval' → mesh_list_pending_approvals
     * count:0 (inbox miss); (2) the auto-approve settle gate is torn down each busy phase
     * so the 600ms settle never accrues → auto-approve never fires; (3) a mesh_approve
     * landing on a busy frame hits "Not in approval state". The existing FLAP machinery
     * (AUTO_APPROVE_FLAP_CONTINUITY_MS) only keeps the settle gate warm while status is
     * STILL waiting_approval (buttons scrolled out) — it does nothing once the FSM fully
     * commits to 'busy', and it never stabilises the status the inbox samples.
     *
     * Fix: when the raw adapter status flaps to generating/busy/idle but a
     * waiting_approval WITH a concrete modal was observed within this window, overlay
     * the cached modal and report status='waiting_approval'. This stabilized status
     * feeds getState (→ inbox), detectStatusTransition (→ event emission), and
     * maybeAutoApproveStatus (→ settle gate) uniformly, so the approval both registers
     * in the inbox and settles for auto-approve across the flap. Bounded (a genuine
     * resume that never returns to approval unmasks after this window) and scoped at the
     * call site to autonomous mesh sessions. 4000ms bridges the observed ~2-3s flap with
     * margin while staying well under AUTO_APPROVE_MASK_STALL_MS (a truly stalled/absent
     * approval still surfaces).
     */
    private static readonly APPROVAL_STICKY_FLAP_MS;
    /**
     * FALSE-IDLE (inter-approval quiet valley): grace window after an auto-approve
     * (or mesh_approve) RESOLVES a modal during which a subsequent generating→idle
     * quiet valley must NOT be treated as turn completion.
     *
     * The RCA: auto-approve resolves a modal → the agent resumes the same turn →
     * between resolving that approval and preparing the next tool/approval the agent
     * falls briefly silent. The FSM sees idle + a recorded mid-turn assistant bubble
     * and fires an early agent:generating_completed even though the turn is still in
     * flight. Live evidence showed the same session resuming waiting_approval ~13s
     * after a "clean" completion emit.
     *
     * The window must be comfortably larger than the observed resume gap (~13s) so
     * the valley is bridged, but not so large that a turn that genuinely ended right
     * after an approval is held for an annoying stretch. 18s clears 13s with margin
     * while capping the worst-case extra hold on a truly-finished turn at 18s (still
     * well under COMPLETED_FINALIZATION_MAX_WAIT_MS's 30s hard bound). The recency is
     * measured from the engine's lastApprovalResolvedAt, which is stamped ONLY by
     * resolveModal (auto-approve fire / dashboard / mesh_approve) — so a plain turn
     * with no approval never carries recency and is never held (no regression).
     */
    private static readonly APPROVAL_RESUME_GRACE_MS;
    private static readonly MESH_WORKER_STALL_IDLE_THRESHOLD_MS;
    private static readonly MESH_WORKER_STALL_TURN_THRESHOLD_MS;
    private static readonly MESH_WORKER_STALL_REFIRE_COOLDOWN_MS;
    private adapter;
    private context;
    private events;
    private lastStatus;
    private agentReadyEmitted;
    private generatingStartedAt;
    private meshStallAnchorAt;
    private meshStallEmittedForAnchor;
    private meshStallTurnActiveLast;
    private meshStallLastFiredAt;
    private busyEpoch;
    private fastCollapseSynthesizedTaskId;
    private startupGraceCollapseAt;
    private meshTaskInjectedAt;
    private settings;
    private monitor;
    private generatingDebounceTimer;
    private generatingDebouncePending;
    private lastApprovalEventFingerprint;
    private autoApproveBusy;
    private autoApproveBusyTimer;
    private lastAutoApprovalSignature;
    private pendingAutoApprovalSignature;
    private pendingAutoApprovalSince;
    private autoApproveSettleTimer;
    private autoApproveInactiveSince;
    private autoApproveLastModalSeenAt;
    private lastAutoApproveFiredAt;
    private approvalStickyLastConcreteAt;
    private approvalStickyModal;
    private approvalStickyEntrySeq;
    private autoApproveMaskSince;
    private stalledApprovalNudgeEpisode;
    private readonly manualAttendance;
    private controlValues;
    private summaryMetadata;
    private appliedEffectKeys;
    private historyWriter;
    private runtimeMessages;
    private lastPersistedHistoryMessages;
    private lastAcknowledgedUserInputAt;
    private recentUserInputAcks;
    private lastNativeSourceCanonicalCheckAt;
    private lastNativeSourceCanonicalCacheKey;
    private cachedSqliteDb;
    private cachedSqliteDbPath;
    private cachedSqliteDbMissingUntil;
    readonly instanceId: string;
    private suppressIdleHistoryReplay;
    private errorMessage;
    private errorReason;
    private activeInteractivePrompt;
    private presentationMode;
    private providerSessionId?;
    private launchMode;
    private initialThinkingLevel?;
    private readonly startedAt;
    private onProviderSessionResolved?;
    constructor(provider: ProviderModule, workingDir: string, cliArgs?: string[], instanceId?: string, transportFactory?: PtyTransportFactory, options?: {
        providerSessionId?: string;
        launchMode?: 'new' | 'resume' | 'manual';
        extraEnv?: Record<string, string>;
        /** BRAIN-ROUTING: standard thinking level to apply post-launch via the
         *  provider's thinkingControlId (runtime-control providers like hermes).
         *  Providers using thinkingLaunchArgs get it at spawn instead and ignore this. */
        initialThinkingLevel?: string;
        onProviderSessionResolved?: (info: {
            instanceId: string;
            providerType: string;
            providerName: string;
            workspace: string;
            providerSessionId: string;
            previousProviderSessionId?: string;
        }) => void;
    });
    refreshProviderDefinition(provider: ProviderModule): void;
    init(context: InstanceContext): Promise<void>;
    onTick(): Promise<void>;
    /**
     * Generic session ID probe using declarative ProviderSessionProbe config.
     * Replaces the previously duplicated probeOpenCode/Codex/Goose functions.
     */
    private probeSessionIdFromConfig;
    getState(): ProviderState;
    setPresentationMode(mode: 'terminal' | 'chat'): void;
    getPresentationMode(): 'terminal' | 'chat';
    getHotChatSessionState(): HotChatSessionState;
    getSessionModalState(sessionId?: string): SessionModalState;
    updateSettings(newSettings: Record<string, any>): void;
    /**
     * Stamp a direct-dispatch mesh assignment on this instance.
     * setupMeshEventForwarding reads settings.meshNodeFor + meshActiveTaskId to
     * route generating_completed back to the originating coordinator. Without
     * this stamp, mesh_send_task --direct targets a plain CLI session whose
     * completion events silently drop because the forwarder has nothing to
     * match against.
     */
    attachMeshAssignment(assignment: {
        meshId: string;
        nodeId?: string;
        taskId?: string;
        dispatchNonce?: number;
        coordinatorDaemonId?: string;
        coordinatorSessionId?: string;
    }): void;
    /**
     * Clear a previously-attached mesh assignment after the task reaches a
     * terminal state. Leaving meshNodeFor pinned would route this session's
     * subsequent unrelated turns (e.g. ad-hoc dashboard chats) to the
     * coordinator as if they were task completions.
     *
     * MESHID-DROP-ON-DETACH (Fix C): a coordinator-LAUNCHED worker session
     * (launchedByCoordinator) holds its mesh membership (meshNodeFor / meshNodeId /
     * meshCoordinatorDaemonId) at the SESSION level — set once at launch
     * (mesh_launch_session / queue auto-launch), independent of any single task.
     * The original detach wiped meshNodeFor + meshNodeId together with the
     * task-level meshActiveTaskId, so the FIRST task completion stripped the
     * membership and EVERY subsequent completion forwarded with meshId absent —
     * resolveWorkerDelegateRouting fell to mesh_unresolved and the coordinator
     * rejected the forward "meshId required". For a launched member we therefore
     * clear ONLY the task-level marker (meshActiveTaskId) and preserve the
     * session-level membership so its next task's completion still resolves.
     * A task-less ad-hoc turn on a preserved-membership session is NOT misrouted:
     * its completion carries no taskId and the session holds no active assignment,
     * so the forwarder's WARMUPGAP guard skips the dispatch-row flip (it only
     * injects a benign task-less notification). A NON-launched session (a plain CLI
     * session adopted by mesh_send_task --direct, launchedByCoordinator falsy)
     * keeps the original full clear so an ad-hoc session is never left pinned.
     */
    detachMeshAssignment(): void;
    /**
     * The resolved modal-park status of this session, or null when it is not
     * parked on a modal awaiting a human answer. Mirrors the overlay logic in
     * getState(): an active AskUserQuestion interactive prompt resolves to
     * waiting_choice; otherwise the adapter's waiting_approval (tool consent)
     * counts — UNLESS auto-approve will dismiss it, in which case the session is
     * effectively generating and is NOT modal-parked. This is the single signal
     * the mesh force-inject guard consults, and the same status string the
     * reconcile loop reads off get_status_metadata. Lowercase literals only —
     * the SessionStatus enum is forked across modules and waiting_choice is
     * absent from some of them.
     */
    resolveModalParkStatus(): 'waiting_choice' | 'waiting_approval' | null;
    /**
     * APPROVAL-INBOX-BLINDSPOT (Fix A): true when this session's approval modal was — or is
     * being — resolved LOCALLY within the recent cooldown. Two independent positive signals:
     *   (1) auto-approve fired its resolveModal within APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS
     *       (lastAutoApproveFiredAt), or
     *   (2) the underlying adapter reports isApprovalRecentlyResolved() — its own resolve
     *       cooldown, which also covers a dashboard / mesh_approve resolution.
     * The mesh event forwarder uses this to decide whether an agent:waiting_approval from an
     * auto-approving worker can be safely SUPPRESSED (a local resolution is in flight) or must
     * be FORWARDED (auto-approve is configured but has NOT actually resolved this modal, so the
     * coordinator/inbox must be told). Keying suppression on real resolution — not just the
     * autoApprove *intent* — is the blind-spot fix: a never-resolving worker approval is no
     * longer silently dropped.
     */
    approvalRecentlyResolvedLocally(now?: number): boolean;
    /**
     * NOTIF-HELD-DRAIN: true when this `waiting_approval` is a routine, transient tool-consent
     * of an autonomously-progressing mesh session rather than a genuine human-await modal —
     * i.e. it is a mesh coordinator/worker session, a turn is actively in flight
     * (hasAdapterPendingResponse), and no human is attending it by hand. Such a consent is
     * driven to resolution by the harness/operator as part of the in-flight turn, so holding
     * the mesh's completion events behind it (modal_parked) is the false-positive that stalls
     * delivery. Narrow by design: manual attendance or a non-progressing session falls through
     * to the genuine-modal classification.
     */
    private isTransientToolConsent;
    /** True when this session is parked on a modal awaiting a human answer. */
    isModalParked(): boolean;
    /**
     * PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
     * reconcile loop must consult — the RAW adapter turn-state, with the
     * auto-approve "hold-idle" visual mask STRIPPED.
     *
     * getState().status overlays `autoApproveHoldIdle`/`autoApproveActive` to paint a
     * genuinely-idle adapter as `generating` (a UI-flicker suppression while an
     * auto-approve key-press settles — see getState() ~:800). That mask is correct
     * for the dashboard, but the reconcile loop trusts it as "the coordinator is
     * busy" and therefore HOLDS a worker's completion under
     * `generating_no_idle_coordinator` even though the coordinator's PTY is at a real
     * turn end and would accept the inject as a turn — the completion is stranded.
     *
     * This accessor reports the drain truth instead:
     *   - 'modal_parked' — a GENUINE human-await modal (AskUserQuestion / a non-
     *     transient tool-consent). Still excluded from drain (a force-inject here
     *     writes raw keystrokes the modal eats → data corruption). Mirrors
     *     isModalParked(), evaluated first so a parked session never reads idle.
     *   - 'idle' — the RAW adapter is at a turn end (adapter.getStatus(allowParse:false)
     *     === 'idle') and the session is not modal-parked. Drain-eligible REGARDLESS
     *     of the auto-approve mask. This is the case the mask used to hide.
     *   - 'generating' — the raw adapter is genuinely mid-turn. Held (a raw PTY write
     *     into a generating claude-cli is not consumed as a turn → data loss). The
     *     intentional removal of force-inject-into-generating is preserved.
     *   - 'other' — any other raw status (error / starting / waiting_choice handled by
     *     modal-park above). Not a drain target.
     *
     * Uses allowParse:false (engine.activeModal only, side-effect-free) so it never
     * mutates the very auto-approve mask state the diagnostics read.
     */
    getDrainStatus(): 'idle' | 'generating' | 'modal_parked' | 'other';
    onEvent(event: string, data?: any): void;
    recordAcknowledgedUserInput(input: InputEnvelope | string): void;
    /** Drop user-input ack entries older than the dedup window so the map can't grow unbounded. */
    private pruneRecentUserInputAcks;
    /**
     * Owner token for this session in the antigravity conversation-claim
     * registry. Keyed on the daemon instance id — the SAME value the session
     * registry stores as this session's `sessionId` (see cli-manager
     * `sessionRegistry.register({ sessionId: cliInstance.instanceId })`) and the
     * read side hands the dispatcher as `instanceId`. Both sides therefore
     * derive the identical `iid:<instanceId>` token, so the claims the
     * dispatcher records under this session are exactly the ones dispose()
     * releases.
     *
     * This must NOT be derived from a spawn timestamp: the instance's
     * `startedAt`, the adapter's `spawnedAtMs`, and the session registry's
     * `spawnedAtMs` are three INDEPENDENT `Date.now()` samples for the one
     * session, so a workspace+spawn-time token computed here would never equal
     * the read side's — the claim isolation then silently collapses and two
     * concurrent antigravity sessions cross-bind each other's conversation .db
     * (coordinator+worker chat crosswire).
     */
    private antigravityClaimOwner;
    dispose(): void;
    private completedDebounceTimer;
    private completedDebouncePending;
    private lastExternalCompletionProbe;
    /**
     * The final assistant summary of the last completed turn, cached at
     * completion-emit time. For a native-source provider (antigravity) whose
     * assistant answer lives only in native-history — never in the PTY parse that
     * feeds activeChat.messages — the dashboard's preview / lastMessageRole /
     * completionMarker would otherwise never see the answer and show the session
     * stuck on the user prompt. getState() appends this cached assistant bubble to
     * the status messages when the PTY tail has none, so those fields reflect the
     * real last answer with ZERO per-tick native reads (the native read already ran
     * once at completion). Reset on the next turn's start.
     */
    private lastCompletionSummary;
    private enforceFreshSessionLaunchIfNeeded;
    /**
     * BRAIN-ROUTING (runtime-control thinking axis): for a provider that selects
     * reasoning effort via a runtime control instead of a launch arg (e.g. hermes
     * `reasoning`), apply the requested initialThinkingLevel after spawn by invoking
     * that control's setScript. The provider names the control via thinkingControlId.
     * The standard level is mapped through thinkingLevelMap first (same as the
     * launch-arg path). Best-effort: any failure logs and never blocks launch.
     */
    private applyInitialThinkingLevelViaControl;
    private completionHasFinalAssistantMessage;
    private recordPendingTranscriptProbe;
    /**
     * The spawned CLI's env overrides (e.g. the mesh coordinator points hermes
     * at a per-coordinator HERMES_HOME so its state.db lives in a tmpdir instead
     * of ~/.hermes). The native-history executor expands `${HERMES_HOME:-~/.hermes}`
     * from this map, so the completion gate MUST pass it through — otherwise the
     * gate reads ~/.hermes, finds no coordinator-session transcript, and
     * false-fires missing_final_assistant on every coordinator turn.
     */
    private spawnedEnvOverrides;
    private readExternalCompletionMessages;
    /**
     * The content of the LAST visible assistant bubble in a message list, or ''
     * when the tail is not an assistant reply. Skips trailing system/tool/activity
     * bubbles; stops (returns '') at the first user/human message. Used only for
     * the dashboard tail-repair cache — a display value, not a completion decision.
     */
    private lastVisibleAssistantSummary;
    private lastVisibleAssistantSummaryDetail;
    /**
     * NOTIF Defect-B: the final assistant summary this instance ALREADY parsed and
     * cached for the current turn (lastCompletionSummary), if any. The evidence
     * probe (completionFinalAssistantEvidence) is a POINT-SAMPLE: on a native-source
     * provider (antigravity) the parsed screen and the native transcript can both
     * momentarily yield no in-turn final assistant at the exact instant the
     * completion gate fires — source='unavailable', missingEvidence=true — even
     * though a prior poll already read the real answer off native-history and cached
     * it here (the same value mesh_read_chat.summary shows). Consulting the cache at
     * emit time lets that already-secured summary count as evidence, so the completion
     * notification carries the answer instead of completion_diagnostic=missing_final_assistant
     * with an empty summary. Returns '' when the cache is empty or was reset by the
     * next turn (see lastCompletionSummary = null on onTurnStarted).
     */
    private cachedCompletionSummaryContent;
    private cachedInTurnCompletionSummaryContent;
    private completionFinalAssistantEvidence;
    private completionFinalSummary;
    private buildCompletedFinalizationDiagnostic;
    private hasAdapterPendingResponse;
    private shouldSuppressStaleParsedBusyStatus;
    private getCompletedFinalizationBlock;
    private hasApprovalResolutionEvidence;
    private approvalResolutionFinalizationBlock;
    private scheduleCompletedDebounceFlush;
    private isMeshWorkerSession;
    /**
     * MESH-READ-TERMINAL (feature 2: RAW terminal read). Public read of the
     * CURRENT rendered PTY viewport for the mesh_read_terminal tool, delegating to
     * the adapter's narrow getTerminalScreenSnapshot() (viewport + cursor + size
     * only; no debug buffers / parser state / history; byte-bounded, bottom-tail
     * preserved).
     *
     * Gated on isMeshWorkerSession(): this raw viewport can expose tokens /
     * command args / env / user data, so only a coordinator-spawned worker session
     * is readable. The MCP layer ALSO cross-checks mesh/session/node ownership
     * (isMeshOwnedDelegateSession) — isMeshWorkerSession alone is a broad
     * "delegated" gate, so the two together block cross-mesh access. Returns null
     * for a non-mesh session so the daemon command surfaces a clean refusal.
     */
    getTerminalScreenSnapshot(maxBytes?: number): {
        text: string;
        cursor: {
            col: number;
            row: number;
        };
        cols: number;
        rows: number;
        truncated: boolean;
        originalBytes: number;
        returnedBytes: number;
        hash: string;
    } | null;
    /**
     * MESH-SEND-KEYS (feature 3: key injection). Public entry for the
     * mesh_send_keys tool, delegating to the adapter's injectKeys() (structured
     * key encoding + atomic write + submit-race recheck + modal fail-closed).
     *
     * Gated on isMeshWorkerSession(): PTY input into a worker is a
     * coordinator-only capability. The MCP layer ALSO cross-checks mesh/session/
     * node ownership (isMeshOwnedDelegateSession) and owns the destructive-key
     * double gate (confirm_destructive + policy) and the audit ledger. Returns a
     * refusal object for a non-mesh session so the daemon command surfaces a clean
     * error (never silently writes to a non-worker PTY).
     */
    injectKeys(items: MeshSendKeyItem[], opts?: {
        allowModalOverride?: boolean;
    }): Promise<{
        ok: true;
        keys: MeshSendKeyName[];
        hasDestructive: boolean;
        submits: boolean;
        bytes: number;
    } | {
        ok: false;
        refused: 'submit_race' | 'actionable_modal' | 'not_mesh_worker' | 'unsupported';
        keys: MeshSendKeyName[];
        hasDestructive: boolean;
    }>;
    /**
     * MESH-STALL-WATCH (feature 1: STALL detection). Status-agnostic stall
     * watchdog for coordinator-spawned mesh worker sessions. Driven by the
     * ProviderInstanceManager's existing 5s onTick loop (NO new timer) — see
     * ProviderInstanceManager.startTicking. Reuses the adapter's raw-PTY-output
     * clock (lastOutputAt, bumped on every output chunk) as the sole signal: if a
     * live worker's screen has been byte-for-byte unchanged past the turn-scoped
     * threshold (below), fire ONE informational monitor:no_progress event down the
     * existing task_stalled ledger + pendingCoordinatorEvent path.
     *
     * The reported status is read for TWO bounded purposes only — it does NOT
     * suppress the fire (sticky-status blindness would hide a real wedge):
     *   • Fix B (anchor re-arm on turn end): the FSM's completion/idle transition
     *     never touches the stall anchor, so a completed worker that goes idle would
     *     otherwise keep counting from its LAST pre-completion output and false-fire
     *     in the quiet valley right after finishing. We detect the turn-active edge
     *     (hasAdapterPendingResponse()) and, on active → inactive, re-arm the anchor
     *     to `now` so the post-completion idle valley starts a fresh clock.
     *   • Fix C (turn-scoped threshold): while a turn is genuinely in flight the bar
     *     is raised (MESH_WORKER_STALL_TURN_THRESHOLD_MS) to absorb long normal
     *     thinking gaps; outside a turn the tighter idle bound applies. This is a
     *     RAISE, not a skip — a real mid-turn wedge still fires late at the turn bound.
     *
     * Anchoring: the episode arms against the current lastOutputAt; a worker that
     * has emitted nothing yet (lastOutputAt === 0) anchors on this.startedAt (spawn
     * time) so a silent spawn is still caught. Any new output re-arms the anchor
     * and clears the emitted flag, so one continuous stall emits at most once and a
     * later stall re-arms cleanly. Fix E adds a per-session refire cooldown so a
     * dribble of one-byte-per-few-minutes output cannot page the coordinator on
     * every re-arm.
     */
    checkMeshWorkerStall(now?: number): void;
    /**
     * FALSE-STALL-WATCHDOG-OVERFIRE: drop the entire stall episode for this session.
     * Called when the session is no longer a mesh worker or the PTY is dead — the
     * next live tick re-arms a fresh episode. Clears the fix-B turn-edge state and
     * the fix-E refire cooldown alongside the base anchor so a re-armed session
     * starts with a clean slate (a restart is not throttled by a prior stall).
     */
    private resetMeshStallEpisode;
    /**
     * AUTOAPPROVE-FLAP-RECUR (Fix A+B): how long a busy blip / modal scroll-out may
     * persist before the in-progress settle gate is torn down. For a delegated
     * worker whose auto-approve episode is genuinely still cycling (mask clock
     * alive), the FSM's full waiting_approval → busy → waiting_approval flap runs
     * on a multi-second period, so the settle continuity window is extended to
     * AUTO_APPROVE_FLAP_CONTINUITY_MS to bridge it (still bounded, and still capped
     * by AUTO_APPROVE_MASK_STALL_MS). Every other case — foreground/attended
     * session, or no active mask episode — keeps the tight default hysteresis so a
     * genuine resolution frees the gate promptly.
     */
    private autoApproveContinuityWindowMs;
    /**
     * The settle-gate identity signature for a raw activeModal, or null when the
     * modal is NOT a concrete auto-approvable consent prompt (no captured buttons,
     * a picker/confirm kind, or no reliable affirmative+decline anchor). Mirrors the
     * gates the auto-approve fire path applies before computing modalSignature, so
     * the mask-stall nudge can ask the SAME question the settle gate is tracking —
     * "is THIS frame's modal the identity the settle clock is accruing against?" —
     * without duplicating the button-pick logic. The signature is message +
     * normalized affirmative label only (no volatile counters/button set), matching
     * the fire path exactly (AUTOAPPROVE-SETTLE-FLAP).
     */
    private approvableModalSignature;
    private isAutonomousMeshSession;
    /**
     * FALSE-IDLE: are we inside the post-approval resume grace window? True when this
     * is an autonomous auto-approving mesh session AND the engine resolved a modal
     * (auto-approve / mesh_approve) within APPROVAL_RESUME_GRACE_MS. This is the single
     * "auto-approve recency" judgment shared by Fix 1 (the SETTLE-VALLEY completion
     * hold below) and Fix 2 (the FSM-level applyIdle hysteresis in cli-state-engine).
     *
     * Scoped to autonomous auto-approving sessions so a foreground/attended session,
     * or a session with auto-approve off (whose approvals a human answers), is never
     * held. The recency clock (adapter.lastApprovalResolvedAt) is 0 until the first
     * resolveModal, so a plain turn that never saw an approval always returns false.
     */
    private inApprovalResumeGrace;
    /**
     * ARCH-REFACTOR R1: the taskId to attribute the CURRENTLY-completing turn to.
     * Prefers the per-turn binding (engine.currentTurnTaskId, set when the turn was
     * submitted and surviving until the next turn starts) over the last-write-wins
     * session scalar (settings.meshActiveTaskId). The scalar is retained only as a
     * backward-compat alias for the "current/last assignment" and is the source of the
     * NOTIF-MISDELIVER / TASK-MSG-MISROUTE race: a second task attaching before this
     * turn completes overwrites it. Returns undefined for a non-task ad-hoc turn.
     */
    private completingTurnTaskId;
    /**
     * ANTIGRAVITY-PREMATURE-COMPLETION gate: has the CURRENTLY-injected task actually
     * entered generating (a real onTurnStarted for it)? Used to reject stale external-
     * native completion evidence that predates the injected task's turn.
     *
     * The injected task's id is the session scalar `meshActiveTaskId`, stamped by
     * attachMeshAssignment BEFORE the PTY turn starts. That stamp also records
     * `meshTaskInjectedAt`. The turn that has genuinely started is marked by
     * `adapter.currentTurnStartedAt` (set ONLY by onTurnStarted). Two naive signals both
     * FAIL for a reused-idle session:
     *  - `currentTurnStartedAt > 0` alone: it persists from the PRIOR turn, so it is
     *    already > 0 the instant a new task is injected (pre-onTurnStarted).
     *  - `currentTurnTaskId === meshActiveTaskId` alone: forceSendMessage (the mesh
     *    inject path) pre-binds currentTurnTaskId to the new taskId at inject time,
     *    BEFORE the turn starts, so this matches prematurely too.
     * The robust discriminator is TEMPORAL: the producing turn must have STARTED AFTER
     * the injection — `currentTurnStartedAt > meshTaskInjectedAt`. Only then has the
     * injected task's own onTurnStarted fired.
     *  - No injected task since boot (meshTaskInjectedAt === 0, e.g. an ad-hoc/dashboard
     *    turn or a non-mesh session): fall back to the plain "a turn has started" check
     *    so non-mesh completion is unaffected.
     * Fails CLOSED for the injected-but-not-started window; open once the injected turn is
     * genuinely underway (preserving the rc.480/481 completion-fires win).
     */
    private injectedTaskHasStartedGenerating;
    private meshTraceCtx;
    private completionTraceOn;
    private fsmTraceOn;
    private recordCompletionGateTrace;
    private recordFsmTransitionTrace;
    private flushCompletedDebounceIfFinalized;
    /**
     * A-3 (CLI 완료판정 통합): single authoritative emit for a CLI turn's
     * `agent:generating_completed` event. The completion JUDGMENT — WHETHER and
     * WHEN a turn is done (settle windows, continuity guards, the finalization
     * gate, the short-gen / startup-grace / no-progress-monitor discriminators) —
     * stays at each call site, where it is legitimately path-specific. What used
     * to be duplicated across all five completion paths was the EVENT-SHAPE
     * assembly: the `event` name, the conditional `taskId` spread, and the
     * optional `finalSummary` / `evidenceLevel` / `completionDiagnostic` fields.
     * Folding that assembly here removes the divergence (e.g. one site spreading
     * taskId, others omitting it) without touching any judgment. Callers pass the
     * values they have already computed; omitted optionals are simply absent from
     * the emitted event, exactly as each inline builder produced before.
     */
    private emitGeneratingCompleted;
    /**
     * AUTOAPPROVE-FLAP-INBOX-MISSING sticky-approval overlay. Returns the adapterStatus a
     * flap-prone claude-cli approval SHOULD present this frame — either the raw status
     * unchanged, or, when the raw status has momentarily flapped OFF a recently-dominant
     * concrete approval, a synthetic `waiting_approval` re-presenting the cached modal.
     *
     * Records the concrete approval whenever the raw status is waiting_approval WITH
     * buttons. On a subsequent non-approval frame (the spec `approval→busy` flap), if that
     * concrete approval was seen within APPROVAL_STICKY_FLAP_MS AND the engine has NOT
     * resolved a modal since (lastApprovalResolvedAt not advanced past the sticky start),
     * overlay the cached modal + waiting_approval so the inbox / auto-approve / mesh_approve
     * all see the stable approval. A genuine resolution (auto-approve or mesh_approve fires
     * resolveModal → lastApprovalResolvedAt advances) clears the sticky immediately, so a
     * legitimate post-approval resume is NEVER masked as a lingering approval. Bounded by the
     * window, and scoped to autonomous mesh sessions (a foreground/attended or non-mesh
     * session, where a human answers the prompt, is returned untouched).
     */
    private stabilizeFlappingApprovalStatus;
    private maybeAutoApproveStatus;
    /**
     * Re-drive the auto-approve check after the settle quiet window elapses.
     * The PTY may have gone silent once the approval prompt finished painting,
     * so no status-change frame is guaranteed to re-enter maybeAutoApproveStatus
     * — this timer-driven re-check picks up the now-settled modal and fires.
     * Deliberately lighter than detectStatusTransition(): it only re-evaluates
     * the approval decision; the next real PTY frame refreshes visible status.
     */
    private recheckAutoApproveSettled;
    /**
     * Emit the queue-claim agent:ready event at most once per session. Both the
     * boot-time starting→idle one-shot and the fsmReadySeen re-arm call this; the
     * agentReadyEmitted guard ensures the second caller is a no-op so a worker is
     * never claimed twice and a queued task is never double-dispatched.
     */
    private emitAgentReadyOnce;
    /**
     * GENERATING-BOUNDARY synthetic emit for a first turn that started AND finished
     * inside the startup-grace window without the FSM ever observing a 'generating'
     * frame (an unobservably-fast turn). Synthesizes the agent:generating_started +
     * agent:generating_completed pair so the mesh coordinator learns the worker went
     * idle. Returns true iff it synthesized.
     *
     * Two callers share this defense line:
     *  - 'startup_grace_fast_collapse' — the starting→idle transition (the FSM whose
     *    spec lacks/hadn't-synced the starting→busy edge collapses starting→idle
     *    directly, with no intervening 'generating' frame).
     *  - 'startup_grace_idle_turn_collapse' — the idle→idle no-status-change poll
     *    (the launch settle already drained starting→idle BEFORE the first turn, so
     *    the turn runs+completes while status stays 'idle' the whole time and
     *    detectStatusTransition never re-enters its change block — the live rc.403
     *    Probe1 miss).
     *
     * False-positive safety (must NOT fire on a benign boot): currentTurnTaskId is
     * set ONLY by onTurnStarted (a real turn STARTED this boot) and persists past
     * completion, so it excludes a true idle boot (null) and a queued-pending first
     * turn that only runs after grace (onTurnStarted not yet called → null).
     * !hasAdapterPendingResponse() excludes a turn still mid-flight. generating
     * never armed (generatingStartedAt===0 && !generatingDebouncePending) means the
     * whole idle→busy→idle never happened for this turn. The once-per-turn guard
     * (fastCollapseSynthesizedTaskId) keeps the re-polled idle-stayed caller from
     * re-emitting every poll.
     */
    private maybeSynthesizeStartupGraceCollapse;
    private detectStatusTransition;
    private pushEvent;
    private flushEvents;
    private applyProviderResponse;
    getAdapter(): ProviderCliAdapter;
    get cliType(): string;
    get cliName(): string;
    private shouldAutoApprove;
    /** @see ProviderInstance.noteManualInteraction */
    noteManualInteraction(now?: number, opts?: {
        passive?: boolean;
    }): void;
    /**
     * Whether auto-approve should be treated as active *right now* for display
     * and firing decisions: the configured intent AND the user is not currently
     * attending this session by hand. When a human is attending, auto-approve is
     * held so the modal stays visible and they can drive it via the controlbar.
     * Provider-agnostic — the attendance signal is the command set, never any
     * CLI-specific modal text.
     */
    private autoApproveEffectivelyActive;
    private autoApproveMaskStalled;
    /**
     * NOTIF-APPROVAL-MASKED (Q1b): surface a delegated worker's STALLED auto-approve modal
     * to the mesh COORDINATOR, decoupled from the dashboard visible-status mask.
     *
     * When auto-approve is configured but the episode never settles (modal parse miss / the
     * settle gate never satisfied), getState()/detectStatusTransition() fold the raw
     * `waiting_approval` into `generating` to suppress dashboard flicker — so
     * detectStatusTransition()'s `waiting_approval` arm never runs and NO agent:waiting_approval
     * event is emitted. The coordinator's real-time approval-nudge delivery then has no input and
     * the worker's stuck modal is never surfaced (the live ~25s stall). The dashboard mask is
     * intentional and stays; this emits the coordinator nudge exactly ONCE, gated on the SAME
     * raw-waiting_approval + mask-stalled signal resolveModalParkStatus() distinguishes, the
     * instant the mask-stall threshold trips (the same moment getState un-folds the mask).
     *
     * Only delegated worker sessions qualify: a foreground session has no coordinator to notify,
     * and its own dashboard mask already reveals the modal on stall. A normally-resolving
     * auto-approve never reaches AUTO_APPROVE_MASK_STALL_MS, so it emits nothing here; and if a
     * masked approval clears just as this fires, rc.455's isApprovalNudgeResolved stale-drop
     * discards the nudge coordinator-side without noise. Dedup is per-episode (keyed on the
     * mask-clock value) so a modal that flaps between parsed/unparsed states is announced once.
     */
    private maybeEmitStalledApprovalNudge;
    private recordAutoApproval;
    recordApprovalSelection(buttonText: string): void;
    private maybeAppendRuntimeRecoveryMessage;
    private appendRuntimeSystemMessage;
    private appendRuntimeMessage;
    mergeRuntimeChatMessages(parsedMessages: ChatMessage[]): ChatMessage[];
    private promoteProviderSessionId;
    private shouldHydrateExistingProviderHistory;
    private shouldSuppressFreshLaunchStartupReplay;
    private syncCanonicalSavedHistoryIfNeeded;
    private restorePersistedHistoryFromCurrentSession;
    private getProbeDirectories;
    private buildSqlPlaceholderList;
    private querySqliteText;
}
