
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5e17bd3d-c041-5a8e-a4da-cf706c1fbadb")}catch(e){}}();
import { prepareAgentLaunch, } from "./agent-session-adapters.js";
import { hasClaudeWorkspaceTrustPrompt, shouldAutoConfirmClaudeWorkspaceTrust, stopWorkspaceTrustTimers, WORKSPACE_TRUST_CONFIRM_DELAY_MS, } from "./claude-workspace-trust.js";
import { hasCodexWorkspaceTrustPrompt, shouldAutoConfirmCodexWorkspaceTrust } from "./codex-workspace-trust.js";
import { PtySession } from "./pty-session.js";
import { reduceSessionTransition } from "./session-state-machine.js";
import { createTerminalProtocolFilterState, disableOsc11BackgroundQueryIntercept, filterTerminalProtocolOutput, } from "./terminal-protocol-filter.js";
const MAX_WORKSPACE_TRUST_BUFFER_CHARS = 16_384;
const AUTO_RESTART_WINDOW_MS = 5_000;
const MAX_AUTO_RESTARTS_PER_WINDOW = 3;
// OpenCode can query OSC 11 before the browser terminal is attached and ready to answer.
// We intercept that startup probe during history replay and early PTY output, synthesize a
// background-color reply, then disable the filter once a live terminal listener has attached.
const OSC_BACKGROUND_QUERY_REPLY = "\u001b]11;rgb:1717/1717/2121\u001b\\";
function now() {
    return Date.now();
}
function createDefaultSummary(taskId) {
    return {
        taskId,
        state: "idle",
        agentId: null,
        workspacePath: null,
        pid: null,
        startedAt: null,
        updatedAt: now(),
        lastOutputAt: null,
        reviewReason: null,
        exitCode: null,
        lastHookAt: null,
        latestHookActivity: null,
        warningMessage: null,
        latestTurnCheckpoint: null,
        previousTurnCheckpoint: null,
    };
}
function cloneSummary(summary) {
    return {
        ...summary,
    };
}
function updateSummary(entry, patch) {
    entry.summary = {
        ...entry.summary,
        ...patch,
        updatedAt: now(),
    };
    return entry.summary;
}
function isActiveState(state) {
    return state === "running" || state === "awaiting_review";
}
function cloneStartTaskSessionRequest(request) {
    return {
        ...request,
        args: [...request.args],
        env: request.env ? { ...request.env } : undefined,
    };
}
function cloneStartShellSessionRequest(request) {
    return {
        ...request,
        args: request.args ? [...request.args] : undefined,
        env: request.env ? { ...request.env } : undefined,
    };
}
function formatSpawnFailure(binary, error) {
    const message = error instanceof Error ? error.message : String(error);
    const normalized = message.toLowerCase();
    if (normalized.includes("posix_spawnp failed") || normalized.includes("enoent")) {
        return `Failed to launch "${binary}". Command not found. Install a supported agent CLI and select it in Settings.`;
    }
    return `Failed to launch "${binary}": ${message}`;
}
function formatShellSpawnFailure(binary, error) {
    const message = error instanceof Error ? error.message : String(error);
    const normalized = message.toLowerCase();
    if (normalized.includes("posix_spawnp failed") || normalized.includes("enoent")) {
        return `Failed to launch "${binary}". Command not found on this system.`;
    }
    return `Failed to launch "${binary}": ${message}`;
}
function buildTerminalEnvironment(...sources) {
    return {
        ...process.env,
        ...Object.assign({}, ...sources),
        COLORTERM: "truecolor",
        TERM: "xterm-256color",
        TERM_PROGRAM: "kanban",
    };
}
export class TerminalSessionManager {
    entries = new Map();
    summaryListeners = new Set();
    onSummary(listener) {
        this.summaryListeners.add(listener);
        return () => {
            this.summaryListeners.delete(listener);
        };
    }
    hydrateFromRecord(record) {
        for (const [taskId, summary] of Object.entries(record)) {
            this.entries.set(taskId, {
                summary: cloneSummary(summary),
                active: null,
                listenerIdCounter: 1,
                listeners: new Map(),
                restartRequest: null,
                suppressAutoRestartOnExit: false,
                autoRestartTimestamps: [],
                pendingAutoRestart: null,
            });
        }
    }
    getSummary(taskId) {
        const entry = this.entries.get(taskId);
        return entry ? cloneSummary(entry.summary) : null;
    }
    listSummaries() {
        return Array.from(this.entries.values()).map((entry) => cloneSummary(entry.summary));
    }
    attach(taskId, listener) {
        const entry = this.ensureEntry(taskId);
        listener.onState?.(cloneSummary(entry.summary));
        const replayFilterState = createTerminalProtocolFilterState({
            interceptOsc11BackgroundQueries: true,
            suppressDeviceAttributeQueries: entry.active?.terminalProtocolFilter.suppressDeviceAttributeQueries ?? false,
        });
        for (const chunk of entry.active?.session.getOutputHistory() ?? []) {
            const filteredChunk = filterTerminalProtocolOutput(replayFilterState, chunk, {
                onOsc11BackgroundQuery: () => entry.active?.session.write(OSC_BACKGROUND_QUERY_REPLY),
            });
            if (filteredChunk.byteLength > 0) {
                listener.onOutput?.(filteredChunk);
            }
        }
        if (entry.active && listener.onOutput) {
            disableOsc11BackgroundQueryIntercept(entry.active.terminalProtocolFilter);
        }
        const listenerId = entry.listenerIdCounter;
        entry.listenerIdCounter += 1;
        entry.listeners.set(listenerId, listener);
        return () => {
            entry.listeners.delete(listenerId);
        };
    }
    async startTaskSession(request) {
        const entry = this.ensureEntry(request.taskId);
        entry.restartRequest = {
            kind: "task",
            request: cloneStartTaskSessionRequest(request),
        };
        if (entry.active && isActiveState(entry.summary.state)) {
            return cloneSummary(entry.summary);
        }
        if (entry.active) {
            stopWorkspaceTrustTimers(entry.active);
            entry.active.session.stop();
            entry.active = null;
        }
        const cols = Number.isFinite(request.cols) && (request.cols ?? 0) > 0 ? Math.floor(request.cols ?? 0) : 120;
        const rows = Number.isFinite(request.rows) && (request.rows ?? 0) > 0 ? Math.floor(request.rows ?? 0) : 40;
        const launch = await prepareAgentLaunch({
            taskId: request.taskId,
            agentId: request.agentId,
            binary: request.binary,
            args: request.args,
            autonomousModeEnabled: request.autonomousModeEnabled,
            cwd: request.cwd,
            prompt: request.prompt,
            startInPlanMode: request.startInPlanMode,
            resumeFromTrash: request.resumeFromTrash,
            env: request.env,
            workspaceId: request.workspaceId,
        });
        const env = buildTerminalEnvironment(request.env, launch.env);
        // Adapters can wrap the configured agent binary when they need extra runtime wiring
        // (for example, Codex uses a wrapper script to watch session logs for hook transitions).
        const commandBinary = launch.binary ?? request.binary;
        const commandArgs = [...launch.args];
        const hasCodexLaunchSignature = [commandBinary, ...commandArgs].some((part) => part.toLowerCase().includes("codex"));
        let session;
        try {
            session = PtySession.spawn({
                binary: commandBinary,
                args: commandArgs,
                cwd: request.cwd,
                env,
                cols,
                rows,
                onData: (chunk) => {
                    if (!entry.active) {
                        return;
                    }
                    const filteredChunk = filterTerminalProtocolOutput(entry.active.terminalProtocolFilter, chunk, {
                        onOsc11BackgroundQuery: () => entry.active?.session.write(OSC_BACKGROUND_QUERY_REPLY),
                    });
                    if (filteredChunk.byteLength === 0) {
                        return;
                    }
                    const needsDecodedOutput = entry.active.workspaceTrustBuffer !== null ||
                        (entry.active.detectOutputTransition !== null &&
                            (entry.active.shouldInspectOutputForTransition?.(entry.summary) ?? true));
                    const data = needsDecodedOutput ? filteredChunk.toString("utf8") : "";
                    if (entry.active.workspaceTrustBuffer !== null) {
                        entry.active.workspaceTrustBuffer += data;
                        if (entry.active.workspaceTrustBuffer.length > MAX_WORKSPACE_TRUST_BUFFER_CHARS) {
                            entry.active.workspaceTrustBuffer = entry.active.workspaceTrustBuffer.slice(-MAX_WORKSPACE_TRUST_BUFFER_CHARS);
                        }
                        if (!entry.active.autoConfirmedWorkspaceTrust && entry.active.workspaceTrustConfirmTimer === null) {
                            const hasClaudePrompt = hasClaudeWorkspaceTrustPrompt(entry.active.workspaceTrustBuffer);
                            const hasCodexPrompt = hasCodexWorkspaceTrustPrompt(entry.active.workspaceTrustBuffer);
                            if (hasClaudePrompt || hasCodexPrompt) {
                                entry.active.autoConfirmedWorkspaceTrust = true;
                                const trustConfirmDelayMs = WORKSPACE_TRUST_CONFIRM_DELAY_MS;
                                entry.active.workspaceTrustConfirmTimer = setTimeout(() => {
                                    const activeEntry = this.entries.get(request.taskId)?.active;
                                    if (!activeEntry || !activeEntry.autoConfirmedWorkspaceTrust) {
                                        return;
                                    }
                                    activeEntry.session.write("\r");
                                    activeEntry.workspaceTrustConfirmTimer = null;
                                }, trustConfirmDelayMs);
                            }
                        }
                    }
                    updateSummary(entry, { lastOutputAt: now() });
                    const adapterEvent = entry.active.detectOutputTransition?.(data, entry.summary) ?? null;
                    if (adapterEvent) {
                        const requiresEnterForCodex = adapterEvent.type === "agent.prompt-ready" &&
                            entry.summary.agentId === "codex" &&
                            !entry.active.awaitingCodexPromptAfterEnter;
                        if (!requiresEnterForCodex) {
                            const summary = this.applySessionEvent(entry, adapterEvent);
                            if (adapterEvent.type === "agent.prompt-ready" && entry.summary.agentId === "codex") {
                                entry.active.awaitingCodexPromptAfterEnter = false;
                            }
                            for (const taskListener of entry.listeners.values()) {
                                taskListener.onState?.(cloneSummary(summary));
                            }
                            this.emitSummary(summary);
                        }
                    }
                    for (const taskListener of entry.listeners.values()) {
                        taskListener.onOutput?.(filteredChunk);
                    }
                },
                onExit: (event) => {
                    const currentEntry = this.entries.get(request.taskId);
                    if (!currentEntry) {
                        return;
                    }
                    const currentActive = currentEntry.active;
                    if (!currentActive) {
                        return;
                    }
                    stopWorkspaceTrustTimers(currentActive);
                    const summary = this.applySessionEvent(currentEntry, {
                        type: "process.exit",
                        exitCode: event.exitCode,
                        interrupted: currentActive.session.wasInterrupted(),
                    });
                    const shouldAutoRestart = this.shouldAutoRestart(currentEntry);
                    for (const taskListener of currentEntry.listeners.values()) {
                        taskListener.onState?.(cloneSummary(summary));
                        taskListener.onExit?.(event.exitCode);
                    }
                    currentEntry.active = null;
                    this.emitSummary(summary);
                    if (shouldAutoRestart) {
                        this.scheduleAutoRestart(currentEntry);
                    }
                    const cleanupFn = currentActive.onSessionCleanup;
                    currentActive.onSessionCleanup = null;
                    if (cleanupFn) {
                        cleanupFn().catch(() => {
                            // Best effort: cleanup failure is non-critical.
                        });
                    }
                },
            });
        }
        catch (error) {
            if (launch.cleanup) {
                void launch.cleanup().catch(() => {
                    // Best effort: cleanup failure is non-critical.
                });
            }
            const summary = updateSummary(entry, {
                state: "failed",
                agentId: request.agentId,
                workspacePath: request.cwd,
                pid: null,
                startedAt: null,
                lastOutputAt: null,
                reviewReason: "error",
                exitCode: null,
                lastHookAt: null,
                latestHookActivity: null,
                latestTurnCheckpoint: null,
                previousTurnCheckpoint: null,
            });
            this.emitSummary(summary);
            throw new Error(formatSpawnFailure(commandBinary, error));
        }
        const active = {
            session,
            workspaceTrustBuffer: shouldAutoConfirmClaudeWorkspaceTrust(request.agentId, request.cwd) ||
                shouldAutoConfirmCodexWorkspaceTrust(request.agentId, request.cwd) ||
                hasCodexLaunchSignature
                ? ""
                : null,
            cols,
            rows,
            terminalProtocolFilter: createTerminalProtocolFilterState({
                interceptOsc11BackgroundQueries: true,
                suppressDeviceAttributeQueries: request.agentId === "droid",
            }),
            onSessionCleanup: launch.cleanup ?? null,
            detectOutputTransition: launch.detectOutputTransition ?? null,
            shouldInspectOutputForTransition: launch.shouldInspectOutputForTransition ?? null,
            awaitingCodexPromptAfterEnter: false,
            autoConfirmedWorkspaceTrust: false,
            workspaceTrustConfirmTimer: null,
        };
        entry.active = active;
        const startedAt = now();
        updateSummary(entry, {
            state: request.resumeFromTrash ? "awaiting_review" : "running",
            agentId: request.agentId,
            workspacePath: request.cwd,
            pid: session.pid,
            startedAt,
            lastOutputAt: null,
            reviewReason: request.resumeFromTrash ? "attention" : null,
            exitCode: null,
            lastHookAt: null,
            latestHookActivity: null,
            warningMessage: null,
            latestTurnCheckpoint: null,
            previousTurnCheckpoint: null,
        });
        this.emitSummary(entry.summary);
        return cloneSummary(entry.summary);
    }
    async startShellSession(request) {
        const entry = this.ensureEntry(request.taskId);
        entry.restartRequest = {
            kind: "shell",
            request: cloneStartShellSessionRequest(request),
        };
        if (entry.active && entry.summary.state === "running") {
            return cloneSummary(entry.summary);
        }
        if (entry.active) {
            stopWorkspaceTrustTimers(entry.active);
            entry.active.session.stop();
            entry.active = null;
        }
        const cols = Number.isFinite(request.cols) && (request.cols ?? 0) > 0 ? Math.floor(request.cols ?? 0) : 120;
        const rows = Number.isFinite(request.rows) && (request.rows ?? 0) > 0 ? Math.floor(request.rows ?? 0) : 40;
        const env = buildTerminalEnvironment(request.env);
        let session;
        try {
            session = PtySession.spawn({
                binary: request.binary,
                args: request.args ?? [],
                cwd: request.cwd,
                env,
                cols,
                rows,
                onData: (chunk) => {
                    if (!entry.active) {
                        return;
                    }
                    const filteredChunk = filterTerminalProtocolOutput(entry.active.terminalProtocolFilter, chunk, {
                        onOsc11BackgroundQuery: () => entry.active?.session.write(OSC_BACKGROUND_QUERY_REPLY),
                    });
                    if (filteredChunk.byteLength === 0) {
                        return;
                    }
                    if (entry.active.workspaceTrustBuffer !== null) {
                        entry.active.workspaceTrustBuffer += filteredChunk.toString("utf8");
                        if (entry.active.workspaceTrustBuffer.length > MAX_WORKSPACE_TRUST_BUFFER_CHARS) {
                            entry.active.workspaceTrustBuffer = entry.active.workspaceTrustBuffer.slice(-MAX_WORKSPACE_TRUST_BUFFER_CHARS);
                        }
                    }
                    updateSummary(entry, { lastOutputAt: now() });
                    for (const taskListener of entry.listeners.values()) {
                        taskListener.onOutput?.(filteredChunk);
                    }
                },
                onExit: (event) => {
                    const currentEntry = this.entries.get(request.taskId);
                    if (!currentEntry) {
                        return;
                    }
                    const currentActive = currentEntry.active;
                    if (!currentActive) {
                        return;
                    }
                    stopWorkspaceTrustTimers(currentActive);
                    const summary = updateSummary(currentEntry, {
                        state: currentActive.session.wasInterrupted() ? "interrupted" : "idle",
                        reviewReason: currentActive.session.wasInterrupted() ? "interrupted" : null,
                        exitCode: event.exitCode,
                        pid: null,
                    });
                    for (const taskListener of currentEntry.listeners.values()) {
                        taskListener.onState?.(cloneSummary(summary));
                        taskListener.onExit?.(event.exitCode);
                    }
                    currentEntry.active = null;
                    this.emitSummary(summary);
                },
            });
        }
        catch (error) {
            const summary = updateSummary(entry, {
                state: "failed",
                agentId: null,
                workspacePath: request.cwd,
                pid: null,
                startedAt: null,
                lastOutputAt: null,
                reviewReason: "error",
                exitCode: null,
                lastHookAt: null,
                latestHookActivity: null,
                latestTurnCheckpoint: null,
                previousTurnCheckpoint: null,
            });
            this.emitSummary(summary);
            throw new Error(formatShellSpawnFailure(request.binary, error));
        }
        const active = {
            session,
            workspaceTrustBuffer: null,
            cols,
            rows,
            terminalProtocolFilter: createTerminalProtocolFilterState({
                interceptOsc11BackgroundQueries: true,
            }),
            onSessionCleanup: null,
            detectOutputTransition: null,
            shouldInspectOutputForTransition: null,
            awaitingCodexPromptAfterEnter: false,
            autoConfirmedWorkspaceTrust: false,
            workspaceTrustConfirmTimer: null,
        };
        entry.active = active;
        updateSummary(entry, {
            state: "running",
            agentId: null,
            workspacePath: request.cwd,
            pid: session.pid,
            startedAt: now(),
            lastOutputAt: null,
            reviewReason: null,
            exitCode: null,
            lastHookAt: null,
            latestHookActivity: null,
            warningMessage: null,
            latestTurnCheckpoint: null,
            previousTurnCheckpoint: null,
        });
        this.emitSummary(entry.summary);
        return cloneSummary(entry.summary);
    }
    recoverStaleSession(taskId) {
        const entry = this.entries.get(taskId);
        if (!entry) {
            return null;
        }
        if (entry.active || !isActiveState(entry.summary.state)) {
            return cloneSummary(entry.summary);
        }
        const summary = updateSummary(entry, {
            state: "idle",
            agentId: null,
            workspacePath: null,
            pid: null,
            startedAt: null,
            lastOutputAt: null,
            reviewReason: null,
            exitCode: null,
            lastHookAt: null,
            latestHookActivity: null,
            latestTurnCheckpoint: null,
            previousTurnCheckpoint: null,
        });
        for (const listener of entry.listeners.values()) {
            listener.onState?.(cloneSummary(summary));
        }
        this.emitSummary(summary);
        return cloneSummary(summary);
    }
    writeInput(taskId, data) {
        const entry = this.entries.get(taskId);
        if (!entry?.active) {
            return null;
        }
        if (entry.summary.agentId === "codex" &&
            entry.summary.state === "awaiting_review" &&
            (entry.summary.reviewReason === "hook" ||
                entry.summary.reviewReason === "attention" ||
                entry.summary.reviewReason === "error") &&
            (data.includes(13) || data.includes(10))) {
            entry.active.awaitingCodexPromptAfterEnter = true;
        }
        entry.active.session.write(data);
        return cloneSummary(entry.summary);
    }
    resize(taskId, cols, rows, pixelWidth, pixelHeight) {
        const entry = this.entries.get(taskId);
        if (!entry?.active) {
            return false;
        }
        const safeCols = Math.max(1, Math.floor(cols));
        const safeRows = Math.max(1, Math.floor(rows));
        const safePixelWidth = Number.isFinite(pixelWidth ?? Number.NaN) ? Math.floor(pixelWidth) : undefined;
        const safePixelHeight = Number.isFinite(pixelHeight ?? Number.NaN)
            ? Math.floor(pixelHeight)
            : undefined;
        const normalizedPixelWidth = safePixelWidth !== undefined && safePixelWidth > 0 ? safePixelWidth : undefined;
        const normalizedPixelHeight = safePixelHeight !== undefined && safePixelHeight > 0 ? safePixelHeight : undefined;
        entry.active.session.resize(safeCols, safeRows, normalizedPixelWidth, normalizedPixelHeight);
        entry.active.cols = safeCols;
        entry.active.rows = safeRows;
        return true;
    }
    pauseOutput(taskId) {
        const entry = this.entries.get(taskId);
        if (!entry?.active) {
            return false;
        }
        entry.active.session.pause();
        return true;
    }
    resumeOutput(taskId) {
        const entry = this.entries.get(taskId);
        if (!entry?.active) {
            return false;
        }
        entry.active.session.resume();
        return true;
    }
    transitionToReview(taskId, reason) {
        const entry = this.entries.get(taskId);
        if (!entry) {
            return null;
        }
        if (reason !== "hook") {
            return cloneSummary(entry.summary);
        }
        const before = entry.summary;
        const summary = this.applySessionEvent(entry, { type: "hook.to_review" });
        if (summary !== before && entry.active) {
            for (const listener of entry.listeners.values()) {
                listener.onState?.(cloneSummary(summary));
            }
            this.emitSummary(summary);
        }
        return cloneSummary(summary);
    }
    applyHookActivity(taskId, activity) {
        const entry = this.entries.get(taskId);
        if (!entry) {
            return null;
        }
        const hasActivityUpdate = typeof activity.activityText === "string" ||
            typeof activity.toolName === "string" ||
            typeof activity.toolInputSummary === "string" ||
            typeof activity.finalMessage === "string" ||
            typeof activity.hookEventName === "string" ||
            typeof activity.notificationType === "string" ||
            typeof activity.source === "string";
        if (!hasActivityUpdate) {
            return cloneSummary(entry.summary);
        }
        const previous = entry.summary.latestHookActivity;
        const next = {
            activityText: typeof activity.activityText === "string" ? activity.activityText : (previous?.activityText ?? null),
            toolName: typeof activity.toolName === "string" ? activity.toolName : (previous?.toolName ?? null),
            toolInputSummary: typeof activity.toolInputSummary === "string"
                ? activity.toolInputSummary
                : (previous?.toolInputSummary ?? null),
            finalMessage: typeof activity.finalMessage === "string" ? activity.finalMessage : (previous?.finalMessage ?? null),
            hookEventName: typeof activity.hookEventName === "string" ? activity.hookEventName : (previous?.hookEventName ?? null),
            notificationType: typeof activity.notificationType === "string"
                ? activity.notificationType
                : (previous?.notificationType ?? null),
            source: typeof activity.source === "string" ? activity.source : (previous?.source ?? null),
        };
        const didChange = next.activityText !== (previous?.activityText ?? null) ||
            next.toolName !== (previous?.toolName ?? null) ||
            next.toolInputSummary !== (previous?.toolInputSummary ?? null) ||
            next.finalMessage !== (previous?.finalMessage ?? null) ||
            next.hookEventName !== (previous?.hookEventName ?? null) ||
            next.notificationType !== (previous?.notificationType ?? null) ||
            next.source !== (previous?.source ?? null);
        if (!didChange) {
            return cloneSummary(entry.summary);
        }
        const summary = updateSummary(entry, {
            lastHookAt: now(),
            latestHookActivity: next,
        });
        if (entry.active) {
            for (const listener of entry.listeners.values()) {
                listener.onState?.(cloneSummary(summary));
            }
        }
        this.emitSummary(summary);
        return cloneSummary(summary);
    }
    transitionToRunning(taskId) {
        const entry = this.entries.get(taskId);
        if (!entry) {
            return null;
        }
        const before = entry.summary;
        const summary = this.applySessionEvent(entry, { type: "hook.to_in_progress" });
        if (summary !== before && entry.active) {
            for (const listener of entry.listeners.values()) {
                listener.onState?.(cloneSummary(summary));
            }
            this.emitSummary(summary);
        }
        return cloneSummary(summary);
    }
    applyTurnCheckpoint(taskId, checkpoint) {
        const entry = this.entries.get(taskId);
        if (!entry) {
            return null;
        }
        const latestCheckpoint = entry.summary.latestTurnCheckpoint ?? null;
        if (latestCheckpoint?.ref === checkpoint.ref && latestCheckpoint.commit === checkpoint.commit) {
            return cloneSummary(entry.summary);
        }
        const summary = updateSummary(entry, {
            previousTurnCheckpoint: latestCheckpoint,
            latestTurnCheckpoint: checkpoint,
        });
        if (entry.active) {
            for (const listener of entry.listeners.values()) {
                listener.onState?.(cloneSummary(summary));
            }
        }
        this.emitSummary(summary);
        return cloneSummary(summary);
    }
    stopTaskSession(taskId) {
        const entry = this.entries.get(taskId);
        if (!entry?.active) {
            return entry ? cloneSummary(entry.summary) : null;
        }
        entry.suppressAutoRestartOnExit = true;
        const cleanupFn = entry.active.onSessionCleanup;
        entry.active.onSessionCleanup = null;
        stopWorkspaceTrustTimers(entry.active);
        entry.active.session.stop();
        if (cleanupFn) {
            cleanupFn().catch(() => {
                // Best effort: cleanup failure is non-critical.
            });
        }
        return cloneSummary(entry.summary);
    }
    markInterruptedAndStopAll() {
        const activeEntries = Array.from(this.entries.values()).filter((entry) => entry.active != null);
        for (const entry of activeEntries) {
            if (!entry.active) {
                continue;
            }
            stopWorkspaceTrustTimers(entry.active);
            entry.active.session.stop({ interrupted: true });
        }
        return activeEntries.map((entry) => cloneSummary(entry.summary));
    }
    applySessionEvent(entry, event) {
        const transition = reduceSessionTransition(entry.summary, event);
        if (!transition.changed) {
            return entry.summary;
        }
        if (transition.clearAttentionBuffer && entry.active) {
            if (entry.active.workspaceTrustBuffer !== null) {
                entry.active.workspaceTrustBuffer = "";
            }
        }
        if (entry.active && transition.changed && transition.patch.state === "awaiting_review") {
            entry.active.awaitingCodexPromptAfterEnter = false;
        }
        return updateSummary(entry, transition.patch);
    }
    ensureEntry(taskId) {
        const existing = this.entries.get(taskId);
        if (existing) {
            return existing;
        }
        const created = {
            summary: createDefaultSummary(taskId),
            active: null,
            listenerIdCounter: 1,
            listeners: new Map(),
            restartRequest: null,
            suppressAutoRestartOnExit: false,
            autoRestartTimestamps: [],
            pendingAutoRestart: null,
        };
        this.entries.set(taskId, created);
        return created;
    }
    shouldAutoRestart(entry) {
        const wasSuppressed = entry.suppressAutoRestartOnExit;
        entry.suppressAutoRestartOnExit = false;
        if (wasSuppressed) {
            return false;
        }
        if (entry.listeners.size === 0 || entry.restartRequest?.kind !== "task") {
            return false;
        }
        const currentTime = now();
        entry.autoRestartTimestamps = entry.autoRestartTimestamps.filter((timestamp) => currentTime - timestamp < AUTO_RESTART_WINDOW_MS);
        if (entry.autoRestartTimestamps.length >= MAX_AUTO_RESTARTS_PER_WINDOW) {
            return false;
        }
        entry.autoRestartTimestamps.push(currentTime);
        return true;
    }
    scheduleAutoRestart(entry) {
        if (entry.pendingAutoRestart) {
            return;
        }
        const restartRequest = entry.restartRequest;
        if (!restartRequest || restartRequest.kind !== "task") {
            return;
        }
        let pendingAutoRestart = null;
        pendingAutoRestart = (async () => {
            try {
                await this.startTaskSession(cloneStartTaskSessionRequest(restartRequest.request));
            }
            catch (error) {
                const message = error instanceof Error ? error.message : String(error);
                const summary = updateSummary(entry, {
                    warningMessage: message,
                });
                const output = Buffer.from(`\r\n[kanban] ${message}\r\n`, "utf8");
                for (const listener of entry.listeners.values()) {
                    listener.onOutput?.(output);
                    listener.onState?.(cloneSummary(summary));
                }
                this.emitSummary(summary);
            }
            finally {
                if (entry.pendingAutoRestart === pendingAutoRestart) {
                    entry.pendingAutoRestart = null;
                }
            }
        })();
        entry.pendingAutoRestart = pendingAutoRestart;
    }
    emitSummary(summary) {
        const snapshot = cloneSummary(summary);
        for (const listener of this.summaryListeners) {
            listener(snapshot);
        }
    }
}
//# sourceMappingURL=session-manager.js.map
//# debugId=5e17bd3d-c041-5a8e-a4da-cf706c1fbadb
