import { matchesKey as tuiMatchesKey } from "@earendil-works/pi-tui";
export const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
export const ANIMATION_FRAME_MS = 80;
export const STREAMING_RENDER_THROTTLE_MS = 80;
const STREAMING_TEXT_TAIL_LINES = 240;
const STREAMING_TEXT_TAIL_CHARS = 16_000;
export function matchesKey(data, key) {
    if (key === "enter" && (data === "\r" || data === "\n"))
        return true;
    if (key === "backspace" && (data === "\x7f" || data === "\b"))
        return true;
    if (key === "escape" && data === "\x1b")
        return true;
    if (key === "ctrl+f" && data === "\x06")
        return true;
    return tuiMatchesKey(data, key);
}
export function parseBashInput(text) {
    if (!text.startsWith("!"))
        return undefined;
    const excludeFromContext = text.startsWith("!!");
    const command = text.slice(excludeFromContext ? 2 : 1).trim();
    return { command, excludeFromContext };
}
export function cacheKey(parts) {
    return JSON.stringify(parts);
}
export function isChatMessageEntry(entry) {
    if (!("role" in entry) || !("kind" in entry))
        return false;
    const candidate = entry;
    switch (candidate.kind) {
        case "assistant":
            return candidate.role === "assistant" && candidate.message !== undefined;
        case "tool":
            return candidate.role === "tool" && "toolName" in candidate && "toolCallId" in candidate && "args" in candidate;
        case "bashExecution":
            return candidate.role === "tool" && candidate.message !== undefined;
        case "user":
            return candidate.role === "user" && typeof candidate.text === "string";
        case "custom":
            return candidate.role === "custom" && candidate.message !== undefined;
        case "branchSummary":
            return candidate.role === "summary" && candidate.message !== undefined;
        case "system":
            return candidate.role === "system" && candidate.message !== undefined;
        default:
            return false;
    }
}
export function isMessageLike(message) {
    return message !== null && typeof message === "object" && "role" in message;
}
export function isUserMessageLike(message) {
    return isMessageLike(message) && message.role === "user";
}
export function userMessageSignature(text) {
    return text.trim();
}
export function extractMessageText(content) {
    if (typeof content === "string")
        return content;
    if (!Array.isArray(content))
        return "";
    const parts = [];
    for (const item of content) {
        if (item == null)
            continue;
        if (typeof item === "string") {
            parts.push(item);
            continue;
        }
        const obj = item;
        if (typeof obj.text === "string")
            parts.push(obj.text);
        else if (obj.type === "text" && typeof obj.text === "string")
            parts.push(obj.text);
    }
    return parts.join("");
}
export function tailStreamingText(text) {
    if (text.length <= STREAMING_TEXT_TAIL_CHARS &&
        text.split("\n").length <= STREAMING_TEXT_TAIL_LINES) {
        return text;
    }
    const byChars = text.slice(-STREAMING_TEXT_TAIL_CHARS);
    const lines = byChars.split("\n");
    const tail = lines.length > STREAMING_TEXT_TAIL_LINES
        ? lines.slice(-STREAMING_TEXT_TAIL_LINES).join("\n")
        : byChars;
    return `[earlier streaming output hidden while attached]\n\n${tail.trimStart()}`;
}
export function spinnerFrame() {
    const idx = Math.floor(Date.now() / ANIMATION_FRAME_MS) % SPINNER_FRAMES.length;
    return SPINNER_FRAMES[idx];
}
export function stripAnsi(s) {
    return s.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "");
}
export function errorMessage(error) {
    return error instanceof Error ? error.message : String(error);
}
//# sourceMappingURL=chat-session-host-utils.js.map