"use strict";
/**
 * Vibe Local CLI tool implementation
 * Provides integration with vibe-local (vibe-coder) in interactive mode
 *
 * @remarks Issue #368: Rewritten from non-interactive pipe mode to interactive REPL mode.
 * Previous implementation used `echo 'msg' | vibe-local` which caused the process to exit
 * immediately with "(Cancelled)" + "Goodbye!", making response polling impossible.
 * Now launches `vibe-local -y` in interactive mode within tmux (same approach as Claude/Codex/Gemini).
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.VibeLocalTool = void 0;
const base_1 = require("./base");
const types_1 = require("./types");
const tmux_1 = require("../tmux/tmux");
const pasted_text_helper_1 = require("../pasted-text-helper");
const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
const db_instance_1 = require("../db-instance");
const db_1 = require("../db");
const logger_1 = require("../../lib/logger");
const logger = (0, logger_1.createLogger)('cli-tools/vibe-local');
/**
 * Extract error message from unknown error type (DRY)
 */
function getErrorMessage(error) {
    return error instanceof Error ? error.message : String(error);
}
/**
 * Wait for vibe-local to initialize after launch.
 * vibe-local shows a permission check prompt, banner, and model loading.
 */
const VIBE_LOCAL_INIT_WAIT_MS = 5000;
/**
 * Vibe Local CLI tool implementation
 * Manages vibe-local interactive sessions using tmux
 */
class VibeLocalTool extends base_1.BaseCLITool {
    id = 'vibe-local';
    name = 'Vibe Local';
    command = 'vibe-local';
    /**
     * Check if vibe-local session is running for a worktree
     */
    async isRunning(worktreeId) {
        const sessionName = this.getSessionName(worktreeId);
        return await (0, tmux_1.hasSession)(sessionName);
    }
    /**
     * Start a new vibe-local session for a worktree
     * Launches `vibe-local -y` in interactive mode within tmux
     *
     * @param worktreeId - Worktree ID
     * @param worktreePath - Worktree path
     */
    async startSession(worktreeId, worktreePath) {
        const vibeLocalAvailable = await this.isInstalled();
        if (!vibeLocalAvailable) {
            throw new Error('vibe-local is not installed or not in PATH');
        }
        const sessionName = this.getSessionName(worktreeId);
        const exists = await (0, tmux_1.hasSession)(sessionName);
        if (exists) {
            logger.info('vibe-local-session');
            return;
        }
        try {
            // Create tmux session with large history buffer
            await (0, tmux_1.createSession)({
                sessionName,
                workingDirectory: worktreePath,
                historyLimit: 50000,
            });
            // Wait a moment for the session to be created
            await new Promise((resolve) => setTimeout(resolve, 100));
            // Read Ollama model and context window preferences from DB
            // [SEC-001] Re-validate model name at point of use (defense-in-depth)
            // [S1-005] DB direct access follows existing vibeLocalModel pattern;
            // future DIP refactoring should pass these as startSession() arguments.
            let vibeLocalCommand = 'vibe-local -y';
            try {
                const db = (0, db_instance_1.getDbInstance)();
                const wt = (0, db_1.getWorktreeById)(db, worktreeId);
                if (wt?.vibeLocalModel && types_1.OLLAMA_MODEL_PATTERN.test(wt.vibeLocalModel)) {
                    vibeLocalCommand += ` -m ${wt.vibeLocalModel}`;
                }
                // [C2-008] contextWindow from the same wt object (no additional DB call)
                const ctxWindow = wt?.vibeLocalContextWindow;
                // [SEC-002] Defense-in-depth: re-validate at point of use
                // [S4-001] Number() cast for additional safety in template literal
                if ((0, types_1.isValidVibeLocalContextWindow)(ctxWindow)) {
                    vibeLocalCommand += ` --context-window ${Number(ctxWindow)}`;
                }
            }
            catch {
                // DB read failure is non-fatal; use defaults
            }
            // Start vibe-local in interactive mode with auto-approve (-y)
            // -y flag skips the permission confirmation prompt
            await (0, tmux_1.sendKeys)(sessionName, vibeLocalCommand, true);
            // Wait for vibe-local to initialize (banner + model loading)
            await new Promise((resolve) => setTimeout(resolve, VIBE_LOCAL_INIT_WAIT_MS));
            logger.info('started-vibe-local-session:sessionname');
        }
        catch (error) {
            const errorMessage = getErrorMessage(error);
            throw new Error(`Failed to start Vibe Local session: ${errorMessage}`);
        }
    }
    /**
     * Send a message to vibe-local interactive session
     *
     * @param worktreeId - Worktree ID
     * @param message - Message to send
     */
    async sendMessage(worktreeId, message) {
        const sessionName = this.getSessionName(worktreeId);
        const exists = await (0, tmux_1.hasSession)(sessionName);
        if (!exists) {
            throw new Error(`Vibe Local session ${sessionName} does not exist. Start the session first.`);
        }
        try {
            // Send message to vibe-local (without Enter)
            await (0, tmux_1.sendKeys)(sessionName, message, false);
            // Wait a moment for the text to be typed
            await new Promise((resolve) => setTimeout(resolve, 100));
            // vibe-local uses IME mode: first Enter creates a new line,
            // second Enter on empty line submits the message.
            // Send Enter twice with a short delay between.
            await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
            await new Promise((resolve) => setTimeout(resolve, 200));
            await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
            // Wait a moment for the message to be processed
            await new Promise((resolve) => setTimeout(resolve, 200));
            // Detect [Pasted text] and resend Enter for multi-line messages
            if (message.includes('\n')) {
                await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
            }
            // Issue #405: Invalidate cache after sending message
            (0, tmux_capture_cache_1.invalidateCache)(sessionName);
            logger.info('sent-message-to-vibe-local-session:sessi');
        }
        catch (error) {
            const errorMessage = getErrorMessage(error);
            throw new Error(`Failed to send message to Vibe Local: ${errorMessage}`);
        }
    }
    /**
     * Kill vibe-local session
     *
     * @param worktreeId - Worktree ID
     */
    async killSession(worktreeId) {
        const sessionName = this.getSessionName(worktreeId);
        try {
            const exists = await (0, tmux_1.hasSession)(sessionName);
            if (exists) {
                // Send Ctrl+C to interrupt any running operation
                await (0, tmux_1.sendSpecialKey)(sessionName, 'C-c');
                await new Promise((resolve) => setTimeout(resolve, 300));
                // Send Ctrl+C again to ensure exit
                await (0, tmux_1.sendSpecialKey)(sessionName, 'C-c');
                await new Promise((resolve) => setTimeout(resolve, 500));
            }
            // Kill the tmux session
            const killed = await (0, tmux_1.killSession)(sessionName);
            if (killed) {
                logger.info('stopped-vibe-local-session:sessionname');
            }
        }
        catch (error) {
            logger.error('session:stop-failed', { error: getErrorMessage(error) });
            throw error;
        }
    }
}
exports.VibeLocalTool = VibeLocalTool;
