import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useEffect, useState } from "react";
import { Box, Text, useInput } from "ink";
import { formatCompactTokens, formatCost, formatSessionTokens, shortenMiddle } from "../format.js";
import { computeComposerLayout } from "../layout.js";
import { formatElapsed, pulseGlyph, randomRunStatusSeed, runStatusParts, spinnerFrameMs, spinnerGlyph, waveFrameMs } from "../runStatus.js";
import { GradientText, RainbowText, WaveText, ultraGradients } from "./AnimatedText.js";
import { attachmentSymbol, extractAttachmentPaths, sanitizePastedText } from "./attachments.js";
import { ExperimentalBanner } from "./Banner.js";
import { composerView, deleteComposerText, insertComposerText } from "./composer.js";
import { CommandPalette } from "./CommandPalette.js";
import { estimateGeminiCost, formatSavedCost } from "./geminiPricing.js";
import { computeExperimentalLayout, windowRows } from "./layout.js";
import { symbols, workStateColor } from "./theme.js";
import { buildShellRows, buildTodoDock, truncate } from "./transcriptRows.js";
import { hasUltraMode, splitUltraSegments } from "./ultraModes.js";
/**
 * Fullscreen experimental shell — a Claude-Code / Codex-CLI flavoured layout:
 * compact header, scrolling transcript, a first-class todo dock, prominent
 * approvals, a categorized command palette, and a bottom-pinned composer.
 *
 * Purely presentational. Keyboard routing (palette navigation, approval keys,
 * scrolling, mode toggle) stays in App's central useInput; only the composer
 * owns its own typing input.
 */
