"use strict";
/**
 * Common CLI tool patterns for response detection
 * Shared between response-poller.ts and API routes
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.GEMINI_PROMPT_PATTERN = exports.MAX_PASTED_TEXT_RETRIES = exports.PASTED_TEXT_DETECT_DELAY = exports.PASTED_TEXT_PATTERN = exports.CODEX_SEPARATOR_PATTERN = exports.CODEX_PROMPT_PATTERN = exports.CLAUDE_TRUST_DIALOG_PATTERN = exports.CLAUDE_SEPARATOR_PATTERN = exports.CLAUDE_PROMPT_PATTERN = exports.CODEX_THINKING_PATTERN = exports.CLAUDE_THINKING_PATTERN = exports.CLAUDE_SPINNER_CHARS = void 0;
exports.detectThinking = detectThinking;
exports.getCliToolPatterns = getCliToolPatterns;
exports.stripAnsi = stripAnsi;
exports.buildDetectPromptOptions = buildDetectPromptOptions;
const logger_1 = require("./logger");
const logger = (0, logger_1.createLogger)('cli-patterns');
/**
 * Claude CLI spinner characters (expanded set)
 * These are shown when Claude is thinking/processing
 */
exports.CLAUDE_SPINNER_CHARS = [
    '✻', '✽', '⏺', '·', '∴', '✢', '✳', '✶',
    '⦿', '◉', '●', '○', '◌', '◎', '⊙', '⊚',
    '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏', // Braille spinner
];
/**
 * Claude thinking pattern
 * Matches spinner character followed by activity text ending with …
 * The text can contain spaces (e.g., "Verifying implementation (dead code detection)…")
 *
 * Alternative 2: "esc to interrupt" status bar text (Issue #XXX)
 * Claude Code shows "esc to interrupt" in the terminal status bar during active processing.
 * Previous pattern required closing paren `to interrupt\)` matching `(esc to interrupt)`,
 * but Claude Code v2.x status bar format uses `· esc to interrupt ·` without parens.
 * Updated to match `esc to interrupt` which covers both formats.
 */
exports.CLAUDE_THINKING_PATTERN = new RegExp(`[${exports.CLAUDE_SPINNER_CHARS.join('')}]\\s+.+…|esc to interrupt`, 'm');
/**
 * Codex thinking pattern
 * Matches activity indicators like "• Planning", "• Searching", etc.
 * T1.1: Extended to include "Ran" and "Deciding"
 */
exports.CODEX_THINKING_PATTERN = /•\s*(Planning|Searching|Exploring|Running|Thinking|Working|Reading|Writing|Analyzing|Ran|Deciding)/m;
/**
 * Claude prompt pattern (waiting for input)
 * Supports both legacy '>' and new '❯' (U+276F) prompt characters
 * Issue #132: Also matches prompts with recommended commands (e.g., "❯ /work-plan")
 *
 * Matches:
 * - Empty prompt: "❯ " or "> "
 * - Prompt with command: "❯ /work-plan" or "> npm install"
 */
exports.CLAUDE_PROMPT_PATTERN = /^[>❯](\s*$|\s+\S)/m;
/**
 * Claude separator pattern
 */
exports.CLAUDE_SEPARATOR_PATTERN = /^─{10,}$/m;
/**
 * Claude trust dialog pattern (Issue #201)
 *
 * Matches the "Quick safety check" dialog displayed by Claude CLI v2.x
 * when accessing a workspace for the first time.
 *
 * Intentionally uses partial matching (no line-start anchor ^):
 * Other pattern constants (CLAUDE_PROMPT_PATTERN, CLAUDE_SEPARATOR_PATTERN, etc.)
 * use line-start anchors (^), but this pattern needs to match at any position
 * within the tmux output buffer because the dialog text may appear after
 * tmux padding or other output. (SF-001)
 */