export function ExperimentalShell(props) {
    const approvalActive = Boolean(props.pendingApproval || props.bypassConfirmation || props.reauthActive || props.updatePrompt || props.updateBusy);
    const layout = computeExperimentalLayout({
        rows: props.rows,
        columns: props.columns,
        composerInput: props.input,
        paletteItemCount: props.paletteItems.length,
        approvalActive,
        todoCount: props.todos.length,
        hasArtifacts: props.artifacts.length > 0,
    });
    return (_jsxs(Box, { flexDirection: "column", height: layout.rootHeight, overflowY: "hidden", children: [_jsx(ShellHeader, { ...props }), layout.artifactsHeight > 0 ? _jsx(ArtifactsBar, { artifacts: props.artifacts, width: layout.transcriptWidth }) : null, _jsx(ShellTranscript, { lines: props.lines, isRunning: props.isRunning, ultramaxxRun: props.ultramaxxRun, scrollOffset: props.transcriptScrollOffset, height: layout.transcriptHeight, width: layout.transcriptWidth }), layout.todoDockHeight > 0 ? (_jsx(ShellTodoDock, { todos: props.todos, todoFrame: props.todoFrame, height: layout.todoDockHeight, width: layout.transcriptWidth })) : null, props.reauthActive ? (_jsx(ShellReauth, { busy: props.reauthBusy })) : props.updatePrompt || props.updateBusy ? (_jsx(ShellUpdate, { prompt: props.updatePrompt, busy: props.updateBusy })) : approvalActive ? (_jsx(ShellApproval, { request: props.pendingApproval, bypassConfirmation: props.bypassConfirmation })) : null, props.paletteItems.length > 0 ? (_jsx(CommandPalette, { items: props.paletteItems, selectedIndex: props.paletteIndex, width: layout.transcriptWidth })) : null, _jsx(ShellComposer, { input: props.input, isRunning: props.isRunning, ultramaxxRun: props.ultramaxxRun, approvalActive: approvalActive, workState: props.workState, status: props.status, draftTokens: props.draftTokens, sessionTelemetry: props.sessionTelemetry, width: layout.transcriptWidth, onAttach: props.onAttach, onChange: props.onChange, onSubmit: props.onSubmit }), _jsx(ShellFooter, { agentMode: props.agentMode, paletteOpen: props.paletteItems.length > 0 })] }));
}
function ShellUpdate(props) {
    const [frame, setFrame] = useState(0);
    useEffect(() => {
        if (!props.busy) {
            setFrame(0);
            return;
        }
        const timer = setInterval(() => {
            setFrame((current) => current + 1);
        }, spinnerFrameMs);
        return () => {
            clearInterval(timer);
        };
    }, [props.busy]);
    const latestVersion = props.prompt?.latestVersion ?? "";
    const command = props.prompt?.command ?? "npm update -g @jx-grxf/patchpilot";
    return (_jsxs(Box, { borderStyle: "round", borderColor: "yellow", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: [symbols.update, " PATCHPILOT UPDATE AVAILABLE"] }), props.busy ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "cyan", children: [_jsx(Text, { bold: true, children: spinnerGlyph(frame) }), " Updating PatchPilot\u2026"] }), _jsx(Text, { color: "gray", children: command })] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "white", children: ["Install PatchPilot ", latestVersion, " now?"] }), _jsxs(Text, { color: "gray", children: ["Current ", props.prompt?.currentVersion ?? "-", " \u00B7 source ", props.prompt?.source ?? "npm", " \u00B7 ", command] }), _jsxs(Text, { children: [_jsx(Text, { color: "green", bold: true, children: "[y]" }), _jsx(Text, { color: "gray", children: " update   " }), _jsx(Text, { color: "red", bold: true, children: "[n / esc]" }), _jsx(Text, { color: "gray", children: " skip" })] })] }))] }));
}
function ShellHeader(props) {
    const accent = workStateColor(props.workState);
    const hostLabel = props.provider === "ollama" ? props.activeHost?.host.deviceName ?? "ollama" : `${props.provider} api`;
    const modeColor = props.agentMode === "bypass" ? "red" : props.agentMode === "build" ? "yellow" : "green";
    const modeLabel = props.agentMode === "bypass" ? "build+bypass" : props.agentMode;
    const writeLabel = props.allowWrite ? "on" : props.agentMode === "build" ? "approval" : "off";
    const shellLabel = props.allowShell ? "on" : props.agentMode === "build" ? "approval" : "off";
    // Gemini-Wrapper rides the free Gemini Web route; show what the same tokens
    // would have cost on the paid Gemini API — i.e. the running saved amount.
    const savedUsd = props.provider === "gemini-wrapper"
        ? estimateGeminiCost(props.sessionTelemetry.promptTokens, props.sessionTelemetry.responseTokens, props.model)
        : null;
    return (_jsxs(Box, { borderStyle: "round", borderColor: accent, flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { wrap: "truncate", children: [_jsxs(Text, { color: "cyan", bold: true, children: [symbols.assistant, " PatchPilot"] }), _jsx(Text, { color: "gray", children: " \u00B7 " }), _jsxs(Text, { color: "white", children: [props.provider, "/", shortenMiddle(props.model, 24)] }), _jsx(Text, { color: "gray", children: " on " }), _jsx(Text, { color: "white", children: shortenMiddle(hostLabel, 16) })] }), _jsxs(Text, { wrap: "truncate", children: [savedUsd !== null ? (_jsxs(Text, { children: [_jsxs(Text, { color: "green", bold: true, children: ["saved ", formatSavedCost(savedUsd)] }), _jsx(Text, { color: "gray", children: " \u00B7 " })] })) : null, _jsx(Text, { color: "gray", children: "mode " }), _jsx(Text, { color: modeColor, bold: true, children: modeLabel })] })] }), _jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { color: "gray", wrap: "truncate", children: [symbols.bullet, " ", shortenMiddle(props.workspace, 34), _jsx(Text, { color: "gray", children: "  write " }), _jsx(Text, { color: props.allowWrite ? "red" : "gray", children: writeLabel }), _jsx(Text, { color: "gray", children: "  shell " }), _jsx(Text, { color: props.allowShell ? "red" : "gray", children: shellLabel })] }), _jsxs(Text, { color: "gray", wrap: "truncate", children: [formatSessionTokens(props.sessionTelemetry), " \u00B7 ", formatCost(props.sessionTelemetry.estimatedCostUsd)] })] })] }));
}
/** Compact bar listing attached documents and files PatchPilot created. */
function ArtifactsBar(props) {
    const visible = props.artifacts.slice(-10);
    return (_jsx(Box, { borderStyle: "round", borderColor: "gray", paddingX: 1, overflowY: "hidden", children: _jsxs(Text, { wrap: "truncate", children: [_jsxs(Text, { color: "gray", children: [symbols.assistant, " artifacts "] }), visible.map((artifact, index) => (_jsxs(Text, { children: [index > 0 ? _jsx(Text, { color: "gray", children: "   " }) : null, _jsxs(Text, { color: artifact.origin === "created" ? "green" : "cyan", children: [attachmentSymbol(artifact.kind), " ", artifact.label] }), _jsx(Text, { color: "gray", children: artifact.origin === "created" ? " (new)" : "" })] }, artifact.id)))] }) }));
}
function ShellTranscript(props) {
    const rows = buildShellRows(props.lines, props.width);
    const [frame, setFrame] = useState(0);
    // Animate when a row is rainbow-tagged, or when any row spells an ultra
    // keyword — so submitted ultra keywords keep flowing their gradient.
    const hasRainbowRows = rows.some((row) => row.effect === "rainbow" || hasUltraMode(row.text));
    useEffect(() => {
        if (!hasRainbowRows) {
            setFrame(0);
            return;
        }
        const timer = setInterval(() => {
            setFrame((current) => current + 1);
        }, waveFrameMs);
        return () => {
            clearInterval(timer);
        };
    }, [hasRainbowRows]);
    const preferredBannerHeight = props.width >= 88 && props.height >= 20 ? 12 : 3;
    const bannerHeight = Math.max(0, Math.min(props.height - 2, preferredBannerHeight));
    const viewport = Math.max(1, props.height - 2);
    // The banner is part of the scrollable content — it sits above the first
    // transcript row and scrolls away like any other chat message.
    const total = bannerHeight + rows.length;
    const overflow = total > viewport;
    // Reserve one row for the scroll indicator when content overflows.
    const contentViewport = Math.max(1, overflow ? viewport - 1 : viewport);
    const window = windowRows(total, contentViewport, props.scrollOffset);
    // Slice the banner and the text rows out of the shared window.
    const bannerVisibleStart = Math.min(window.start, bannerHeight);
    const bannerVisibleEnd = Math.min(window.end, bannerHeight);
    const bannerVisible = Math.max(0, bannerVisibleEnd - bannerVisibleStart);
    const rowStart = Math.max(0, window.start - bannerHeight);
    const rowEnd = Math.max(0, window.end - bannerHeight);
    const visibleRows = rows.slice(rowStart, rowEnd);
    const borderColor = props.ultramaxxRun ? "magenta" : props.isRunning ? "yellow" : "cyan";
    return (_jsxs(Box, { borderStyle: "round", borderColor: borderColor, flexDirection: "column", paddingX: 1, height: props.height, overflowY: "hidden", children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: [bannerVisible > 0 ? (_jsx(Box, { height: bannerVisible, flexShrink: 0, overflowY: "hidden", children: _jsx(Box, { flexDirection: "column", marginTop: -bannerVisibleStart, children: _jsx(ExperimentalBanner, { width: props.width, height: bannerHeight }) }) })) : null, visibleRows.map((row, index) => _jsx(ShellRowView, { row: row, frame: frame }, `row-${index}`))] }), window.hasOverflow ? (_jsxs(Text, { color: "gray", children: [symbols.todoActive, " ", rowEnd > rowStart ? `${rowStart + 1}–${rowEnd}` : "banner", "/", rows.length, " \u00B7 \u2191\u2193 pgup/pgdn scroll"] })) : null] }));
}
function ShellRowView(props) {
    const symbolColor = props.row.symbolColor ?? props.row.color;
    const labelColor = props.row.labelColor ?? props.row.color;
    const textColor = props.row.textColor ?? props.row.color;
    return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: props.row.effect === "rainbow" && props.row.symbol ? (_jsx(RainbowText, { text: props.row.symbol, frame: props.frame, bold: props.row.bold })) : (_jsx(Text, { color: symbolColor, dimColor: props.row.dim, children: props.row.symbol })) }), _jsx(Box, { width: 12, marginRight: 1, children: props.row.effect === "rainbow" && props.row.label ? (_jsx(RainbowText, { text: props.row.label, frame: props.frame, bold: props.row.bold })) : (_jsx(Text, { color: labelColor, bold: props.row.bold, dimColor: props.row.dim, wrap: "truncate", children: props.row.label })) }), _jsx(Text, { color: textColor, dimColor: props.row.dim, wrap: "truncate", children: splitUltraSegments(props.row.text).map((segment, index) => segment.mode ? (_jsx(GradientText, { text: segment.text, palette: ultraGradients[segment.mode], frame: props.frame + index, bold: true }, `ultra-${index}`)) : (_jsx(Text, { children: segment.text }, `plain-${index}`))) })] }));
}
function ShellTodoDock(props) {
    const rows = buildTodoDock(props.todos, props.width, props.todoFrame);
    const completed = props.todos.filter((todo) => todo.status === "completed").length;
    const total = Math.max(1, props.todos.length);
    const barWidth = 14;
    const filled = Math.min(barWidth, Math.round((completed / total) * barWidth));
    const allDone = completed === props.todos.length;
    return (_jsxs(Box, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, height: props.height, overflowY: "hidden", children: [_jsxs(Box, { children: [_jsxs(Text, { color: "cyan", bold: true, children: [symbols.bullet, " todos", " "] }), _jsx(Text, { color: allDone ? "green" : "yellow", children: symbols.barFilled.repeat(filled) }), _jsx(Text, { color: "gray", dimColor: true, children: symbols.barEmpty.repeat(Math.max(0, barWidth - filled)) }), _jsxs(Text, { color: "gray", children: [" ", completed, "/", props.todos.length] })] }), rows.slice(1).map((row, index) => (_jsx(ShellRowView, { row: row, frame: props.todoFrame }, `todo-${index}`)))] }));
}
function ShellApproval(props) {
    if (props.bypassConfirmation) {
        return (_jsxs(Box, { borderStyle: "double", borderColor: "red", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { color: "red", bold: true, children: [symbols.approval, " ACTION REQUIRED \u00B7 trusted bypass"] }), _jsx(Text, { color: "white", children: "Write and shell tools will run without per-tool prompts for this session." }), _jsx(Text, { color: "gray", children: "Path guards and destructive-shell guards still apply." }), _jsxs(Text, { children: [_jsx(Text, { color: "green", bold: true, children: "[y]" }), _jsx(Text, { color: "gray", children: " accept bypass   " }), _jsx(Text, { color: "red", bold: true, children: "[n / esc]" }), _jsx(Text, { color: "gray", children: " stay build   " }), _jsx(Text, { color: "cyan", bold: true, children: "[tab]" }), _jsx(Text, { color: "gray", children: " back to plan" })] })] }));
    }
    const request = props.request;
    if (!request) {
        return _jsx(Box, {});
    }
    const target = approvalTarget(request.arguments);
    return (_jsxs(Box, { borderStyle: "double", borderColor: "yellow", flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { color: "yellow", bold: true, children: [symbols.approval, " APPROVAL \u00B7 ", request.tool] }), _jsxs(Text, { color: "gray", children: ["needs ", request.permission, " \u00B7 risk ", request.risk] })] }), _jsxs(Text, { color: "white", wrap: "truncate", children: [symbols.arrow, " ", request.preview] }), target ? (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "gray", children: target.kind === "command" || target.kind === "script" ? "$ " : "" }), _jsx(Text, { color: "cyan", wrap: "truncate", children: target.value })] })) : null, _jsxs(Text, { children: [_jsx(Text, { color: "green", bold: true, children: "[y]" }), _jsx(Text, { color: "gray", children: " allow once   " }), _jsx(Text, { color: "yellow", bold: true, children: "[a]" }), _jsx(Text, { color: "gray", children: " allow session   " }), _jsx(Text, { color: "red", bold: true, children: "[n / esc]" }), _jsx(Text, { color: "gray", children: " deny" })] })] }));
}
function ShellReauth(props) {
    const [frame, setFrame] = useState(0);
    useEffect(() => {
        if (!props.busy) {
            setFrame(0);
            return;
        }
        const timer = setInterval(() => {
            setFrame((current) => current + 1);
        }, spinnerFrameMs);
        return () => {
            clearInterval(timer);
        };
    }, [props.busy]);
    return (_jsxs(Box, { borderStyle: "round", borderColor: "yellow", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: [symbols.reauth, " GEMINI COOKIES EXPIRED"] }), props.busy ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "cyan", children: [_jsx(Text, { bold: true, children: spinnerGlyph(frame) }), " Refreshing Gemini browser cookies\u2026"] }), _jsx(Text, { color: "gray", children: "Importing from your signed-in browser. The prompt retries automatically on success." })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: "white", children: "Refresh the Gemini browser cookies and retry your last prompt automatically?" }), _jsx(Text, { color: "gray", children: "PatchPilot re-imports cookies from your signed-in browser. Secret values are not printed." }), _jsxs(Text, { children: [_jsx(Text, { color: "green", bold: true, children: "[y]" }), _jsx(Text, { color: "gray", children: " refresh & retry   " }), _jsx(Text, { color: "red", bold: true, children: "[n / esc]" }), _jsx(Text, { color: "gray", children: " dismiss" })] })] }))] }));
}
function ShellComposer(props) {
    const [frame, setFrame] = useState(0);
    const [runningSince, setRunningSince] = useState(null);
    const [verbSeed, setVerbSeed] = useState(() => randomRunStatusSeed());
    // Token totals captured at run start so the live counter shows tokens spent
    // *this run*, not the whole session — Claude-Code-style "(2m 0s · ↑ 6.1k)".
    const [runStartTokens, setRunStartTokens] = useState(null);
    const [cursor, setCursor] = useState(props.input.length);
    const layout = computeComposerLayout({
        input: props.input,
        width: props.width,
        promptWidth: 2,
        minHeight: 3,
        maxHeight: 7,
    });
    // Animate while running, and also while the draft contains an ultra keyword
    // so its gradient flows as you type.
    const animating = props.isRunning || hasUltraMode(props.input);
    useEffect(() => {
        if (!props.isRunning) {
            setRunningSince(null);
            setRunStartTokens(null);
        }
        else {
            setRunningSince((current) => {
                if (current === null) {
                    setVerbSeed(randomRunStatusSeed());
                    return Date.now();
                }
                return current;
            });
            setRunStartTokens((current) => current ?? { input: props.sessionTelemetry.promptTokens, output: props.sessionTelemetry.responseTokens });
        }
        if (!animating) {
            setFrame(0);
            return;
        }
        const timer = setInterval(() => {
            setFrame((current) => current + 1);
        }, waveFrameMs);
        return () => {
            clearInterval(timer);
        };
    }, [props.isRunning, animating]);
    // Keep the cursor valid when the draft is replaced from outside (submit,
    // slash-command fill, /clear).
    useEffect(() => {
        setCursor((current) => Math.min(current, props.input.length));
    }, [props.input]);
    const typingActive = !props.isRunning && !props.approvalActive;
    useInput((value, key) => {
        if (!typingActive) {
            return;
        }
        const safeCursor = Math.max(0, Math.min(cursor, props.input.length));
        if (key.return) {
            if (key.shift || key.meta || key.super) {
                const next = insertComposerText(props.input, safeCursor, "\n");
                props.onChange(next.input);
                setCursor(next.cursor);
                return;
            }
            props.onSubmit(props.input);
            return;
        }
        if (key.leftArrow) {
            setCursor(Math.max(0, safeCursor - 1));
            return;
        }
        if (key.rightArrow) {
            setCursor(Math.min(props.input.length, safeCursor + 1));
            return;
        }
        if (key.home || (key.ctrl && value === "a")) {
            setCursor(0);
            return;
        }
        if (key.end || (key.ctrl && value === "e")) {
            setCursor(props.input.length);
            return;
        }
        if (key.backspace) {
            const next = deleteComposerText(props.input, safeCursor, "backward");
            props.onChange(next.input);
            setCursor(next.cursor);
            return;
        }
        if (key.delete) {
            const next = deleteComposerText(props.input, safeCursor, "forward");
            props.onChange(next.input);
            setCursor(next.cursor);
            return;
        }
        if (key.tab || key.escape || key.upArrow || key.downArrow || key.pageUp || key.pageDown || key.ctrl || value.length === 0) {
            return;
        }
        // Normalise pasted text so a multi-line paste cannot corrupt the editor.
        const pasted = sanitizePastedText(value);
        // Pasted paths to images / documents become attachment chips.
        const attachmentPaths = extractAttachmentPaths(pasted);
        if (attachmentPaths) {
            const chip = `${attachmentPaths.map((path) => props.onAttach(path)).join(" ")} `;
            const next = insertComposerText(props.input, safeCursor, chip);
            props.onChange(next.input);
            setCursor(next.cursor);
            return;
        }
        const next = insertComposerText(props.input, safeCursor, pasted);
        props.onChange(next.input);
        setCursor(next.cursor);
    }, { isActive: typingActive });
    const elapsedMs = runningSince ? Date.now() - runningSince : 0;
    // Real token counter for the active run: cumulative provider-reported tokens
    // minus the totals captured when the run started. Works for every provider
    // because it reads the shared session telemetry, not provider internals.
    const runInputTokens = runStartTokens ? Math.max(0, props.sessionTelemetry.promptTokens - runStartTokens.input) : 0;
    const runOutputTokens = runStartTokens ? Math.max(0, props.sessionTelemetry.responseTokens - runStartTokens.output) : 0;
    const accent = props.isRunning ? (props.ultramaxxRun ? "magenta" : "yellow") : props.approvalActive ? "yellow" : "cyan";
    const parts = runStatusParts({ workState: props.workState, status: props.status, elapsedMs, seed: verbSeed });
    const safeCursor = Math.max(0, Math.min(cursor, props.input.length));
    const editorRows = layout.editorRows;
    const view = composerView(props.input, safeCursor, layout.inputWidth, editorRows);
    const showPlaceholder = props.input.length === 0;
    // The editor area always renders exactly `editorRows` rows so the composer's
    // real height matches the reserved layout height — no dead space anywhere.
    const editorContent = [];
    for (let index = 0; index < editorRows; index += 1) {
        if (props.isRunning && index === 0) {
            editorContent.push(_jsxs(Box, { children: [props.ultramaxxRun ? _jsx(RainbowText, { text: `${pulseGlyph(frame)} `, frame: frame, bold: true }) : (_jsxs(Text, { color: "cyan", bold: true, children: [pulseGlyph(frame), " "] })), props.ultramaxxRun ? (_jsx(RainbowText, { text: parts.verb, frame: frame, bold: true })) : (_jsx(WaveText, { text: parts.verb, frame: frame, bold: true })), _jsxs(Text, { color: "gray", children: ["  ·  ", parts.state, parts.detail ? ` · ${parts.detail}` : ""] }), _jsxs(Text, { color: "gray", children: ["  (", formatElapsed(elapsedMs), " · ", _jsxs(Text, { color: "cyan", children: ["\u2191 ", formatCompactTokens(runInputTokens)] }), _jsxs(Text, { color: "gray", children: [" \u2193 ", formatCompactTokens(runOutputTokens), " tokens"] }), ")"] })] }, "editor-run"));
        }
        else if (!props.isRunning && props.approvalActive && index === 0) {
            editorContent.push(_jsxs(Box, { children: [_jsxs(Text, { color: "yellow", bold: true, children: [symbols.approval, " approval waiting"] }), _jsx(Text, { color: "gray", children: " \u2014 respond above before typing" })] }, "editor-approval"));
        }
        else if (!props.isRunning && !props.approvalActive && showPlaceholder && index === 0) {
            editorContent.push(_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: "cyan", bold: true, children: symbols.user }) }), _jsx(Text, { inverse: true, children: " " }), _jsx(Text, { color: "gray", children: " Ask PatchPilot, or press / for commands\u2026" })] }, "editor-placeholder"));
        }
        else if (!props.isRunning && !props.approvalActive && !showPlaceholder && index < view.rows.length) {
            const row = view.rows[index] ?? "";
            editorContent.push(_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: "cyan", bold: true, children: index === 0 && view.hiddenAbove === 0 ? symbols.user : " " }) }), index === view.cursorRow ? (_jsx(ComposerCursorRow, { text: row, cursorCol: view.cursorCol, frame: frame })) : (_jsx(Text, { children: splitUltraSegments(row).map((segment, segmentIndex) => segment.mode ? (_jsx(GradientText, { text: segment.text, palette: ultraGradients[segment.mode], frame: index + segmentIndex, bold: true }, `seg-${segmentIndex}`)) : (_jsx(Text, { color: "white", children: segment.text }, `seg-${segmentIndex}`))) }))] }, `editor-${index}`));
        }
        else {
            editorContent.push(_jsx(Box, { height: 1 }, `editor-pad-${index}`));
        }
    }
    return (_jsxs(Box, { borderStyle: "round", borderColor: accent, flexDirection: "column", paddingX: 1, height: layout.height + 2, overflowY: "hidden", children: [_jsx(Box, { flexDirection: "column", height: editorRows, overflowY: "hidden", children: editorContent }), _jsx(Text, { color: "gray", wrap: "truncate", children: props.isRunning
                    ? props.ultramaxxRun
                        ? "ULTRAMAXX run — escalated reasoning & step budget · esc stops the run."
                        : "Run active — type /commands only, esc stops the run."
                    : props.approvalActive
                        ? "Approval pending — y once · a session · n deny."
                        : `${props.draftTokens} tok draft${view.hiddenAbove > 0 ? ` · ${view.hiddenAbove} line${view.hiddenAbove === 1 ? "" : "s"} above` : ""} · ←→ move · ⏎ send · shift+⏎ newline · type ultramaxx to go hard` })] }));
}
/** Render a composer text part, gradient-animated when it is an ultra keyword. */
function ComposerPart(props) {
    if (props.mode) {
        return _jsx(GradientText, { text: props.text, palette: ultraGradients[props.mode], frame: props.frame, bold: true });
    }
    return _jsx(Text, { color: "white", children: props.text });
}
/**
 * Render one composer row with the block cursor at the given column, keeping
 * ultra keywords gradient-coloured around the caret.
 */
function ComposerCursorRow(props) {
    const col = Math.max(0, Math.min(props.cursorCol, props.text.length));
    const segments = splitUltraSegments(props.text);
    const nodes = [];
    let pos = 0;
    let key = 0;
    for (const segment of segments) {
        const start = pos;
        const end = pos + segment.text.length;
        if (segment.text.length > 0 && col >= start && col < end) {
            const local = col - start;
            const before = segment.text.slice(0, local);
            const at = segment.text.slice(local, local + 1) || " ";
            const after = segment.text.slice(local + 1);
            if (before) {
                nodes.push(_jsx(ComposerPart, { text: before, mode: segment.mode, frame: props.frame }, `p-${key++}`));
            }
            nodes.push(_jsx(Text, { inverse: true, children: at }, `p-${key++}`));
            if (after) {
                nodes.push(_jsx(ComposerPart, { text: after, mode: segment.mode, frame: props.frame }, `p-${key++}`));
            }
        }
        else if (segment.text.length > 0) {
            nodes.push(_jsx(ComposerPart, { text: segment.text, mode: segment.mode, frame: props.frame }, `p-${key++}`));
        }
        pos = end;
    }
    if (col >= props.text.length) {
        nodes.push(_jsx(Text, { inverse: true, children: " " }, `p-${key++}`));
    }
    return _jsx(Text, { children: nodes });
}
function ShellFooter(props) {
    return (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { color: "gray", wrap: "truncate", children: [_jsx(Text, { color: "cyan", children: "tab" }), " plan/build/bypass ", _jsx(Text, { color: "gray", children: "\u00B7" }), " ", _jsx(Text, { color: "cyan", children: "/" }), " palette ", _jsx(Text, { color: "gray", children: "\u00B7" }), " ", _jsx(Text, { color: "cyan", children: "\u2191\u2193" }), " ", props.paletteOpen ? "pick" : "scroll", " ", _jsx(Text, { color: "gray", children: "\u00B7" }), " ", _jsx(Text, { color: "cyan", children: "esc" }), " ", props.paletteOpen ? "close" : "step stop / double force", " ", _jsx(Text, { color: "gray", children: "\u00B7" }), " ", _jsxs(Text, { color: "gray", children: ["mode ", props.agentMode] })] }) }));
}
function approvalTarget(args) {
    if (typeof args.path === "string" && args.path) {
        return { kind: "path", value: truncate(args.path, 64) };
    }
    if (typeof args.script === "string" && args.script) {
        return { kind: "script", value: truncate(args.script, 64) };
    }
    if (typeof args.command === "string" && args.command) {
        return { kind: "command", value: truncate(args.command, 64) };
    }
    return null;
}
//# sourceMappingURL=ExperimentalShell.js.map