exports.CLAUDE_TRUST_DIALOG_PATTERN = /Yes, I trust this folder/m;
/**
 * Codex prompt pattern
 * T1.2: Improved to detect empty prompts as well
 */
exports.CODEX_PROMPT_PATTERN = /^›\s*/m;
/**
 * Codex separator pattern
 */
exports.CODEX_SEPARATOR_PATTERN = /^─.*Worked for.*─+$/m;
/**
 * Pasted text pattern
 *
 * Claude CLI displays this when it detects multi-line text paste in the
 * ink-based TextInput. The pattern matches the folded display format.
 *
 * @example "[Pasted text #1 +46 lines]"
 * @see Issue #212, #163
 * @designNote PASTE-001: Pattern matches the start of the indicator only.
 *   The line count (+XX lines) is variable, so we match the fixed prefix
 *   to minimize false negatives. False positive risk is low because
 *   "[Pasted text #" is a unique format generated by Claude CLI's ink renderer.
 * @designNote PASTE-001-FP (SF-S4-002): When used in skipPatterns,
 *   line-level matching could filter legitimate response lines if Claude's
 *   answer text happens to contain "[Pasted text #". This is unlikely and
 *   acceptable -- only the affected line would be lost.
 */
exports.PASTED_TEXT_PATTERN = /\[Pasted text #\d+/;
/**
 * Pasted text detection delay (milliseconds)
 *
 * Wait time after sendKeys for tmux buffer to reflect [Pasted text] display.
 *
 * @see Issue #212
 * @designNote PASTE-002: 500ms is the empirically measured time for
 *   Claude CLI's ink rendering to complete. capturePane({ startLine: -10 })
 *   reads only the last 10 lines since [Pasted text] appears in the most
 *   recent few lines.
 */
exports.PASTED_TEXT_DETECT_DELAY = 500;
/**
 * Pasted text detection max retries
 *
 * @see Issue #212
 * @designNote PASTE-003: 3 retries x 500ms = max 1500ms additional delay.
 *   Typically resolves on the first attempt (+500ms).
 */
exports.MAX_PASTED_TEXT_RETRIES = 3;
/**
 * Gemini shell prompt pattern
 */
exports.GEMINI_PROMPT_PATTERN = /^(%|\$|.*@.*[%$#])\s*$/m;
/**
 * Detect if CLI tool is showing "thinking" indicator
 */
function detectThinking(cliToolId, content) {
    const log = logger.withContext({ cliToolId });
    log.debug('detectThinking:check', { contentLength: content.length });
    let result;
    switch (cliToolId) {
        case 'claude':
            result = exports.CLAUDE_THINKING_PATTERN.test(content);
            break;
        case 'codex':
            result = exports.CODEX_THINKING_PATTERN.test(content);
            break;
        case 'gemini':
            // Gemini doesn't have a thinking indicator in one-shot mode
            result = false;
            break;
        default:
            result = exports.CLAUDE_THINKING_PATTERN.test(content);
    }
    log.debug('detectThinking:result', { isThinking: result });
    return result;
}
/**
 * Get CLI tool patterns for response extraction
 */
function getCliToolPatterns(cliToolId) {
    switch (cliToolId) {
        case 'claude':
            return {
                promptPattern: exports.CLAUDE_PROMPT_PATTERN,
                separatorPattern: exports.CLAUDE_SEPARATOR_PATTERN,
                thinkingPattern: exports.CLAUDE_THINKING_PATTERN,
                skipPatterns: [
                    /^─{10,}$/, // Separator lines
                    /^[>❯]\s*$/, // Prompt line (legacy '>' and new '❯')
                    exports.CLAUDE_THINKING_PATTERN, // Thinking indicators
                    /^\s*[⎿⏋]\s+Tip:/, // Tip lines
                    /^\s*Tip:/, // Tip lines
                    /^\s*\?\s*for shortcuts/, // Shortcuts hint
                    /to interrupt\)/, // Part of "esc to interrupt" message
                    exports.PASTED_TEXT_PATTERN, // [Pasted text #N +XX lines] (Issue #212)
                ],
            };
        case 'codex':
            return {
                promptPattern: exports.CODEX_PROMPT_PATTERN,
                separatorPattern: exports.CODEX_SEPARATOR_PATTERN,
                thinkingPattern: exports.CODEX_THINKING_PATTERN,
                skipPatterns: [
                    /^─.*─+$/, // Separator lines
                    /^›\s*$/, // Empty prompt line
                    /^›\s+(Implement|Find and fix|Type)/, // New prompt suggestions
                    exports.CODEX_THINKING_PATTERN, // Activity indicators
                    /^\s*\d+%\s+context left/, // Context indicator
                    /^\s*for shortcuts$/, // Shortcuts hint
                    /╭─+╮/, // Box drawing (top)
                    /╰─+╯/, // Box drawing (bottom)
                    // T1.3: Additional skip patterns for Codex
                    /•\s*Ran\s+/, // Command execution lines
                    /^\s*└/, // Tree output (completion indicator)
                    /^\s*│/, // Continuation lines
                    /\(.*esc to interrupt\)/, // Interrupt hint
                    exports.PASTED_TEXT_PATTERN, // [Pasted text #N +XX lines] (Issue #212, defensive)
                ],
            };
        case 'gemini':
            return {
                promptPattern: exports.GEMINI_PROMPT_PATTERN,
                separatorPattern: /^gemini\s+--\s+/m,
                thinkingPattern: /(?!)/m, // Never matches - one-shot execution
                skipPatterns: [
                    /^gemini\s+--\s+/, // Command line itself
                    exports.GEMINI_PROMPT_PATTERN, // Shell prompt lines
                    /^\s*$/, // Empty lines
                ],
            };
        default:
            // Default to Claude patterns
            return getCliToolPatterns('claude');
    }
}
/**
 * Strip ANSI escape codes from a string.
 * Optimized version at module level for performance.
 *
 * Covers:
 * - SGR sequences: ESC[Nm (colors, bold, underline, etc.)
 * - OSC sequences: ESC]...BEL (window title, hyperlinks, etc.)
 * - CSI sequences: ESC[...letter (cursor movement, erase, etc.)
 *
 * Known limitations (SEC-002):
 * - 8-bit CSI (0x9B): C1 control code form of CSI is not covered
 * - DEC private modes: ESC[?25h and similar are not covered
 * - Character set switching: ESC(0, ESC(B are not covered
 * - Some RGB color forms: ESC[38;2;r;g;bm may not be fully matched
 *
 * In practice, tmux capture-pane output rarely contains these sequences,
 * so the risk is low. Future consideration: adopt the `strip-ansi` npm package
 * for more comprehensive coverage.
 */
const ANSI_PATTERN = /\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\[[0-9;]*m/g;
function stripAnsi(str) {
    return str.replace(ANSI_PATTERN, '');
}
/**
 * Build DetectPromptOptions for a given CLI tool.
 * Centralizes cliToolId-to-options mapping logic (DRY - MF-001).
 *
 * prompt-detector.ts remains CLI tool independent (Issue #161 principle);
 * this function lives in cli-patterns.ts which already depends on CLIToolType.
 *
 * [Future extension memo (C-002)]
 * If CLI tool count grows significantly (currently 3), consider migrating
 * to a CLIToolConfig registry pattern where tool-specific settings
 * (including promptDetectionOptions) are managed in a Record<CLIToolType, CLIToolConfig>.
 *
 * @param cliToolId - CLI tool identifier
 * @returns DetectPromptOptions for the tool, or undefined for default behavior
 */
function buildDetectPromptOptions(cliToolId) {
    if (cliToolId === 'claude') {
        return { requireDefaultIndicator: false };
    }
    return undefined; // Default behavior (requireDefaultIndicator = true)
}
